diff --git a/include/blisp.h b/include/blisp.h index af6cb04..ddc6bc1 100644 --- a/include/blisp.h +++ b/include/blisp.h @@ -5,6 +5,13 @@ #include "blisp_chip.h" +struct blisp_segment_header { + uint32_t dest_addr; + uint32_t length; + uint32_t reserved; + uint32_t crc32; +}; + struct blisp_device { struct blisp_chip* chip; void* serial_port; @@ -24,6 +31,12 @@ int32_t blisp_device_init(struct blisp_device* device, struct blisp_chip* chip); int32_t blisp_device_open(struct blisp_device* device, const char* port_name); int32_t blisp_device_handshake(struct blisp_device* device); int32_t blisp_device_get_boot_info(struct blisp_device* device, struct blisp_boot_info* boot_info); +int32_t blisp_device_load_boot_header(struct blisp_device* device, uint8_t* boot_header); +int32_t blisp_device_load_segment_header(struct blisp_device* device, struct blisp_segment_header* segment_header); +int32_t blisp_device_load_segment_data(struct blisp_device* device, uint8_t* segment_data, uint32_t segment_data_length); +int32_t blisp_device_write_memory(struct blisp_device* device, uint32_t address, uint32_t value); +int32_t blisp_device_check_image(struct blisp_device* device); +int32_t blisp_device_run_image(struct blisp_device* device); void blisp_device_close(struct blisp_device* device); #endif \ No newline at end of file diff --git a/include/blisp_chip.h b/include/blisp_chip.h index ddd27cf..4edee2b 100644 --- a/include/blisp_chip.h +++ b/include/blisp_chip.h @@ -10,6 +10,7 @@ enum blisp_chip_type { struct blisp_chip { // TODO: Move elsewhere? enum blisp_chip_type type; + const char* type_str; bool usb_isp_available; }; diff --git a/lib/blisp.c b/lib/blisp.c index bafc6d6..8a1adf3 100644 --- a/lib/blisp.c +++ b/lib/blisp.c @@ -59,11 +59,11 @@ int32_t blisp_device_open(struct blisp_device* device, const char* port_name) uint32_t vid, pid; sp_get_port_usb_vid_pid(serial_port, &vid, &pid); device->is_usb = pid == 0xFFFF; - if (device->is_usb) { - device->current_baud_rate = 2000000; - } else { +// if (device->is_usb) { +// device->current_baud_rate = 2000000; +// } else { device->current_baud_rate = 500000; - } +// } sp_set_baudrate(serial_port, device->current_baud_rate); device->serial_port = serial_port; return 0; @@ -76,8 +76,8 @@ int32_t blisp_send_command(struct blisp_device* device, uint8_t command, void* p device->tx_buffer[0] = command; device->tx_buffer[1] = 0; - device->tx_buffer[2] = (payload_size >> 8) & 0xFF; - device->tx_buffer[3] = payload_size & 0xFF; + device->tx_buffer[2] = payload_size & 0xFF; + device->tx_buffer[3] = (payload_size >> 8) & 0xFF; if (add_checksum) { uint32_t checksum = 0; checksum += device->tx_buffer[2] + device->tx_buffer[3]; @@ -97,13 +97,28 @@ int32_t blisp_send_command(struct blisp_device* device, uint8_t command, void* p } int32_t blisp_receive_response(struct blisp_device* device, bool expect_payload) { + // TODO: Check checksum int ret; struct sp_port* serial_port = device->serial_port; ret = sp_blocking_read(serial_port, &device->rx_buffer[0], 2, 300); if (ret < 2) { return -1; + } else if (device->rx_buffer[0] == 'O' && device->rx_buffer[1] == 'K') { + if (expect_payload) { + sp_blocking_read(serial_port, &device->rx_buffer[2], 2, 100); + uint16_t data_length = (device->rx_buffer[3] << 8) | (device->rx_buffer[2]); + sp_blocking_read(serial_port, &device->rx_buffer[0], data_length, 100); + return data_length; + } + return 0; + } else if (device->rx_buffer[0] == 'P' && device->rx_buffer[1] == 'D') { + return -1; + } else if (device->rx_buffer[0] == 'F' && device->rx_buffer[1] == 'L') { + sp_blocking_read(serial_port, &device->rx_buffer[2], 2, 100); + device->error_code = (device->rx_buffer[3] << 8) | (device->rx_buffer[2]); + return -4; // Failed } - + return -1; } int32_t blisp_device_handshake(struct blisp_device* device) @@ -112,21 +127,27 @@ int32_t blisp_device_handshake(struct blisp_device* device) uint8_t handshake_buffer[600]; struct sp_port* serial_port = device->serial_port; - if (device->is_usb) { - sp_blocking_write(serial_port, "BOUFFALOLAB5555RESET\0\0", 22, 100); - } uint32_t bytes_count = 0.003f * (float)device->current_baud_rate / 10.0f; // TODO: 0.003f is only for BL70X! if (bytes_count > 600) bytes_count = 600; memset(handshake_buffer, 'U', bytes_count); - ret = sp_blocking_write(serial_port, handshake_buffer, bytes_count, 100); - if (ret < 0) { - return -1; + + for (uint8_t i = 0; i < 5; i++) { + if (device->is_usb) { + sp_blocking_write(serial_port, "BOUFFALOLAB5555RESET\0\0", 22, + 100); + } + + ret = sp_blocking_write(serial_port, handshake_buffer, bytes_count, + 100); + if (ret < 0) { + return -1; + } + ret = sp_blocking_read(serial_port, device->rx_buffer, 2, 100); + if (ret == 2 && device->rx_buffer[0] == 'O' && device->rx_buffer[1] == 'K') { + return 0; + } } - ret = sp_blocking_read(serial_port, device->rx_buffer, 2, 100); - if (ret < 2 || device->rx_buffer[0] != 'O' || device->rx_buffer[1] != 'K') { - return -4; // didn't received response - } - return 0; + return -4; // didn't received response } int32_t blisp_device_get_boot_info(struct blisp_device* device, struct blisp_boot_info* boot_info) @@ -137,6 +158,94 @@ int32_t blisp_device_get_boot_info(struct blisp_device* device, struct blisp_boo if (ret < 0) return ret; ret = blisp_receive_response(device, true); + if (ret < 0) return ret; + + if (device->chip->type == BLISP_CHIP_BL70X) { + memcpy(boot_info->boot_rom_version, &device->rx_buffer[0], 4); // TODO: Endianess + memcpy(boot_info->chip_id, &device->rx_buffer[16], 8); + } + return 0; +} + +// TODO: Use struct instead of uint8_t* +int32_t blisp_device_load_boot_header(struct blisp_device* device, uint8_t* boot_header) +{ + int ret; + ret = blisp_send_command(device, 0x11, boot_header, 176, false); + if (ret < 0) return ret; + ret = blisp_receive_response(device, false); + if (ret < 0) return ret; + + return 0; +} + +int32_t blisp_device_load_segment_header(struct blisp_device* device, struct blisp_segment_header* segment_header) +{ + int ret; + ret = blisp_send_command(device, 0x17, segment_header, 16, false); + if (ret < 0) return ret; + ret = blisp_receive_response(device, false); + if (ret < 0) return ret; + + return 0; +} + +int32_t blisp_device_load_segment_data(struct blisp_device* device, uint8_t* segment_data, uint32_t segment_data_length) +{ + int ret; + ret = blisp_send_command(device, 0x18, segment_data, segment_data_length, false); + if (ret < 0) return ret; + ret = blisp_receive_response(device, true); // TODO: Handle response + if (ret < 0) return ret; + + return 0; +} + +int32_t blisp_device_check_image(struct blisp_device* device) +{ + int ret; + ret = blisp_send_command(device, 0x19, NULL, 0, false); + if (ret < 0) return ret; + ret = blisp_receive_response(device, false); + if (ret < 0) return ret; + + return 0; +} + +int32_t blisp_device_write_memory(struct blisp_device* device, uint32_t address, uint32_t value) +{ + int ret; + uint8_t payload[8]; + *(uint32_t*)(payload) = address; + *(uint32_t*)(payload + 4) = value; // TODO: Endianness + ret = blisp_send_command(device, 0x50, payload, 8, false); + if (ret < 0) return ret; + ret = blisp_receive_response(device, false); + if (ret < 0) return ret; + + return 0; +} + +int32_t blisp_device_run_image(struct blisp_device* device) +{ + int ret; + + if (device->chip->type == BLISP_CHIP_BL70X) { // ERRATA + ret = blisp_device_write_memory(device, 0x4000F100, 0x4E424845); + if (ret < 0) return ret; + ret = blisp_device_write_memory(device, 0x4000F104, 0x22010000); + if (ret < 0) return ret; +// ret = blisp_device_write_memory(device, 0x40000018, 0x00000000); +// if (ret < 0) return ret; + ret = blisp_device_write_memory(device, 0x40000018, 0x00000002); + if (ret < 0) return ret; + return 0; + } + + ret = blisp_send_command(device, 0x1A, NULL, 0, false); + if (ret < 0) return ret; + ret = blisp_receive_response(device, false); + if (ret < 0) return ret; return 0; } diff --git a/lib/chip/blisp_chip_bl70x.c b/lib/chip/blisp_chip_bl70x.c index f62f905..8104a24 100644 --- a/lib/chip/blisp_chip_bl70x.c +++ b/lib/chip/blisp_chip_bl70x.c @@ -2,5 +2,6 @@ struct blisp_chip blisp_chip_bl70x = { .type = BLISP_CHIP_BL70X, + .type_str = "bl70x", .usb_isp_available = true }; diff --git a/tools/blisp/src/cmd/write.c b/tools/blisp/src/cmd/write.c index b4e4e77..92cf481 100644 --- a/tools/blisp/src/cmd/write.c +++ b/tools/blisp/src/cmd/write.c @@ -1,17 +1,42 @@ #include "../cmd.h" #include "argtable3.h" #include +#include +#include +#ifdef __linux__ +#include +#include +#endif #define REG_EXTENDED 1 #define REG_ICASE (REG_EXTENDED << 1) static struct arg_rex* cmd; static struct arg_file* binary_to_write; -static struct arg_str* port_name; +static struct arg_str* port_name, *chip_type; static struct arg_end* end; -static void* cmd_write_argtable[4]; +static void* cmd_write_argtable[5]; + +ssize_t +get_binary_folder(char* buffer, uint32_t buffer_size) { +#ifdef __linux__ + readlink("/proc/self/exe", buffer, BUFSIZ); // TODO: Error handling + char* pos = strrchr(buffer, '/'); + pos[0] = '\0'; + return pos - buffer; +#else +#error NOT IMPLEMENTED + WCHAR path[MAX_PATH]; + GetModuleFileName(NULL, path, ARRAYSIZE(path)); +#endif +} void blisp_flash_firmware() { + // TODO: We support currently only BL70X + if (chip_type->count == 0 || strcmp(chip_type->sval[0], "bl70x") != 0) { + fprintf(stderr, "Chip type is invalid.\n"); + return; + } struct blisp_device device; uint32_t ret; ret = blisp_device_init(&device, &blisp_chip_bl70x); @@ -28,9 +53,89 @@ void blisp_flash_firmware() { ret = blisp_device_handshake(&device); if (ret != 0) { fprintf(stderr, "\nFailed to handshake with device.\n"); - return; + goto exit1; } - printf(" OK\n"); + printf(" OK\nGetting chip info..."); + struct blisp_boot_info boot_info; + ret = blisp_device_get_boot_info(&device, &boot_info); + if (ret != 0) { + fprintf(stderr, "\nFailed to get boot info.\n"); + goto exit1; + } + printf(" BootROM version %d.%d.%d.%d, ChipID: %02X%02X%02X%02X%02X%02X%02X%02X\n", + boot_info.boot_rom_version[0], + boot_info.boot_rom_version[1], + boot_info.boot_rom_version[2], + boot_info.boot_rom_version[3], + boot_info.chip_id[0], + boot_info.chip_id[1], + boot_info.chip_id[2], + boot_info.chip_id[3], + boot_info.chip_id[4], + boot_info.chip_id[5], + boot_info.chip_id[6], + boot_info.chip_id[7]); + + char exe_path[PATH_MAX]; + char eflash_loader_path[PATH_MAX]; + get_binary_folder(exe_path, PATH_MAX); // TODO: Error handling + snprintf(eflash_loader_path, PATH_MAX, "%s/data/%s/eflash_loader_32m.bin", exe_path, device.chip->type_str); + + FILE* eflash_loader_file = fopen(eflash_loader_path, "rb"); + uint8_t eflash_loader_header[176]; + fread(eflash_loader_header, 176, 1, eflash_loader_file); // TODO: Error handling + + printf("Loading eflash_loader...\n"); + ret = blisp_device_load_boot_header(&device, eflash_loader_header); + if (ret != 0) { + fprintf(stderr, "Failed to load boot header.\n"); + goto exit1; + } + + uint32_t sent_data = 0; + uint32_t buffer_size = 0; + uint8_t buffer[4092]; + + // TODO: Real checking of segments count + for (uint8_t seg_index = 0; seg_index < 1; seg_index++) { + struct blisp_segment_header segment_header = {0}; + fread(&segment_header, 16, 1, eflash_loader_file); // TODO: Error handling + + ret = blisp_device_load_segment_header(&device, &segment_header); + if (ret != 0) { + fprintf(stderr, "Failed to load segment header.\n"); + goto exit1; + } + printf("Flashing %d. segment\n", seg_index + 1); + printf("0b / %" PRIu32 "b (0.00%%)\n", segment_header.length); + + while (sent_data < segment_header.length) { + buffer_size = segment_header.length - sent_data; + if (buffer_size > 4092) { + buffer_size = 4092; + } + fread(buffer, buffer_size, 1, eflash_loader_file); + blisp_device_load_segment_data(&device, buffer, buffer_size); // TODO: Error handling + sent_data += buffer_size; + printf("%" PRIu32 "b / %" PRIu32 "b (%.2f%%)\n", sent_data, segment_header.length, + (((float)sent_data / (float)segment_header.length) * 100.0f)); + } + } + + ret = blisp_device_check_image(&device); + if (ret != 0) { + fprintf(stderr, "Failed to check image.\n"); + goto exit1; + } + + ret = blisp_device_run_image(&device); + if (ret != 0) { + fprintf(stderr, "Failed to run image.\n"); + goto exit1; + } + +exit1: + if (eflash_loader_file != NULL) fclose(eflash_loader_file); blisp_device_close(&device); } @@ -38,11 +143,12 @@ int8_t cmd_write_args_init() { cmd_write_argtable[0] = cmd = arg_rex1(NULL, NULL, "write", NULL, REG_ICASE, NULL); - cmd_write_argtable[1] = binary_to_write - = arg_file1(NULL, NULL, "", "Binary to write"); + cmd_write_argtable[1] = chip_type = arg_str1("c", "chip", "", "Chip Type (bl70x)"); cmd_write_argtable[2] = port_name = arg_str0("p", "port", "", "Name/Path to the Serial Port (empty for search)"); - cmd_write_argtable[3] = end = arg_end(10); + cmd_write_argtable[3] = binary_to_write + = arg_file1(NULL, NULL, "", "Binary to write"); + cmd_write_argtable[4] = end = arg_end(10); if (arg_nullcheck(cmd_write_argtable) != 0) { fprintf(stderr, "insufficient memory\n");