ibutton-app.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. #include "ibutton-app.h"
  2. #include <stdarg.h>
  3. #include <callback-connector.h>
  4. #include <m-string.h>
  5. const char* iButtonApp::app_folder = "ibutton";
  6. const char* iButtonApp::app_extension = ".ibtn";
  7. void iButtonApp::run(void) {
  8. iButtonEvent event;
  9. bool consumed;
  10. bool exit = false;
  11. scenes[current_scene]->on_enter(this);
  12. while(!exit) {
  13. view.receive_event(&event);
  14. consumed = scenes[current_scene]->on_event(this, &event);
  15. if(!consumed) {
  16. if(event.type == iButtonEvent::Type::EventTypeBack) {
  17. exit = switch_to_previous_scene();
  18. }
  19. }
  20. };
  21. scenes[current_scene]->on_exit(this);
  22. }
  23. iButtonApp::iButtonApp()
  24. : fs_api{"sdcard"}
  25. , sd_ex_api{"sdcard-ex"}
  26. , notification{"notification"} {
  27. api_hal_power_insomnia_enter();
  28. key_worker = new KeyWorker(&ibutton_gpio);
  29. // we need random
  30. srand(DWT->CYCCNT);
  31. }
  32. iButtonApp::~iButtonApp() {
  33. for(std::map<Scene, iButtonScene*>::iterator it = scenes.begin(); it != scenes.end(); ++it) {
  34. delete it->second;
  35. scenes.erase(it);
  36. }
  37. api_hal_power_insomnia_exit();
  38. }
  39. iButtonAppViewManager* iButtonApp::get_view_manager() {
  40. return &view;
  41. }
  42. void iButtonApp::switch_to_next_scene(Scene next_scene) {
  43. previous_scenes_list.push_front(current_scene);
  44. if(next_scene != Scene::SceneExit) {
  45. scenes[current_scene]->on_exit(this);
  46. current_scene = next_scene;
  47. scenes[current_scene]->on_enter(this);
  48. }
  49. }
  50. void iButtonApp::search_and_switch_to_previous_scene(std::initializer_list<Scene> scenes_list) {
  51. Scene previous_scene = Scene::SceneStart;
  52. bool scene_found = false;
  53. while(!scene_found) {
  54. previous_scene = get_previous_scene();
  55. for(Scene element : scenes_list) {
  56. if(previous_scene == element || previous_scene == Scene::SceneStart) {
  57. scene_found = true;
  58. break;
  59. }
  60. }
  61. }
  62. scenes[current_scene]->on_exit(this);
  63. current_scene = previous_scene;
  64. scenes[current_scene]->on_enter(this);
  65. }
  66. bool iButtonApp::switch_to_previous_scene(uint8_t count) {
  67. Scene previous_scene = Scene::SceneStart;
  68. for(uint8_t i = 0; i < count; i++) {
  69. previous_scene = get_previous_scene();
  70. if(previous_scene == Scene::SceneExit) break;
  71. }
  72. if(previous_scene == Scene::SceneExit) {
  73. return true;
  74. } else {
  75. scenes[current_scene]->on_exit(this);
  76. current_scene = previous_scene;
  77. scenes[current_scene]->on_enter(this);
  78. return false;
  79. }
  80. }
  81. iButtonApp::Scene iButtonApp::get_previous_scene() {
  82. Scene scene = previous_scenes_list.front();
  83. previous_scenes_list.pop_front();
  84. return scene;
  85. }
  86. const GpioPin* iButtonApp::get_ibutton_pin() {
  87. // TODO open record
  88. return &ibutton_gpio;
  89. }
  90. KeyWorker* iButtonApp::get_key_worker() {
  91. return key_worker;
  92. }
  93. iButtonKey* iButtonApp::get_key() {
  94. return &key;
  95. }
  96. SdCard_Api* iButtonApp::get_sd_ex_api() {
  97. return sd_ex_api;
  98. }
  99. FS_Api* iButtonApp::get_fs_api() {
  100. return fs_api;
  101. }
  102. char* iButtonApp::get_file_name() {
  103. return file_name;
  104. }
  105. uint8_t iButtonApp::get_file_name_size() {
  106. return file_name_size;
  107. }
  108. void iButtonApp::notify_green_blink() {
  109. notification_message(notification, &sequence_blink_green_10);
  110. }
  111. void iButtonApp::notify_yellow_blink() {
  112. notification_message(notification, &sequence_blink_yellow_10);
  113. }
  114. void iButtonApp::notify_red_blink() {
  115. notification_message(notification, &sequence_blink_red_10);
  116. }
  117. void iButtonApp::notify_error() {
  118. notification_message(notification, &sequence_error);
  119. }
  120. void iButtonApp::notify_success() {
  121. notification_message(notification, &sequence_success);
  122. }
  123. void iButtonApp::notify_green_on() {
  124. notification_message_block(notification, &sequence_set_green_255);
  125. }
  126. void iButtonApp::notify_green_off() {
  127. notification_message(notification, &sequence_reset_green);
  128. }
  129. void iButtonApp::notify_red_on() {
  130. notification_message_block(notification, &sequence_set_red_255);
  131. }
  132. void iButtonApp::notify_red_off() {
  133. notification_message(notification, &sequence_reset_red);
  134. }
  135. void iButtonApp::set_text_store(const char* text...) {
  136. va_list args;
  137. va_start(args, text);
  138. vsnprintf(text_store, text_store_size, text, args);
  139. va_end(args);
  140. }
  141. char* iButtonApp::get_text_store() {
  142. return text_store;
  143. }
  144. uint8_t iButtonApp::get_text_store_size() {
  145. return text_store_size;
  146. }
  147. void iButtonApp::generate_random_name(char* name, uint8_t max_name_size) {
  148. const uint8_t prefix_size = 9;
  149. const char* prefix[prefix_size] = {
  150. "ancient",
  151. "hollow",
  152. "strange",
  153. "disappeared",
  154. "unknown",
  155. "unthinkable",
  156. "unnamable",
  157. "nameless",
  158. "my",
  159. };
  160. const uint8_t suffix_size = 8;
  161. const char* suffix[suffix_size] = {
  162. "door",
  163. "entrance",
  164. "doorway",
  165. "entry",
  166. "portal",
  167. "entree",
  168. "opening",
  169. "crack",
  170. };
  171. sniprintf(
  172. name, max_name_size, "%s_%s", prefix[rand() % prefix_size], suffix[rand() % suffix_size]);
  173. // to upper
  174. name[0] = name[0] - 0x20;
  175. }
  176. // file managment
  177. void iButtonApp::show_file_error_message(const char* error_text) {
  178. set_text_store(error_text);
  179. get_sd_ex_api()->show_error(get_sd_ex_api()->context, get_text_store());
  180. }
  181. bool iButtonApp::save_key(const char* key_name) {
  182. File key_file;
  183. string_t key_file_name;
  184. bool result = false;
  185. FS_Error fs_result;
  186. uint16_t write_count;
  187. // Create ibutton directory if necessary
  188. fs_result = get_fs_api()->common.mkdir(app_folder);
  189. if(fs_result != FSE_OK && fs_result != FSE_EXIST) {
  190. show_file_error_message("Cannot create\napplication folder");
  191. return false;
  192. };
  193. // First remove key if it was saved
  194. string_init_set_str(key_file_name, app_folder);
  195. string_cat_str(key_file_name, "/");
  196. string_cat_str(key_file_name, get_key()->get_name());
  197. string_cat_str(key_file_name, app_extension);
  198. fs_result = get_fs_api()->common.remove(string_get_cstr(key_file_name));
  199. if(fs_result != FSE_OK && fs_result != FSE_NOT_EXIST) {
  200. string_clear(key_file_name);
  201. show_file_error_message("Cannot remove\nold key file");
  202. return false;
  203. };
  204. // Save the key
  205. get_key()->set_name(key_name);
  206. string_set_str(key_file_name, app_folder);
  207. string_cat_str(key_file_name, "/");
  208. string_cat_str(key_file_name, get_key()->get_name());
  209. string_cat_str(key_file_name, app_extension);
  210. bool res = get_fs_api()->file.open(
  211. &key_file, string_get_cstr(key_file_name), FSAM_WRITE, FSOM_CREATE_ALWAYS);
  212. string_clear(key_file_name);
  213. if(res) {
  214. // type header
  215. const char* key_type = "E";
  216. switch(get_key()->get_key_type()) {
  217. case iButtonKeyType::KeyCyfral:
  218. key_type = "C";
  219. break;
  220. case iButtonKeyType::KeyDallas:
  221. key_type = "D";
  222. break;
  223. case iButtonKeyType::KeyMetakom:
  224. key_type = "M";
  225. break;
  226. }
  227. write_count = get_fs_api()->file.write(&key_file, key_type, 1);
  228. if(key_file.error_id != FSE_OK || write_count != 1) {
  229. show_file_error_message("Cannot write\nto key file");
  230. get_fs_api()->file.close(&key_file);
  231. return false;
  232. }
  233. const uint8_t byte_text_size = 4;
  234. char byte_text[byte_text_size];
  235. for(uint8_t i = 0; i < get_key()->get_type_data_size(); i++) {
  236. sniprintf(byte_text, byte_text_size, " %02X", get_key()->get_data()[i]);
  237. write_count = get_fs_api()->file.write(&key_file, byte_text, 3);
  238. if(key_file.error_id != FSE_OK || write_count != 3) {
  239. show_file_error_message("Cannot write\nto key file");
  240. get_fs_api()->file.close(&key_file);
  241. return false;
  242. }
  243. }
  244. result = true;
  245. } else {
  246. show_file_error_message("Cannot create\nnew key file");
  247. }
  248. get_fs_api()->file.close(&key_file);
  249. get_sd_ex_api()->check_error(get_sd_ex_api()->context);
  250. return result;
  251. }
  252. bool iButtonApp::load_key() {
  253. bool result = false;
  254. // Input events and views are managed by file_select
  255. bool res = get_sd_ex_api()->file_select(
  256. get_sd_ex_api()->context,
  257. app_folder,
  258. app_extension,
  259. get_file_name(),
  260. get_file_name_size(),
  261. get_key()->get_name());
  262. if(res) {
  263. string_t key_str;
  264. File key_file;
  265. uint16_t read_count;
  266. // Get key file path
  267. string_init_set_str(key_str, app_folder);
  268. string_cat_str(key_str, "/");
  269. string_cat_str(key_str, get_file_name());
  270. string_cat_str(key_str, app_extension);
  271. // Open key file
  272. get_fs_api()->file.open(
  273. &key_file, string_get_cstr(key_str), FSAM_READ, FSOM_OPEN_EXISTING);
  274. string_clear(key_str);
  275. if(key_file.error_id != FSE_OK) {
  276. show_file_error_message("Cannot open\nkey file");
  277. get_fs_api()->file.close(&key_file);
  278. return false;
  279. }
  280. const uint8_t byte_text_size = 4;
  281. char byte_text[byte_text_size] = {0, 0, 0, 0};
  282. // load type header
  283. read_count = get_fs_api()->file.read(&key_file, byte_text, 1);
  284. if(key_file.error_id != FSE_OK || read_count != 1) {
  285. show_file_error_message("Cannot read\nkey file");
  286. get_fs_api()->file.close(&key_file);
  287. return false;
  288. }
  289. iButtonKeyType key_type = iButtonKeyType::KeyCyfral;
  290. if(strcmp(byte_text, "C") == 0) {
  291. key_type = iButtonKeyType::KeyCyfral;
  292. } else if(strcmp(byte_text, "M") == 0) {
  293. key_type = iButtonKeyType::KeyMetakom;
  294. } else if(strcmp(byte_text, "D") == 0) {
  295. key_type = iButtonKeyType::KeyDallas;
  296. } else {
  297. show_file_error_message("Cannot parse\nkey file");
  298. get_fs_api()->file.close(&key_file);
  299. return false;
  300. }
  301. get_key()->set_type(key_type);
  302. // load data
  303. uint8_t key_data[IBUTTON_KEY_DATA_SIZE] = {0, 0, 0, 0, 0, 0, 0, 0};
  304. for(uint8_t i = 0; i < get_key()->get_type_data_size(); i++) {
  305. // space
  306. read_count = get_fs_api()->file.read(&key_file, byte_text, 1);
  307. if(key_file.error_id != FSE_OK || read_count != 1) {
  308. show_file_error_message("Cannot read\nkey file");
  309. get_fs_api()->file.close(&key_file);
  310. return false;
  311. }
  312. // value
  313. read_count = get_fs_api()->file.read(&key_file, byte_text, 2);
  314. if(key_file.error_id != FSE_OK || read_count != 2) {
  315. show_file_error_message("Cannot read\nkey file");
  316. get_fs_api()->file.close(&key_file);
  317. return false;
  318. }
  319. // convert hex value to byte
  320. key_data[i] = strtol(byte_text, NULL, 16);
  321. }
  322. get_fs_api()->file.close(&key_file);
  323. get_key()->set_name(get_file_name());
  324. get_key()->set_type(key_type);
  325. get_key()->set_data(key_data, IBUTTON_KEY_DATA_SIZE);
  326. result = true;
  327. }
  328. get_sd_ex_api()->check_error(get_sd_ex_api()->context);
  329. return result;
  330. }
  331. bool iButtonApp::delete_key() {
  332. iButtonKey* key = get_key();
  333. string_t key_file_name;
  334. bool result = false;
  335. string_init_set_str(key_file_name, app_folder);
  336. string_cat_str(key_file_name, "/");
  337. string_cat_str(key_file_name, key->get_name());
  338. string_cat_str(key_file_name, app_extension);
  339. result = (get_fs_api()->common.remove(string_get_cstr(key_file_name)) == FSE_OK);
  340. string_clear(key_file_name);
  341. return result;
  342. }