Hi Guys,
I have implemented a way of handling different commands, ICE40 program, flash program etc which is backward compatible with the existing format.
There is a new class CommandStream:
class CommandStream
{
public:
CommandStream(void)
{
Init();
};
void Init(void);
void AddCommandHandler(uint8_t uCommandByte, CommandHandler *pCommandHandler);
uint8_t stream(uint8_t *data, uint32_t len);
private:
typedef enum { stDetect, stDetectCommandByte, stDispatch, stProcessing, stError } StreamState;
StreamState m_state;
uint8_t m_header[3] = {0x7e, 0xaa, 0x99};
uint8_t m_uHeaderScanPos = 0;
CommandHandler *m_pCurrentCommandHandler;
CommandHandler *m_commandHandlers[256] = {0};
};
This is used by the USB callback instead of the Ice40 object:
CommandStream g_commandStream;
static int8_t usbcdc_rxcallback(uint8_t *data, uint32_t *len){
USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &data[0]);
#define COMMAND_HANDLER
#ifdef COMMAND_HANDLER
if(*len)
{
if(!g_commandStream.stream(data, *len))
{
// HAL_UART_Transmit(&huart1, data, *len, HAL_UART_TIMEOUT_VALUE);
// mode_led_toggle();
HAL_UART_Transmit_DMA(&huart1, data, *len);
return USBD_OK;
//if(temp) mode_led_low();
}
}
#else
if(*len)
if(!Ice40.stream(data, *len)){
// HAL_UART_Transmit(&huart1, data, *len, HAL_UART_TIMEOUT_VALUE);
// mode_led_toggle();
HAL_UART_Transmit_DMA(&huart1, data, *len);
return USBD_OK;
//if(temp) mode_led_low();
}
#endif
USBD_CDC_ReceivePacket(&hUsbDeviceFS);
return USBD_OK;
}
There is a pure virtual class CommandHandler that any command needs to inherit from:
class CommandHandler
{
public:
virtual bool streamData(uint8_t *data, uint32_t len, bool bEndStream) = 0;
virtual bool init(void) = 0;
};
init() is called when the Command is recognised in the stream.
streamData() is called with the data from the stream, the 4 byte header 0x7E, 0xAA, 0x99, 0xNN is removed
in Setup() we register our CommandHandlers against a command byte, this is the last byte of the 4 byte header 0x7E, 0xAA, 0x99, 0xNN:
g_commandStream.AddCommandHandler(0x7e, &Ice40);
g_commandStream.AddCommandHandler(0x01, &g_flash);
g_commandStream.AddCommandHandler(0x02, &g_count);
So for the FPGA programming Fpga now inherits from CommandHandler and implements:
bool Fpga::init(void)
{
bool bResult = false;
nbytes = 0;
status_led_high();
flash_SPI_Disable();
if (err = reset(MCNTRL))
flash_SPI_Enable();
else
{
// Send header as this is removed from the stream
nbytes+=4;
write((uint8_t *)&sig, 4);
bResult = true;
}
return bResult;
}
bool Fpga::streamData(uint8_t *data, uint32_t len, bool bEndStream){
bool bResult = true;
nbytes += len;
write(data, len);
if(nbytes >= NBYTES)
{
if(err = config())
status_led_high();
else
status_led_low();
flash_SPI_Enable();
bResult = false;
}
return bResult;
}
I have added a test command that counts the bytes received:
class Count : public CommandHandler
{
public:
virtual bool streamData(uint8_t *data, uint32_t len, bool bEndStream);
virtual bool init(void);
private:
uint32_t m_uCount;
};
bool Count::init(void)
{
cdc_puts("Count::init()\n");
m_uCount = 0;
return true;
}
bool Count::streamData(uint8_t *data, uint32_t len, bool bEndStream)
{
m_uCount+= len;
if(bEndStream)
{
char buffer[128];
sprintf(buffer, "%lu bytes received\n", m_uCount);
cdc_puts(buffer);
return false;
}
else
return true;
}
so the following sent:
Mac-Pro:trail andrewcapon$ cat count.hex
ff 00 00 ff 7e aa 99 02
Mac-Pro:trail andrewcapon$ xxd -r -p count.hex count.bin
Mac-Pro:trail andrewcapon$ cat count.bin chip.bin > countchip.bin
Mac-Pro:trail andrewcapon$ sudo cat countchip.bin > /dev/cu.usbmodem00000000001A1
Gets back from uart
Count::init()
135100 bytes received
and sudo cat chip.bin > /dev/cu.usbmodem00000000001A1
still programs the ICE40 as before.
Also CommandStream handles headers that are byte aligned and can straddle usb packets.
It all works, is it a solution you would be interested in?