#include #include #include #include "setp_tms2812_boot.h" #define NODE_ID 13U #define IMAGE_SIZE 100U typedef struct { uint8_t flash[512]; setp_can_rx_t response_rx; setp_can_packet_t response_packet; uint32_t now_ms; unsigned int response_complete; unsigned int erased; unsigned int rebooted; } fake_t; typedef struct { setp_tms2812_boot_t *boot; fake_t *fake; } request_context_t; static bool fake_send_response(const setp_can_frame_t *frame, void *user) { fake_t *fake = (fake_t *)user; setp_can_rx_result_t result = setp_can_rx_feed( &fake->response_rx, frame, fake->now_ms++, &fake->response_packet); if (result == SETP_CAN_RX_COMPLETE) fake->response_complete++; return result == SETP_CAN_RX_NONE || result == SETP_CAN_RX_COMPLETE; } static bool fake_erase(void *user, uint32_t image_size) { fake_t *fake = (fake_t *)user; if (image_size > sizeof(fake->flash)) return false; (void)memset(fake->flash, 0xFF, sizeof(fake->flash)); fake->erased++; return true; } static bool fake_write(void *user, uint32_t offset, const uint8_t *data, uint16_t length) { fake_t *fake = (fake_t *)user; if (offset + length > sizeof(fake->flash)) return false; (void)memcpy(&fake->flash[offset], data, length); return true; } static bool fake_read(void *user, uint32_t offset, uint8_t *data, uint16_t length) { fake_t *fake = (fake_t *)user; if (offset + length > sizeof(fake->flash)) return false; (void)memcpy(data, &fake->flash[offset], length); return true; } static void fake_reboot(void *user) { ((fake_t *)user)->rebooted++; } static bool send_request_frame(const setp_can_frame_t *frame, void *user) { request_context_t *context = (request_context_t *)user; return setp_tms2812_boot_process(context->boot, frame, context->fake->now_ms++); } static setp_frame_t transact(setp_tms2812_boot_t *boot, fake_t *fake, uint16_t sequence, uint16_t type, const uint8_t *payload, uint16_t payload_length) { uint8_t packet[SETP_FRAME_MAX]; setp_frame_t request; setp_frame_t response; setp_can_id_t id; request_context_t context; size_t packet_length; fake->response_complete = 0U; setp_can_rx_init(&fake->response_rx); request.flags = SETP_FLAG_ACK_REQUIRED | SETP_FLAG_PRIORITY; request.message_type = type; request.source = 0U; request.destination = NODE_ID; request.sequence = sequence; request.payload_length = payload_length; request.payload = payload; packet_length = setp_frame_encode(&request, packet, sizeof(packet)); assert(packet_length != 0U); id.destination = NODE_ID; id.source = 0U; id.priority = 1U; id.channel = 1U; context.boot = boot; context.fake = fake; assert(setp_can_segment(packet, (uint16_t)packet_length, setp_can_id_pack(&id), send_request_frame, &context)); assert(fake->response_complete == 1U); assert(setp_frame_decode_datagram(fake->response_packet.data, fake->response_packet.length, &response)); assert(response.flags & SETP_FLAG_RESPONSE); assert(response.message_type == type); assert(response.sequence == sequence); assert(response.source == NODE_ID); assert(response.destination == 0U); return response; } static void assert_ok(const setp_frame_t *response) { assert(response->payload_length >= 2U); assert(setp_get_u16(response->payload) == SETP_STATUS_OK); assert((response->flags & SETP_FLAG_ERROR) == 0U); } int main(void) { static const uint8_t model[] = "BALZAM-166"; static const uint8_t expected_sha[SETP_SHA256_SIZE] = { 0xBC, 0xE0, 0xAF, 0xF1, 0x9C, 0xF5, 0xAA, 0x6A, 0x74, 0x69, 0xA3, 0x0D, 0x61, 0xD0, 0x4E, 0x43, 0x76, 0xE4, 0xBB, 0xF6, 0x38, 0x10, 0x52, 0xEE, 0x9E, 0x7F, 0x33, 0x92, 0x5C, 0x95, 0x4D, 0x52 }; uint8_t image[IMAGE_SIZE]; uint8_t payload[SETP_MAX_PAYLOAD]; setp_tms2812_boot_t boot; setp_tms2812_boot_config_t config; setp_tms2812_boot_port_t port; setp_fw_begin_t begin; setp_fw_end_t end; setp_fw_status_t status; setp_frame_t response; size_t length; uint32_t offset; uint16_t sequence = 1U; fake_t fake; unsigned int i; (void)memset(&fake, 0, sizeof(fake)); (void)memset(&config, 0, sizeof(config)); (void)memset(&port, 0, sizeof(port)); for (i = 0U; i < IMAGE_SIZE; i++) image[i] = (uint8_t)i; config.node_id = NODE_ID; config.device_class = 0x0166U; config.hardware_version = 1U; config.firmware_version = 2U; config.model = model; config.model_length = (uint8_t)(sizeof(model) - 1U); config.app_base_address = 0x00100000UL; config.max_image_size = sizeof(fake.flash); config.max_block_size = 32U; config.active_slot = 0U; port.send_can = fake_send_response; port.erase_image = fake_erase; port.write_image = fake_write; port.read_image = fake_read; port.reboot = fake_reboot; assert(setp_tms2812_boot_init(&boot, &config, &port, &fake)); response = transact(&boot, &fake, sequence++, SETP_MSG_PING, NULL, 0U); assert_ok(&response); assert(response.payload_length == 6U); (void)memset(&begin, 0, sizeof(begin)); begin.image_size = IMAGE_SIZE; begin.image_crc32 = setp_crc32(image, sizeof(image)); begin.image_version = 0x01020304UL; begin.base_address = config.app_base_address; begin.slot = 0U; begin.flags = SETP_FW_FLAG_RESUME | SETP_FW_FLAG_ERASE_SLOT; begin.block_size = 32U; (void)memcpy(begin.sha256, expected_sha, sizeof(expected_sha)); length = setp_fw_begin_encode(&begin, payload, sizeof(payload)); assert(length != 0U); response = transact(&boot, &fake, sequence++, SETP_MSG_FW_BEGIN, payload, (uint16_t)length); assert_ok(&response); assert(fake.erased == 1U); for (offset = 0U; offset < IMAGE_SIZE;) { uint16_t chunk = (uint16_t)(IMAGE_SIZE - offset); if (chunk > begin.block_size) chunk = begin.block_size; length = setp_fw_data_encode(offset, 0U, &image[offset], chunk, payload, sizeof(payload)); response = transact(&boot, &fake, sequence++, SETP_MSG_FW_DATA, payload, (uint16_t)length); assert_ok(&response); assert(setp_get_u32(&response.payload[2]) == offset + chunk); if (offset == 0U) { response = transact(&boot, &fake, sequence++, SETP_MSG_FW_DATA, payload, (uint16_t)length); assert_ok(&response); assert(setp_get_u32(&response.payload[2]) == chunk); } offset += chunk; } assert(memcmp(fake.flash, image, sizeof(image)) == 0); end.image_size = begin.image_size; end.image_crc32 = begin.image_crc32; (void)memcpy(end.sha256, expected_sha, sizeof(expected_sha)); length = setp_fw_end_encode(&end, payload, sizeof(payload)); response = transact(&boot, &fake, sequence++, SETP_MSG_FW_END, payload, (uint16_t)length); assert_ok(&response); assert(boot.state == SETP_FW_READY); response = transact(&boot, &fake, sequence++, SETP_MSG_FW_STATUS, NULL, 0U); assert_ok(&response); assert(setp_fw_status_decode(&response.payload[2], (uint16_t)(response.payload_length - 2U), &status)); assert(status.state == SETP_FW_READY); assert(status.next_offset == IMAGE_SIZE); response = transact(&boot, &fake, sequence++, SETP_MSG_FW_ACTIVATE, NULL, 0U); assert_ok(&response); assert(fake.rebooted == 1U); puts("SETProtocol v2 TMS320F2812 firmware port tests passed"); return 0; }