eth_save_process.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. #include "eth_save_process.h"
  2. #include <furi.h>
  3. #include <furi_hal.h>
  4. #include <storage/storage.h>
  5. #include <locale/locale.h>
  6. #define TAG "EthSave"
  7. #define STORAGE_FILE_BUF_LEN 50
  8. // fuction spizzhena from archive_favorites.c
  9. static bool storage_read_line(File* file, FuriString* str_result) {
  10. furi_string_reset(str_result);
  11. uint8_t buffer[STORAGE_FILE_BUF_LEN];
  12. bool result = false;
  13. do {
  14. uint16_t read_count = storage_file_read(file, buffer, STORAGE_FILE_BUF_LEN);
  15. if(storage_file_get_error(file) != FSE_OK) {
  16. return false;
  17. }
  18. for(uint16_t i = 0; i < read_count; i++) {
  19. if(buffer[i] == '\n') {
  20. uint32_t position = storage_file_tell(file);
  21. if(storage_file_get_error(file) != FSE_OK) {
  22. return false;
  23. }
  24. position = position - read_count + i + 1;
  25. storage_file_seek(file, position, true);
  26. if(storage_file_get_error(file) != FSE_OK) {
  27. return false;
  28. }
  29. result = true;
  30. break;
  31. } else {
  32. furi_string_push_back(str_result, buffer[i]);
  33. }
  34. }
  35. if(result || read_count == 0) {
  36. break;
  37. }
  38. } while(true);
  39. return result;
  40. }
  41. static bool storage_printf(File* file, const char* format, ...) {
  42. va_list args;
  43. va_start(args, format);
  44. FuriString* fstring = furi_string_alloc_vprintf(format, args);
  45. va_end(args);
  46. if(storage_file_write(file, furi_string_get_cstr(fstring), furi_string_size(fstring)) &&
  47. storage_file_write(file, "\n", 1)) {
  48. furi_string_free(fstring);
  49. return true;
  50. }
  51. furi_string_free(fstring);
  52. return false;
  53. }
  54. static bool storage_write_config(File* file, const EthernetSaveConfig* cfg) {
  55. storage_file_seek(file, 0, true);
  56. storage_file_truncate(file);
  57. bool result = true;
  58. result = result ? storage_printf(
  59. file,
  60. "mac: %02X-%02X-%02X-%02X-%02X-%02X",
  61. cfg->mac[0],
  62. cfg->mac[1],
  63. cfg->mac[2],
  64. cfg->mac[3],
  65. cfg->mac[4],
  66. cfg->mac[5]) :
  67. result;
  68. result = result ?
  69. storage_printf(
  70. file, "ip: %d.%d.%d.%d", cfg->ip[0], cfg->ip[1], cfg->ip[2], cfg->ip[3]) :
  71. result;
  72. result =
  73. result ?
  74. storage_printf(
  75. file, "mask: %d.%d.%d.%d", cfg->mask[0], cfg->mask[1], cfg->mask[2], cfg->mask[3]) :
  76. result;
  77. result = result ? storage_printf(
  78. file,
  79. "gateway: %d.%d.%d.%d",
  80. cfg->gateway[0],
  81. cfg->gateway[1],
  82. cfg->gateway[2],
  83. cfg->gateway[3]) :
  84. result;
  85. result =
  86. result ?
  87. storage_printf(
  88. file, "dns: %d.%d.%d.%d", cfg->dns[0], cfg->dns[1], cfg->dns[2], cfg->dns[3]) :
  89. result;
  90. result = result ? storage_printf(
  91. file,
  92. "ping_ip: %d.%d.%d.%d",
  93. cfg->ping_ip[0],
  94. cfg->ping_ip[1],
  95. cfg->ping_ip[2],
  96. cfg->ping_ip[3]) :
  97. result;
  98. return result;
  99. }
  100. static void read_02X(const char* str, uint8_t* byte) {
  101. uint8_t b[2] = {str[0], str[1]};
  102. for(int i = 0; i < 2; ++i) {
  103. if('0' <= b[i] && b[i] <= '9') {
  104. b[i] -= '0';
  105. } else if('A' <= b[i] && b[i] <= 'F') {
  106. b[i] -= 'A' - 0x0A;
  107. } else {
  108. b[i] = 0;
  109. }
  110. }
  111. *byte = b[1] + (b[0] << 4);
  112. }
  113. static void read_ip(const char* str, uint8_t* ip) {
  114. uint8_t ip_i = 0;
  115. uint8_t i = 0;
  116. uint16_t tmp = 0;
  117. for(;;) {
  118. if('0' <= str[i] && str[i] <= '9') {
  119. tmp = tmp * 10 + str[i] - '0';
  120. } else if(str[i] == '.' || str[i] != '\n' || str[i] != '\0') {
  121. if(tmp <= 0xFF && ip_i < 4) {
  122. ip[ip_i] = tmp;
  123. ip_i += 1;
  124. tmp = 0;
  125. } else {
  126. break;
  127. }
  128. if(str[i] != '\n' && ip_i == 4) {
  129. return;
  130. }
  131. } else {
  132. break;
  133. }
  134. i += 1;
  135. }
  136. FURI_LOG_E(TAG, "cannot parse as ip string [%s]", str);
  137. ip[0] = ip[1] = ip[2] = ip[3] = 0;
  138. return;
  139. }
  140. static void set_default_config(EthernetSaveConfig* cfg) {
  141. const uint8_t def_mac[6] = ETHERNET_SAVE_DEFAULT_MAC;
  142. const uint8_t def_ip[4] = ETHERNET_SAVE_DEFAULT_IP;
  143. const uint8_t def_mask[4] = ETHERNET_SAVE_DEFAULT_MASK;
  144. const uint8_t def_gateway[4] = ETHERNET_SAVE_DEFAULT_GATEWAY;
  145. const uint8_t def_dns[4] = ETHERNET_SAVE_DEFAULT_DNS;
  146. const uint8_t def_ping_ip[4] = ETHERNET_SAVE_DEFAULT_PING_IP;
  147. memcpy(cfg->mac, def_mac, 6);
  148. memcpy(cfg->ip, def_ip, 4);
  149. memcpy(cfg->mask, def_mask, 4);
  150. memcpy(cfg->gateway, def_gateway, 4);
  151. memcpy(cfg->dns, def_dns, 4);
  152. memcpy(cfg->ping_ip, def_ping_ip, 4);
  153. }
  154. bool storage_read_config(File* file, EthernetSaveConfig* cfg) {
  155. FuriString* fstring = furi_string_alloc();
  156. while(storage_read_line(file, fstring)) {
  157. const char* str = furi_string_get_cstr(fstring);
  158. if(!strncmp(str, "mac: ", 5)) {
  159. read_02X(str + strlen("mac: "), &cfg->mac[0]);
  160. read_02X(str + strlen("mac: XX-"), &cfg->mac[1]);
  161. read_02X(str + strlen("mac: XX-XX-"), &cfg->mac[2]);
  162. read_02X(str + strlen("mac: XX-XX-XX-"), &cfg->mac[3]);
  163. read_02X(str + strlen("mac: XX-XX-XX-XX-"), &cfg->mac[4]);
  164. read_02X(str + strlen("mac: XX-XX-XX-XX-XX-"), &cfg->mac[5]);
  165. } else if(!strncmp(str, "ip: ", 4)) {
  166. read_ip(str + strlen("ip: "), cfg->ip);
  167. } else if(!strncmp(str, "mask: ", 6)) {
  168. read_ip(str + strlen("mask: "), cfg->mask);
  169. } else if(!strncmp(str, "gateway: ", 9)) {
  170. read_ip(str + strlen("gateway: "), cfg->gateway);
  171. } else if(!strncmp(str, "dns: ", 5)) {
  172. read_ip(str + strlen("dns: "), cfg->dns);
  173. } else if(!strncmp(str, "ping_ip: ", 9)) {
  174. read_ip(str + strlen("ping_ip: "), cfg->ping_ip);
  175. }
  176. }
  177. furi_string_free(fstring);
  178. return true;
  179. }
  180. void ethernet_save_process_write(const EthernetSaveConfig* config) {
  181. Storage* storage = furi_record_open(RECORD_STORAGE);
  182. File* file = storage_file_alloc(storage);
  183. if(!storage_file_open(file, APP_DATA_PATH("config.txt"), FSAM_WRITE, FSOM_CREATE_ALWAYS)) {
  184. FURI_LOG_E(TAG, "Failed to open file");
  185. storage_file_free(file);
  186. furi_record_close(RECORD_STORAGE);
  187. return;
  188. }
  189. if(!storage_write_config(file, config)) {
  190. FURI_LOG_E(TAG, "Failed to write cpnfig to file");
  191. storage_file_close(file);
  192. storage_file_free(file);
  193. furi_record_close(RECORD_STORAGE);
  194. return;
  195. }
  196. storage_file_close(file);
  197. storage_file_free(file);
  198. furi_record_close(RECORD_STORAGE);
  199. }
  200. void ethernet_save_process_read(EthernetSaveConfig* config) {
  201. Storage* storage = furi_record_open(RECORD_STORAGE);
  202. File* file = storage_file_alloc(storage);
  203. if(!storage_file_open(file, APP_DATA_PATH("config.txt"), FSAM_READ, FSOM_OPEN_EXISTING)) {
  204. FURI_LOG_E(TAG, "Failed to open file or file not exists");
  205. storage_file_free(file);
  206. furi_record_close(RECORD_STORAGE);
  207. return;
  208. }
  209. if(!storage_read_config(file, config)) {
  210. FURI_LOG_E(TAG, "Failed to read config from file");
  211. storage_file_close(file);
  212. storage_file_free(file);
  213. furi_record_close(RECORD_STORAGE);
  214. return;
  215. }
  216. storage_file_close(file);
  217. storage_file_free(file);
  218. furi_record_close(RECORD_STORAGE);
  219. }
  220. EthernetSaveConfig* ethernet_save_process_malloc() {
  221. EthernetSaveConfig* config = malloc(sizeof(EthernetSaveConfig));
  222. set_default_config(config);
  223. ethernet_save_process_read(config);
  224. Storage* storage = furi_record_open(RECORD_STORAGE);
  225. FURI_LOG_E(TAG, "ethernet_save_process_malloc");
  226. File* file = storage_file_alloc(storage);
  227. if(!storage_file_open(file, APP_DATA_PATH("log.txt"), FSAM_WRITE, FSOM_OPEN_APPEND)) {
  228. FURI_LOG_E(TAG, "Failed to open file or file not exists");
  229. storage_file_free(file);
  230. furi_record_close(RECORD_STORAGE);
  231. return NULL;
  232. }
  233. config->log_file = file;
  234. return config;
  235. }
  236. void ethernet_save_process_print(EthernetSaveConfig* config, const char* str) {
  237. furi_assert(config);
  238. DateTime datetime = {0};
  239. furi_hal_rtc_get_datetime(&datetime);
  240. storage_printf(
  241. config->log_file,
  242. "%4d.%02d.%02d-%02d:%2d:%02d || %s",
  243. datetime.year,
  244. datetime.month,
  245. datetime.day,
  246. datetime.hour,
  247. datetime.minute,
  248. datetime.second,
  249. str);
  250. }
  251. void ethernet_save_process_free(EthernetSaveConfig* config) {
  252. FURI_LOG_E(TAG, "ethernet_save_process_free");
  253. ethernet_save_process_write(config);
  254. storage_file_close(config->log_file);
  255. storage_file_free(config->log_file);
  256. furi_record_close(RECORD_STORAGE);
  257. free(config);
  258. }