flipper_i32hex_file.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. #include "flipper_i32hex_file.h"
  2. #include <string.h>
  3. #include <storage/storage.h>
  4. #include <toolbox/stream/stream.h>
  5. #include <toolbox/stream/file_stream.h>
  6. #include <toolbox/hex.h>
  7. //https://en.wikipedia.org/wiki/Intel_HEX
  8. #define TAG "FlipperI32HexFile"
  9. #define COUNT_BYTE_PAYLOAD 32 //how much payload will be used
  10. #define I32HEX_TYPE_DATA 0x00
  11. #define I32HEX_TYPE_END_OF_FILE 0x01
  12. #define I32HEX_TYPE_EXT_LINEAR_ADDR 0x04
  13. #define I32HEX_TYPE_START_LINEAR_ADDR 0x05
  14. struct FlipperI32HexFile {
  15. uint32_t addr;
  16. uint32_t addr_last;
  17. Storage* storage;
  18. Stream* stream;
  19. FuriString* str_data;
  20. FlipperI32HexFileStatus file_open;
  21. };
  22. FlipperI32HexFile* flipper_i32hex_file_open_write(const char* name, uint32_t start_addr) {
  23. furi_assert(name);
  24. FlipperI32HexFile* instance = malloc(sizeof(FlipperI32HexFile));
  25. instance->addr = start_addr;
  26. instance->addr_last = 0;
  27. instance->storage = furi_record_open(RECORD_STORAGE);
  28. instance->stream = file_stream_alloc(instance->storage);
  29. if(file_stream_open(instance->stream, name, FSAM_WRITE, FSOM_CREATE_ALWAYS)) {
  30. instance->file_open = FlipperI32HexFileStatusOpenFileWrite;
  31. FURI_LOG_D(TAG, "Open write file %s", name);
  32. } else {
  33. FURI_LOG_E(TAG, "Failed to open file %s", name);
  34. instance->file_open = FlipperI32HexFileStatusErrorNoOpenFile;
  35. }
  36. instance->str_data = furi_string_alloc();
  37. return instance;
  38. }
  39. FlipperI32HexFile* flipper_i32hex_file_open_read(const char* name) {
  40. furi_assert(name);
  41. FlipperI32HexFile* instance = malloc(sizeof(FlipperI32HexFile));
  42. instance->addr = 0;
  43. instance->addr_last = 0;
  44. instance->storage = furi_record_open(RECORD_STORAGE);
  45. instance->stream = file_stream_alloc(instance->storage);
  46. if(file_stream_open(instance->stream, name, FSAM_READ, FSOM_OPEN_EXISTING)) {
  47. instance->file_open = FlipperI32HexFileStatusOpenFileRead;
  48. FURI_LOG_D(TAG, "Open read file %s", name);
  49. } else {
  50. FURI_LOG_E(TAG, "Failed to open file %s", name);
  51. instance->file_open = FlipperI32HexFileStatusErrorNoOpenFile;
  52. }
  53. instance->str_data = furi_string_alloc();
  54. return instance;
  55. }
  56. void flipper_i32hex_file_close(FlipperI32HexFile* instance) {
  57. furi_assert(instance);
  58. furi_string_free(instance->str_data);
  59. file_stream_close(instance->stream);
  60. stream_free(instance->stream);
  61. furi_record_close(RECORD_STORAGE);
  62. }
  63. FlipperI32HexFileRet flipper_i32hex_file_bin_to_i32hex_set_data(
  64. FlipperI32HexFile* instance,
  65. uint8_t* data,
  66. uint32_t data_size) {
  67. furi_assert(instance);
  68. furi_assert(data);
  69. FlipperI32HexFileRet ret = {.status = FlipperI32HexFileStatusOK, .data_size = 0};
  70. if(instance->file_open != FlipperI32HexFileStatusOpenFileWrite) {
  71. ret.status = FlipperI32HexFileStatusErrorFileWrite;
  72. }
  73. uint8_t count_byte = 0;
  74. uint32_t ind = 0;
  75. uint8_t crc = 0;
  76. furi_string_reset(instance->str_data);
  77. if((instance->addr_last & 0xFF0000) < (instance->addr & 0xFF0000)) {
  78. crc = 0x02 + 0x04 + ((instance->addr >> 24) & 0xFF) + ((instance->addr >> 16) & 0xFF);
  79. crc = 0x01 + ~crc;
  80. //I32HEX_TYPE_EXT_LINEAR_ADDR
  81. furi_string_cat_printf(
  82. instance->str_data, ":02000004%04lX%02X\r\n", (instance->addr >> 16), crc);
  83. instance->addr_last = instance->addr;
  84. }
  85. while(ind < data_size) {
  86. if((ind + COUNT_BYTE_PAYLOAD) > data_size) {
  87. count_byte = data_size - ind;
  88. } else {
  89. count_byte = COUNT_BYTE_PAYLOAD;
  90. }
  91. //I32HEX_TYPE_DATA
  92. furi_string_cat_printf(
  93. instance->str_data, ":%02X%04lX00", count_byte, (instance->addr & 0xFFFF));
  94. crc = count_byte + ((instance->addr >> 8) & 0xFF) + (instance->addr & 0xFF);
  95. for(uint32_t i = 0; i < count_byte; i++) {
  96. furi_string_cat_printf(instance->str_data, "%02X", *data);
  97. crc += *data++;
  98. }
  99. crc = 0x01 + ~crc;
  100. furi_string_cat_printf(instance->str_data, "%02X\r\n", crc);
  101. ind += count_byte;
  102. instance->addr += count_byte;
  103. }
  104. if(instance->file_open) stream_write_string(instance->stream, instance->str_data);
  105. return ret;
  106. }
  107. FlipperI32HexFileRet flipper_i32hex_file_bin_to_i32hex_set_end_line(FlipperI32HexFile* instance) {
  108. furi_assert(instance);
  109. FlipperI32HexFileRet ret = {.status = FlipperI32HexFileStatusOK, .data_size = 0};
  110. if(instance->file_open != FlipperI32HexFileStatusOpenFileWrite) {
  111. ret.status = FlipperI32HexFileStatusErrorFileWrite;
  112. }
  113. furi_string_reset(instance->str_data);
  114. //I32HEX_TYPE_END_OF_FILE
  115. furi_string_cat_printf(instance->str_data, ":00000001FF\r\n");
  116. if(instance->file_open) stream_write_string(instance->stream, instance->str_data);
  117. return ret;
  118. }
  119. void flipper_i32hex_file_bin_to_i32hex_set_addr(FlipperI32HexFile* instance, uint32_t addr) {
  120. furi_assert(instance);
  121. instance->addr = addr;
  122. }
  123. const char* flipper_i32hex_file_get_string(FlipperI32HexFile* instance) {
  124. furi_assert(instance);
  125. return furi_string_get_cstr(instance->str_data);
  126. }
  127. static FlipperI32HexFileRet flipper_i32hex_file_parse_line(
  128. FlipperI32HexFile* instance,
  129. const char* str,
  130. uint8_t* data,
  131. uint32_t data_size) {
  132. furi_assert(instance);
  133. furi_assert(data);
  134. char* str1;
  135. uint32_t data_wrire_ind = 0;
  136. uint32_t data_len = 0;
  137. FlipperI32HexFileRet ret = {.status = FlipperI32HexFileStatusErrorData, .data_size = 0};
  138. //Search for start of data I32HEX
  139. str1 = strstr(str, ":");
  140. do {
  141. if(str1 == NULL) {
  142. ret.status = FlipperI32HexFileStatusErrorData;
  143. break;
  144. }
  145. str1++;
  146. if(!hex_char_to_uint8(*str1, str1[1], data + data_wrire_ind)) {
  147. ret.status = FlipperI32HexFileStatusErrorData;
  148. break;
  149. }
  150. str1++;
  151. if(++data_wrire_ind > data_size) {
  152. ret.status = FlipperI32HexFileStatusErrorOverflow;
  153. break;
  154. }
  155. data_len = 5 + data[0]; // +5 bytes per header and crc
  156. while(data_len > data_wrire_ind) {
  157. str1++;
  158. if(!hex_char_to_uint8(*str1, str1[1], data + data_wrire_ind)) {
  159. ret.status = FlipperI32HexFileStatusErrorData;
  160. break;
  161. }
  162. str1++;
  163. if(++data_wrire_ind > data_size) {
  164. ret.status = FlipperI32HexFileStatusErrorOverflow;
  165. break;
  166. }
  167. }
  168. ret.status = FlipperI32HexFileStatusOK;
  169. ret.data_size = data_wrire_ind;
  170. } while(0);
  171. return ret;
  172. }
  173. static bool flipper_i32hex_file_check_data(uint8_t* data, uint32_t data_size) {
  174. furi_assert(data);
  175. uint8_t crc = 0;
  176. uint32_t data_read_ind = 0;
  177. if(data[0] > data_size) return false;
  178. while(data_read_ind < data_size - 1) {
  179. crc += data[data_read_ind++];
  180. }
  181. return data[data_size - 1] == ((1 + ~crc) & 0xFF);
  182. }
  183. static FlipperI32HexFileRet flipper_i32hex_file_parse(
  184. FlipperI32HexFile* instance,
  185. const char* str,
  186. uint8_t* data,
  187. uint32_t data_size) {
  188. furi_assert(instance);
  189. furi_assert(data);
  190. FlipperI32HexFileRet ret = flipper_i32hex_file_parse_line(instance, str, data, data_size);
  191. if((ret.status == FlipperI32HexFileStatusOK) && (ret.data_size > 4)) {
  192. switch(data[3]) {
  193. case I32HEX_TYPE_DATA:
  194. if(flipper_i32hex_file_check_data(data, ret.data_size)) {
  195. ret.data_size -= 5;
  196. memcpy(data, data + 4, ret.data_size);
  197. ret.status = FlipperI32HexFileStatusData;
  198. } else {
  199. ret.status = FlipperI32HexFileStatusErrorCrc;
  200. ret.data_size = 0;
  201. }
  202. break;
  203. case I32HEX_TYPE_END_OF_FILE:
  204. if(flipper_i32hex_file_check_data(data, ret.data_size)) {
  205. ret.status = FlipperI32HexFileStatusEofFile;
  206. ret.data_size = 0;
  207. } else {
  208. ret.status = FlipperI32HexFileStatusErrorCrc;
  209. ret.data_size = 0;
  210. }
  211. break;
  212. case I32HEX_TYPE_EXT_LINEAR_ADDR:
  213. if(flipper_i32hex_file_check_data(data, ret.data_size)) {
  214. data[0] = data[4];
  215. data[1] = data[5];
  216. data[3] = 0;
  217. data[4] = 0;
  218. ret.status = FlipperI32HexFileStatusUdateAddr;
  219. ret.data_size = 4;
  220. } else {
  221. ret.status = FlipperI32HexFileStatusErrorCrc;
  222. ret.data_size = 0;
  223. }
  224. break;
  225. case I32HEX_TYPE_START_LINEAR_ADDR:
  226. ret.status = FlipperI32HexFileStatusErrorUnsupportedCommand;
  227. ret.data_size = 0;
  228. break;
  229. default:
  230. ret.status = FlipperI32HexFileStatusErrorUnsupportedCommand;
  231. ret.data_size = 0;
  232. break;
  233. }
  234. } else {
  235. ret.status = FlipperI32HexFileStatusErrorData;
  236. ret.data_size = 0;
  237. }
  238. return ret;
  239. }
  240. bool flipper_i32hex_file_check(FlipperI32HexFile* instance) {
  241. furi_assert(instance);
  242. uint32_t data_size = 280;
  243. uint8_t data[280] = {0};
  244. bool ret = true;
  245. if(instance->file_open != FlipperI32HexFileStatusOpenFileRead) {
  246. FURI_LOG_E(TAG, "File is not open");
  247. ret = false;
  248. } else {
  249. stream_rewind(instance->stream);
  250. while(stream_read_line(instance->stream, instance->str_data)) {
  251. FlipperI32HexFileRet parse_ret = flipper_i32hex_file_parse(
  252. instance, furi_string_get_cstr(instance->str_data), data, data_size);
  253. if(parse_ret.status < 0) {
  254. ret = false;
  255. }
  256. }
  257. stream_rewind(instance->stream);
  258. }
  259. return ret;
  260. }
  261. FlipperI32HexFileRet flipper_i32hex_file_i32hex_to_bin_get_data(
  262. FlipperI32HexFile* instance,
  263. uint8_t* data,
  264. uint32_t data_size) {
  265. furi_assert(instance);
  266. furi_assert(data);
  267. FlipperI32HexFileRet ret = {.status = FlipperI32HexFileStatusOK, .data_size = 0};
  268. if(instance->file_open != FlipperI32HexFileStatusOpenFileRead) {
  269. ret.status = FlipperI32HexFileStatusErrorFileRead;
  270. } else {
  271. stream_read_line(instance->stream, instance->str_data);
  272. ret = flipper_i32hex_file_parse(
  273. instance, furi_string_get_cstr(instance->str_data), data, data_size);
  274. }
  275. return ret;
  276. }