Smart-Home am Beispiel der Präsenzerkennung im Raum Projektarbeit Lennart Heimbs, Johannes Krug, Sebastian Dohle und Kevin Holzschuh bei Prof. Oliver Hofmann SS2019
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

MyOTAFirmwareUpdate.cpp 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. /*
  2. * The MySensors Arduino library handles the wireless radio link and protocol
  3. * between your home built sensors/actuators and HA controller of choice.
  4. * The sensors forms a self healing radio network with optional repeaters. Each
  5. * repeater and gateway builds a routing tables in EEPROM which keeps track of the
  6. * network topology allowing messages to be routed to nodes.
  7. *
  8. * Created by Henrik Ekblad <henrik.ekblad@mysensors.org>
  9. * Copyright (C) 2013-2018 Sensnology AB
  10. * Full contributor list: https://github.com/mysensors/MySensors/graphs/contributors
  11. *
  12. * Documentation: http://www.mysensors.org
  13. * Support Forum: http://forum.mysensors.org
  14. *
  15. * This program is free software; you can redistribute it and/or
  16. * modify it under the terms of the GNU General Public License
  17. * version 2 as published by the Free Software Foundation.
  18. */
  19. #include "MyOTAFirmwareUpdate.h"
  20. // global variables
  21. extern MyMessage _msg;
  22. extern MyMessage _msgTmp;
  23. // local variables
  24. #ifdef MY_OTA_USE_I2C_EEPROM
  25. I2CEeprom _flash(MY_OTA_I2C_ADDR);
  26. #elif !defined(MCUBOOT_PRESENT)
  27. SPIFlash _flash(MY_OTA_FLASH_SS, MY_OTA_FLASH_JDECID);
  28. #endif
  29. // Map flash functions
  30. #ifndef MCUBOOT_PRESENT
  31. #define _flash_initialize() _flash.initialize()
  32. #define _flash_readByte(addr) _flash.readByte(addr)
  33. #define _flash_writeBytes( dstaddr, data, size) _flash.writeBytes( dstaddr, data, size)
  34. #define _flash_blockErase32K(num) _flash.blockErase32K(num)
  35. #define _flash_busy() _flash.busy()
  36. #else
  37. #define _flash_initialize() true
  38. #define _flash_readByte(addr) (*((uint8_t *)(addr)))
  39. #define _flash_blockErase32K(num) Flash.erase((uint32_t *)FLASH_AREA_IMAGE_1_OFFSET_0, FLASH_AREA_IMAGE_1_SIZE_0)
  40. #define _flash_busy() false
  41. #endif
  42. LOCAL nodeFirmwareConfig_t _nodeFirmwareConfig;
  43. LOCAL bool _firmwareUpdateOngoing = false;
  44. LOCAL uint32_t _firmwareLastRequest;
  45. LOCAL uint16_t _firmwareBlock;
  46. LOCAL uint8_t _firmwareRetry;
  47. LOCAL bool _firmwareResponse(uint16_t block, uint8_t *data);
  48. LOCAL void readFirmwareSettings(void)
  49. {
  50. hwReadConfigBlock((void*)&_nodeFirmwareConfig, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS,
  51. sizeof(nodeFirmwareConfig_t));
  52. }
  53. LOCAL void firmwareOTAUpdateRequest(void)
  54. {
  55. const uint32_t enterMS = hwMillis();
  56. if (_firmwareUpdateOngoing && (enterMS - _firmwareLastRequest > MY_OTA_RETRY_DELAY)) {
  57. if (!_firmwareRetry) {
  58. setIndication(INDICATION_ERR_FW_TIMEOUT);
  59. OTA_DEBUG(PSTR("!OTA:FRQ:FW UPD FAIL\n")); // fw update failed
  60. // Give up. We have requested MY_OTA_RETRY times without any packet in return.
  61. _firmwareUpdateOngoing = false;
  62. return;
  63. }
  64. _firmwareRetry--;
  65. _firmwareLastRequest = enterMS;
  66. // Time to (re-)request firmware block from controller
  67. requestFirmwareBlock_t firmwareRequest;
  68. firmwareRequest.type = _nodeFirmwareConfig.type;
  69. firmwareRequest.version = _nodeFirmwareConfig.version;
  70. firmwareRequest.block = (_firmwareBlock - 1);
  71. OTA_DEBUG(PSTR("OTA:FRQ:FW REQ,T=%04" PRIX16 ",V=%04" PRIX16 ",B=%04" PRIX16 "\n"),
  72. _nodeFirmwareConfig.type,
  73. _nodeFirmwareConfig.version, _firmwareBlock - 1); // request FW update block
  74. (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_STREAM, ST_FIRMWARE_REQUEST,
  75. false).set(&firmwareRequest, sizeof(requestFirmwareBlock_t)));
  76. }
  77. }
  78. LOCAL bool firmwareOTAUpdateProcess(void)
  79. {
  80. if (_msg.type == ST_FIRMWARE_CONFIG_RESPONSE) {
  81. if(_firmwareUpdateOngoing) {
  82. OTA_DEBUG(PSTR("!OTA:FWP:UPDO\n")); // FW config response received, FW update already ongoing
  83. return true;
  84. }
  85. nodeFirmwareConfig_t *firmwareConfigResponse = (nodeFirmwareConfig_t *)_msg.data;
  86. // compare with current node configuration, if they differ, start FW fetch process
  87. if (memcmp(&_nodeFirmwareConfig, firmwareConfigResponse, sizeof(nodeFirmwareConfig_t))) {
  88. setIndication(INDICATION_FW_UPDATE_START);
  89. OTA_DEBUG(PSTR("OTA:FWP:UPDATE\n")); // FW update initiated
  90. // copy new FW config
  91. (void)memcpy(&_nodeFirmwareConfig, firmwareConfigResponse, sizeof(nodeFirmwareConfig_t));
  92. // Init flash
  93. if (!_flash_initialize()) {
  94. setIndication(INDICATION_ERR_FW_FLASH_INIT);
  95. OTA_DEBUG(PSTR("!OTA:FWP:FLASH INIT FAIL\n")); // failed to initialise flash
  96. _firmwareUpdateOngoing = false;
  97. } else {
  98. // erase lower 32K -> max flash size for ATMEGA328
  99. _flash_blockErase32K(0);
  100. // wait until flash erased
  101. while ( _flash_busy() ) {}
  102. _firmwareBlock = _nodeFirmwareConfig.blocks;
  103. _firmwareUpdateOngoing = true;
  104. // reset flags
  105. _firmwareRetry = MY_OTA_RETRY + 1;
  106. _firmwareLastRequest = 0;
  107. }
  108. return true;
  109. }
  110. OTA_DEBUG(PSTR("OTA:FWP:UPDATE SKIPPED\n")); // FW update skipped, no newer version available
  111. } else if (_msg.type == ST_FIRMWARE_RESPONSE) {
  112. // extract FW block
  113. replyFirmwareBlock_t *firmwareResponse = (replyFirmwareBlock_t *)_msg.data;
  114. // Proceed firmware data
  115. return _firmwareResponse(firmwareResponse->block, firmwareResponse->data);
  116. #ifdef FIRMWARE_PROTOCOL_31
  117. } else if (_msg.type == ST_FIRMWARE_RESPONSE_RLE) {
  118. // RLE encoded block
  119. // extract FW block
  120. replyFirmwareBlockRLE_t *firmwareResponse = (replyFirmwareBlockRLE_t *)_msg.data;
  121. uint8_t data[FIRMWARE_BLOCK_SIZE];
  122. for (uint8_t i=0; i<FIRMWARE_BLOCK_SIZE; i++) {
  123. data[i]=firmwareResponse->data;
  124. }
  125. while ((_firmwareBlock) && (firmwareResponse->number_of_blocks)) {
  126. _firmwareResponse(firmwareResponse->block, data);
  127. firmwareResponse->number_of_blocks--;
  128. firmwareResponse->block--;
  129. }
  130. return true;
  131. #endif
  132. } else {
  133. #ifdef MCUBOOT_PRESENT
  134. if (_msg.type == ST_FIRMWARE_CONFIRM) {
  135. if (*(uint16_t *)MCUBOOT_IMAGE_0_MAGIC_ADDR == ((uint16_t)MCUBOOT_IMAGE_MAGIC)) {
  136. if (*(uint8_t*)(MCUBOOT_IMAGE_0_IMG_OK_ADDR)!=MCUBOOT_IMAGE_0_IMG_OK_BYTE) {
  137. // Calculate data word to write
  138. uint32_t *img_ok_base_addr = (uint32_t*)(MCUBOOT_IMAGE_0_IMG_OK_ADDR & ~3); // align word wise
  139. uint32_t img_ok_data = *img_ok_base_addr;
  140. // Set copy of MCUBOOT_IMAGE_0_IMG_OK_ADDR to MCUBOOT_IMAGE_0_IMG_OK_BYTE (0x01)
  141. uint8_t * img_ok_array = (uint8_t*)(&img_ok_data);
  142. img_ok_array[MCUBOOT_IMAGE_0_IMG_OK_ADDR % 4] = MCUBOOT_IMAGE_0_IMG_OK_BYTE;
  143. // Write word back
  144. Flash.write(img_ok_base_addr, img_ok_data);
  145. }
  146. OTA_DEBUG(PSTR("!OTA:FWP:IMAGE CONFIRMED\n"));
  147. } else {
  148. OTA_DEBUG(PSTR("!OTA:FWP:INVALID MCUBOOT MAGIC\n"));
  149. }
  150. }
  151. #endif
  152. }
  153. return false;
  154. }
  155. LOCAL void presentBootloaderInformation(void)
  156. {
  157. requestFirmwareConfig_t *requestFirmwareConfig = (requestFirmwareConfig_t *)_msgTmp.data;
  158. mSetLength(_msgTmp, sizeof(requestFirmwareConfig_t));
  159. mSetCommand(_msgTmp, C_STREAM);
  160. mSetPayloadType(_msgTmp, P_CUSTOM);
  161. // copy node settings to reqFWConfig
  162. (void)memcpy(requestFirmwareConfig, &_nodeFirmwareConfig, sizeof(nodeFirmwareConfig_t));
  163. // add bootloader information
  164. requestFirmwareConfig->BLVersion = MY_OTA_BOOTLOADER_VERSION;
  165. #ifdef FIRMWARE_PROTOCOL_31
  166. requestFirmwareConfig->blockSize = FIRMWARE_BLOCK_SIZE;
  167. #ifndef MCUBOOT_PRESENT
  168. requestFirmwareConfig->img_commited = 0x2;
  169. requestFirmwareConfig->img_revision = 0x00;
  170. requestFirmwareConfig->img_build_num = 0x00;
  171. #else
  172. requestFirmwareConfig->img_commited = *((uint8_t*)(MCUBOOT_IMAGE_0_IMG_OK_ADDR));
  173. requestFirmwareConfig->img_revision = *((uint16_t*)(MCUBOOT_IMAGE_0_IMG_REVISION_ADDR));
  174. requestFirmwareConfig->img_build_num = *((uint16_t*)(MCUBOOT_IMAGE_0_IMG_BUILD_NUM_ADDR));
  175. #endif
  176. #endif
  177. _firmwareUpdateOngoing = false;
  178. (void)_sendRoute(build(_msgTmp, GATEWAY_ADDRESS, NODE_SENSOR_ID, C_STREAM,
  179. ST_FIRMWARE_CONFIG_REQUEST, false));
  180. }
  181. LOCAL bool isFirmwareUpdateOngoing(void)
  182. {
  183. return _firmwareUpdateOngoing;
  184. }
  185. // do a crc16 on the whole received firmware
  186. LOCAL bool transportIsValidFirmware(void)
  187. {
  188. // init crc
  189. uint16_t crc = ~0;
  190. for (uint32_t i = 0; i < _nodeFirmwareConfig.blocks * FIRMWARE_BLOCK_SIZE; ++i) {
  191. crc ^= _flash_readByte(i + FIRMWARE_START_OFFSET);
  192. for (int8_t j = 0; j < 8; ++j) {
  193. if (crc & 1) {
  194. crc = (crc >> 1) ^ 0xA001;
  195. } else {
  196. crc = (crc >> 1);
  197. }
  198. }
  199. }
  200. OTA_DEBUG(PSTR("OTA:CRC:B=%04" PRIX16 ",C=%04" PRIX16 ",F=%04" PRIX16 "\n"),
  201. _nodeFirmwareConfig.blocks,crc,
  202. _nodeFirmwareConfig.crc);
  203. return crc == _nodeFirmwareConfig.crc;
  204. }
  205. LOCAL bool _firmwareResponse(uint16_t block, uint8_t *data)
  206. {
  207. if (_firmwareUpdateOngoing) {
  208. OTA_DEBUG(PSTR("OTA:FWP:RECV B=%04" PRIX16 "\n"), block); // received FW block
  209. if (block != _firmwareBlock - 1) {
  210. OTA_DEBUG(PSTR("!OTA:FWP:WRONG FWB\n")); // received FW block
  211. // wrong firmware block received
  212. setIndication(INDICATION_FW_UPDATE_RX_ERR);
  213. // no further processing required
  214. return true;
  215. }
  216. setIndication(INDICATION_FW_UPDATE_RX);
  217. // Save block to flash
  218. #ifdef MCUBOOT_PRESENT
  219. uint32_t addr = ((size_t)(((_firmwareBlock - 1) * FIRMWARE_BLOCK_SIZE)) + (size_t)(
  220. FIRMWARE_START_OFFSET));
  221. if (addr<FLASH_AREA_IMAGE_SCRATCH_OFFSET_0) {
  222. Flash.write_block( (uint32_t *)addr, (uint32_t *)data, FIRMWARE_BLOCK_SIZE>>2);
  223. }
  224. #else
  225. _flash_writeBytes( ((_firmwareBlock - 1) * FIRMWARE_BLOCK_SIZE) + FIRMWARE_START_OFFSET,
  226. data, FIRMWARE_BLOCK_SIZE);
  227. #endif
  228. // wait until flash written
  229. while (_flash_busy()) {}
  230. #ifdef OTA_EXTRA_FLASH_DEBUG
  231. {
  232. char prbuf[8];
  233. uint32_t addr = ((_firmwareBlock - 1) * FIRMWARE_BLOCK_SIZE) + FIRMWARE_START_OFFSET;
  234. OTA_DEBUG(PSTR("OTA:FWP:FL DUMP "));
  235. sprintf_P(prbuf,PSTR("%04" PRIX16 ":"), (uint16_t)addr);
  236. MY_SERIALDEVICE.print(prbuf);
  237. for(uint8_t i=0; i<FIRMWARE_BLOCK_SIZE; i++) {
  238. uint8_t data = _flash_readByte(addr + i);
  239. sprintf_P(prbuf,PSTR("%02" PRIX8 ""), (uint8_t)data);
  240. MY_SERIALDEVICE.print(prbuf);
  241. }
  242. OTA_DEBUG(PSTR("\n"));
  243. }
  244. #endif
  245. _firmwareBlock--;
  246. if (!_firmwareBlock) {
  247. // We're done! Do a checksum and reboot.
  248. OTA_DEBUG(PSTR("OTA:FWP:FW END\n")); // received FW block
  249. _firmwareUpdateOngoing = false;
  250. if (transportIsValidFirmware()) {
  251. OTA_DEBUG(PSTR("OTA:FWP:CRC OK\n")); // FW checksum ok
  252. // Write the new firmware config to eeprom
  253. hwWriteConfigBlock((void*)&_nodeFirmwareConfig, (void*)EEPROM_FIRMWARE_TYPE_ADDRESS,
  254. sizeof(nodeFirmwareConfig_t));
  255. #ifndef MCUBOOT_PRESENT
  256. // All seems ok, write size and signature to flash (DualOptiboot will pick this up and flash it)
  257. const uint16_t firmwareSize = FIRMWARE_BLOCK_SIZE * _nodeFirmwareConfig.blocks;
  258. const uint8_t OTAbuffer[FIRMWARE_START_OFFSET] = {'F','L','X','I','M','G',':', (uint8_t)(firmwareSize >> 8), (uint8_t)(firmwareSize & 0xff),':'};
  259. _flash_writeBytes(0, OTAbuffer, FIRMWARE_START_OFFSET);
  260. // wait until flash ready
  261. while (_flash_busy()) {}
  262. #endif
  263. hwReboot();
  264. } else {
  265. setIndication(INDICATION_ERR_FW_CHECKSUM);
  266. OTA_DEBUG(PSTR("!OTA:FWP:CRC FAIL\n"));
  267. }
  268. }
  269. // reset flags
  270. _firmwareRetry = MY_OTA_RETRY + 1;
  271. _firmwareLastRequest = 0;
  272. } else {
  273. OTA_DEBUG(PSTR("!OTA:FWP:NO UPDATE\n"));
  274. }
  275. return true;
  276. }