ibutton-app.cpp 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. #include "ibutton-app.h"
  2. #include <stdarg.h>
  3. #include <callback-connector.h>
  4. #include <m-string.h>
  5. #include <toolbox/path.h>
  6. #include <toolbox/flipper-file-cpp.h>
  7. const char* iButtonApp::app_folder = "/any/ibutton";
  8. const char* iButtonApp::app_extension = ".ibtn";
  9. const char* iButtonApp::app_filetype = "Flipper iButton key";
  10. void iButtonApp::run(void* args) {
  11. iButtonEvent event;
  12. bool consumed;
  13. bool exit = false;
  14. make_app_folder();
  15. if(args && load_key((const char*)args)) {
  16. current_scene = Scene::SceneEmulate;
  17. }
  18. scenes[current_scene]->on_enter(this);
  19. while(!exit) {
  20. view.receive_event(&event);
  21. consumed = scenes[current_scene]->on_event(this, &event);
  22. if(!consumed) {
  23. if(event.type == iButtonEvent::Type::EventTypeBack) {
  24. exit = switch_to_previous_scene();
  25. }
  26. }
  27. };
  28. scenes[current_scene]->on_exit(this);
  29. }
  30. iButtonApp::iButtonApp()
  31. : notification{"notification"}
  32. , storage{"storage"}
  33. , dialogs{"dialogs"} {
  34. furi_hal_power_insomnia_enter();
  35. key_worker = new KeyWorker(&ibutton_gpio);
  36. }
  37. iButtonApp::~iButtonApp() {
  38. for(std::map<Scene, iButtonScene*>::iterator it = scenes.begin(); it != scenes.end(); ++it) {
  39. delete it->second;
  40. scenes.erase(it);
  41. }
  42. delete key_worker;
  43. furi_hal_power_insomnia_exit();
  44. }
  45. iButtonAppViewManager* iButtonApp::get_view_manager() {
  46. return &view;
  47. }
  48. void iButtonApp::switch_to_next_scene(Scene next_scene) {
  49. previous_scenes_list.push_front(current_scene);
  50. if(next_scene != Scene::SceneExit) {
  51. scenes[current_scene]->on_exit(this);
  52. current_scene = next_scene;
  53. scenes[current_scene]->on_enter(this);
  54. }
  55. }
  56. void iButtonApp::search_and_switch_to_previous_scene(std::initializer_list<Scene> scenes_list) {
  57. Scene previous_scene = Scene::SceneStart;
  58. bool scene_found = false;
  59. while(!scene_found) {
  60. previous_scene = get_previous_scene();
  61. for(Scene element : scenes_list) {
  62. if(previous_scene == element || previous_scene == Scene::SceneStart) {
  63. scene_found = true;
  64. break;
  65. }
  66. }
  67. }
  68. scenes[current_scene]->on_exit(this);
  69. current_scene = previous_scene;
  70. scenes[current_scene]->on_enter(this);
  71. }
  72. bool iButtonApp::switch_to_previous_scene(uint8_t count) {
  73. Scene previous_scene = Scene::SceneStart;
  74. for(uint8_t i = 0; i < count; i++) {
  75. previous_scene = get_previous_scene();
  76. if(previous_scene == Scene::SceneExit) break;
  77. }
  78. if(previous_scene == Scene::SceneExit) {
  79. return true;
  80. } else {
  81. scenes[current_scene]->on_exit(this);
  82. current_scene = previous_scene;
  83. scenes[current_scene]->on_enter(this);
  84. return false;
  85. }
  86. }
  87. iButtonApp::Scene iButtonApp::get_previous_scene() {
  88. Scene scene = previous_scenes_list.front();
  89. previous_scenes_list.pop_front();
  90. return scene;
  91. }
  92. const GpioPin* iButtonApp::get_ibutton_pin() {
  93. // TODO open record
  94. return &ibutton_gpio;
  95. }
  96. KeyWorker* iButtonApp::get_key_worker() {
  97. return key_worker;
  98. }
  99. iButtonKey* iButtonApp::get_key() {
  100. return &key;
  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. // file managment
  148. bool iButtonApp::save_key(const char* key_name) {
  149. // Create ibutton directory if necessary
  150. make_app_folder();
  151. FlipperFileCpp file(storage);
  152. string_t key_file_name;
  153. bool result = false;
  154. string_init(key_file_name);
  155. do {
  156. // First remove key if it was saved (we rename the key)
  157. if(!delete_key()) break;
  158. // Save the key
  159. key.set_name(key_name);
  160. // Set full file name, for new key
  161. string_printf(key_file_name, "%s/%s%s", app_folder, key.get_name(), app_extension);
  162. // Open file for write
  163. if(!file.new_write(string_get_cstr(key_file_name))) break;
  164. // Write header
  165. if(!file.write_header_cstr(iButtonApp::app_filetype, 1)) break;
  166. // Write key type
  167. if(!file.write_comment_cstr("Key type can be Cyfral, Dallas or Metakom")) break;
  168. const char* key_type = key.get_key_type_string_by_type(key.get_key_type());
  169. if(!file.write_string_cstr("Key type", key_type)) break;
  170. // Write data
  171. if(!file.write_comment_cstr(
  172. "Data size for Cyfral is 2, for Metakom is 4, for Dallas is 8"))
  173. break;
  174. if(!file.write_hex_array("Data", key.get_data(), key.get_type_data_size())) break;
  175. result = true;
  176. } while(false);
  177. file.close();
  178. string_clear(key_file_name);
  179. if(!result) {
  180. dialog_message_show_storage_error(dialogs, "Cannot save\nkey file");
  181. }
  182. return result;
  183. }
  184. bool iButtonApp::load_key_data(string_t key_path) {
  185. FlipperFileCpp file(storage);
  186. bool result = false;
  187. string_t data;
  188. string_init(data);
  189. do {
  190. if(!file.open_read(string_get_cstr(key_path))) break;
  191. // header
  192. uint32_t version;
  193. if(!file.read_header(data, &version)) break;
  194. if(string_cmp_str(data, iButtonApp::app_filetype) != 0) break;
  195. if(version != 1) break;
  196. // key type
  197. iButtonKeyType type;
  198. if(!file.read_string("Key type", data)) break;
  199. if(!key.get_key_type_by_type_string(string_get_cstr(data), &type)) break;
  200. // key data
  201. uint8_t key_data[IBUTTON_KEY_DATA_SIZE] = {0};
  202. if(!file.read_hex_array("Data", key_data, key.get_type_data_size_by_type(type))) break;
  203. key.set_type(type);
  204. key.set_data(key_data, IBUTTON_KEY_DATA_SIZE);
  205. result = true;
  206. } while(false);
  207. file.close();
  208. string_clear(data);
  209. if(!result) {
  210. dialog_message_show_storage_error(dialogs, "Cannot load\nkey file");
  211. }
  212. return result;
  213. }
  214. bool iButtonApp::load_key(const char* key_name) {
  215. bool result = false;
  216. string_t key_path;
  217. string_init_set_str(key_path, key_name);
  218. result = load_key_data(key_path);
  219. if(result) {
  220. path_extract_filename_no_ext(key_name, key_path);
  221. get_key()->set_name(string_get_cstr(key_path));
  222. }
  223. string_clear(key_path);
  224. return result;
  225. }
  226. bool iButtonApp::load_key() {
  227. bool result = false;
  228. // Input events and views are managed by file_select
  229. bool res = dialog_file_select_show(
  230. dialogs,
  231. app_folder,
  232. app_extension,
  233. get_file_name(),
  234. get_file_name_size(),
  235. get_key()->get_name());
  236. if(res) {
  237. string_t key_str;
  238. // Get key file path
  239. string_init_printf(key_str, "%s/%s%s", app_folder, get_file_name(), app_extension);
  240. result = load_key_data(key_str);
  241. if(result) {
  242. get_key()->set_name(get_file_name());
  243. }
  244. string_clear(key_str);
  245. }
  246. return result;
  247. }
  248. bool iButtonApp::delete_key() {
  249. string_t file_name;
  250. bool result = false;
  251. string_init_printf(file_name, "%s/%s%s", app_folder, get_key()->get_name(), app_extension);
  252. result = storage_simply_remove(storage, string_get_cstr(file_name));
  253. string_clear(file_name);
  254. return result;
  255. }
  256. void iButtonApp::make_app_folder() {
  257. if(!storage_simply_mkdir(storage, app_folder)) {
  258. dialog_message_show_storage_error(dialogs, "Cannot create\napp folder");
  259. }
  260. }