From dc8703206e3f0f69605c56d0e1127f7e17f3476a Mon Sep 17 00:00:00 2001 From: Jan Sucan Date: Tue, 4 Jun 2019 14:34:27 +0200 Subject: Initial commit --- impl/DMBootloader/DMBootloader.atsln | 19 ++ .../DMBootloader/DMBootloader.componentinfo.xml | 4 + impl/DMBootloader/DMBootloader/DMBootloader.cproj | 128 +++++++++ .../DMBootloader/Release/DMBootloader.bin | Bin 0 -> 8868 bytes impl/DMBootloader/DMBootloader/main.c | 21 ++ impl/DMBootloader/DMBootloader/protocol.c | 298 +++++++++++++++++++++ impl/DMBootloader/DMBootloader/protocol.h | 8 + 7 files changed, 478 insertions(+) create mode 100644 impl/DMBootloader/DMBootloader.atsln create mode 100644 impl/DMBootloader/DMBootloader/DMBootloader.componentinfo.xml create mode 100644 impl/DMBootloader/DMBootloader/DMBootloader.cproj create mode 100644 impl/DMBootloader/DMBootloader/Release/DMBootloader.bin create mode 100644 impl/DMBootloader/DMBootloader/main.c create mode 100644 impl/DMBootloader/DMBootloader/protocol.c create mode 100644 impl/DMBootloader/DMBootloader/protocol.h (limited to 'impl/DMBootloader') diff --git a/impl/DMBootloader/DMBootloader.atsln b/impl/DMBootloader/DMBootloader.atsln new file mode 100644 index 0000000..9c2407b --- /dev/null +++ b/impl/DMBootloader/DMBootloader.atsln @@ -0,0 +1,19 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Atmel Studio Solution File, Format Version 11.00 +VisualStudioVersion = 14.0.23107.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{54F91283-7BC4-4236-8FF9-10F437C3AD48}") = "DMBootloader", "DMBootloader\DMBootloader.cproj", "{DCE6C7E3-EE26-4D79-826B-08594B9AD897}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Release|AVR = Release|AVR + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {DCE6C7E3-EE26-4D79-826B-08594B9AD897}.Release|AVR.ActiveCfg = Release|AVR + {DCE6C7E3-EE26-4D79-826B-08594B9AD897}.Release|AVR.Build.0 = Release|AVR + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/impl/DMBootloader/DMBootloader/DMBootloader.componentinfo.xml b/impl/DMBootloader/DMBootloader/DMBootloader.componentinfo.xml new file mode 100644 index 0000000..e275755 --- /dev/null +++ b/impl/DMBootloader/DMBootloader/DMBootloader.componentinfo.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/impl/DMBootloader/DMBootloader/DMBootloader.cproj b/impl/DMBootloader/DMBootloader/DMBootloader.cproj new file mode 100644 index 0000000..9f3da61 --- /dev/null +++ b/impl/DMBootloader/DMBootloader/DMBootloader.cproj @@ -0,0 +1,128 @@ + + + + 2.0 + 7.0 + com.Atmel.AVRGCC32.C + dce6c7e3-ee26-4d79-826b-08594b9ad897 + AT32UC3C2512C + none + Executable + C + $(MSBuildProjectName) + .elf + $(MSBuildProjectDirectory)\$(Configuration) + DMBootloader + DMBootloader + DMBootloader + Native + true + false + true + true + 0x20000000 + + true + exception_table + 2 + 0 + + + + + + + + + + + + + 0 + + com.atmel.avrdbg.tool.jtagice3plus + J30200039974 + 0x0 + + + + 7500000 + + JTAG + + com.atmel.avrdbg.tool.jtagice3plus + J30200039974 + JTAGICE3 + + JTAG + 7500000 + + + + + True + True + True + True + + + NDEBUG + + + + + %24(PackRepoDir)\atmel\UC3C_DFP\1.0.49\include\AT32UC3C2512C + .. + ../../../DiagnosticModule/DiagnosticModule + + + Optimize (-O1) + True + True + True + True + True + True + + + libm + libDiagnosticModule.a + + + + + ../../../DiagnosticModule/DiagnosticModule/Release + + + True + True + True + + + %24(PackRepoDir)\atmel\UC3C_DFP\1.0.49\include\AT32UC3C2512C + + + + + %24(PackRepoDir)\atmel\UC3C_DFP\1.0.49\include\AT32UC3C2512C + + + + + + + "$(ToolchainDir)\avr32-objcopy.exe" -O binary $(OutputDirectory)\$(OutputFileName)$(OutputFileExtension) $(OutputDirectory)\$(OutputFileName).bin + + + + compile + + + compile + + + compile + + + + \ No newline at end of file diff --git a/impl/DMBootloader/DMBootloader/Release/DMBootloader.bin b/impl/DMBootloader/DMBootloader/Release/DMBootloader.bin new file mode 100644 index 0000000..c455753 Binary files /dev/null and b/impl/DMBootloader/DMBootloader/Release/DMBootloader.bin differ diff --git a/impl/DMBootloader/DMBootloader/main.c b/impl/DMBootloader/DMBootloader/main.c new file mode 100644 index 0000000..8626f3a --- /dev/null +++ b/impl/DMBootloader/DMBootloader/main.c @@ -0,0 +1,21 @@ +/* Author: Jan Sucan */ + +#include +#include +#include + +int +main(void) +{ + diagnostic_module_init(); + // Odteraz su hlavne hodiny na 64,512 MHz + + // Prijem a spracovavanie prikazov + protocol_loop(); + // Sem uz sa tok programu nikdy nedostane, pretoze sa bud opakovane spracovavaju + // prikazu pre zapis, mazanie a citanie stranok, alebo sa vykona prikaz pre + // spustenie aplikacneho firmware a ten prevezme riadenie namiesto Bootloaderu + while (1) { + ; + } +} diff --git a/impl/DMBootloader/DMBootloader/protocol.c b/impl/DMBootloader/DMBootloader/protocol.c new file mode 100644 index 0000000..115e0ce --- /dev/null +++ b/impl/DMBootloader/DMBootloader/protocol.c @@ -0,0 +1,298 @@ +/* Author: Jan Sucan */ + +#include +#include +#include + +#include + +/** + * @brief Ziskanie cisla prikazu z bufferu pre data prijate cez YUP. + */ +#define PROTOCOL_GET_CMD_NUMBER(b) (b[0]) + +/** + * @brief Ziskanie cisla stranky z bufferu pre data prijate cez YUP. + */ +#define PROTOCOL_GET_PAGE_NUMBER(b) (GET_UINT16_T_FROM_BYTES(b, 1)) + +/** + * @brief Minimum prijatych bajtov, aby sa uz jednalo o nejaky platny prikaz. + */ +#define PROTOCOL_MINIMAL_SIZE 3 + +/** + * @brief Maximum prijatych bajtov, aby sa este jednalo o nejaky platny prikaz. + */ +#define PROTOCOL_MAX_RECEIVED_BYTES 515 + +/** + * @brief Maximum odosielanych bajtov. + */ +#define PROTOCOL_MAX_SEND_BYTES 513 + +/** + * @brief Nazov aplikacie. + * + * Pouzity v identifikacnom retazci aplikacie. + */ +#define PROTOCOL_APPLICATION_NAME "DMBootloader" + +/** + * @brief Verzia aplikacie. + * + * Pouzita v identifikacnom retazci aplikacie. + */ +#define PROTOCOL_APPLICATION_VERSION "0.1.0" + +enum protocol_return_codes { + PROTOCOL_OK = 0x00, + // Chyby protokolu + PROTOCOL_ERROR_UNKNOWN_CMD = 0x10, + PROTOCOL_ERROR_MISSING_PAGENUM, + PROTOCOL_ERROR_PAGENUM_OUT_OF_BOUNDS, + PROTOCOL_ERROR_MISSING_DATA, + PROTOCOL_ERROR_EXTRA_DATA, + // Chyby FLASH subsystemu + PROTOCOL_ERROR_FLASH_WRITE = 0x30, + PROTOCOL_ERROR_FLASH_ERASE, + PROTOCOL_ERROR_FLASH_READ +}; + +enum protocol_command_codes { + PROTOCOL_CMD_WRITE_PAGE = 0, + PROTOCOL_CMD_ERASE_PAGE, + PROTOCOL_CMD_READ_PAGE, + PROTOCOL_CMD_EXEC_APPLICATION, + PROTOCOL_CMD_GET_APPLICATION_ID = UINT8_MAX +}; + +/** + * @brief Pocet aplikacnych prikazov podporovanych touto aplikaciou. + */ +#define PROTOCOL_CMD_COUNT 5 + +// Parametre dat pre kontrolu prikazov, minumum a maximum bajtov +typedef struct cmd_data_size_s { + size_t min_bytes; + size_t max_bytes; +} cmd_data_size_t; + +const cmd_data_size_t cmd_data_sizes[PROTOCOL_CMD_COUNT] = { + {PROTOCOL_MINIMAL_SIZE + 1, PROTOCOL_MAX_RECEIVED_BYTES}, // PROTOCOL_CMD_WRITE_PAGE + {PROTOCOL_MINIMAL_SIZE, PROTOCOL_MINIMAL_SIZE}, // PROTOCOL_CMD_ERASE_PAGE + {PROTOCOL_MINIMAL_SIZE, PROTOCOL_MINIMAL_SIZE}, // PROTOCOL_CMD_READ_PAGE + {PROTOCOL_MINIMAL_SIZE, PROTOCOL_MINIMAL_SIZE} // PROTOCOL_CMD_EXEC_APPLICATION +}; + +static bool protocol_is_cmd_code_valid(uint8_t cmd_code); +static void protocol_send_reply_with_data(uint8_t ret_code, uint8_t * const data, uint16_t data_size); +static void protocol_send_reply(uint8_t ret_code); +static bool protocol_cmd_has_minimal_size(uint8_t cmd_code, size_t cmd_bytes); +static bool protocol_cmd_has_extra_data(uint8_t cmd_code, size_t cmd_bytes); +static bool protocol_cmd_contains_page_number(size_t cmd_bytes); + +/** + * @brief Prikazova slucka aplikacneho protokolu bootloaderu. + * + * Podporovane prikazy: + * Zapis stranky: + * 1 B - kod prikazu + * 2 B - cislo stranky (od 0) + * 1 az 512 B - dat stranky + * Odpoved: + * 1 B - navratovy kod + * + * Mazanie stranky: + * 1 B - kod prikazu + * 2 B - cislo stranky (od 0) + * Odpoved: + * 1 B - navratovy kod + * + * Citanie stranky: + * 1 B - kod prikazu + * 2 B - cislo stranky (od 0) + * Odpoved: + * 1 B - navratovy kod + * 0 alebo 512 B - data stranky, 512B len pri spravnom prikaze + * + * Predanie riadenia na stranku: + * 1 B - kod prikazu + * 2 B - cislo stranky (od 0) + * Odpoved: + * 1 B - navratovy kod + * + * Ziskanie identifikacneho retazca aplikacie: + * 1 B - kod prikazu + * Odpoved: + * ASCII znaky ID retazca bez ukoncovacieho znaku '\0'. + */ +void +protocol_loop(void) +{ + while (1) { + // Najviac dat (1 + 2 + 512 = 515B) sa bude prijimat pre prikaz zapisu stranky + uint8_t buf[PROTOCOL_MAX_RECEIVED_BYTES]; + size_t bytes_received; + + // Prijmu sa data prikazu + while (data_receive(buf, PROTOCOL_MAX_RECEIVED_BYTES, &bytes_received) != DATA_OK); + + // Skontroluje sa cislo prikazu, urcite sa prijal aspon 1B + // Funkciam pre prikazy sa uz nemusi predavat cislo prikazu + // Kontrola ci je velkost dat prikazu v prislusnych medziach + const uint8_t cmd_number = PROTOCOL_GET_CMD_NUMBER(buf); + + if (!protocol_is_cmd_code_valid(cmd_number)) { + // Nezname cislo prikazu + protocol_send_reply(PROTOCOL_ERROR_UNKNOWN_CMD); + } + + // Cislo prikazu je OK + if (cmd_number == PROTOCOL_CMD_GET_APPLICATION_ID) { + // Prikaz pre ziskanie identifikacneho retazca aplikacie je OK + // Zostavi sa identifikacny retazec + char id_string[64]; + int id_string_length = firmware_identification_string(id_string, PROTOCOL_APPLICATION_NAME, PROTOCOL_APPLICATION_VERSION); + // Odosle sa + data_send((uint8_t *) id_string, id_string_length); + // Vsetky dalsie prikazy obsahuju viac bajtov pre kontrolu + } else if (!protocol_cmd_contains_page_number(bytes_received)) { + // Cislo stranky nie je pritomne + protocol_send_reply(PROTOCOL_ERROR_MISSING_PAGENUM); + } else if (!FLASH_IS_VALID_VIRT_PAGE_NUMBER(PROTOCOL_GET_PAGE_NUMBER(buf))) { + // Cislo stranky nie z platneho rozsahu + protocol_send_reply(PROTOCOL_ERROR_PAGENUM_OUT_OF_BOUNDS); + } else if (!protocol_cmd_has_minimal_size(cmd_number, bytes_received)) { + // Prikazu chybaju data + protocol_send_reply(PROTOCOL_ERROR_MISSING_DATA); + } else if (protocol_cmd_has_extra_data(cmd_number, bytes_received)) { + // Prikaz obsahuje data navyse + protocol_send_reply(PROTOCOL_ERROR_EXTRA_DATA); + } else { + // Prikaz OK, cislo stranky OK, velkost dat OK + int r = -1; + const uint16_t page_num = PROTOCOL_GET_PAGE_NUMBER(buf); + + switch (cmd_number) { + case PROTOCOL_CMD_WRITE_PAGE: + // Od velkosti dat sa odcita 1B prikazu a 2B cisla stranky + r = flash_write_virtual_page(page_num, buf + 3, bytes_received - 3); + protocol_send_reply((r == 0) ? PROTOCOL_OK : PROTOCOL_ERROR_FLASH_WRITE); + break; + + case PROTOCOL_CMD_ERASE_PAGE: + r = flash_erase_virtual_page(page_num); + protocol_send_reply((r == 0) ? PROTOCOL_OK : PROTOCOL_ERROR_FLASH_ERASE); + break; + + case PROTOCOL_CMD_READ_PAGE: + // Nacitavame az za 0. bajt, ten nechavame pre navratovy kod odpovede, aby sme recyklovali buffer + r = flash_read_virtual_page(page_num, buf + 1); + if (r == 0) { + // Uspech, mame data + protocol_send_reply_with_data(PROTOCOL_OK, buf, PROTOCOL_MAX_SEND_BYTES); + } else { + // Chyba + protocol_send_reply(PROTOCOL_ERROR_FLASH_READ); + } + break; + + case PROTOCOL_CMD_EXEC_APPLICATION: + // Odpoved sa musi poslat vopred, pretoze po spustenie uz strati Bootloader riadenie + protocol_send_reply(PROTOCOL_OK); + exec_application_firmware_at_virtual_page(page_num); + break; + } + } + + } +} + +/** + * @brief Kontrola, ci je cislo prikazu platne. + * + * @param cmd_code Cislo prikazu. + * + * @retval true Cislo prikazu je platne. + * @retval false Neplatne cislo prikazu. + */ +bool +protocol_is_cmd_code_valid(uint8_t cmd_code) +{ + return ((cmd_code == PROTOCOL_CMD_WRITE_PAGE) + || (cmd_code == PROTOCOL_CMD_ERASE_PAGE) + || (cmd_code == PROTOCOL_CMD_READ_PAGE) + || (cmd_code == PROTOCOL_CMD_EXEC_APPLICATION) + || (cmd_code == PROTOCOL_CMD_GET_APPLICATION_ID)); +} + +/** + * @brief Odoslanie odpovede aplikacneho protokolu, ktora nesie data. + * + * @param ret_code Navratovy kod v odpovedi. + * @param data Ukazovatel na buffer dat pre odoslanie. Musi mat vyhradeny prvy bajt pre umiestnenie navratoveho kodu. + * @param data_size Velkost bufferu v bajtoch. + */ +void +protocol_send_reply_with_data(uint8_t ret_code, uint8_t * const data, uint16_t data_size) +{ + data[0] = ret_code; + // Predpoklada sa, ze sa odosiela navratovy kod 1B + 512B dat stranky + data_send(data, data_size); +} + +/** + * @brief Odoslanie odpovede aplikacneho protokolu bez pripojenych dat. + * + * @param ret_code Navratovy kod v odpovedi. + */ +void +protocol_send_reply(uint8_t ret_code) +{ + // Nekontroluje sa uspesnost odoslania + data_send(&ret_code, 1); +} + +/** + * @brief Kontrola, ci prijaty prikaz obsahuje aj cislo stranky. + * + * @param cmd_bytes Velkost prijateho prikazu v bajtoch. + * + * @retval true Prikaz obsahuje cislo stranky. + * @retval false Prikaz neobsahuje cislo stranky. + */ +bool +protocol_cmd_contains_page_number(size_t cmd_bytes) { + return (cmd_bytes >= PROTOCOL_MINIMAL_SIZE); +} + +/** + * @brief Kontrola, ci konkretny prijaty prikaz obsahuje aspon minumum dat, aby bol platny. + * + * @param cmd_code Kod prijateho prikazu. + * @param cmd_bytes Velkost prijateho prikazu v bajtoch. + * + * @retval true Prikaz je platny. + * @retval false Prikaz nie je platny. + */ +bool +protocol_cmd_has_minimal_size(uint8_t cmd_code, size_t cmd_bytes) +{ + return (cmd_bytes >= cmd_data_sizes[cmd_code].min_bytes); +} + +/** + * @brief Kontrola, ci konkretny prijaty prikaz obsahuje zbytocne data navyse. + * + * @param cmd_code Kod prijateho prikazu. + * @param cmd_bytes Velkost prijateho prikazu v bajtoch. + * + * @retval true Prikaz je platny. + * @retval false Prikaz nie je platny pretoze obsahuje zbytocne data navyse. + */ +bool +protocol_cmd_has_extra_data(uint8_t cmd_code, size_t cmd_bytes) +{ + return (cmd_bytes > cmd_data_sizes[cmd_code].max_bytes); +} diff --git a/impl/DMBootloader/DMBootloader/protocol.h b/impl/DMBootloader/DMBootloader/protocol.h new file mode 100644 index 0000000..16959cf --- /dev/null +++ b/impl/DMBootloader/DMBootloader/protocol.h @@ -0,0 +1,8 @@ +/* Author: Jan Sucan */ + +#ifndef PROTOCOL_H_ +#define PROTOCOL_H_ + +void protocol_loop(void); + +#endif /* PROTOCOL_H_ */ \ No newline at end of file -- cgit v1.2.3