From 46ffc509c163a2e75ea7afc1066a6e9af895ac00 Mon Sep 17 00:00:00 2001 From: Lars Schmertmann Date: Mon, 14 Sep 2015 14:19:42 +0200 Subject: [PATCH] Added App/Tool/Example for usage of additional flash on econotag/mc1322x --- .travis.yml | 1 + examples/econotag-flash-test/Makefile | 31 ++ examples/econotag-flash-test/README | 6 + .../econotag-flash-test/econotag-flash-test.c | 195 +++++++++++ .../econotag-flash-test.cfg | 7 + .../econotag-flash-test/econotag-flash-test.h | 66 ++++ platform/econotag/apps/flash/Makefile.flash | 1 + platform/econotag/apps/flash/flash.c | 207 +++++++++++ platform/econotag/apps/flash/flash.h | 178 ++++++++++ .../15-compile-arm-apcs-ports/Makefile | 1 + tools/blaster/Makefile | 19 + tools/blaster/README | 10 + tools/blaster/blaster.c | 330 ++++++++++++++++++ tools/blaster/blaster.h | 72 ++++ 14 files changed, 1124 insertions(+) create mode 100644 examples/econotag-flash-test/Makefile create mode 100644 examples/econotag-flash-test/README create mode 100644 examples/econotag-flash-test/econotag-flash-test.c create mode 100644 examples/econotag-flash-test/econotag-flash-test.cfg create mode 100644 examples/econotag-flash-test/econotag-flash-test.h create mode 100644 platform/econotag/apps/flash/Makefile.flash create mode 100644 platform/econotag/apps/flash/flash.c create mode 100644 platform/econotag/apps/flash/flash.h create mode 100644 tools/blaster/Makefile create mode 100644 tools/blaster/README create mode 100644 tools/blaster/blaster.c create mode 100644 tools/blaster/blaster.h diff --git a/.travis.yml b/.travis.yml index 98f98edff..b426b7c8b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -36,6 +36,7 @@ before_script: tar xjf arm-2008q3*.tar.bz2 -C /tmp/ && sudo cp -f -r /tmp/arm-2008q3/* /usr/ && rm -rf /tmp/arm-2008q3 arm-2008q3*.tar.bz2 && + sudo apt-get -qq install libconfig-dev uuid-dev libqrencode-dev && arm-none-eabi-gcc --version ; fi diff --git a/examples/econotag-flash-test/Makefile b/examples/econotag-flash-test/Makefile new file mode 100644 index 000000000..82905440e --- /dev/null +++ b/examples/econotag-flash-test/Makefile @@ -0,0 +1,31 @@ +CONTIKI = ../.. +LIBMC1322X = ../../../libmc1322x + +CONTIKI_PROJECT = econotag-flash-test +TARGET = econotag +CLEAN = *.d $(CONTIKI_PROJECT)_e_$(TARGET).bin $(CONTIKI_PROJECT)_e_$(TARGET).txt $(CONTIKI_PROJECT)_e_$(TARGET).pbm + +all: $(CONTIKI_PROJECT) blast + +CFLAGS += -DFLASH_CONF_B1=30 +CFLAGS += -DFLASH_CONF_B2=10 + +APPS += flash + +flash: + $(LIBMC1322X)/tools/mc1322x-load \ + -f $(LIBMC1322X)/tests/flasher_$(TARGET).bin \ + -s $(CONTIKI_PROJECT)_e_$(TARGET).bin \ + -c 'sudo $(LIBMC1322X)/tools/ftditools/bbmc -l $(TARGET) -i 0 reset' \ + -t /dev/ttyUSB1 -l + +clear: + $(LIBMC1322X)/tools/ftditools/bbmc -l $(TARGET) -i 0 erase + +blast: $(CONTIKI)/tools/blaster/blaster + $(CONTIKI)/tools/blaster/blaster $(CONTIKI_PROJECT).cfg + +$(CONTIKI)/tools/blaster/blaster: $(CONTIKI)/tools/blaster/blaster.c + (cd $(CONTIKI)/tools/blaster && $(MAKE)) + +include $(CONTIKI)/Makefile.include diff --git a/examples/econotag-flash-test/README b/examples/econotag-flash-test/README new file mode 100644 index 000000000..ee8aa7d3d --- /dev/null +++ b/examples/econotag-flash-test/README @@ -0,0 +1,6 @@ +Its important to use -l as a flash parameter for mc1322xload. + +Use "make flash" to start upload. Maybe u need +to change the location of libmc1322x in Makefile. + +With "make clear" you can erase all flash data. diff --git a/examples/econotag-flash-test/econotag-flash-test.c b/examples/econotag-flash-test/econotag-flash-test.c new file mode 100644 index 000000000..04ef42d8f --- /dev/null +++ b/examples/econotag-flash-test/econotag-flash-test.c @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2014, Lars Schmertmann . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + */ + +/** + * \file + * Flash test + * + * This file contains tests for econotag flash app + * + * \author + * Lars Schmertmann + */ + +#include "flash.h" +#include "contiki.h" + +#include +#include +#include + +#include "../../tools/blaster/blaster.h" +#include "econotag-flash-test.h" + +void +output_result(uint32_t i, uint32_t fail) +{ + if(fail) { + printf(" Test %u failed!\n", i); + } else { printf(" Test %u succeed!\n", i); + } +} +void +test_flash_1() +{ + uint8_t buffer[12]; + uint32_t check_int, my_int = 12345678; + + flash_setVar("Hello World!", RES_MY_STRING_1, LEN_MY_STRING_1); + + flash_getVar(buffer, RES_MY_STRING_1, LEN_MY_STRING_1); + output_result(1, memcmp(buffer, "Hello World!", 12)); + + flash_setVar("Heureka!", RES_MY_STRING_2, LEN_MY_STRING_2); + + flash_getVar(buffer, RES_MY_STRING_1, LEN_MY_STRING_1); + output_result(2, memcmp(buffer, "Hello World!", 12)); + + flash_getVar(buffer, RES_MY_STRING_2, LEN_MY_STRING_2); + output_result(3, memcmp(buffer, "Heureka!", 8)); + + flash_setVar(&my_int, RES_MY_INTEGER, LEN_MY_INTEGER); + + flash_getVar(&check_int, RES_MY_INTEGER, LEN_MY_INTEGER); + output_result(4, check_int != my_int); + + flash_getVar(buffer, RES_MY_STRING_1, LEN_MY_STRING_1); + output_result(5, memcmp(buffer, "Hello World!", 12)); + + flash_getVar(buffer, RES_MY_STRING_2, LEN_MY_STRING_2); + output_result(6, memcmp(buffer, "Heureka!", 8)); +} +void +test_flash_2() +{ + uint8_t buffer[12]; + uint32_t check_int, my_int = 12345678; + + flash_getVar(&check_int, RES_MY_INTEGER, LEN_MY_INTEGER); + output_result(1, check_int != my_int); + + flash_getVar(buffer, RES_MY_STRING_1, LEN_MY_STRING_1); + output_result(2, memcmp(buffer, "Hello World!", 12)); + + flash_getVar(buffer, RES_MY_STRING_2, LEN_MY_STRING_2); + output_result(3, memcmp(buffer, "Heureka!", 8)); + + /* Block 1 max usage is 30 Byte -> Optimisation in Makefile */ + output_result(4, flash_setVar("test", 0, 1) != gNvmErrInvalidPointer_c); + output_result(5, flash_setVar("test", 30, 1) != gNvmErrInvalidPointer_c); + output_result(6, flash_setVar("test", 29, 2) != gNvmErrAddressSpaceOverflow_c); + + /* Block 2 max usage is 10 Byte -> Optimisation in Makefile */ + output_result(7, flash_setVar("test", 4096, 1) != gNvmErrInvalidPointer_c); + output_result(8, flash_setVar("test", 4096 + 10, 1) != gNvmErrInvalidPointer_c); + output_result(9, flash_setVar("test", 4096 + 9, 2) != gNvmErrAddressSpaceOverflow_c); +} +void +test_flash_blaster() +{ + uint8_t buffer[64]; + + flash_getVar(buffer, RES_NAME, LEN_NAME); + output_result(1, memcmp(buffer, "Econotag Flash Test Device", 27)); + + flash_getVar(buffer, RES_MODEL, LEN_MODEL); + output_result(2, memcmp(buffer, "Model 1234 for testing purposes only", 37)); +} +void +test_flash_stack() +{ + uint8_t buffer[32]; + flash_stack_init(); + + output_result(1, flash_stack_size() != 0); + + flash_stack_push("Hello World!", 12); + output_result(2, flash_stack_size() != 12); + + flash_stack_read(buffer, 0, 12); + output_result(3, memcmp(buffer, "Hello World!", 12)); + + flash_stack_push("I love Contiki!", 15); + output_result(4, flash_stack_size() != 27); + + flash_stack_read(buffer, 0, 12); + output_result(5, memcmp(buffer, "Hello World!", 12)); + + flash_stack_read(buffer, 12, 15); + output_result(6, memcmp(buffer, "I love Contiki!", 15)); + + flash_stack_init(); + output_result(7, flash_stack_size() != 0); + + uint32_t i; + for(i = 1; i < 256; i++) { + flash_stack_push("I love Contiki! ", 16); + } + output_result(8, flash_stack_size() != 4080); + + output_result(9, flash_stack_push("1I love Contiki! ", 17) != gNvmErrAddressSpaceOverflow_c); +} +/* Start Process */ +PROCESS(server_firmware, "Server Firmware"); +AUTOSTART_PROCESSES(&server_firmware); + +PROCESS_THREAD(server_firmware, ev, data) { + PROCESS_BEGIN(); + + if(flash_cmp("\001", RES_DONTCLEAR, LEN_DONTCLEAR)) { + printf("Initializing flash ... "); + flash_init(); + printf("DONE\n"); + flash_setVar("\001", RES_DONTCLEAR, LEN_DONTCLEAR); + printf("Starting flash tests 1:\n"); + test_flash_1(); + int i; + for(i = 0; i < 1024; i++) { + printf("Reboot ...\r"); + } + soft_reset(); + } else { + printf("Initialization not wished\n"); + } + printf("Starting flash tests 2:\n"); + test_flash_2(); + + printf("Starting flash stack tests:\n"); + test_flash_stack(); + + printf("Starting flash blaster tests:\n"); + test_flash_blaster(); + + PROCESS_END(); +} diff --git a/examples/econotag-flash-test/econotag-flash-test.cfg b/examples/econotag-flash-test/econotag-flash-test.cfg new file mode 100644 index 000000000..9b26c4adb --- /dev/null +++ b/examples/econotag-flash-test/econotag-flash-test.cfg @@ -0,0 +1,7 @@ +input = "econotag-flash-test_econotag"; +output = "econotag-flash-test_e_econotag"; +eui = [ 0x2, 0x0, 0x0, 0x0, 0x12, 0x34, 0x56, 0x78 ]; +uuid = "cbf9889f-dc0e-4c18-9aa9-93509a6c102a"; +psk = "yCh0OXnSkFT-eXKE"; +name = "Econotag Flash Test Device"; +model = "Model 1234 for testing purposes only"; diff --git a/examples/econotag-flash-test/econotag-flash-test.h b/examples/econotag-flash-test/econotag-flash-test.h new file mode 100644 index 000000000..469d93faa --- /dev/null +++ b/examples/econotag-flash-test/econotag-flash-test.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2014, Lars Schmertmann . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + */ + +/** + * \file + * Flash Management + * + * This file contains Pointers for manual flash management. + * + * \author + * Lars Schmertmann + */ + +#ifndef ECONOTAG_FLASH_TEST_H_ +#define ECONOTAG_FLASH_TEST_H_ + +/* Pointer for Block 1 --------------- */ + +#define RES_DONTCLEAR 1 +#define LEN_DONTCLEAR 1 + +#define RES_MY_STRING_1 2 +#define LEN_MY_STRING_1 12 + +#define RES_MY_STRING_2 14 +#define LEN_MY_STRING_2 8 + +/* Pointer for Block 2 --------------- */ + +#define RES_MY_INTEGER (4096 + 1) +#define LEN_MY_INTEGER 4 + +/* ------------------------------------ */ + +#endif /* ECONOTAG_FLASH_TEST_H_ */ diff --git a/platform/econotag/apps/flash/Makefile.flash b/platform/econotag/apps/flash/Makefile.flash new file mode 100644 index 000000000..d78891b5c --- /dev/null +++ b/platform/econotag/apps/flash/Makefile.flash @@ -0,0 +1 @@ +flash_src = flash.c diff --git a/platform/econotag/apps/flash/flash.c b/platform/econotag/apps/flash/flash.c new file mode 100644 index 000000000..959724697 --- /dev/null +++ b/platform/econotag/apps/flash/flash.c @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2014, Lars Schmertmann . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + */ + +#include "flash.h" + +#define FLASH_BLOCK_SIZE 0x01000 + +#define FLASH_BLOCK_11 0x18000 +#define FLASH_BLOCK_21 0x1A000 + +#ifndef FLASH_CONF_B1 +#define FLASH_CONF_B1 FLASH_BLOCK_SIZE +#endif + +#ifndef FLASH_CONF_B2 +#define FLASH_CONF_B2 FLASH_BLOCK_SIZE +#endif + +#define DEBUG 0 + +#if DEBUG +#include +#include "mc1322x.h" +#define PRINTF(...) printf(__VA_ARGS__) +#else +#define PRINTF(...) +#endif + +uint16_t stackPointer; + +/* private prototypes ----------------------------------------------------- */ + +flash_addr_t getAddr(flash_addr_t address); + +/* public functions -------------------------------------------------------- */ + +void +flash_init() +{ + PRINTF("Initializing flash ... "); + + nvm_erase(gNvmInternalInterface_c, gNvmType_SST_c, 0x0F000000); + + nvm_write(gNvmInternalInterface_c, gNvmType_SST_c, "\001", FLASH_BLOCK_11, 1); + nvm_write(gNvmInternalInterface_c, gNvmType_SST_c, "\001", FLASH_BLOCK_21, 1); + + uint32_t i; + for(i = 1; i < 0x2000; i++) { +#if DEBUG + if(i % 0x400 == 0) { + PRINTF(" ."); + } +#endif + nvm_write(gNvmInternalInterface_c, gNvmType_SST_c, "\0", FLASH_BLOCK_11 + i, 1); + nvm_write(gNvmInternalInterface_c, gNvmType_SST_c, "\0", FLASH_BLOCK_21 + i, 1); + } + + PRINTF("DONE\n"); +} +nvmErr_t +flash_getVar(void *dest, flash_addr_t address, uint32_t numBytes) +{ + address = getAddr(address); + + if(address >= 0x18000 && address <= 0x1EFFF) { + PRINTF("Read from Adress: %p\n", address); + nvmErr_t err = nvm_read(gNvmInternalInterface_c, gNvmType_SST_c, dest, address, numBytes); + if(err) { + PRINTF("Read error, nmv_error: %u\n", err); + return err; + } + return gNvmErrNoError_c; + } + + PRINTF("Read error - Invalid pointer.\n"); + return gNvmErrInvalidPointer_c; +} +nvmErr_t +flash_setVar(void *src, flash_addr_t address, uint32_t numBytes) +{ +#if DEBUG + printf("SetVar - START . "); + uint32_t time = *MACA_CLK; +#endif + + if(address >= 8192) { + PRINTF("Write error - Invalid pointer.\n"); + return gNvmErrInvalidPointer_c; + } + uint32_t block_len = (address < 4096 ? FLASH_CONF_B1 : FLASH_CONF_B2); + + address = getAddr(address); + + flash_addr_t src_block = address & 0xFF000; + flash_addr_t dst_block = src_block ^ 0x01000; + address = address & 0x00FFF; + + if(address < 1 || address >= block_len) { + PRINTF("Write error - Invalid pointer.\n"); + return gNvmErrInvalidPointer_c; + } + if(address + numBytes > block_len) { + PRINTF("Write error - Var is to long.\n"); + return gNvmErrAddressSpaceOverflow_c; + } + + nvm_erase(gNvmInternalInterface_c, gNvmType_SST_c, 1 << (dst_block / FLASH_BLOCK_SIZE)); + + uint32_t i; + uint8_t buf; + for(i = 0; i < address; i++) { + nvm_read(gNvmInternalInterface_c, gNvmType_SST_c, &buf, src_block + i, 1); + nvm_write(gNvmInternalInterface_c, gNvmType_SST_c, &buf, dst_block + i, 1); + } + PRINTF("Write to adress: %p\n", dst_block + i); + nvm_write(gNvmInternalInterface_c, gNvmType_SST_c, src, dst_block + i, numBytes); + for(i += numBytes; i < block_len; i++) { + nvm_read(gNvmInternalInterface_c, gNvmType_SST_c, &buf, src_block + i, 1); + nvm_write(gNvmInternalInterface_c, gNvmType_SST_c, &buf, dst_block + i, 1); + } + + nvm_erase(gNvmInternalInterface_c, gNvmType_SST_c, 1 << (src_block / FLASH_BLOCK_SIZE)); + +#if DEBUG + time = *MACA_CLK - time; + printf("FINISHED AFTER %u MS\n", time / 250); +#endif + + return gNvmErrNoError_c; +} +nvmErr_t +flash_cmp(void *src, flash_addr_t address, uint32_t numBytes) +{ + address = getAddr(address); + + if(address >= 0x18000 && address <= 0x1EFFF) { + return nvm_verify(gNvmInternalInterface_c, gNvmType_SST_c, src, address, numBytes); + } + PRINTF("Read error - Invalid pointer.\n"); + return gNvmErrInvalidPointer_c; +} +void +flash_stack_init() +{ + stackPointer = 0; + nvm_erase(gNvmInternalInterface_c, gNvmType_SST_c, 1 << (FLASH_STACK / FLASH_BLOCK_SIZE)); +} +nvmErr_t +flash_stack_push(uint8_t *src, uint32_t numBytes) +{ + if(stackPointer + numBytes > FLASH_BLOCK_SIZE) { + return gNvmErrAddressSpaceOverflow_c; + } + + nvm_write(gNvmInternalInterface_c, gNvmType_SST_c, src, FLASH_STACK + stackPointer, numBytes); + stackPointer += numBytes; + return gNvmErrNoError_c; +} +uint32_t +flash_stack_size() +{ + return stackPointer; +} +/* private functions ------------------------------------------------------- */ + +flash_addr_t +getAddr(flash_addr_t address) +{ + if(address >= 0x02000) { + return address; + } + + flash_addr_t block = (address & 0x01000 ? FLASH_BLOCK_21 : FLASH_BLOCK_11); + uint8_t blockcheck = (flash_cmp("\001", block, 1) == 0 ? 0 : 1); + return block + (blockcheck << 12) + (address & 0x00FFF); +} diff --git a/platform/econotag/apps/flash/flash.h b/platform/econotag/apps/flash/flash.h new file mode 100644 index 000000000..a50bddc80 --- /dev/null +++ b/platform/econotag/apps/flash/flash.h @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2014, Lars Schmertmann . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + */ + +/** + * \file + * App for easy usage of additional flash memory + * + * Purposes of the different flash blocks + * 1 : 0x18000 - 0x18FFF : Random access block 1.1 + * 2 : 0x19000 - 0x19FFF : Random access block 1.2 + * 3 : 0x1A000 - 0x1AFFF : Random access block 2.1 + * 4 : 0x1B000 - 0x1BFFF : Random access block 2.2 + * 5 : 0x1C000 - 0x1CFFF : Stack without pop function + * 6 : 0x1D000 - 0x1DFFF : Read only + * 7 : 0x1E000 - 0x1EFFF : Read only + * 8 : 0x1F000 - 0x1FFFF : System reserved + * + * This app only allows write access to blocks 1 - 5 + * and read access to blocks 1 - 7. + * + * To use the stack in block 5 you need: flash_stack_init, + * flash_stack_push, flash_stack_size, flash_stack_read. + * + * To use the random access blocks 1.x and 2.x you need: flash_init, + * flash_getVar, flash_setVar, flash_cmp. + * + * Blocks 1.x and 2.x are accessible with adresses + * 0x0001 - 0x0FFF and 0x1001 - 0x1FFF. + * + * To be able to write to flash memory, its required to delete + * it first, but its only possible to delete a full block. So this + * app copies the data of a block, changing the requested data. + * Copying a block needs time. So when you only use the first N bytes, + * you can set FLASH_CONF_B1=N and FLASH_CONF_B2=N in your makefile + * to optimize speed. + * + * You can find an example in examples/econotag-flash-test. + * + * \author + * Lars Schmertmann + */ + +#ifndef FLASH_H_ +#define FLASH_H_ + +#include + +#define FLASH_STACK 0x1C000 + +typedef uint32_t flash_addr_t; + +/** + * \brief Initialize or clear random access blocks + * + * To use the random access blocks, you need to call this + * function first. You can also use it to delete all data + * in this blocks. + */ +void flash_init(); + +/** + * \brief Read data from flash memory + * + * Reads data from flash memory and stores it into RAM. + * You can read the flash area 0x18000 - 0x1EFFF. Addresses + * 0x0000 - 0x1FFF will be mapped to 0x18000 - 0x1BFFF. + * + * \param dest Memory area to store the data + * \param address Area in flash memory to read from + * \param numBytes Number of bytes to read + * + * \return gNvmErrNoError_c (0) if read was successfull + */ +nvmErr_t flash_getVar(void *dest, flash_addr_t address, uint32_t numBytes); + +/** + * \brief Write data to flash memory + * + * Writes data to flash memory. Valid addresses are + * 0x0001 - 0x0FFF and 0x1001 - 0x1FFF -> Mapped to + * 0x18000 - 0x1BFFF. + * + * \param src Memory area with data to store in flash memory + * \param address Area in flash memory to write + * \param numBytes Number of bytes to write + * + * \return gNvmErrNoError_c (0) if write was successfull + */ +nvmErr_t flash_setVar(void *src, flash_addr_t address, uint32_t numBytes); + +/** + * \brief Compares data from RAM with flash memory + * + * Compares data from RAM with flash memory. + * Valid addresses are 0x18000 - 0x1EFFF. Addresses + * 0x0 - 0x1FFF will be mapped to 0x18000 - 0x1BFFF. + * + * \param src Memory area with data to compare + * \param address Area in flash memory + * \param numBytes Number of bytes to compare + * + * \return 0 if data is matching + */ +nvmErr_t flash_cmp(void *src, flash_addr_t address, uint32_t numBytes); + +/** + * \brief Stack initialisation + * + * Clears and initializes the stack. + */ +void flash_stack_init(); + +/** + * \brief Push data to stack + * + * Pushes numBytes from src to stack into flash memory. + * + * \param src Memory area with data to store in flash memory + * \param numBytes Number of bytes to write + * + * \return gNvmErrNoError_c (0) if push was successfull + */ +nvmErr_t flash_stack_push(uint8_t *src, uint32_t numBytes); + +/** + * \brief Stacksize + * + * Returns the size of data in stack + * + * \return Number of bytes in stack + */ +uint32_t flash_stack_size(); + +/** + * \brief Read data from stack + * + * Reads data from stack (without removing it) and stores it into RAM. + * + * \param dest Memory area to store the data + * \param offset Position in stack to read from + * \param numBytes Number of bytes to read + * + * \return gNvmErrNoError_c (0) if read was successfull + */ +#define flash_stack_read(dest, offset, numBytes) flash_getVar(dest, FLASH_STACK + (offset), numBytes) + +#endif /* FLASH_H_ */ diff --git a/regression-tests/15-compile-arm-apcs-ports/Makefile b/regression-tests/15-compile-arm-apcs-ports/Makefile index e73a9a39f..767bed60f 100644 --- a/regression-tests/15-compile-arm-apcs-ports/Makefile +++ b/regression-tests/15-compile-arm-apcs-ports/Makefile @@ -8,6 +8,7 @@ ipv6/rpl-border-router/econotag \ er-rest-example/econotag \ webserver-ipv6/econotag \ ipv6/multicast/econotag \ +econotag-flash-test/econotag \ TOOLS= diff --git a/tools/blaster/Makefile b/tools/blaster/Makefile new file mode 100644 index 000000000..ceafb5cca --- /dev/null +++ b/tools/blaster/Makefile @@ -0,0 +1,19 @@ +CC = gcc +CFLAGS = -Wall -g +HEADERS = + +all: blaster + +depend: + sudo apt-get install libconfig8-dev uuid-dev libqrencode-dev + +%.o: %.c $(HEADERS) + $(CC) -c $(CFLAGS) -o $@ $< + +blaster: blaster.o + $(CC) $(CFLAGS) -o $@ $^ -lconfig -luuid -lqrencode + +clean: + rm *.o blaster + +.PHONY: all depend clean diff --git a/tools/blaster/README b/tools/blaster/README new file mode 100644 index 000000000..7fd109460 --- /dev/null +++ b/tools/blaster/README @@ -0,0 +1,10 @@ +Blaster extends the compiled firmware with additional data for +storing into flash memory. See examples/econotag-flash-test for +usage. Its written for Econotag / MC1322X + +./blaster [ ...] +To Generate a default configuration file, use blaster without parameter. + +Its important to use -l as a flash parameter. + +mc1322x-load -f flasher_econotag.bin -s firmware.bin -t /dev/ttyUSB1 -l diff --git a/tools/blaster/blaster.c b/tools/blaster/blaster.c new file mode 100644 index 000000000..ff074c479 --- /dev/null +++ b/tools/blaster/blaster.c @@ -0,0 +1,330 @@ +/* + * Copyright (c) 2014, Lars Schmertmann . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "blaster.h" + +char *anschars = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_-"; + +/* ---------------------------------------------------------------------------- */ + +FILE *openFile(const char *name, const char *appendix, const char *mode); +void writeStandardConfig(); +void writeImg(FILE *file, unsigned char *data, int width); + +/* ---------------------------------------------------------------------------- */ + +int +main(int nArgs, char **argv) +{ + unsigned int c, i, config; + unsigned int buf[64]; + + if(nArgs < 2) { + writeStandardConfig(); + + fprintf(stderr, "Missing parameter: ./blaster [ ...]\n"); + fprintf(stderr, "Configuration template was created ib config.cfg.\n"); + + exit(EXIT_FAILURE); + } + + /* qrdata = "UUID:PSK\0" */ + char qrdata[54]; + qrdata[36] = ':'; + qrdata[53] = '\0'; + + config_t cfg; + for(config = 1; config < nArgs; config++) { + config_init(&cfg); + config_setting_t *setting; + const char *str_val; + if(access(argv[config], F_OK) == 0) { + config_read_file(&cfg, argv[config]); + } else { + fprintf(stderr, "Unable to read config file.\n"); + exit(EXIT_FAILURE); + } + fprintf(stdout, "Working on %s ... ", argv[config]); + + config_lookup_string(&cfg, "input", &str_val); + FILE *in_bin = openFile(str_val, ".bin", "r"); + + config_lookup_string(&cfg, "output", &str_val); + FILE *out_bin = openFile(str_val, ".bin", "w"); + FILE *out_txt = openFile(str_val, ".txt", "w"); + FILE *out_pbm = openFile(str_val, ".pbm", "w"); + + char output[131072]; + for(i = 8; (c = fgetc(in_bin)) != EOF; i++) { + output[i] = (unsigned char)c; + } + /* Set original length of firmware in little endian format ------------------- */ + unsigned int length = i - 8; + memcpy(output + 4, (const void *)&length, 4); + fprintf(out_txt, "Length: %u = 0x%08x\n", length, length); + + /* Fill additional flash with zeros for initialisation */ + for(; i < 0x1F000; i++) { + output[i] = 0x00; + } + + /* Example: Write an CoRE-Link-Answer for CoAP -------------------------------- */ + char *buffer = ";rt=\"dev.info\";if=\"core.rp\"," + ";rt=\"dev.info\";if=\"core.rp\"," + ";rt=\"dev.info\";if=\"core.rp\""; + memcpy(output + RES_D_CORE, buffer, LEN_D_CORE); + + /* Contiki configuration ------------------------------------------------------ */ + output[RES_CONFIG + 0] = 0x22; + output[RES_CONFIG + 1] = 0x13; + output[RES_CONFIG + 2] = 1; + output[RES_CONFIG + 3] = 0; + + setting = config_lookup(&cfg, "eui"); + for(i = 0; i < 8; i++) { + output[RES_CONFIG + 8 + i] = config_setting_get_int_elem(setting, 7 - i); + } + fprintf(out_txt, + "EUI: %02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x\n", + (uint8_t)output[RES_CONFIG + 15], + (uint8_t)output[RES_CONFIG + 14], + (uint8_t)output[RES_CONFIG + 13], + (uint8_t)output[RES_CONFIG + 12], + (uint8_t)output[RES_CONFIG + 11], + (uint8_t)output[RES_CONFIG + 10], + (uint8_t)output[RES_CONFIG + 9], + (uint8_t)output[RES_CONFIG + 8] + ); + + output[RES_CONFIG + 16] = 15; + output[RES_CONFIG + 17] = 17; + output[RES_CONFIG + 18] = 0; + output[RES_CONFIG + 19] = 0; + output[RES_CONFIG + 20] = 5; + output[RES_CONFIG + 21] = 0; + output[RES_CONFIG + 22] = 0; + output[RES_CONFIG + 23] = 0; + + /* Example: Set UUID ---------------------------------------------------------- */ + config_lookup_string(&cfg, "uuid", &str_val); + memcpy(qrdata, str_val, 36); + unsigned char uuid_bin[16]; + uuid_parse(str_val, uuid_bin); + for(i = 0; i < 16; i++) { + output[RES_UUID + i] = uuid_bin[i]; + } + fprintf(out_txt, "UUID: %s\n", str_val); + + /* Example: Set PSK ----------------------------------------------------------- */ + config_lookup_string(&cfg, "psk", &str_val); + memcpy(qrdata + 37, str_val, 16); + for(i = 0; i < 16; i++) { + output[RES_PSK + i] = str_val[i]; + } + fprintf(out_txt, "PSK: %.*s\n", 16, str_val); + memcpy(output + RES_ANSCHARS, anschars, LEN_ANSCHARS); + + /* Example: ECC base point and order for secp256r1 ---------------------------- */ + uint32_t *base_x = (uint32_t *)(output + RES_ECC_BASE_X); + base_x[0] = 0xd898c296; + base_x[1] = 0xf4a13945; + base_x[2] = 0x2deb33a0; + base_x[3] = 0x77037d81; + base_x[4] = 0x63a440f2; + base_x[5] = 0xf8bce6e5; + base_x[6] = 0xe12c4247; + base_x[7] = 0x6b17d1f2; + + uint32_t *base_y = (uint32_t *)(output + RES_ECC_BASE_Y); + base_y[0] = 0x37bf51f5; + base_y[1] = 0xcbb64068; + base_y[2] = 0x6b315ece; + base_y[3] = 0x2bce3357; + base_y[4] = 0x7c0f9e16; + base_y[5] = 0x8ee7eb4a; + base_y[6] = 0xfe1a7f9b; + base_y[7] = 0x4fe342e2; + + uint32_t *order = (uint32_t *)(output + RES_ECC_ORDER); + order[0] = 0xFC632551; + order[1] = 0xF3B9CAC2; + order[2] = 0xA7179E84; + order[3] = 0xBCE6FAAD; + order[4] = 0xFFFFFFFF; + order[5] = 0xFFFFFFFF; + order[6] = 0x00000000; + order[7] = 0xFFFFFFFF; + + /* Example: Set name ---------------------------------------------------------- */ + config_lookup_string(&cfg, "name", &str_val); + snprintf(output + RES_NAME, LEN_NAME, "%s", str_val); + fprintf(out_txt, "Name: %s\n", str_val); + + /* Example: Set model---------------------------------------------------------- */ + config_lookup_string(&cfg, "model", &str_val); + snprintf(output + RES_MODEL, LEN_MODEL, "%s", str_val); + fprintf(out_txt, "Model: %s\n", str_val); + + /* Example: Set time ---------------------------------------------------------- */ + time_t my_time = time(NULL); + memcpy(output + RES_FLASHTIME, (void *)&my_time, LEN_FLASHTIME); + struct tm *timeinfo = localtime(&my_time); + fwrite(buf, 1, strftime((char *)buf, 64, "Created on %d.%m.%Y um %H:%M:%S", timeinfo), out_txt); + + /* Output result -------------------------------------------------------------- */ + for(i = 4; i < 0x1F000; i++) { + fputc(output[i], out_bin); + } + + /* Generate QR-Code ----------------------------------------------------------- */ + QRcode *code = QRcode_encodeString8bit(qrdata, 3, QR_ECLEVEL_L); + writeImg(out_pbm, code->data, code->width); + + fclose(in_bin); + fclose(out_bin); + fclose(out_txt); + fclose(out_pbm); + + fprintf(stdout, "DONE\n"); + } + + exit(EXIT_SUCCESS); +} +/* ---------------------------------------------------------------------------- */ + +FILE * +openFile(const char *name, const char *appendix, const char *mode) +{ + char filename[64]; + sprintf(filename, "%s%s", name, appendix); + FILE *file = fopen(filename, mode); + if(file == NULL) { + perror("Wasn't able to open file."); + exit(EXIT_FAILURE); + } + return file; +} +void +writeStandardConfig() +{ + unsigned int i; + + config_t cfg; + config_init(&cfg); + config_setting_t *setting; + + config_setting_t *root = config_root_setting(&cfg); + + setting = config_setting_add(root, "input", CONFIG_TYPE_STRING); + config_setting_set_string(setting, "dff_econotag"); + + setting = config_setting_add(root, "output", CONFIG_TYPE_STRING); + config_setting_set_string(setting, "dff_e_econotag"); + + uint8_t eui[8] = { 0x02, 0x00, 0x00, 0x00, 0x12, 0x34, 0x56, 0x78 }; + config_setting_t *array = config_setting_add(root, "eui", CONFIG_TYPE_ARRAY); + for(i = 0; i < 8; ++i) { + setting = config_setting_add(array, NULL, CONFIG_TYPE_INT); + config_setting_set_format(setting, CONFIG_FORMAT_HEX); + config_setting_set_int(setting, eui[i]); + } + + unsigned char uuid_bin[16]; + uuid_generate(uuid_bin); + char uuid[37]; + uuid_unparse(uuid_bin, uuid); + setting = config_setting_add(root, "uuid", CONFIG_TYPE_STRING); + config_setting_set_string(setting, uuid); + + char psk[17]; + psk[16] = '\0'; + FILE *fd = fopen("/dev/urandom", "r"); + if(fd == NULL) { + perror("Wasn't able to open /dev/urandom: "); + return; + } + for(i = 0; i < 16; i++) { + int c; + while((c = fgetc(fd)) == EOF) ; + psk[i] = anschars[c % 64]; + } + if(fclose(fd) == -1) { + perror("Wasn't able to close /dev/urandom: "); + } + setting = config_setting_add(root, "psk", CONFIG_TYPE_STRING); + config_setting_set_string(setting, psk); + + setting = config_setting_add(root, "name", CONFIG_TYPE_STRING); + config_setting_set_string(setting, "Blaster Standard Device"); + + setting = config_setting_add(root, "model", CONFIG_TYPE_STRING); + config_setting_set_string(setting, "Model 1234 for testing purposes only"); + + config_write_file(&cfg, "config.cfg"); +} +void +writeImg(FILE *file, unsigned char *data, int width) +{ + unsigned int buf[width]; + + fprintf(file, "P4\n# %s\n%3u %3u\n", "QR-Code", width * 32, width * 32); + + int x, y; + for(y = 0; y < width; y++) { + for(x = 0; x < width; x++) { + if(data[(y * width) + x] & 0x01) { + buf[x] = 0xFFFFFFFF; + } else { + buf[x] = 0x00000000; + } + } + for(x = 0; x < 32; x++) { + fwrite(buf, 4, width, file); + } + } +} diff --git a/tools/blaster/blaster.h b/tools/blaster/blaster.h new file mode 100644 index 000000000..085abf855 --- /dev/null +++ b/tools/blaster/blaster.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2014, Lars Schmertmann . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This file is part of the Contiki operating system. + * + */ + +/* Purposes of the different flash blocks */ +/* 0x18000 - 0x18FFF : Random access block 1.1 */ +/* 0x19000 - 0x19FFF : Random access block 1.2 */ +/* 0x1A000 - 0x1AFFF : Random access block 2.1 */ +/* 0x1B000 - 0x1BFFF : Random access block 2.2 */ +/* 0x1C000 - 0x1CFFF : Stack without pop function */ +/* 0x1D000 - 0x1DFFF : Read only <- This is what blaster user */ +/* 0x1E000 - 0x1EFFF : Read only <- This is what blaster user */ +/* 0x1F000 - 0x1FFFF : System reserved */ + +#ifndef BLASTER_H_ +#define BLASTER_H_ + +#define RES_D_CORE 0x1D000 +#define LEN_D_CORE 0x6F + +#define RES_CONFIG 0x1E000 +#define LEN_CONFIG 0x12 +#define RES_UUID 0x1E020 +#define LEN_UUID 0x10 +#define RES_PSK 0x1E030 +#define LEN_PSK 0x10 +#define RES_ANSCHARS 0x1E040 +#define LEN_ANSCHARS 0x40 +#define RES_ECC_BASE_X 0x1E080 +#define LEN_ECC_BASE_X 0x20 +#define RES_ECC_BASE_Y 0x1E0A0 +#define LEN_ECC_BASE_Y 0x20 +#define RES_ECC_ORDER 0x1E0C0 +#define LEN_ECC_ORDER 0x20 +#define RES_NAME 0x1E0E0 +#define LEN_NAME 0x40 +#define RES_MODEL 0x1E120 +#define LEN_MODEL 0x40 +#define RES_FLASHTIME 0x1E160 +#define LEN_FLASHTIME 0x04 + +#endif /* BLASTER_H_ */