DFU Process

Handling a software update is done through READ_DFU and WRITE_DFU function.

The following Interrupt lines must be used to derive the state:

  • DFU_START_IRQ
  • DFU_PACKET_IRQ
  • DFU_STOP_IRQ

Whenever a software update is triggered, the DFU_START_IRQ goes high.

Then the fixture must get ready for receiving firmware. One of the following responses of the Fixture is required:

  • 0x0: DFU_ACCEPT
  • 0x1 – 0xFF: DFU_ABORT

A fixture responds by using WRITE_DFU function. The Timeout for the response is set to 20 seconds. Writing a response will disable the DFU_START_IRQ flag.

After accepting the DFU, the Vision Controller starts to send firmware packets. Each packet has a unique id which is counted upwards. Length is variable up to 200Byte. Default length is 128 Byte. packetNr is stored in Big Endian not Little Endian!

data[0]data[1]data[2]data[2]...data[202]
packetNrpacketNrdata[0]dmx[1]...dmx[200]

After reading the packet, the next packet will be transfered automatically. No extra response necessary.

If there occurs an error it is possible to abort the DFU early by writing a response greater than 0 (0x1 – 0xFF).

DFU is aborted if no packet is read for 30 seconds. It can take up to 30 seconds before the first packet arrives. Please make sure not to abort before this timeout.

After receiving the last packet, DFU_STOP_IRQ flag will go high in order to signal that all packets are transfered and DFU transmission is finished.

Now a last response from the fixture is required. The response should be one of the following:

  • 0x0: DFU_SUCCESS
  • 0x1: DFU_ERROR_FLASH_ERASE
  • 0x2: DFU_ERROR_NOT_IN_PROGRESS
  • 0x3: DFU_ERROR_CORRUPTED_HEADER
  • 0x4: DFU_ERROR_CORRUPTED_IMAGE
  • 0x5: DFU_ERROR_INVALID_IMAGE_VERSION
  • 0x6: DFU_ERROR_NO_PREAMBLE
  • 0x7: DFU_ERROR_INVALID_FIXTURE_ID
  • 0x8: DFU_ERROR_UNKNOWN
  • 0x9: DFU_ERROR_SIGNATURE_NECESSARY_NOT_FOUND
  • 0x0A: DFU_ERROR_PACKET_TIMEOUT
  • 0x0B – 0xFF: Reserved

Here is an pseudo code example for receiving the data via the application firmware instead of using a boot-loader to receive the data as the example provides it:

#define DFU_BOOT_DELAY_MS     1000
#define MAX_FIRMWARE_SIZE     (256 * 1024u) // example

typedef enum
{
    DFU_STATE_IDLE = 0,
    DFU_STATE_RECEIVING,
    DFU_STATE_ERROR,
    DFU_STATE_BOOT_PENDING
} dfu_state_t;

static dfu_state_t dfuState = DFU_STATE_IDLE;
static uint32_t dfuDataCounter = 0;
static uint16_t dfuPacketCounter = 0;

static uint8_t firmwareData[MAX_FIRMWARE_SIZE]; // Just dummy, use flash to write here
 
static void Dfu_Reset(void)
{
    dfuState = DFU_STATE_IDLE;
    dfuDataCounter = 0;
    dfuPacketCounter = 0;
}

static void Dfu_Abort(uint8_t errorCode)
{
    vision_writeDfu(errorCode);
    Dfu_Reset();
}

static bool Dfu_StoragePrepare(void)
{
    // Erase temporary DFU flash area here.
    // Return false if erase failed.
    return true;
}

static bool Dfu_StorageWrite(uint32_t offset, const uint8_t *data, uint16_t length)
{
    // Write data to temporary DFU flash area.
    // Handle flash alignment here.
    // Return false if flash write failed.
    (void)offset;
    (void)data;
    (void)length;

    return true;
}

static bool Dfu_CheckFirmwareDataValid(uint32_t imageSize)
{
    if (imageSize == 0)
    {
        return false;
    }

    if (imageSize > MAX_FIRMWARE_SIZE)
    {
        return false;
    }

    // Recommended checks:
    // - image header valid
    // - target device / hardware ID valid
    // - firmware size valid
    // - CRC/hash valid
    // - version valid
    //
    // Final signature/security validation should also be done by bootloader.

    return true;
}

static void Dfu_StartBootloaderTimer(void)
{
    // Start one-shot timer, for example 100 ms.
    // After timeout call Dfu_BootloaderTimerElapsed().
}

static void Dfu_SetBootloaderPendingFlag(void)
{
    // Store persistent bootloader request.
    // Options:
    // - backup register
    // - retained RAM magic value
    // - flash flag
    //
    // Bootloader must check this after reset.
}


static void Dfu_BootloaderTimerElapsed(void)
{
    if (dfuState != DFU_STATE_BOOT_PENDING)
    {
        return;
    }

    Dfu_SetBootloaderPendingFlag();

    __disable_irq();

    // Optional:
    // deinit peripherals
    // flush logs
    // stop radio/SPI/UART cleanly

    NVIC_SystemReset();
}


  // Callback Implementation SPI Library ---------------------------------------------------------------------
 
 static void DfuFlagReceivedCallback(vision_dfu_flag_t flag)
{

	if(flag == VISION_DFUFLAG_STOP)
	{
		if (dfuState != DFU_STATE_RECEIVING)
		{
			Dfu_Abort(DFU_ERROR_NOT_IN_PROGRESS);
			return;
		}

		if (!Dfu_CheckFirmwareDataValid(dfuDataCounter))
		{
			Dfu_Abort(DFU_ERROR_CORRUPTED_IMAGE);
			return;
		}

		dfuState = DFU_STATE_BOOT_PENDING;

		// Tell sender that application-side receive/validation was okay.
		vision_writeDfu(DFU_SUCCESS);

		// Do not reset state here.
		// Wait until the response had enough time to leave the device.
		Dfu_StartBootloaderTimer();
		return;
	} 
	else if(flag == VISION_DFUFLAG_START)
	{
		Dfu_Reset();

		if (!Dfu_StoragePrepare())
		{
			Dfu_Abort(DFU_ERROR_FLASH);
			return;
		}

		dfuState = DFU_STATE_RECEIVING;

		// State is valid before response is sent.
		vision_writeDfu(DFU_SUCCESS);
		return;
	}
}
static void DfuDataReceivedCallback(uint16_t packetNr,const uint8_t* buf, uint16_t length)
{
	 if (dfuState != DFU_STATE_RECEIVING)
    {
        vision_writeDfu(DFU_ERROR_NOT_IN_PROGRESS);
        return;
    }

    if (buf == NULL || length == 0)
    {
        Dfu_Abort(DFU_ERROR_INVALID_PACKET);
        return;
    }

    if (packetNr != dfuPacketCounter)
    {
        Dfu_Abort(DFU_ERROR_WRONG_PACKETNR);
        return;
    }

    if ((uint32_t)length > (MAX_FIRMWARE_SIZE - dfuDataCounter))
    {
        Dfu_Abort(DFU_ERROR_IMAGE_TOO_LARGE);
        return;
    }

    if (!Dfu_StorageWrite(dfuDataCounter, buf, length))
    {
        Dfu_Abort(DFU_ERROR_FLASH);
        return;
    }

    dfuDataCounter += length;
    dfuPacketCounter++;

}
© KKT Künzler Technologies GbR.
Developed by KKT - Künzler Technologies GbR