From 63085ebd4c96d76ef9fc441e97362530308f3711 Mon Sep 17 00:00:00 2001 From: yul Date: Thu, 19 May 2022 14:57:38 +0200 Subject: [PATCH] first commit --- bootloader.c | 76 ++++ cr_startup_lpc175x_6x.c | 367 +++++++++++++++++ crc.c | 52 +++ crc.h | 82 ++++ crp.c | 27 ++ iap.c | 138 +++++++ iap.h | 43 ++ log | 893 ++++++++++++++++++++++++++++++++++++++++ mylab2-programmer.py | 209 ++++++++++ sonic_50b03eb0.bin | Bin 0 -> 298816 bytes uart.c | 62 +++ uart.h | 59 +++ uart_commands.c | 105 +++++ uart_commands.h | 30 ++ 14 files changed, 2143 insertions(+) create mode 100644 bootloader.c create mode 100644 cr_startup_lpc175x_6x.c create mode 100644 crc.c create mode 100644 crc.h create mode 100644 crp.c create mode 100644 iap.c create mode 100644 iap.h create mode 100644 log create mode 100644 mylab2-programmer.py create mode 100644 sonic_50b03eb0.bin create mode 100644 uart.c create mode 100644 uart.h create mode 100644 uart_commands.c create mode 100644 uart_commands.h diff --git a/bootloader.c b/bootloader.c new file mode 100644 index 0000000..b3ce05e --- /dev/null +++ b/bootloader.c @@ -0,0 +1,76 @@ +/* +=============================================================================== + Name : bootloader.c + Author : $(author) + Version : + Copyright : $(copyright) + Description : main definition +=============================================================================== +*/ + +#ifdef __USE_CMSIS +#include "LPC17xx.h" +#endif + +#include + +#include +#include + +#include "uart_commands.h" + +error_code status; + +char okk[4] = "OK\r\n"; +char errr[5] = "ERR\r\n"; + +char buff[256]; + + + +cmd_t cmd; + +uint32_t offset, total_size, offset_pointer; + +crc_t crc_prog, crc_data; + + +// TODO: insert other include files here + +// TODO: insert other definitions and declarations here + +int main(void) { + uart_init(115200); + //iap_read_part_id(); + //iap_copy_to_flash(0x8000,(uint8_t*)test, 4); + while(1){ + uart_receive_command(buff); + uart_parse_command(buff, &cmd); + if (strcmp("GETID", cmd.argv[0])==0){ + uart_commands_getid(&status); + }else if(strcmp("GETSERIAL", cmd.argv[0])==0){ + uart_commands_getserial(&status); + }else if(strcmp("PROG", cmd.argv[0])==0){ + crc_prog = uart_string_to_int(cmd.argv[3]); + total_size = uart_string_to_int(cmd.argv[2]); + offset = uart_string_to_int(cmd.argv[1]); + crc_data = uart_commands_prog(); + offset_pointer = offset; + }else if(strcmp("DATA", cmd.argv[0])==0){ + int size = uart_string_to_int(cmd.argv[1]); + crc_t local_checksum = uart_string_to_int(cmd.argv[2]); + uart_commands_data(&status, size, &crc_data, local_checksum, offset_pointer); + if(status == 0) offset_pointer += size; + }else if(strcmp("CHECK", cmd.argv[0])==0){ + if(crc_prog == crc_data){ + uart_send(okk, 5); + }else{ + uart_send(errr, 6); + } + } + + //uart_commands_data(&status, 0x00004000, 0x00048f40, 0x4); + } + while(1); + return 0 ; +} diff --git a/cr_startup_lpc175x_6x.c b/cr_startup_lpc175x_6x.c new file mode 100644 index 0000000..94fb767 --- /dev/null +++ b/cr_startup_lpc175x_6x.c @@ -0,0 +1,367 @@ +//***************************************************************************** +// LPC175x_6x Microcontroller Startup code for use with LPCXpresso IDE +// +// Version : 150706 +//***************************************************************************** +// +// Copyright(C) NXP Semiconductors, 2014-2015, 2020 +// All rights reserved. +// +// NXP Confidential. This software is owned or controlled by NXP and may only be +// used strictly in accordance with the applicable license terms. +// +// By expressly accepting such terms or by downloading, installing, activating +// and/or otherwise using the software, you are agreeing that you have read, and +// that you agree to comply with and are bound by, such license terms. +// +// If you do not agree to be bound by the applicable license terms, then you may not +// retain, install, activate or otherwise use the software. +//***************************************************************************** + +#if defined (__cplusplus) +#ifdef __REDLIB__ +#error Redlib does not support C++ +#else +//***************************************************************************** +// +// The entry point for the C++ library startup +// +//***************************************************************************** +extern "C" { + extern void __libc_init_array(void); +} +#endif +#endif + +#define WEAK __attribute__ ((weak)) +#define ALIAS(f) __attribute__ ((weak, alias (#f))) + +//***************************************************************************** +#if defined (__cplusplus) +extern "C" { +#endif + +//***************************************************************************** +#if defined (__USE_CMSIS) || defined (__USE_LPCOPEN) +// Declaration of external SystemInit function +extern void SystemInit(void); +#endif + +//***************************************************************************** +// +// Forward declaration of the default handlers. These are aliased. +// When the application defines a handler (with the same name), this will +// automatically take precedence over these weak definitions +// +//***************************************************************************** + void ResetISR(void); +WEAK void NMI_Handler(void); +WEAK void HardFault_Handler(void); +WEAK void MemManage_Handler(void); +WEAK void BusFault_Handler(void); +WEAK void UsageFault_Handler(void); +WEAK void SVC_Handler(void); +WEAK void DebugMon_Handler(void); +WEAK void PendSV_Handler(void); +WEAK void SysTick_Handler(void); +WEAK void IntDefaultHandler(void); + +//***************************************************************************** +// +// Forward declaration of the specific IRQ handlers. These are aliased +// to the IntDefaultHandler, which is a 'forever' loop. When the application +// defines a handler (with the same name), this will automatically take +// precedence over these weak definitions +// +//***************************************************************************** +void WDT_IRQHandler(void) ALIAS(IntDefaultHandler); +void TIMER0_IRQHandler(void) ALIAS(IntDefaultHandler); +void TIMER1_IRQHandler(void) ALIAS(IntDefaultHandler); +void TIMER2_IRQHandler(void) ALIAS(IntDefaultHandler); +void TIMER3_IRQHandler(void) ALIAS(IntDefaultHandler); +void UART0_IRQHandler(void) ALIAS(IntDefaultHandler); +void UART1_IRQHandler(void) ALIAS(IntDefaultHandler); +void UART2_IRQHandler(void) ALIAS(IntDefaultHandler); +void UART3_IRQHandler(void) ALIAS(IntDefaultHandler); +void PWM1_IRQHandler(void) ALIAS(IntDefaultHandler); +void I2C0_IRQHandler(void) ALIAS(IntDefaultHandler); +void I2C1_IRQHandler(void) ALIAS(IntDefaultHandler); +void I2C2_IRQHandler(void) ALIAS(IntDefaultHandler); +void SPI_IRQHandler(void) ALIAS(IntDefaultHandler); +void SSP0_IRQHandler(void) ALIAS(IntDefaultHandler); +void SSP1_IRQHandler(void) ALIAS(IntDefaultHandler); +void PLL0_IRQHandler(void) ALIAS(IntDefaultHandler); +void RTC_IRQHandler(void) ALIAS(IntDefaultHandler); +void EINT0_IRQHandler(void) ALIAS(IntDefaultHandler); +void EINT1_IRQHandler(void) ALIAS(IntDefaultHandler); +void EINT2_IRQHandler(void) ALIAS(IntDefaultHandler); +void EINT3_IRQHandler(void) ALIAS(IntDefaultHandler); +void ADC_IRQHandler(void) ALIAS(IntDefaultHandler); +void BOD_IRQHandler(void) ALIAS(IntDefaultHandler); +void USB_IRQHandler(void) ALIAS(IntDefaultHandler); +void CAN_IRQHandler(void) ALIAS(IntDefaultHandler); +void DMA_IRQHandler(void) ALIAS(IntDefaultHandler); +void I2S_IRQHandler(void) ALIAS(IntDefaultHandler); +#if defined (__USE_LPCOPEN) +void ETH_IRQHandler(void) ALIAS(IntDefaultHandler); +#else +void ENET_IRQHandler(void) ALIAS(IntDefaultHandler); +#endif +void RIT_IRQHandler(void) ALIAS(IntDefaultHandler); +void MCPWM_IRQHandler(void) ALIAS(IntDefaultHandler); +void QEI_IRQHandler(void) ALIAS(IntDefaultHandler); +void PLL1_IRQHandler(void) ALIAS(IntDefaultHandler); +void USBActivity_IRQHandler(void) ALIAS(IntDefaultHandler); +void CANActivity_IRQHandler(void) ALIAS(IntDefaultHandler); + +//***************************************************************************** +// +// The entry point for the application. +// __main() is the entry point for Redlib based applications +// main() is the entry point for Newlib based applications +// +//***************************************************************************** +#if defined (__REDLIB__) +extern void __main(void); +#endif +extern int main(void); +//***************************************************************************** +// +// External declaration for the pointer to the stack top from the Linker Script +// +//***************************************************************************** +extern void _vStackTop(void); + +//***************************************************************************** +// +// External declaration for LPC MCU vector table checksum from Linker Script +// +//***************************************************************************** +WEAK extern void __valid_user_code_checksum(); + +//***************************************************************************** +#if defined (__cplusplus) +} // extern "C" +#endif +//***************************************************************************** +// +// The vector table. +// This relies on the linker script to place at correct location in memory. +// +//***************************************************************************** +extern void (* const g_pfnVectors[])(void); +__attribute__ ((used,section(".isr_vector"))) +void (* const g_pfnVectors[])(void) = { + // Core Level - CM3 + &_vStackTop, // The initial stack pointer + ResetISR, // The reset handler + NMI_Handler, // The NMI handler + HardFault_Handler, // The hard fault handler + MemManage_Handler, // The MPU fault handler + BusFault_Handler, // The bus fault handler + UsageFault_Handler, // The usage fault handler + __valid_user_code_checksum, // LPC MCU Checksum + 0, // Reserved + 0, // Reserved + 0, // Reserved + SVC_Handler, // SVCall handler + DebugMon_Handler, // Debug monitor handler + 0, // Reserved + PendSV_Handler, // The PendSV handler + SysTick_Handler, // The SysTick handler + + // Chip Level - LPC17 + WDT_IRQHandler, // 16, 0x40 - WDT + TIMER0_IRQHandler, // 17, 0x44 - TIMER0 + TIMER1_IRQHandler, // 18, 0x48 - TIMER1 + TIMER2_IRQHandler, // 19, 0x4c - TIMER2 + TIMER3_IRQHandler, // 20, 0x50 - TIMER3 + UART0_IRQHandler, // 21, 0x54 - UART0 + UART1_IRQHandler, // 22, 0x58 - UART1 + UART2_IRQHandler, // 23, 0x5c - UART2 + UART3_IRQHandler, // 24, 0x60 - UART3 + PWM1_IRQHandler, // 25, 0x64 - PWM1 + I2C0_IRQHandler, // 26, 0x68 - I2C0 + I2C1_IRQHandler, // 27, 0x6c - I2C1 + I2C2_IRQHandler, // 28, 0x70 - I2C2 + SPI_IRQHandler, // 29, 0x74 - SPI + SSP0_IRQHandler, // 30, 0x78 - SSP0 + SSP1_IRQHandler, // 31, 0x7c - SSP1 + PLL0_IRQHandler, // 32, 0x80 - PLL0 (Main PLL) + RTC_IRQHandler, // 33, 0x84 - RTC + EINT0_IRQHandler, // 34, 0x88 - EINT0 + EINT1_IRQHandler, // 35, 0x8c - EINT1 + EINT2_IRQHandler, // 36, 0x90 - EINT2 + EINT3_IRQHandler, // 37, 0x94 - EINT3 + ADC_IRQHandler, // 38, 0x98 - ADC + BOD_IRQHandler, // 39, 0x9c - BOD + USB_IRQHandler, // 40, 0xA0 - USB + CAN_IRQHandler, // 41, 0xa4 - CAN + DMA_IRQHandler, // 42, 0xa8 - GP DMA + I2S_IRQHandler, // 43, 0xac - I2S +#if defined (__USE_LPCOPEN) + ETH_IRQHandler, // 44, 0xb0 - Ethernet +#else + ENET_IRQHandler, // 44, 0xb0 - Ethernet +#endif + RIT_IRQHandler, // 45, 0xb4 - RITINT + MCPWM_IRQHandler, // 46, 0xb8 - Motor Control PWM + QEI_IRQHandler, // 47, 0xbc - Quadrature Encoder + PLL1_IRQHandler, // 48, 0xc0 - PLL1 (USB PLL) + USBActivity_IRQHandler, // 49, 0xc4 - USB Activity interrupt to wakeup + CANActivity_IRQHandler, // 50, 0xc8 - CAN Activity interrupt to wakeup +}; + +//***************************************************************************** +// Functions to carry out the initialization of RW and BSS data sections. These +// are written as separate functions rather than being inlined within the +// ResetISR() function in order to cope with MCUs with multiple banks of +// memory. +//***************************************************************************** +__attribute__ ((section(".after_vectors"))) +void data_init(unsigned int romstart, unsigned int start, unsigned int len) { + unsigned int *pulDest = (unsigned int*) start; + unsigned int *pulSrc = (unsigned int*) romstart; + unsigned int loop; + for (loop = 0; loop < len; loop = loop + 4) + *pulDest++ = *pulSrc++; +} + +__attribute__ ((section(".after_vectors"))) +void bss_init(unsigned int start, unsigned int len) { + unsigned int *pulDest = (unsigned int*) start; + unsigned int loop; + for (loop = 0; loop < len; loop = loop + 4) + *pulDest++ = 0; +} + +//***************************************************************************** +// The following symbols are constructs generated by the linker, indicating +// the location of various points in the "Global Section Table". This table is +// created by the linker via the Code Red managed linker script mechanism. It +// contains the load address, execution address and length of each RW data +// section and the execution and length of each BSS (zero initialized) section. +//***************************************************************************** +extern unsigned int __data_section_table; +extern unsigned int __data_section_table_end; +extern unsigned int __bss_section_table; +extern unsigned int __bss_section_table_end; + +//***************************************************************************** +// Reset entry point for your code. +// Sets up a simple runtime environment and initializes the C/C++ +// library. +//***************************************************************************** +__attribute__ ((section(".after_vectors"))) +void +ResetISR(void) { + + // + // Copy the data sections from flash to SRAM. + // + unsigned int LoadAddr, ExeAddr, SectionLen; + unsigned int *SectionTableAddr; + + // Load base address of Global Section Table + SectionTableAddr = &__data_section_table; + + // Copy the data sections from flash to SRAM. + while (SectionTableAddr < &__data_section_table_end) { + LoadAddr = *SectionTableAddr++; + ExeAddr = *SectionTableAddr++; + SectionLen = *SectionTableAddr++; + data_init(LoadAddr, ExeAddr, SectionLen); + } + // At this point, SectionTableAddr = &__bss_section_table; + // Zero fill the bss segment + while (SectionTableAddr < &__bss_section_table_end) { + ExeAddr = *SectionTableAddr++; + SectionLen = *SectionTableAddr++; + bss_init(ExeAddr, SectionLen); + } + +#if defined (__USE_CMSIS) || defined (__USE_LPCOPEN) + SystemInit(); +#endif + +#if defined (__cplusplus) + // + // Call C++ library initialisation + // + __libc_init_array(); +#endif + +#if defined (__REDLIB__) + // Call the Redlib library, which in turn calls main() + __main() ; +#else + main(); +#endif + + // + // main() shouldn't return, but if it does, we'll just enter an infinite loop + // + while (1) { + ; + } +} + +//***************************************************************************** +// Default exception handlers. Override the ones here by defining your own +// handler routines in your application code. +//***************************************************************************** +__attribute__ ((section(".after_vectors"))) +void NMI_Handler(void) +{ while(1) {} +} + +__attribute__ ((section(".after_vectors"))) +void HardFault_Handler(void) +{ while(1) {} +} + +__attribute__ ((section(".after_vectors"))) +void MemManage_Handler(void) +{ while(1) {} +} + +__attribute__ ((section(".after_vectors"))) +void BusFault_Handler(void) +{ while(1) {} +} + +__attribute__ ((section(".after_vectors"))) +void UsageFault_Handler(void) +{ while(1) {} +} + +__attribute__ ((section(".after_vectors"))) +void SVC_Handler(void) +{ while(1) {} +} + +__attribute__ ((section(".after_vectors"))) +void DebugMon_Handler(void) +{ while(1) {} +} + +__attribute__ ((section(".after_vectors"))) +void PendSV_Handler(void) +{ while(1) {} +} + +__attribute__ ((section(".after_vectors"))) +void SysTick_Handler(void) +{ while(1) {} +} + +//***************************************************************************** +// +// Processor ends up here if an unexpected interrupt occurs or a specific +// handler is not present in the application code. +// +//***************************************************************************** +__attribute__ ((section(".after_vectors"))) +void IntDefaultHandler(void) +{ while(1) {} +} diff --git a/crc.c b/crc.c new file mode 100644 index 0000000..7db6454 --- /dev/null +++ b/crc.c @@ -0,0 +1,52 @@ +/** + * \file crc.c + * Functions and types for CRC checks. + * + * Generated on Sun Dec 18 16:52:06 2016, + * by pycrc v0.9, https://pycrc.org + * using the configuration: + * Width = 32 + * Poly = 0x04c11db7 + * Xor_In = 0xffffffff + * ReflectIn = True + * Xor_Out = 0xffffffff + * ReflectOut = True + * Algorithm = table-driven + *****************************************************************************/ +#include "crc.h" /* include the header file generated with pycrc */ +#include +#include + +/** + * Static table used for the table_driven implementation. + *****************************************************************************/ +static const crc_t crc_table[16] = { + 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, + 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c +}; + +/** + * Update the crc value with new data. + * + * \param crc The current crc value. + * \param data Pointer to a buffer of \a data_len bytes. + * \param data_len Number of bytes in the \a data buffer. + * \return The updated crc value. + *****************************************************************************/ +crc_t crc_update(crc_t crc, const void *data, size_t data_len) +{ + const unsigned char *d = (const unsigned char *)data; + unsigned int tbl_idx; + + while (data_len--) { + tbl_idx = crc ^ (*d >> (0 * 4)); + crc = crc_table[tbl_idx & 0x0f] ^ (crc >> 4); + tbl_idx = crc ^ (*d >> (1 * 4)); + crc = crc_table[tbl_idx & 0x0f] ^ (crc >> 4); + + d++; + } + return crc & 0xffffffff; +} + + diff --git a/crc.h b/crc.h new file mode 100644 index 0000000..4b45157 --- /dev/null +++ b/crc.h @@ -0,0 +1,82 @@ +/** + * \file crc.h + * Functions and types for CRC checks. + * + * Generated on Sun Dec 18 16:52:09 2016, + * by pycrc v0.9, https://pycrc.org + * using the configuration: + * Width = 32 + * Poly = 0x04c11db7 + * Xor_In = 0xffffffff + * ReflectIn = True + * Xor_Out = 0xffffffff + * ReflectOut = True + * Algorithm = table-driven + *****************************************************************************/ +#ifndef __CRC_H__ +#define __CRC_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * The definition of the used algorithm. + * + * This is not used anywhere in the generated code, but it may be used by the + * application code to call algoritm-specific code, is desired. + *****************************************************************************/ +#define CRC_ALGO_TABLE_DRIVEN 1 + + +/** + * The type of the CRC values. + * + * This type must be big enough to contain at least 32 bits. + *****************************************************************************/ +typedef uint_fast32_t crc_t; + + +/** + * Calculate the initial crc value. + * + * \return The initial crc value. + *****************************************************************************/ +static inline crc_t crc_init(void) +{ + return 0xffffffff; +} + + +/** + * Update the crc value with new data. + * + * \param crc The current crc value. + * \param data Pointer to a buffer of \a data_len bytes. + * \param data_len Number of bytes in the \a data buffer. + * \return The updated crc value. + *****************************************************************************/ +crc_t crc_update(crc_t crc, const void *data, size_t data_len); + + +/** + * Calculate the final crc value. + * + * \param crc The current crc value. + * \return The final crc value. + *****************************************************************************/ +static inline crc_t crc_finalize(crc_t crc) +{ + return crc ^ 0xffffffff; +} + + +#ifdef __cplusplus +} /* closing brace for extern "C" */ +#endif + +#endif /* __CRC_H__ */ diff --git a/crp.c b/crp.c new file mode 100644 index 0000000..6e33068 --- /dev/null +++ b/crp.c @@ -0,0 +1,27 @@ +//***************************************************************************** +// crp.c +// +// Source file to create CRP word expected by LPCXpresso IDE linker +//***************************************************************************** +// +// Copyright(C) NXP Semiconductors, 2013, 2020 +// All rights reserved. +// +// NXP Confidential. This software is owned or controlled by NXP and may only be +// used strictly in accordance with the applicable license terms. +// +// By expressly accepting such terms or by downloading, installing, activating +// and/or otherwise using the software, you are agreeing that you have read, and +// that you agree to comply with and are bound by, such license terms. +// +// If you do not agree to be bound by the applicable license terms, then you may not +// retain, install, activate or otherwise use the software. +//***************************************************************************** + +#if defined (__CODE_RED) +#include +// Variable to store CRP value in. Will be placed automatically +// by the linker when "Enable Code Read Protect" selected. +// See crp.h header for more information +__CRP const unsigned int CRP_WORD = CRP_NO_CRP ; +#endif diff --git a/iap.c b/iap.c new file mode 100644 index 0000000..5e49178 --- /dev/null +++ b/iap.c @@ -0,0 +1,138 @@ +/* +=============================================================================== + Name : iap.c + Author : $(author) + Version : + Copyright : $(copyright) + Description : main definition +=============================================================================== +*/ + +#ifdef __USE_CMSIS +#include "LPC17xx.h" +#endif + +#include "iap.h" + +uint32_t command[5]; +uint32_t output[5]; +IAP iap_entry =(IAP) IAP_LOCATION; + + +volatile char test[32] = {'t', 'e', 's', 't', 'i', 'n', 'g', '!', + 't', 'e', 's', 't', 'i', 'n', 'g', '!', + 't', 'e', 's', 't', 'i', 'n', 'g', '!', + 't', 'e', 's', 't', 'i', 'n', 'g', '!'}; + +void iap_everything_is_alright(void){ + LPC_GPIO2->FIOPIN = 0x00; +} +void iap_something_went_wrong(int error_code){ + LPC_GPIO2->FIOPIN = error_code; +} +void iap_entry_wrapped(void){ + __disable_irq(); + iap_entry(command, output); + __enable_irq(); +} + +/*void iap_read_part_id(void){ + command[0] = 54; + iap_entry_wrapped(); + if(output[0] == IAP_CMD_SUCCESS){ + iap_everything_is_alright(); + printf("part id is %d\n", output[1]); + }else{ + iap_something_went_wrong(output[0]); + } +}*/ + +void iap_prepare_sectors(error_code* status, int start, int end){ + command[0] = 50; + command[1] = start; + command[2] = end; + iap_entry_wrapped(); + if(output[0] == IAP_CMD_SUCCESS) { + iap_everything_is_alright(); + *status = 0; + }else{ + iap_something_went_wrong(output[0]); + *status = -1; + } +} + +void iap_erase_sectors(error_code* status, int start, int end){ + iap_prepare_sectors(status, start, end); + command[0] = 52; //erase sectors + command[1] = start; //start sector + command[2] = end; //end sector + command[3] = IAP_CLOCK_100M; + iap_entry_wrapped(); + if(output[0] == IAP_CMD_SUCCESS) { + iap_everything_is_alright(); + }else{ + iap_something_went_wrong(output[0]); + } +} + +uint32_t iap_read_part_id(error_code* status){ + //iap_prepare_sectors(dst_flash, dst_flash+num_bytes-1); + iap_prepare_sectors(status, 2, 9); + command[0] = 54; + iap_entry_wrapped(); + if(output[0] == IAP_CMD_SUCCESS) { + iap_everything_is_alright(); + *status = 0; + return output[1]; + }else{ + iap_something_went_wrong(output[0]); + *status = -1; + return -1; + } +} + +void iap_copy_to_flash(error_code* status, int dst_flash, uint32_t* src_ram, int num_bytes){ + iap_prepare_sectors(status, dst_flash, dst_flash+num_bytes); + //iap_prepare_sectors(2, 9); + command[0] = 51; + command[1] = dst_flash; + command[2] = *src_ram; + command[3] = num_bytes; + iap_entry_wrapped(); + if(output[0] == IAP_CMD_SUCCESS) { + iap_everything_is_alright(); + *status = 0; + }else{ + iap_something_went_wrong(output[0]); + *status = -1; + } +} + +void iap_read_serial(error_code* status, uint32_t* res){ + iap_prepare_sectors(status, 2, 9); + command[0] = 58; + iap_entry_wrapped(); + if(output[0] == IAP_CMD_SUCCESS) { + iap_everything_is_alright(); + *status = 0; + res[0] = output[1]; + res[1] = output[2]; + res[2] = output[3]; + res[3] = output[4]; + }else{ + iap_something_went_wrong(output[0]); + *status = -1; + } +} + +// TODO: insert other include files here + +// TODO: insert other definitions and declarations here +/* +int main(void) { + LPC_PINCON->PINSEL4 &= ~0xFF; //Configure the PORT2 Pins as GPIO; + LPC_GPIO2->FIODIR = 0xff; //Configure the PORT2 pins as OUTPUT; + iap_read_part_id(); + iap_erase_sectors(2, 9); + iap_copy_to_flash(0x8000,(uint8_t*)test, 4); +}*/ diff --git a/iap.h b/iap.h new file mode 100644 index 0000000..cc780b8 --- /dev/null +++ b/iap.h @@ -0,0 +1,43 @@ +#include + +#include + +#define IAP_LOCATION 0x1FFF1FF1 +#define IAP_CMD_SUCCESS 0 +#define IAP_INVALID_COMMAND 1 +#define IAP_SRC_ADDR_ERROR 2 +#define IAP_DST_ADDR_ERROR 3 +#define IAP_SRC_ADDR_NOT_MAPPED 4 +#define IAP_DST_ADDR_NOT_MAPPED 5 +#define IAP_COUNT_ERROR 6 +#define IAP_INVALID_SECTOR 7 +#define IAP_SECTOR_NOT_BLANK 8 +#define IAP_SECTOR_NOT_PREPARED_FOR_WRITE_OPERATION 9 +#define IAP_COMPARE_ERROR 10 +#define IAP_BUSY 11 +#define IAP_CLOCK_100M 100000 + + +typedef enum _error_code { + ok, general_error, invalid_command, global_checksum, + local_checksum, erase_error, write_error, invalid_size, + invalid_offset, invalid_arguments +} error_code; + +typedef void (*IAP)(unsigned int[], unsigned int[]); + + +void iap_everything_is_alright(void); +void iap_something_went_wrong(int error_code); + + +void iap_prepare_sectors(error_code* status, int start, int end); + +void iap_erase_sectors(error_code* status, int start, int end); + +void iap_copy_to_flash(error_code* status, int dst_flash, uint32_t* src_ram, int num_bytes); + +uint32_t iap_read_part_id(error_code* status); + +void iap_read_serial(error_code* status, uint32_t* res); + diff --git a/log b/log new file mode 100644 index 0000000..f42e956 --- /dev/null +++ b/log @@ -0,0 +1,893 @@ +python3 mylab2-programmer.py --port /dev/ttyUSB0 sonic_50b03eb0.bin --verbose +>>> b'GETID\r\n' +<<< b'OK\r\n' +<<< b'0x26113f37\r\n' +>>> b'GETSERIAL\r\n' +<<< b'OK\r\n' +<<< b'0x101600caf27a5225a53f5f9f50020c2\r\n' +Connecté au bootloader myLab2-MIP: +PartID: 0x26113f37 +Serial: 0x101600caf27a5225a53f5f9f50020c2 +Envoi sonic_50b03eb0.bin à la myLab2, taille: 298816, CRC32: 0x50b03eb0, bs=1024 +>>> b'PROG,0x00004000,0x00048f40,0x50b03eb0\r\n' +<<< b'OK\r\n' +Envoi bloc 1/292 (0x00000000 à 0x000003ff) +>>> b'DATA,0x0400,0x743f4089\r\n' +<<< b'OK\r\n' +Envoi bloc 2/292 (0x00000400 à 0x000007ff) +>>> b'DATA,0x0400,0xb6e5b801\r\n' +<<< b'OK\r\n' +Envoi bloc 3/292 (0x00000800 à 0x00000bff) +>>> b'DATA,0x0400,0xb03a067d\r\n' +<<< b'OK\r\n' +Envoi bloc 4/292 (0x00000c00 à 0x00000fff) +>>> b'DATA,0x0400,0x32a91d8d\r\n' +<<< b'OK\r\n' +Envoi bloc 5/292 (0x00001000 à 0x000013ff) +>>> b'DATA,0x0400,0x03a96542\r\n' +<<< b'OK\r\n' +Envoi bloc 6/292 (0x00001400 à 0x000017ff) +>>> b'DATA,0x0400,0xaf5221cc\r\n' +<<< b'OK\r\n' +Envoi bloc 7/292 (0x00001800 à 0x00001bff) +>>> b'DATA,0x0400,0xeca6a6a0\r\n' +<<< b'OK\r\n' +Envoi bloc 8/292 (0x00001c00 à 0x00001fff) +>>> b'DATA,0x0400,0x786e241a\r\n' +<<< b'OK\r\n' +Envoi bloc 9/292 (0x00002000 à 0x000023ff) +>>> b'DATA,0x0400,0xd84c0e06\r\n' +<<< b'OK\r\n' +Envoi bloc 10/292 (0x00002400 à 0x000027ff) +>>> b'DATA,0x0400,0x91e29ff7\r\n' +<<< b'OK\r\n' +Envoi bloc 11/292 (0x00002800 à 0x00002bff) +>>> b'DATA,0x0400,0x90c3380c\r\n' +<<< b'OK\r\n' +Envoi bloc 12/292 (0x00002c00 à 0x00002fff) +>>> b'DATA,0x0400,0x4309179b\r\n' +<<< b'OK\r\n' +Envoi bloc 13/292 (0x00003000 à 0x000033ff) +>>> b'DATA,0x0400,0x206c4b74\r\n' +<<< b'OK\r\n' +Envoi bloc 14/292 (0x00003400 à 0x000037ff) +>>> b'DATA,0x0400,0xcb32819b\r\n' +<<< b'OK\r\n' +Envoi bloc 15/292 (0x00003800 à 0x00003bff) +>>> b'DATA,0x0400,0xff10adbc\r\n' +<<< b'OK\r\n' +Envoi bloc 16/292 (0x00003c00 à 0x00003fff) +>>> b'DATA,0x0400,0x704a5bea\r\n' +<<< b'OK\r\n' +Envoi bloc 17/292 (0x00004000 à 0x000043ff) +>>> b'DATA,0x0400,0x08bbbd57\r\n' +<<< b'OK\r\n' +Envoi bloc 18/292 (0x00004400 à 0x000047ff) +>>> b'DATA,0x0400,0x2609eaaa\r\n' +<<< b'OK\r\n' +Envoi bloc 19/292 (0x00004800 à 0x00004bff) +>>> b'DATA,0x0400,0xf98d6399\r\n' +<<< b'OK\r\n' +Envoi bloc 20/292 (0x00004c00 à 0x00004fff) +>>> b'DATA,0x0400,0xdb949daf\r\n' +<<< b'OK\r\n' +Envoi bloc 21/292 (0x00005000 à 0x000053ff) +>>> b'DATA,0x0400,0x5cc74aa0\r\n' +<<< b'OK\r\n' +Envoi bloc 22/292 (0x00005400 à 0x000057ff) +>>> b'DATA,0x0400,0xd22a8b62\r\n' +<<< b'OK\r\n' +Envoi bloc 23/292 (0x00005800 à 0x00005bff) +>>> b'DATA,0x0400,0xded1be71\r\n' +<<< b'OK\r\n' +Envoi bloc 24/292 (0x00005c00 à 0x00005fff) +>>> b'DATA,0x0400,0xc9102f12\r\n' +<<< b'OK\r\n' +Envoi bloc 25/292 (0x00006000 à 0x000063ff) +>>> b'DATA,0x0400,0x7d7a5c4c\r\n' +<<< b'OK\r\n' +Envoi bloc 26/292 (0x00006400 à 0x000067ff) +>>> b'DATA,0x0400,0xefb5af2e\r\n' +<<< b'OK\r\n' +Envoi bloc 27/292 (0x00006800 à 0x00006bff) +>>> b'DATA,0x0400,0xefb5af2e\r\n' +<<< b'OK\r\n' +Envoi bloc 28/292 (0x00006c00 à 0x00006fff) +>>> b'DATA,0x0400,0xd3265046\r\n' +<<< b'OK\r\n' +Envoi bloc 29/292 (0x00007000 à 0x000073ff) +>>> b'DATA,0x0400,0x9e107903\r\n' +<<< b'OK\r\n' +Envoi bloc 30/292 (0x00007400 à 0x000077ff) +>>> b'DATA,0x0400,0xecc38415\r\n' +<<< b'OK\r\n' +Envoi bloc 31/292 (0x00007800 à 0x00007bff) +>>> b'DATA,0x0400,0x84a0604f\r\n' +<<< b'OK\r\n' +Envoi bloc 32/292 (0x00007c00 à 0x00007fff) +>>> b'DATA,0x0400,0xefb5af2e\r\n' +<<< b'OK\r\n' +Envoi bloc 33/292 (0x00008000 à 0x000083ff) +>>> b'DATA,0x0400,0xefb5af2e\r\n' +<<< b'OK\r\n' +Envoi bloc 34/292 (0x00008400 à 0x000087ff) +>>> b'DATA,0x0400,0x3866cad8\r\n' +<<< b'OK\r\n' +Envoi bloc 35/292 (0x00008800 à 0x00008bff) +>>> b'DATA,0x0400,0xefb5af2e\r\n' +<<< b'OK\r\n' +Envoi bloc 36/292 (0x00008c00 à 0x00008fff) +>>> b'DATA,0x0400,0x6cc8853d\r\n' +<<< b'OK\r\n' +Envoi bloc 37/292 (0x00009000 à 0x000093ff) +>>> b'DATA,0x0400,0xc44f4bff\r\n' +<<< b'OK\r\n' +Envoi bloc 38/292 (0x00009400 à 0x000097ff) +>>> b'DATA,0x0400,0xb50c0027\r\n' +<<< b'OK\r\n' +Envoi bloc 39/292 (0x00009800 à 0x00009bff) +>>> b'DATA,0x0400,0x950d6587\r\n' +<<< b'OK\r\n' +Envoi bloc 40/292 (0x00009c00 à 0x00009fff) +>>> b'DATA,0x0400,0x354871d0\r\n' +<<< b'OK\r\n' +Envoi bloc 41/292 (0x0000a000 à 0x0000a3ff) +>>> b'DATA,0x0400,0xefb5af2e\r\n' +<<< b'OK\r\n' +Envoi bloc 42/292 (0x0000a400 à 0x0000a7ff) +>>> b'DATA,0x0400,0xefb5af2e\r\n' +<<< b'OK\r\n' +Envoi bloc 43/292 (0x0000a800 à 0x0000abff) +>>> b'DATA,0x0400,0x94c72b47\r\n' +<<< b'OK\r\n' +Envoi bloc 44/292 (0x0000ac00 à 0x0000afff) +>>> b'DATA,0x0400,0xefb5af2e\r\n' +<<< b'OK\r\n' +Envoi bloc 45/292 (0x0000b000 à 0x0000b3ff) +>>> b'DATA,0x0400,0xf63fdc5e\r\n' +<<< b'OK\r\n' +Envoi bloc 46/292 (0x0000b400 à 0x0000b7ff) +>>> b'DATA,0x0400,0x7203b3f5\r\n' +<<< b'OK\r\n' +Envoi bloc 47/292 (0x0000b800 à 0x0000bbff) +>>> b'DATA,0x0400,0x29b270e4\r\n' +<<< b'OK\r\n' +Envoi bloc 48/292 (0x0000bc00 à 0x0000bfff) +>>> b'DATA,0x0400,0x2db03acb\r\n' +<<< b'OK\r\n' +Envoi bloc 49/292 (0x0000c000 à 0x0000c3ff) +>>> b'DATA,0x0400,0xefb5af2e\r\n' +<<< b'OK\r\n' +Envoi bloc 50/292 (0x0000c400 à 0x0000c7ff) +>>> b'DATA,0x0400,0xefb5af2e\r\n' +<<< b'OK\r\n' +Envoi bloc 51/292 (0x0000c800 à 0x0000cbff) +>>> b'DATA,0x0400,0xc8d176f3\r\n' +<<< b'OK\r\n' +Envoi bloc 52/292 (0x0000cc00 à 0x0000cfff) +>>> b'DATA,0x0400,0xefb5af2e\r\n' +<<< b'OK\r\n' +Envoi bloc 53/292 (0x0000d000 à 0x0000d3ff) +>>> b'DATA,0x0400,0xdc2d9889\r\n' +<<< b'OK\r\n' +Envoi bloc 54/292 (0x0000d400 à 0x0000d7ff) +>>> b'DATA,0x0400,0xce3f9041\r\n' +<<< b'OK\r\n' +Envoi bloc 55/292 (0x0000d800 à 0x0000dbff) +>>> b'DATA,0x0400,0xc81d96b9\r\n' +<<< b'OK\r\n' +Envoi bloc 56/292 (0x0000dc00 à 0x0000dfff) +>>> b'DATA,0x0400,0xd1971639\r\n' +<<< b'OK\r\n' +Envoi bloc 57/292 (0x0000e000 à 0x0000e3ff) +>>> b'DATA,0x0400,0xe1fec03e\r\n' +<<< b'OK\r\n' +Envoi bloc 58/292 (0x0000e400 à 0x0000e7ff) +>>> b'DATA,0x0400,0xefb5af2e\r\n' +<<< b'OK\r\n' +Envoi bloc 59/292 (0x0000e800 à 0x0000ebff) +>>> b'DATA,0x0400,0xefb5af2e\r\n' +<<< b'OK\r\n' +Envoi bloc 60/292 (0x0000ec00 à 0x0000efff) +>>> b'DATA,0x0400,0x07eecd61\r\n' +<<< b'OK\r\n' +Envoi bloc 61/292 (0x0000f000 à 0x0000f3ff) +>>> b'DATA,0x0400,0xefb5af2e\r\n' +<<< b'OK\r\n' +Envoi bloc 62/292 (0x0000f400 à 0x0000f7ff) +>>> b'DATA,0x0400,0x378f2e3a\r\n' +<<< b'OK\r\n' +Envoi bloc 63/292 (0x0000f800 à 0x0000fbff) +>>> b'DATA,0x0400,0xf4752beb\r\n' +<<< b'OK\r\n' +Envoi bloc 64/292 (0x0000fc00 à 0x0000ffff) +>>> b'DATA,0x0400,0x1361f2d5\r\n' +<<< b'OK\r\n' +Envoi bloc 65/292 (0x00010000 à 0x000103ff) +>>> b'DATA,0x0400,0x90f09d53\r\n' +<<< b'OK\r\n' +Envoi bloc 66/292 (0x00010400 à 0x000107ff) +>>> b'DATA,0x0400,0x982225b1\r\n' +<<< b'OK\r\n' +Envoi bloc 67/292 (0x00010800 à 0x00010bff) +>>> b'DATA,0x0400,0xefb5af2e\r\n' +<<< b'OK\r\n' +Envoi bloc 68/292 (0x00010c00 à 0x00010fff) +>>> b'DATA,0x0400,0xa7ce9994\r\n' +<<< b'OK\r\n' +Envoi bloc 69/292 (0x00011000 à 0x000113ff) +>>> b'DATA,0x0400,0xefb5af2e\r\n' +<<< b'OK\r\n' +Envoi bloc 70/292 (0x00011400 à 0x000117ff) +>>> b'DATA,0x0400,0xefb5af2e\r\n' +<<< b'OK\r\n' +Envoi bloc 71/292 (0x00011800 à 0x00011bff) +>>> b'DATA,0x0400,0x0b5d0a73\r\n' +<<< b'OK\r\n' +Envoi bloc 72/292 (0x00011c00 à 0x00011fff) +>>> b'DATA,0x0400,0x1f13ca84\r\n' +<<< b'OK\r\n' +Envoi bloc 73/292 (0x00012000 à 0x000123ff) +>>> b'DATA,0x0400,0xfba052c3\r\n' +<<< b'OK\r\n' +Envoi bloc 74/292 (0x00012400 à 0x000127ff) +>>> b'DATA,0x0400,0x2ee8ea2a\r\n' +<<< b'OK\r\n' +Envoi bloc 75/292 (0x00012800 à 0x00012bff) +>>> b'DATA,0x0400,0xefb5af2e\r\n' +<<< b'OK\r\n' +Envoi bloc 76/292 (0x00012c00 à 0x00012fff) +>>> b'DATA,0x0400,0xefb5af2e\r\n' +<<< b'OK\r\n' +Envoi bloc 77/292 (0x00013000 à 0x000133ff) +>>> b'DATA,0x0400,0x58bd92dd\r\n' +<<< b'OK\r\n' +Envoi bloc 78/292 (0x00013400 à 0x000137ff) +>>> b'DATA,0x0400,0xefb5af2e\r\n' +<<< b'OK\r\n' +Envoi bloc 79/292 (0x00013800 à 0x00013bff) +>>> b'DATA,0x0400,0xefb5af2e\r\n' +<<< b'OK\r\n' +Envoi bloc 80/292 (0x00013c00 à 0x00013fff) +>>> b'DATA,0x0400,0x28c08220\r\n' +<<< b'OK\r\n' +Envoi bloc 81/292 (0x00014000 à 0x000143ff) +>>> b'DATA,0x0400,0x72d754e4\r\n' +<<< b'OK\r\n' +Envoi bloc 82/292 (0x00014400 à 0x000147ff) +>>> b'DATA,0x0400,0x2d7942d6\r\n' +<<< b'OK\r\n' +Envoi bloc 83/292 (0x00014800 à 0x00014bff) +>>> b'DATA,0x0400,0xc506a186\r\n' +<<< b'OK\r\n' +Envoi bloc 84/292 (0x00014c00 à 0x00014fff) +>>> b'DATA,0x0400,0xefb5af2e\r\n' +<<< b'OK\r\n' +Envoi bloc 85/292 (0x00015000 à 0x000153ff) +>>> b'DATA,0x0400,0xefb5af2e\r\n' +<<< b'OK\r\n' +Envoi bloc 86/292 (0x00015400 à 0x000157ff) +>>> b'DATA,0x0400,0xcdf8f836\r\n' +<<< b'OK\r\n' +Envoi bloc 87/292 (0x00015800 à 0x00015bff) +>>> b'DATA,0x0400,0xefb5af2e\r\n' +<<< b'OK\r\n' +Envoi bloc 88/292 (0x00015c00 à 0x00015fff) +>>> b'DATA,0x0400,0x6a5c9725\r\n' +<<< b'OK\r\n' +Envoi bloc 89/292 (0x00016000 à 0x000163ff) +>>> b'DATA,0x0400,0xa3d2ba5f\r\n' +<<< b'OK\r\n' +Envoi bloc 90/292 (0x00016400 à 0x000167ff) +>>> b'DATA,0x0400,0xdabfd721\r\n' +<<< b'OK\r\n' +Envoi bloc 91/292 (0x00016800 à 0x00016bff) +>>> b'DATA,0x0400,0xc3168641\r\n' +<<< b'OK\r\n' +Envoi bloc 92/292 (0x00016c00 à 0x00016fff) +>>> b'DATA,0x0400,0xb3f0c585\r\n' +<<< b'OK\r\n' +Envoi bloc 93/292 (0x00017000 à 0x000173ff) +>>> b'DATA,0x0400,0xefb5af2e\r\n' +<<< b'OK\r\n' +Envoi bloc 94/292 (0x00017400 à 0x000177ff) +>>> b'DATA,0x0400,0x4f0ab4ec\r\n' +<<< b'OK\r\n' +Envoi bloc 95/292 (0x00017800 à 0x00017bff) +>>> b'DATA,0x0400,0xefb5af2e\r\n' +<<< b'OK\r\n' +Envoi bloc 96/292 (0x00017c00 à 0x00017fff) +>>> b'DATA,0x0400,0xefb5af2e\r\n' +<<< b'OK\r\n' +Envoi bloc 97/292 (0x00018000 à 0x000183ff) +>>> b'DATA,0x0400,0x600e10fc\r\n' +<<< b'OK\r\n' +Envoi bloc 98/292 (0x00018400 à 0x000187ff) +>>> b'DATA,0x0400,0xca0a6740\r\n' +<<< b'OK\r\n' +Envoi bloc 99/292 (0x00018800 à 0x00018bff) +>>> b'DATA,0x0400,0x3db01e96\r\n' +<<< b'OK\r\n' +Envoi bloc 100/292 (0x00018c00 à 0x00018fff) +>>> b'DATA,0x0400,0x12be8748\r\n' +<<< b'OK\r\n' +Envoi bloc 101/292 (0x00019000 à 0x000193ff) +>>> b'DATA,0x0400,0x92420a9c\r\n' +<<< b'OK\r\n' +Envoi bloc 102/292 (0x00019400 à 0x000197ff) +>>> b'DATA,0x0400,0xefb5af2e\r\n' +<<< b'OK\r\n' +Envoi bloc 103/292 (0x00019800 à 0x00019bff) +>>> b'DATA,0x0400,0x0a720279\r\n' +<<< b'OK\r\n' +Envoi bloc 104/292 (0x00019c00 à 0x00019fff) +>>> b'DATA,0x0400,0xefb5af2e\r\n' +<<< b'OK\r\n' +Envoi bloc 105/292 (0x0001a000 à 0x0001a3ff) +>>> b'DATA,0x0400,0xae4b70e7\r\n' +<<< b'OK\r\n' +Envoi bloc 106/292 (0x0001a400 à 0x0001a7ff) +>>> b'DATA,0x0400,0x1dfc98c2\r\n' +<<< b'OK\r\n' +Envoi bloc 107/292 (0x0001a800 à 0x0001abff) +>>> b'DATA,0x0400,0xd7133a9d\r\n' +<<< b'OK\r\n' +Envoi bloc 108/292 (0x0001ac00 à 0x0001afff) +>>> b'DATA,0x0400,0xca4c0f59\r\n' +<<< b'OK\r\n' +Envoi bloc 109/292 (0x0001b000 à 0x0001b3ff) +>>> b'DATA,0x0400,0xb5236d41\r\n' +<<< b'OK\r\n' +Envoi bloc 110/292 (0x0001b400 à 0x0001b7ff) +>>> b'DATA,0x0400,0xfd5cb16b\r\n' +<<< b'OK\r\n' +Envoi bloc 111/292 (0x0001b800 à 0x0001bbff) +>>> b'DATA,0x0400,0xefb5af2e\r\n' +<<< b'OK\r\n' +Envoi bloc 112/292 (0x0001bc00 à 0x0001bfff) +>>> b'DATA,0x0400,0xbceb5cfa\r\n' +<<< b'OK\r\n' +Envoi bloc 113/292 (0x0001c000 à 0x0001c3ff) +>>> b'DATA,0x0400,0xefb5af2e\r\n' +<<< b'OK\r\n' +Envoi bloc 114/292 (0x0001c400 à 0x0001c7ff) +>>> b'DATA,0x0400,0x0aeca21f\r\n' +<<< b'OK\r\n' +Envoi bloc 115/292 (0x0001c800 à 0x0001cbff) +>>> b'DATA,0x0400,0x4a26b094\r\n' +<<< b'OK\r\n' +Envoi bloc 116/292 (0x0001cc00 à 0x0001cfff) +>>> b'DATA,0x0400,0xc1bc99b7\r\n' +<<< b'OK\r\n' +Envoi bloc 117/292 (0x0001d000 à 0x0001d3ff) +>>> b'DATA,0x0400,0xb08ce103\r\n' +<<< b'OK\r\n' +Envoi bloc 118/292 (0x0001d400 à 0x0001d7ff) +>>> b'DATA,0x0400,0xefb5af2e\r\n' +<<< b'OK\r\n' +Envoi bloc 119/292 (0x0001d800 à 0x0001dbff) +>>> b'DATA,0x0400,0xefb5af2e\r\n' +<<< b'OK\r\n' +Envoi bloc 120/292 (0x0001dc00 à 0x0001dfff) +>>> b'DATA,0x0400,0xf465ab82\r\n' +<<< b'OK\r\n' +Envoi bloc 121/292 (0x0001e000 à 0x0001e3ff) +>>> b'DATA,0x0400,0xefb5af2e\r\n' +<<< b'OK\r\n' +Envoi bloc 122/292 (0x0001e400 à 0x0001e7ff) +>>> b'DATA,0x0400,0x0c11b8c0\r\n' +<<< b'OK\r\n' +Envoi bloc 123/292 (0x0001e800 à 0x0001ebff) +>>> b'DATA,0x0400,0x2c04d917\r\n' +<<< b'OK\r\n' +Envoi bloc 124/292 (0x0001ec00 à 0x0001efff) +>>> b'DATA,0x0400,0xa3553245\r\n' +<<< b'OK\r\n' +Envoi bloc 125/292 (0x0001f000 à 0x0001f3ff) +>>> b'DATA,0x0400,0x09143cae\r\n' +<<< b'OK\r\n' +Envoi bloc 126/292 (0x0001f400 à 0x0001f7ff) +>>> b'DATA,0x0400,0xf2d45f03\r\n' +<<< b'OK\r\n' +Envoi bloc 127/292 (0x0001f800 à 0x0001fbff) +>>> b'DATA,0x0400,0x06d86dec\r\n' +<<< b'OK\r\n' +Envoi bloc 128/292 (0x0001fc00 à 0x0001ffff) +>>> b'DATA,0x0400,0xefb5af2e\r\n' +<<< b'OK\r\n' +Envoi bloc 129/292 (0x00020000 à 0x000203ff) +>>> b'DATA,0x0400,0x99311ca4\r\n' +<<< b'OK\r\n' +Envoi bloc 130/292 (0x00020400 à 0x000207ff) +>>> b'DATA,0x0400,0xefb5af2e\r\n' +<<< b'OK\r\n' +Envoi bloc 131/292 (0x00020800 à 0x00020bff) +>>> b'DATA,0x0400,0x9538ede0\r\n' +<<< b'OK\r\n' +Envoi bloc 132/292 (0x00020c00 à 0x00020fff) +>>> b'DATA,0x0400,0x01f1d0aa\r\n' +<<< b'OK\r\n' +Envoi bloc 133/292 (0x00021000 à 0x000213ff) +>>> b'DATA,0x0400,0x5fc36d67\r\n' +<<< b'OK\r\n' +Envoi bloc 134/292 (0x00021400 à 0x000217ff) +>>> b'DATA,0x0400,0x3b61ca7b\r\n' +<<< b'OK\r\n' +Envoi bloc 135/292 (0x00021800 à 0x00021bff) +>>> b'DATA,0x0400,0xd4401316\r\n' +<<< b'OK\r\n' +Envoi bloc 136/292 (0x00021c00 à 0x00021fff) +>>> b'DATA,0x0400,0xefb5af2e\r\n' +<<< b'OK\r\n' +Envoi bloc 137/292 (0x00022000 à 0x000223ff) +>>> b'DATA,0x0400,0xefb5af2e\r\n' +<<< b'OK\r\n' +Envoi bloc 138/292 (0x00022400 à 0x000227ff) +>>> b'DATA,0x0400,0xc74fc22d\r\n' +<<< b'OK\r\n' +Envoi bloc 139/292 (0x00022800 à 0x00022bff) +>>> b'DATA,0x0400,0xefb5af2e\r\n' +<<< b'OK\r\n' +Envoi bloc 140/292 (0x00022c00 à 0x00022fff) +>>> b'DATA,0x0400,0x8c44f3c3\r\n' +<<< b'OK\r\n' +Envoi bloc 141/292 (0x00023000 à 0x000233ff) +>>> b'DATA,0x0400,0xf2a29ff4\r\n' +<<< b'OK\r\n' +Envoi bloc 142/292 (0x00023400 à 0x000237ff) +>>> b'DATA,0x0400,0x62d2a1ce\r\n' +<<< b'OK\r\n' +Envoi bloc 143/292 (0x00023800 à 0x00023bff) +>>> b'DATA,0x0400,0xf3c597f7\r\n' +<<< b'OK\r\n' +Envoi bloc 144/292 (0x00023c00 à 0x00023fff) +>>> b'DATA,0x0400,0xf94dec31\r\n' +<<< b'OK\r\n' +Envoi bloc 145/292 (0x00024000 à 0x000243ff) +>>> b'DATA,0x0400,0xefb5af2e\r\n' +<<< b'OK\r\n' +Envoi bloc 146/292 (0x00024400 à 0x000247ff) +>>> b'DATA,0x0400,0xfd2ac2a6\r\n' +<<< b'OK\r\n' +Envoi bloc 147/292 (0x00024800 à 0x00024bff) +>>> b'DATA,0x0400,0xefb5af2e\r\n' +<<< b'OK\r\n' +Envoi bloc 148/292 (0x00024c00 à 0x00024fff) +>>> b'DATA,0x0400,0xe1320841\r\n' +<<< b'OK\r\n' +Envoi bloc 149/292 (0x00025000 à 0x000253ff) +>>> b'DATA,0x0400,0x59fa90e6\r\n' +<<< b'OK\r\n' +Envoi bloc 150/292 (0x00025400 à 0x000257ff) +>>> b'DATA,0x0400,0x079d54cc\r\n' +<<< b'OK\r\n' +Envoi bloc 151/292 (0x00025800 à 0x00025bff) +>>> b'DATA,0x0400,0xb914ab8f\r\n' +<<< b'OK\r\n' +Envoi bloc 152/292 (0x00025c00 à 0x00025fff) +>>> b'DATA,0x0400,0x79ba480c\r\n' +<<< b'OK\r\n' +Envoi bloc 153/292 (0x00026000 à 0x000263ff) +>>> b'DATA,0x0400,0xefb5af2e\r\n' +<<< b'OK\r\n' +Envoi bloc 154/292 (0x00026400 à 0x000267ff) +>>> b'DATA,0x0400,0xefb5af2e\r\n' +<<< b'OK\r\n' +Envoi bloc 155/292 (0x00026800 à 0x00026bff) +>>> b'DATA,0x0400,0x261d6cea\r\n' +<<< b'OK\r\n' +Envoi bloc 156/292 (0x00026c00 à 0x00026fff) +>>> b'DATA,0x0400,0xefb5af2e\r\n' +<<< b'OK\r\n' +Envoi bloc 157/292 (0x00027000 à 0x000273ff) +>>> b'DATA,0x0400,0xbd079d5d\r\n' +<<< b'OK\r\n' +Envoi bloc 158/292 (0x00027400 à 0x000277ff) +>>> b'DATA,0x0400,0x2fde35b9\r\n' +<<< b'OK\r\n' +Envoi bloc 159/292 (0x00027800 à 0x00027bff) +>>> b'DATA,0x0400,0x0f804b73\r\n' +<<< b'OK\r\n' +Envoi bloc 160/292 (0x00027c00 à 0x00027fff) +>>> b'DATA,0x0400,0xd8f5c66f\r\n' +<<< b'OK\r\n' +Envoi bloc 161/292 (0x00028000 à 0x000283ff) +>>> b'DATA,0x0400,0xc673f60e\r\n' +<<< b'OK\r\n' +Envoi bloc 162/292 (0x00028400 à 0x000287ff) +>>> b'DATA,0x0400,0xefb5af2e\r\n' +<<< b'OK\r\n' +Envoi bloc 163/292 (0x00028800 à 0x00028bff) +>>> b'DATA,0x0400,0xff57319f\r\n' +<<< b'OK\r\n' +Envoi bloc 164/292 (0x00028c00 à 0x00028fff) +>>> b'DATA,0x0400,0xefb5af2e\r\n' +<<< b'OK\r\n' +Envoi bloc 165/292 (0x00029000 à 0x000293ff) +>>> b'DATA,0x0400,0xefb5af2e\r\n' +<<< b'OK\r\n' +Envoi bloc 166/292 (0x00029400 à 0x000297ff) +>>> b'DATA,0x0400,0x1ea86e8c\r\n' +<<< b'OK\r\n' +Envoi bloc 167/292 (0x00029800 à 0x00029bff) +>>> b'DATA,0x0400,0x4c712980\r\n' +<<< b'OK\r\n' +Envoi bloc 168/292 (0x00029c00 à 0x00029fff) +>>> b'DATA,0x0400,0xf1bdce3d\r\n' +<<< b'OK\r\n' +Envoi bloc 169/292 (0x0002a000 à 0x0002a3ff) +>>> b'DATA,0x0400,0x95d3cfd3\r\n' +<<< b'OK\r\n' +Envoi bloc 170/292 (0x0002a400 à 0x0002a7ff) +>>> b'DATA,0x0400,0xdc7ef068\r\n' +<<< b'OK\r\n' +Envoi bloc 171/292 (0x0002a800 à 0x0002abff) +>>> b'DATA,0x0400,0xefb5af2e\r\n' +<<< b'OK\r\n' +Envoi bloc 172/292 (0x0002ac00 à 0x0002afff) +>>> b'DATA,0x0400,0x48aee718\r\n' +<<< b'OK\r\n' +Envoi bloc 173/292 (0x0002b000 à 0x0002b3ff) +>>> b'DATA,0x0400,0x3cb0b52c\r\n' +<<< b'OK\r\n' +Envoi bloc 174/292 (0x0002b400 à 0x0002b7ff) +>>> b'DATA,0x0400,0x7c7f908f\r\n' +<<< b'OK\r\n' +Envoi bloc 175/292 (0x0002b800 à 0x0002bbff) +>>> b'DATA,0x0400,0xd8fc6d9c\r\n' +<<< b'OK\r\n' +Envoi bloc 176/292 (0x0002bc00 à 0x0002bfff) +>>> b'DATA,0x0400,0x1341e75e\r\n' +<<< b'OK\r\n' +Envoi bloc 177/292 (0x0002c000 à 0x0002c3ff) +>>> b'DATA,0x0400,0x7c3dbc9c\r\n' +<<< b'OK\r\n' +Envoi bloc 178/292 (0x0002c400 à 0x0002c7ff) +>>> b'DATA,0x0400,0x757ca3fd\r\n' +<<< b'OK\r\n' +Envoi bloc 179/292 (0x0002c800 à 0x0002cbff) +>>> b'DATA,0x0400,0x3cb0b52c\r\n' +<<< b'OK\r\n' +Envoi bloc 180/292 (0x0002cc00 à 0x0002cfff) +>>> b'DATA,0x0400,0x3cb0b52c\r\n' +<<< b'OK\r\n' +Envoi bloc 181/292 (0x0002d000 à 0x0002d3ff) +>>> b'DATA,0x0400,0x647fe3d7\r\n' +<<< b'OK\r\n' +Envoi bloc 182/292 (0x0002d400 à 0x0002d7ff) +>>> b'DATA,0x0400,0x3cb0b52c\r\n' +<<< b'OK\r\n' +Envoi bloc 183/292 (0x0002d800 à 0x0002dbff) +>>> b'DATA,0x0400,0x552c3917\r\n' +<<< b'OK\r\n' +Envoi bloc 184/292 (0x0002dc00 à 0x0002dfff) +>>> b'DATA,0x0400,0xabde84c3\r\n' +<<< b'OK\r\n' +Envoi bloc 185/292 (0x0002e000 à 0x0002e3ff) +>>> b'DATA,0x0400,0xbcd84cfd\r\n' +<<< b'OK\r\n' +Envoi bloc 186/292 (0x0002e400 à 0x0002e7ff) +>>> b'DATA,0x0400,0xc7f7005d\r\n' +<<< b'OK\r\n' +Envoi bloc 187/292 (0x0002e800 à 0x0002ebff) +>>> b'DATA,0x0400,0x0dbd37fa\r\n' +<<< b'OK\r\n' +Envoi bloc 188/292 (0x0002ec00 à 0x0002efff) +>>> b'DATA,0x0400,0x3cb0b52c\r\n' +<<< b'OK\r\n' +Envoi bloc 189/292 (0x0002f000 à 0x0002f3ff) +>>> b'DATA,0x0400,0x0c77f51b\r\n' +<<< b'OK\r\n' +Envoi bloc 190/292 (0x0002f400 à 0x0002f7ff) +>>> b'DATA,0x0400,0x3cb0b52c\r\n' +<<< b'OK\r\n' +Envoi bloc 191/292 (0x0002f800 à 0x0002fbff) +>>> b'DATA,0x0400,0x3cb0b52c\r\n' +<<< b'OK\r\n' +Envoi bloc 192/292 (0x0002fc00 à 0x0002ffff) +>>> b'DATA,0x0400,0xe8a9a1dd\r\n' +<<< b'OK\r\n' +Envoi bloc 193/292 (0x00030000 à 0x000303ff) +>>> b'DATA,0x0400,0x9f59d483\r\n' +<<< b'OK\r\n' +Envoi bloc 194/292 (0x00030400 à 0x000307ff) +>>> b'DATA,0x0400,0x14c1d17d\r\n' +<<< b'OK\r\n' +Envoi bloc 195/292 (0x00030800 à 0x00030bff) +>>> b'DATA,0x0400,0x6c1dcfa0\r\n' +<<< b'OK\r\n' +Envoi bloc 196/292 (0x00030c00 à 0x00030fff) +>>> b'DATA,0x0400,0xf898a883\r\n' +<<< b'OK\r\n' +Envoi bloc 197/292 (0x00031000 à 0x000313ff) +>>> b'DATA,0x0400,0x3cb0b52c\r\n' +<<< b'OK\r\n' +Envoi bloc 198/292 (0x00031400 à 0x000317ff) +>>> b'DATA,0x0400,0x48f9eead\r\n' +<<< b'OK\r\n' +Envoi bloc 199/292 (0x00031800 à 0x00031bff) +>>> b'DATA,0x0400,0x3cb0b52c\r\n' +<<< b'OK\r\n' +Envoi bloc 200/292 (0x00031c00 à 0x00031fff) +>>> b'DATA,0x0400,0x25aaa865\r\n' +<<< b'OK\r\n' +Envoi bloc 201/292 (0x00032000 à 0x000323ff) +>>> b'DATA,0x0400,0x319590be\r\n' +<<< b'OK\r\n' +Envoi bloc 202/292 (0x00032400 à 0x000327ff) +>>> b'DATA,0x0400,0x6df5ac5c\r\n' +<<< b'OK\r\n' +Envoi bloc 203/292 (0x00032800 à 0x00032bff) +>>> b'DATA,0x0400,0x8d8cc48d\r\n' +<<< b'OK\r\n' +Envoi bloc 204/292 (0x00032c00 à 0x00032fff) +>>> b'DATA,0x0400,0xc89c2fd7\r\n' +<<< b'OK\r\n' +Envoi bloc 205/292 (0x00033000 à 0x000333ff) +>>> b'DATA,0x0400,0x05bb6835\r\n' +<<< b'OK\r\n' +Envoi bloc 206/292 (0x00033400 à 0x000337ff) +>>> b'DATA,0x0400,0x3cb0b52c\r\n' +<<< b'OK\r\n' +Envoi bloc 207/292 (0x00033800 à 0x00033bff) +>>> b'DATA,0x0400,0x534c79ab\r\n' +<<< b'OK\r\n' +Envoi bloc 208/292 (0x00033c00 à 0x00033fff) +>>> b'DATA,0x0400,0xefb5af2e\r\n' +<<< b'OK\r\n' +Envoi bloc 209/292 (0x00034000 à 0x000343ff) +>>> b'DATA,0x0400,0x0444a8a9\r\n' +<<< b'OK\r\n' +Envoi bloc 210/292 (0x00034400 à 0x000347ff) +>>> b'DATA,0x0400,0xcf45508e\r\n' +<<< b'OK\r\n' +Envoi bloc 211/292 (0x00034800 à 0x00034bff) +>>> b'DATA,0x0400,0x8e06c2c8\r\n' +<<< b'OK\r\n' +Envoi bloc 212/292 (0x00034c00 à 0x00034fff) +>>> b'DATA,0x0400,0xfa4f8566\r\n' +<<< b'OK\r\n' +Envoi bloc 213/292 (0x00035000 à 0x000353ff) +>>> b'DATA,0x0400,0xa4be5b03\r\n' +<<< b'OK\r\n' +Envoi bloc 214/292 (0x00035400 à 0x000357ff) +>>> b'DATA,0x0400,0xefb5af2e\r\n' +<<< b'OK\r\n' +Envoi bloc 215/292 (0x00035800 à 0x00035bff) +>>> b'DATA,0x0400,0x47100cfe\r\n' +<<< b'OK\r\n' +Envoi bloc 216/292 (0x00035c00 à 0x00035fff) +>>> b'DATA,0x0400,0xccfa36dd\r\n' +<<< b'OK\r\n' +Envoi bloc 217/292 (0x00036000 à 0x000363ff) +>>> b'DATA,0x0400,0x53eabdc3\r\n' +<<< b'OK\r\n' +Envoi bloc 218/292 (0x00036400 à 0x000367ff) +>>> b'DATA,0x0400,0xc6f6f848\r\n' +<<< b'OK\r\n' +Envoi bloc 219/292 (0x00036800 à 0x00036bff) +>>> b'DATA,0x0400,0x6bcd01e0\r\n' +<<< b'OK\r\n' +Envoi bloc 220/292 (0x00036c00 à 0x00036fff) +>>> b'DATA,0x0400,0xa61603de\r\n' +<<< b'OK\r\n' +Envoi bloc 221/292 (0x00037000 à 0x000373ff) +>>> b'DATA,0x0400,0xa2598fc5\r\n' +<<< b'OK\r\n' +Envoi bloc 222/292 (0x00037400 à 0x000377ff) +>>> b'DATA,0x0400,0x27a82e49\r\n' +<<< b'OK\r\n' +Envoi bloc 223/292 (0x00037800 à 0x00037bff) +>>> b'DATA,0x0400,0x0b2f921e\r\n' +<<< b'OK\r\n' +Envoi bloc 224/292 (0x00037c00 à 0x00037fff) +>>> b'DATA,0x0400,0x3c5323a1\r\n' +<<< b'OK\r\n' +Envoi bloc 225/292 (0x00038000 à 0x000383ff) +>>> b'DATA,0x0400,0x39c02243\r\n' +<<< b'OK\r\n' +Envoi bloc 226/292 (0x00038400 à 0x000387ff) +>>> b'DATA,0x0400,0x2342ae03\r\n' +<<< b'OK\r\n' +Envoi bloc 227/292 (0x00038800 à 0x00038bff) +>>> b'DATA,0x0400,0x536a74f3\r\n' +<<< b'OK\r\n' +Envoi bloc 228/292 (0x00038c00 à 0x00038fff) +>>> b'DATA,0x0400,0x61348b91\r\n' +<<< b'OK\r\n' +Envoi bloc 229/292 (0x00039000 à 0x000393ff) +>>> b'DATA,0x0400,0x74489bbc\r\n' +<<< b'OK\r\n' +Envoi bloc 230/292 (0x00039400 à 0x000397ff) +>>> b'DATA,0x0400,0xfde3b1df\r\n' +<<< b'OK\r\n' +Envoi bloc 231/292 (0x00039800 à 0x00039bff) +>>> b'DATA,0x0400,0x1d7b4a06\r\n' +<<< b'OK\r\n' +Envoi bloc 232/292 (0x00039c00 à 0x00039fff) +>>> b'DATA,0x0400,0xed5dc596\r\n' +<<< b'OK\r\n' +Envoi bloc 233/292 (0x0003a000 à 0x0003a3ff) +>>> b'DATA,0x0400,0xb522deb3\r\n' +<<< b'OK\r\n' +Envoi bloc 234/292 (0x0003a400 à 0x0003a7ff) +>>> b'DATA,0x0400,0x0896f10b\r\n' +<<< b'OK\r\n' +Envoi bloc 235/292 (0x0003a800 à 0x0003abff) +>>> b'DATA,0x0400,0xb4b63fd3\r\n' +<<< b'OK\r\n' +Envoi bloc 236/292 (0x0003ac00 à 0x0003afff) +>>> b'DATA,0x0400,0x555dd6c6\r\n' +<<< b'OK\r\n' +Envoi bloc 237/292 (0x0003b000 à 0x0003b3ff) +>>> b'DATA,0x0400,0x9fc70584\r\n' +<<< b'OK\r\n' +Envoi bloc 238/292 (0x0003b400 à 0x0003b7ff) +>>> b'DATA,0x0400,0x06d0aedc\r\n' +<<< b'OK\r\n' +Envoi bloc 239/292 (0x0003b800 à 0x0003bbff) +>>> b'DATA,0x0400,0x19f5015b\r\n' +<<< b'OK\r\n' +Envoi bloc 240/292 (0x0003bc00 à 0x0003bfff) +>>> b'DATA,0x0400,0xa9523fd5\r\n' +<<< b'OK\r\n' +Envoi bloc 241/292 (0x0003c000 à 0x0003c3ff) +>>> b'DATA,0x0400,0x46b65734\r\n' +<<< b'OK\r\n' +Envoi bloc 242/292 (0x0003c400 à 0x0003c7ff) +>>> b'DATA,0x0400,0xbf04b212\r\n' +<<< b'OK\r\n' +Envoi bloc 243/292 (0x0003c800 à 0x0003cbff) +>>> b'DATA,0x0400,0xb2bb9e5c\r\n' +<<< b'OK\r\n' +Envoi bloc 244/292 (0x0003cc00 à 0x0003cfff) +>>> b'DATA,0x0400,0x0c7c8dda\r\n' +<<< b'OK\r\n' +Envoi bloc 245/292 (0x0003d000 à 0x0003d3ff) +>>> b'DATA,0x0400,0x0a7d25ac\r\n' +<<< b'OK\r\n' +Envoi bloc 246/292 (0x0003d400 à 0x0003d7ff) +>>> b'DATA,0x0400,0x89a9f3ce\r\n' +<<< b'OK\r\n' +Envoi bloc 247/292 (0x0003d800 à 0x0003dbff) +>>> b'DATA,0x0400,0xb11cc12f\r\n' +<<< b'OK\r\n' +Envoi bloc 248/292 (0x0003dc00 à 0x0003dfff) +>>> b'DATA,0x0400,0xc59de2eb\r\n' +<<< b'OK\r\n' +Envoi bloc 249/292 (0x0003e000 à 0x0003e3ff) +>>> b'DATA,0x0400,0xf0561443\r\n' +<<< b'OK\r\n' +Envoi bloc 250/292 (0x0003e400 à 0x0003e7ff) +>>> b'DATA,0x0400,0xe7af97e4\r\n' +<<< b'OK\r\n' +Envoi bloc 251/292 (0x0003e800 à 0x0003ebff) +>>> b'DATA,0x0400,0x5e3ef771\r\n' +<<< b'OK\r\n' +Envoi bloc 252/292 (0x0003ec00 à 0x0003efff) +>>> b'DATA,0x0400,0xd0eb8e02\r\n' +<<< b'OK\r\n' +Envoi bloc 253/292 (0x0003f000 à 0x0003f3ff) +>>> b'DATA,0x0400,0x90229cba\r\n' +<<< b'OK\r\n' +Envoi bloc 254/292 (0x0003f400 à 0x0003f7ff) +>>> b'DATA,0x0400,0xf0115912\r\n' +<<< b'OK\r\n' +Envoi bloc 255/292 (0x0003f800 à 0x0003fbff) +>>> b'DATA,0x0400,0x56428172\r\n' +<<< b'OK\r\n' +Envoi bloc 256/292 (0x0003fc00 à 0x0003ffff) +>>> b'DATA,0x0400,0x4f1b8f39\r\n' +<<< b'OK\r\n' +Envoi bloc 257/292 (0x00040000 à 0x000403ff) +>>> b'DATA,0x0400,0xc1e1b48c\r\n' +<<< b'OK\r\n' +Envoi bloc 258/292 (0x00040400 à 0x000407ff) +>>> b'DATA,0x0400,0x21f743e0\r\n' +<<< b'OK\r\n' +Envoi bloc 259/292 (0x00040800 à 0x00040bff) +>>> b'DATA,0x0400,0x7a7683bc\r\n' +<<< b'OK\r\n' +Envoi bloc 260/292 (0x00040c00 à 0x00040fff) +>>> b'DATA,0x0400,0xb4f08c87\r\n' +<<< b'OK\r\n' +Envoi bloc 261/292 (0x00041000 à 0x000413ff) +>>> b'DATA,0x0400,0x966ba76b\r\n' +<<< b'OK\r\n' +Envoi bloc 262/292 (0x00041400 à 0x000417ff) +>>> b'DATA,0x0400,0x5a786873\r\n' +<<< b'OK\r\n' +Envoi bloc 263/292 (0x00041800 à 0x00041bff) +>>> b'DATA,0x0400,0x5990bd26\r\n' +<<< b'OK\r\n' +Envoi bloc 264/292 (0x00041c00 à 0x00041fff) +>>> b'DATA,0x0400,0x7fce1c7e\r\n' +<<< b'OK\r\n' +Envoi bloc 265/292 (0x00042000 à 0x000423ff) +>>> b'DATA,0x0400,0x9a254d51\r\n' +<<< b'OK\r\n' +Envoi bloc 266/292 (0x00042400 à 0x000427ff) +>>> b'DATA,0x0400,0xe7922aa5\r\n' +<<< b'OK\r\n' +Envoi bloc 267/292 (0x00042800 à 0x00042bff) +>>> b'DATA,0x0400,0x2efd9b5b\r\n' +<<< b'OK\r\n' +Envoi bloc 268/292 (0x00042c00 à 0x00042fff) +>>> b'DATA,0x0400,0x807332d9\r\n' +<<< b'OK\r\n' +Envoi bloc 269/292 (0x00043000 à 0x000433ff) +>>> b'DATA,0x0400,0x75b40d3f\r\n' +<<< b'OK\r\n' +Envoi bloc 270/292 (0x00043400 à 0x000437ff) +>>> b'DATA,0x0400,0xd0885472\r\n' +<<< b'OK\r\n' +Envoi bloc 271/292 (0x00043800 à 0x00043bff) +>>> b'DATA,0x0400,0x8c59c72d\r\n' +<<< b'OK\r\n' +Envoi bloc 272/292 (0x00043c00 à 0x00043fff) +>>> b'DATA,0x0400,0xf3fe1e75\r\n' +<<< b'OK\r\n' +Envoi bloc 273/292 (0x00044000 à 0x000443ff) +>>> b'DATA,0x0400,0x48c349af\r\n' +<<< b'OK\r\n' +Envoi bloc 274/292 (0x00044400 à 0x000447ff) +>>> b'DATA,0x0400,0x1aceeecf\r\n' +<<< b'OK\r\n' +Envoi bloc 275/292 (0x00044800 à 0x00044bff) +>>> b'DATA,0x0400,0xabf3b4ce\r\n' +<<< b'OK\r\n' +Envoi bloc 276/292 (0x00044c00 à 0x00044fff) +>>> b'DATA,0x0400,0x06e5a042\r\n' +<<< b'OK\r\n' +Envoi bloc 277/292 (0x00045000 à 0x000453ff) +>>> b'DATA,0x0400,0x2a56de6b\r\n' +<<< b'OK\r\n' +Envoi bloc 278/292 (0x00045400 à 0x000457ff) +>>> b'DATA,0x0400,0xf253173d\r\n' +<<< b'OK\r\n' +Envoi bloc 279/292 (0x00045800 à 0x00045bff) +>>> b'DATA,0x0400,0xca83a9b9\r\n' +<<< b'OK\r\n' +Envoi bloc 280/292 (0x00045c00 à 0x00045fff) +>>> b'DATA,0x0400,0x8721bea2\r\n' +<<< b'OK\r\n' +Envoi bloc 281/292 (0x00046000 à 0x000463ff) +>>> b'DATA,0x0400,0x14955fd4\r\n' +<<< b'OK\r\n' +Envoi bloc 282/292 (0x00046400 à 0x000467ff) +>>> b'DATA,0x0400,0x2aec8a44\r\n' +<<< b'OK\r\n' +Envoi bloc 283/292 (0x00046800 à 0x00046bff) +>>> b'DATA,0x0400,0x2aec8a44\r\n' +<<< b'OK\r\n' +Envoi bloc 284/292 (0x00046c00 à 0x00046fff) +>>> b'DATA,0x0400,0x2aec8a44\r\n' +<<< b'OK\r\n' +Envoi bloc 285/292 (0x00047000 à 0x000473ff) +>>> b'DATA,0x0400,0x2aec8a44\r\n' +<<< b'OK\r\n' +Envoi bloc 286/292 (0x00047400 à 0x000477ff) +>>> b'DATA,0x0400,0xcc9f7252\r\n' +<<< b'OK\r\n' +Envoi bloc 287/292 (0x00047800 à 0x00047bff) +>>> b'DATA,0x0400,0x79303db9\r\n' +<<< b'OK\r\n' +Envoi bloc 288/292 (0x00047c00 à 0x00047fff) +>>> b'DATA,0x0400,0x6e24d3bc\r\n' +<<< b'OK\r\n' +Envoi bloc 289/292 (0x00048000 à 0x000483ff) +>>> b'DATA,0x0400,0x26003be4\r\n' +<<< b'OK\r\n' +Envoi bloc 290/292 (0x00048400 à 0x000487ff) +>>> b'DATA,0x0400,0x1acf3ad9\r\n' +<<< b'OK\r\n' +Envoi bloc 291/292 (0x00048800 à 0x00048bff) +>>> b'DATA,0x0400,0xd07c4f3d\r\n' +<<< b'OK\r\n' +Envoi bloc 292/292 (0x00048c00 à 0x00048f3f) +>>> b'DATA,0x0340,0x86335944\r\n' +<<< b'OK\r\n' +>>> b'CHECK\r\n' +<<< b'OK\r\n' +Vérification OK + diff --git a/mylab2-programmer.py b/mylab2-programmer.py new file mode 100644 index 0000000..9d68611 --- /dev/null +++ b/mylab2-programmer.py @@ -0,0 +1,209 @@ +''' +Script de programmation pour le bootloader myLab2 du cours MIP + +Christian Abegg, HEPIA +''' + + +import argparse +import binascii +import sys +try: + import serial +except: + print("pyserial est requis: pip3 install pyserial") + +DEFAULT_PORT = '/dev/ttyUSB0' +BL_ERR_CODE = {'0': 'Success', 1: 'Erreur générale', '2': 'Commande invalide', + '3': 'Checksum global incorrect', '4': 'Checksum de bloc incorrect', + '5': 'Erreur lors de l’effacement', '6': 'Erreur lors de l’écriture', + '7': 'Taille des données invalide', '8': 'Offset invalide', + '9': 'Argument(s) invalide(s)', + '99': 'Pas de réponse'} +LPC1769_PARTID = 0x26113f37 +LPC1769_FLASH_SIZE = 0x80000 +APP_OFFSET = 0x4000 +MAX_PROG_SIZE = LPC1769_FLASH_SIZE - APP_OFFSET + +def show_error(error_code): + if error_code != 0: + return "Erreur {} lors de la commande: {}".format(error_code, BL_ERR_CODE.get(error_code, '---')) + +def raise_error(error_code): + raise Exception(show_error(error_code)) + +class MyLab2: + def __init__(self, serialport, verbose=False, timeout=1): + self.v = verbose + self.connected = False + if timeout == -1: + self.timeout = 0 + elif timeout == 0: + self.timeout = None + else: + self.timeout = timeout + try: + self.port = serial.Serial(serialport, baudrate=115200, bytesize=8, + stopbits=1, parity=serial.PARITY_NONE, timeout=self.timeout) + + # Empty buffer in case some char are left in FTDI device + self.port.timeout = 0.01 + for i in range(16): + self.port.read() + self.port.timeout = self.timeout + + self.partid = self.get_part_id() + self.serial = self.get_serial() + if self.partid and self.serial: + self.connected = True + + except Exception as e: + print("Impossible d'établir la connexion à la carte: {}".format(e)) + self.port = None + self.connected = False + if sys.platform.startswith('win') and 'PermissionError' in str(e): + print("Windows refuse l'accès au port série spécifié. " + "Vérifiez que vous n'avez pas d'autres applications qui utilisent ce port.") + + def run_cmd(self, cmd, wait_answer=True): + send_buf = "{}\r\n".format(cmd).encode() + if self.v: print(">>> {}".format(send_buf)) + self.port.write(send_buf) + self.last_cmd = cmd + if not wait_answer: + return 0, None + retcode = self.port.readline() + if self.v: print("<<< {}".format(retcode)) + retcode = retcode.strip().decode() + if retcode == "OK": + # Read answer + if cmd.startswith("GETID") or cmd.startswith("GETSERIAL"): + retvalue = self.port.readline() + if self.v: print("<<< {}".format(retvalue)) + return 0, retvalue.strip().decode() + else: + return 0, None + else: + if not retcode: + return '99', None + err = retcode.split(",")[-1] + return err, None + + def get_answer(self): + retcode = self.port.readline() + if self.v: print("<<< {}".format(retcode)) + retcode = retcode.strip().decode() + if retcode == "OK": + return 0, None + else: + if not retcode: + return '99', None + err = retcode.split(",")[-1] + return err, None + + def get_part_id(self): + code, val = self.run_cmd("GETID") + return val + + def get_serial(self): + code, val = self.run_cmd("GETSERIAL") + return val + + def write_program(self, filename, blocksize=1024, fuzzing=False): + if not self.partid or int(self.partid, 16) != LPC1769_PARTID: + raise Exception("Part id non reconnu: {}".format(self.partid)) + try: + with open(filename, 'rb') as file: + bindata = file.read() + except Exception as e: + print("Impossible d'ouvrir le fichier '{}': {}".format(filename, e)) + return + + if len(bindata) > MAX_PROG_SIZE: + raise Exception("Taille du fichier binaire trop grande: {} (le maximum est de {})".format(len(bindata), + MAX_PROG_SIZE)) + + binfile_crc = binascii.crc32(bindata) + binfile_length = len(bindata) + nb_blocs = binfile_length//blocksize + 1 + print("Envoi {} à la myLab2, taille: {}, CRC32: {}, bs={}".format(filename, + binfile_length, + hex(binfile_crc), + blocksize)) + _r, _ = self.run_cmd("PROG,0x{:08x},0x{:08x},0x{:08x}".format(APP_OFFSET, binfile_length, binfile_crc)) + if _r: + raise_error(_r) + remaining_size = binfile_length + position = 0 + for block in range(nb_blocs): + if remaining_size < blocksize: + blocksize = remaining_size + blockcrc = binascii.crc32(bindata[position:(position+blocksize)]) + if self.v: + print("Envoi bloc {:3d}/{:3d} (0x{:08x} à 0x{:08x})".format(block+1, nb_blocs, + position, + position + blocksize - 1)) + else: + print("\r{:3d}% ".format(int(position / binfile_length * 100)), end='') + self.run_cmd("DATA,0x{:04x},0x{:08x}".format(blocksize, blockcrc), wait_answer=False) + + # send the data + blockdata = bindata[position:(position + blocksize)] + is_fuzz = False + if fuzzing and block == 3: + # TODO: Meilleur fuzzing + blockdata = b'\x02' + bindata[position+1:(position+blocksize)] + is_fuzz = True + self.port.write(blockdata) + _r, _ = self.get_answer() + if _r: + print(show_error(_r)) + if is_fuzz: + print("Note: le fuzzing était actif sur ce bloc") + return + if is_fuzz: + print("!!! Fuzzing actif lors de l'envoi de ce bloc, mais la carte a quand même validé le CRC !!!") + # if ok.... + position += blocksize + remaining_size -= blocksize + if not self.v: + print("\r{:3d}% ".format(int(position/binfile_length*100)), end='') + + if not self.v: + print() + _r, _ = self.run_cmd("CHECK") + if _r: + raise_error(_r) + else: + print("Vérification OK") + + def __str__(self): + if not self.connected: + return "Pas de connexion au bootloader myLab2-MIP" + return "Connecté au bootloader myLab2-MIP:\nPartID: {}\nSerial: {}".format(self.partid, + self.serial) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='Programmeur pour bootloader myLab2 MIP') + parser.add_argument('--port', default=DEFAULT_PORT, + help='Port série à utiliser pour la communication, "{}" par défaut'.format(DEFAULT_PORT)) + parser.add_argument('--fuzzing', action="store_true", + help='Introduit des erreurs lors de la programmation') + parser.add_argument('--verbose', dest="verbose", action="store_true", + help='Mode verbeux') + parser.add_argument('binfile', default='', + help='Programme à écrire, au format bin') + parser.add_argument('--blksize', default=1024, type=int, + help='Taille des blocs lors de l\'envoi') + parser.add_argument('--timeout', default=2, type=int, + help='Durée en secondes après laquelle la réponse doit être reçue. 0=attente infinie') + args = parser.parse_args() + ml2 = MyLab2(args.port, verbose=args.verbose, timeout=args.timeout) + print(ml2) + if not ml2.connected: + sys.exit(1) + try: + ml2.write_program(args.binfile, blocksize=args.blksize, fuzzing=args.fuzzing) + except Exception as e: + print("Erreur lors de la programmation: {}".format(e)) diff --git a/sonic_50b03eb0.bin b/sonic_50b03eb0.bin new file mode 100644 index 0000000000000000000000000000000000000000..f497d516d11f14430ccea4009559d324bfd904f7 GIT binary patch literal 298816 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 &= ~(3<<6); + + LPC_SC->PCLKSEL0 |= 1<<6; // pclk set to 100 MHz + + LPC_PINCON->PINSEL0 |= (1<<4); //TXD0 + + LPC_PINCON->PINSEL0 |= (1<<6); //RXD0 + + + uint32_t Fdiv = (UART_PCLK)/(16*baudrate); + LPC_UART0->LCR = 0x83; + LPC_UART0->DLM = (Fdiv>>8)&0xff; + LPC_UART0->DLL = Fdiv&0xff; + + LPC_UART0->LCR = 0x3; + LPC_UART0->FCR = 0x07|(2<<6);//(2<<6) to active RX trigger level +} + +void uart_send(char* buff, uint32_t length){ + int tmp; + while (length-- != 0 ){ + LPC_UART0->THR = *buff++; + while(((LPC_UART0->LSR)&(1<<5)) == 0);//stuck in while when U1THR contains valid data + tmp = LPC_UART0->RBR; + LPC_GPIO2->FIOCLR = 0xff; + LPC_GPIO2->FIOSET = tmp; + } + +} + +void uart_receive_command(char* chara){ + char* curr = chara; + while(strncmp(curr, "\r\n", 2) != 0){ + while(((LPC_UART0->LSR)&(1)) == 0); + *curr = LPC_UART0->RBR; + if(strncmp(curr, "\r\n", 2) != 0) curr++; + } +} + +void uart_receive_data(uint8_t* chara){ + uint8_t* curr = chara; + while(*curr != '\0'){ + while(((LPC_UART0->LSR)&(1)) == 0); + *curr = LPC_UART0->RBR; + curr++; + } +} diff --git a/uart.h b/uart.h new file mode 100644 index 0000000..c54416f --- /dev/null +++ b/uart.h @@ -0,0 +1,59 @@ +/* + * uart.h + * + * Created on: 15 Mar 2022 + * Author: pika + */ + +#ifndef UART_H_ +#define UART_H_ + +#ifndef __SYSTEM_LPC17xx_H +#define __SYSTEM_LPC17xx_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __USE_CMSIS +#include "LPC17xx.h" +#endif + +#include +#include + +#endif /* __SYSTEM_LPC17xx_H */ + +#define DLAB_SET LPC_UART1->LCR |= (1<<7) //DLAB == 1 +#define DLAB_CLR LPC_UART1->LCR &= ~(1<<7) //DLAB == 0 //not needed + +#define SIZE_OF_BUFFER 8 +#define UART_PCLK (100000000) + +typedef struct circbuff_t{ +uint8_t data[SIZE_OF_BUFFER]; +uint16_t ptr_write; +uint16_t ptr_read; +} circbuff; + + + +void uart_init(uint32_t baudrate); + +void uart_send(char* buff, uint32_t length); + +void uart_receive_command(char* chara); + +void uart_receive_data(uint8_t* chara); + + +#define THRE (1<<5) +#define MULVAL 15 +#define DIVADDVAL 2 +#define Ux_FIFO_EN (1<<0) +#define RX_FIFO_RST (1<<1) +#define TX_FIFO_RST (1<<2) +#define DLAB_BIT (1<<7) +#define CARRIAGE_RETURN 0x0D + +#endif /* UART_H_ */ diff --git a/uart_commands.c b/uart_commands.c new file mode 100644 index 0000000..fef33a4 --- /dev/null +++ b/uart_commands.c @@ -0,0 +1,105 @@ +#include "uart_commands.h" + +static uint8_t data[4096]; + +char OK[4] = "OK\r\n"; +char ERR[5] = "ERR\r\n"; + +void uart_commands_getid(error_code* status){ + char hex[15]; + uint32_t res = iap_read_part_id(status); + sprintf(hex, "0x%x\r\n", res); + if(*status == 0){ + uart_send(OK, 5); + uart_send(hex, 12); + } +} + + +void uart_commands_getserial(error_code* status){ + char hex[40]; + uint32_t res[4]; + iap_read_serial(status, res); + sprintf(hex, "0x%x%x%x%x\r\n", res[0], res[1], res[2], res[3]); + if(*status == 0){ + uart_send(OK, 5); + uart_send(hex, 35); + } +} + +crc_t uart_commands_prog(void){ + return crc_init(); + uart_send(OK, 5); +} + +void uart_commands_data(error_code* status, int size, crc_t* checksum_global, crc_t checksum_loc, int offset){ + uart_receive_data(data); + crc_t checksum_tmp = crc_init(); + checksum_tmp = crc_update(checksum_tmp, data, size); + if(checksum_loc == checksum_tmp){ + int tmp = size; + while(tmp > 4096){ + iap_copy_to_flash(status, offset, &checksum_loc, 4096); + if(*status != ok){ + uart_send(ERR, 6); + } + tmp = tmp - 4096; + } + while(tmp > 1024){ + iap_copy_to_flash(status, offset, &checksum_loc, 1024); + if(*status != ok){ + uart_send(ERR, 6); + } + tmp = tmp - 1024; + } + while(tmp > 512){ + iap_copy_to_flash(status, offset, &checksum_loc, 512); + if(*status != ok){ + uart_send(ERR, 6); + } + tmp = tmp - 512; + } + while(tmp > 256){ + iap_copy_to_flash(status, offset, &checksum_loc, 256); + if(*status != ok){ + uart_send(ERR, 6); + } + tmp = tmp - 256; + } + *checksum_global = crc_update(*checksum_global, data, size); + }else{ + uart_send(ERR, 6); + } +} + + +// return: -1 in case of ERR otherwise 0. +int uart_parse_command(char *user_input, cmd_t *cmd) { + + //Initialize a simple command (empty, simple, foreground) + cmd->argv = NULL; + cmd->argc = -1; + + //Separate string in different token (i.e. command name + params + &) + do { + //A new element will be added + cmd->argc += 1; + + //Allocate a new pointer on char for next argv element + if((cmd->argv = realloc(cmd->argv, (cmd->argc+1)*sizeof(char*))) == NULL) + perror("uart_parse_command::realloc"); + + //Get the adress of the next token (could be NULL to indicate end of argv) + cmd->argv[cmd->argc] = strtok(user_input, DELIMIERS); + user_input = NULL; //Useless to execute it each time but easier than having two different strtok calls + } while (cmd->argv[cmd->argc] != NULL); // while there are still tokens + + + return 0; +} + +uint32_t uart_string_to_int(const char *str) { + // Convert input in port number + unsigned long int hex = strtoul(str, NULL, 16); + return hex; +} diff --git a/uart_commands.h b/uart_commands.h new file mode 100644 index 0000000..840b701 --- /dev/null +++ b/uart_commands.h @@ -0,0 +1,30 @@ +#include +#include +#include + +#include "uart.h" +#include "iap.h" +#include "crc.h" + +#define DELIMIERS "," + + + + +typedef struct cmd { + char** argv; // a first command splitted as arguments in the argv style + int argc; // number of arguments in the first command +} cmd_t; + + +void uart_commands_getid(error_code* status); + +void uart_commands_getserial(error_code* status); + +crc_t uart_commands_prog(void); + +void uart_commands_data(error_code* status, int size, crc_t* checksum_global, crc_t checksum_loc, int offset); + +int uart_parse_command(char *user_input, cmd_t *cmd); + +uint32_t uart_string_to_int(const char* str);