Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 122 additions & 0 deletions lib_device_control/apps/dfu_control_server.xc
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
// Copyright 2026 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.

#include <stdint.h>
#include <string.h>

#include "control.h"
#include "dfu.h"
#include "dfu_commands.h"

// Non-USB transport; sending block number with payload.
struct dfu_dnload_header {
uint16_t block_num;
uint16_t pad;
};

/* FROM LIB_XUA - TODO - check reboot cycle time etc. 1*/
/* Windows core USB/device driver stack may not like device coming off bus for
* a very short period of less than 500ms. Enforce at least 500ms by stalling.
* This may not have the desired effect depending on whether 'off the bus'
* requires device terminations disabled (PHY off). In that case we would be
* better off doing the reboot to DFU and then delaying PHY initialisation
* instead. Suggest revisiting.
*/
#define DELAY_BEFORE_REBOOT_TO_DFU_MS 500

/* TODO - rework */
/**
* Hardware build section
*
* Information about hardware available during factory programming
*
*/

// // hardcoded value based on quadflash library
// #define QUADFLASH_SPISPEC_SIZE_WORDS 28

// struct dp_hardware_build {
// uint32_t tag;
// uint32_t build; /**< type of build such as prototype or test */
// union {
// uint32_t words[QUADFLASH_SPISPEC_SIZE_WORDS];
// #ifdef __xcore__
// fl_QuadDeviceSpec structure[1];
// #endif
// } spispec;
// uint32_t checksum;
// };

[[combinable]]
void dfu_control_server(server interface control dfu_control_interface /* fl_QSPIPorts * unsafe qspi_ports, */) {
uint8_t local_payload[I2C_DATA_MAX_BYTES];
struct dfu_write_command_state dfu_write_command_state = { false };
timer dfu_timer;
unsigned dfu_time;

while(1)
{
select
{
case dfu_control_interface.register_resources(control_resid_t resources[MAX_RESOURCES_PER_INTERFACE], unsigned &num_resources):
resources[0] = RESOURCE_ID_DFU;
num_resources = 1;
break;

case dfu_control_interface.write_command(control_resid_t resid, control_cmd_t cmd,
const uint8_t payload[payload_len], unsigned payload_len) -> control_ret_t ret:

if (payload_len > sizeof(local_payload)) {
ret = CONTROL_DATA_LENGTH_ERROR;
break;
}

size_t header_size = sizeof(struct dfu_dnload_header);
struct dfu_dnload_header header;
memcpy(&header, payload, header_size);
memcpy(local_payload, &payload[header_size], (payload_len - header_size));

ret = dfu_handle_write_command(CONTROL_CMD_VALUE(cmd), header.block_num, local_payload, (payload_len - header_size), dfu_write_command_state);

// WAS for reset timeout handling - might be needed/helpful for poll timeout handling, TBC
// if (dfu_write_command_state.timeout.enable) {
// unsigned now;
// dfu_timer :> now;
// //debug_printf("now = %d\n", now);
// dfu_time = now + dfu_write_command_state.timeout.delta;
// }
if (dfu_write_command_state.needs_reboot) {
dfu_timer :> dfu_time;
dfu_timer when timerafter(dfu_time + (DELAY_BEFORE_REBOOT_TO_DFU_MS * XS1_TIMER_KHZ)) :> void;
// DFUDelay(DELAY_BEFORE_REBOOT_TO_DFU_MS * XS1_TIMER_KHZ);
device_reboot();
}
break;

case dfu_control_interface.read_command(control_resid_t resid, control_cmd_t cmd,
uint8_t payload[payload_len], unsigned payload_len) -> control_ret_t ret:
if (payload_len > sizeof(local_payload)) {
ret = CONTROL_DATA_LENGTH_ERROR;
break;
}
// TODO - fix length handling into and out of read_command()
memcpy(local_payload, payload, payload_len);
ret = dfu_handle_read_command(CONTROL_CMD_VALUE(cmd), local_payload, payload_len);
memcpy(payload, local_payload, payload_len);
break;

// WAS for reset timeout handling - might be needed/helpful for poll timeout handling, TBC
// case dfu_write_command_state.timeout.enable => dfu_timer when timerafter(dfu_time) :> void:
// { timer tmr;
// int t;
// tmr :> t;
// //debug_printf("t = %d\n", t);
// }
// //debug_printf("GPIO server: DFU timeout\n");
// dfu_timeout_detach();
// dfu_write_command_state.timeout.enable = false;
// break;

}// select
}//While 1
}
7 changes: 7 additions & 0 deletions lib_device_control/inc/control_transport_shared.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@
*/
#define IS_CONTROL_CMD_READ(c) ((c) & 0x80)

/**
* Returns the command value with the read/write bit cleared.
*
* \param[in,out] c The transport command code convert to an application command code.
*/
#define CONTROL_CMD_VALUE(c) ((c) & ~0x80)

/**
* Sets the read bit on a command code
*
Expand Down
5 changes: 5 additions & 0 deletions lib_device_control/lib_build_info.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,9 @@ elseif (TRANSPORT_UPPER STREQUAL "XSCOPE")
list(APPEND LIB_XC_SRCS adapters/transport_xscope.xc)
endif()

# Add DFU control server source files based on configuration
if (CONTROL_APP_DFU)
list(APPEND LIB_XC_SRCS apps/dfu_control_server.xc)
endif()

XMOS_REGISTER_MODULE()