kisChang / stm32dfu

STM32 DFU Lib And Example
https://kischang.github.io/stm32dfu/example/
MIT License
2 stars 0 forks source link

Example is not working #1

Open EG-Julien opened 1 month ago

EG-Julien commented 1 month ago

Hello, I'm trying to implement DFU in my react project.

I've tried a lot of different things without any success.

My code:

import React, { Component } from 'react';
import stm32dfu from 'stm32dfu';

import { Buffer } from "buffer"

class DfuUploader extends Component {
  constructor(props) {
    super(props);
    this.state = {
      dfuImage: null,
      error: null,
      loading: true,
      deviceSettings: null,
    };
    this.flashFirmware = this.flashFirmware.bind(this);
    this.initializeDevice = this.initializeDevice.bind(this);
  }

  async componentDidMount() {
    await this.fetchDfuFile();
  }

  async fetchDfuFile() {
    try {
      const response = await fetch('/public/firmwares/firmware.bin');

      if (!response.ok) {
        throw new Error('Network response was not ok');
      }

      const fileBlob = await response.blob();
      console.log('File Blob:', fileBlob);

      const arrayBuffer = await fileBlob.arrayBuffer().then();
      console.log('Array Buffer:', arrayBuffer);

      if (!arrayBuffer) {
        throw new Error('Failed to convert Blob to ArrayBuffer');
      }

      // Pass the Uint8Array to parseDfuImage
      const parsedDfuImage = stm32dfu.parseDfuImage(arrayBuffer);
      console.log('Parsed DFU Image:', parsedDfuImage);

      this.setState({
        dfuImage: parsedDfuImage,
        loading: false,
      });
    } catch (error) {
      console.error('Error fetching or parsing DFU file:', error);
      this.setState({
        error: error.message,
        loading: false,
      });
    }
  }

  async initializeDevice() {
    try {
      const deviceSettings = await stm32dfu.findAllStm32Device(0x0483); // Replace with the actual vendorId

      if (!deviceSettings.length) {
        throw new Error('No STM32 devices found');
      }

      const device = await stm32dfu.getDfu(deviceSettings[0].device, deviceSettings[0]);

      this.setState({ deviceSettings, device });
    } catch (error) {
      console.error('Error initializing device:', error);
      this.setState({
        error: error.message,
      });
    }
  }

  async flashFirmware() {
    const { deviceSettings, dfuImage } = this.state;

    if (!deviceSettings || !dfuImage) {
      console.error('Device settings or DFU image is not available.');
      return;
    }

    const flashSetting = {
      logger: {
        debug: (...data) => { console.log(data); },
        info: (...data) => { console.log(data); },
        warn: (...data) => { console.log(data); },
        error: (...data) => { console.log(data); },
      },
      handler: (done, total) => {
        console.log(`${done} / ${total}`);
      },
    };

    try {
      await stm32dfu.flash(deviceSettings[0], dfuImage, flashSetting);
      console.log('Firmware flashed successfully!');
    } catch (error) {
      console.error('Error flashing firmware:', error);
    }
  }

  render() {
    const { error, loading } = this.state;

    return (
      <div>
        <h1>DFU Uploader</h1>
        {error ? (
          <p>Error: {error}</p>
        ) : loading ? (
          <p>Loading DFU file...</p>
        ) : (
          <div>
            <p>DFU Image successfully parsed!</p>
            <button onClick={this.initializeDevice}>Initialize Device</button>
            <button onClick={this.flashFirmware}>Flash Firmware</button>
          </div>
        )}
      </div>
    );
  }
}

export default DfuUploader;

I'm always getting this error : Error: e2.slice(...).readInt32LE is not a function ... I'm pretty sure I missed something, but I can't find out. I'm guessing that my firmwareFile is not in the correct buffer format to pass it but idk ... Does one have an idea ?

Thanks.

kisChang commented 1 month ago

This code is from long time ago, I can't remember many details....

From the error message, it seems that stm32dfu.parseDfuImage did not work. Because it receives Buffer(NodeJS) and you pass in ArrayBuffer(Brower JavaScript). ArrayBuffer does not have a readInt32LE method. You can try

let buffer = Buffer.from(arrayBuffer);
stm32dfu.parseDfuImage(buffer);
EG-Julien commented 1 month ago

Hello, Yes but it was one of the only one with a working demo ...

Thanks for the tips, indeed it worked but unfortunately the "parseDfuImage" method make the app crash (out of memory).

The firmware file that I use for testing is something like 62KB ... It work just fine with the demo.

How the demo is working ? It didn't utilize the librairy, did it ?

kisChang commented 1 month ago

No time to modify the demo🤣🤣🤣 so ”change demo “ on TODO list

Reply 1 In addition, does the code you mentioned work well in my demo(https://kischang.top/stm32dfu/example/)? It seems that my stm32dfu is not used in the demo You can study the specific code logic of the demo(on dfu-util.js).

Reply 2 on my real project like this (woring fine):

const reader = new FileReader()
reader.onload = () => {
  this.dfuImg = stm32dfu.parseDfuImage(Buffer.from(reader.result))
  this.flashEx5Once_byFile(this.dfuImg, efile.name)
}
reader.readAsArrayBuffer(efile)
function flashEx5Once_byFile (fwData, fwVersion) {
let devNum = this.devNum_now

this.index = 4
this.clearLog()
this.appendFlashLog('开始刷入固件')
this.appendFlashLog(`固件版本:${fwVersion}`)
this.dfuList = await stm32dfu.findAllStm32Device(0x0483);

let deviceSetting = this.dfuList[devNum];
let set = {
  logger : {
    debug: (...data) => {this.appendFlashLog(data)},
    info: (...data) => {this.appendFlashLog(data)},
    warn: (...data) => {this.appendFlashLog(data)},
    error: (...data) => {this.appendFlashLog(data)},
  },
  handler: (done, total) => {
    this.progressIndex = done;
    this.progressMax = total;
    this.appendFlashLog(`${done} / ${total}\n`)
  }
};
stm32dfu.flash(deviceSetting, fwData, set)
.then((code) => {
  if (code) {
    this.appendFlashLog('\n固件刷入成功!\n')
    this.index = 5
  } else {
    this.appendFlashLog('\n固件刷入失败\n')
  }
}).catch(err => {
  this.appendFlashLog('\n固件刷入失败: ' + err + '\n')
  this.appendFlashLog('\n如果固件有读写保护,请先尝试执行关闭读写保护,再重新连接至PC后再次尝试刷入固件\n')
})
},

But your problem is ”out of memory“ 62kb It should not be out of memory (my firmware img 300kb+)

I think you can step through the debugger to find the cause.

EG-Julien commented 1 month ago

Hello, Yes don't worry I'm not asking you to modify the demo, It's just boring since I'm really close to make it works (well ... I hope).

In addition, does the code you mentioned work well in my demo ?

Sounds like you modified something in your exemple, it was working few days ago ... It misses the stm32dfu lib : GET https://kischang.top/stm32dfu/dist/stm32dfu.js net::ERR_ABORTED 404 (Not Found)

I tried with different file and it appears that the parseDfuImage is crashing on .bin file but is working great on .elf file. In the demo it was working fine with both file type.

on my real project like this (woring fine):

I dug a bit deeper in the dfu-utils.js and the lib. It seems that my main problem is not related to the file but I'm not able to fetch the memory correctly from the device. I'm able to read the interfaces, but I can't retrieve memory information from it.

CleanShot 2024-07-17 at 11 05 10@2x

At the bottom of the image, in interface -> name I should have @Internal Flash /0x08000000/128*0002Kg but it's empty. Which return an error since the lib is trying to extract start addr and memory size from the name. I can't understand why it can't get the name ... Could it be cause I'm using React with Vite ?

Here is my code, pretty close to yours ....

const [dfuList, setDfuList] = useState([]);
    const [dfuImg, setDfuImg] = useState(null);

    const fileChange = (event) => {
        const file = event.target.files[0];
        if (file)
        {
            const reader = new FileReader();
            reader.onload = () => {
                const dfuImage = stm32dfu.parseDfuImage(Buffer.from(reader.result));
                setDfuImg(dfuImage);
                flash(dfuImage, file.name)
            };

            reader.readAsArrayBuffer(file);
        }
    }

    const flash = async (fwData, fwVersion) => {
        const devices = await stm32dfu.DFU.findDeviceDfuInterfaces(0x0483); // STM32 Bootloader vendorID
        setDfuList(devices);

        console.log("fileData " + fwVersion + " : ", fwData)
        console.log("devices : ", devices);

        const deviceSettings = devices[0];

        let set = {
            logger: {
                debug: (...data) => console.log(data),
                info: (...data) => console.log(data),
                warn: (...data) => console.log(data),
                error: (...data) => console.log(data),
            },
            handler: (done, total) => {
                console.log(`Progress : ${done} / ${total}`);
            },
        };

        const code = await stm32dfu.flash(deviceSettings, fwData, set);

        if (code)
        {
            console.log(code);
        } else
        {
            console.error(code);
        }
    }