barcode_generator.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  1. #include "barcode_generator.h"
  2. static BarcodeType* barcodeTypes[NUMBER_OF_BARCODE_TYPES];
  3. void init_types() {
  4. BarcodeType* upcA = malloc(sizeof(BarcodeType));
  5. upcA->name = "UPC-A";
  6. upcA->numberOfDigits = 12;
  7. upcA->startPos = 19;
  8. upcA->bartype = BarTypeUPCA;
  9. barcodeTypes[0] = upcA;
  10. BarcodeType* ean8 = malloc(sizeof(BarcodeType));
  11. ean8->name = "EAN-8";
  12. ean8->numberOfDigits = 8;
  13. ean8->startPos = 33;
  14. ean8->bartype = BarTypeEAN8;
  15. barcodeTypes[1] = ean8;
  16. BarcodeType* ean13 = malloc(sizeof(BarcodeType));
  17. ean13->name = "EAN-13";
  18. ean13->numberOfDigits = 13;
  19. ean13->startPos = 19;
  20. ean13->bartype = BarTypeEAN13;
  21. barcodeTypes[2] = ean13;
  22. }
  23. void draw_digit(
  24. Canvas* canvas,
  25. int digit,
  26. BarEncodingType rightHand,
  27. int startingPosition,
  28. bool drawlines) {
  29. char digitStr[2];
  30. snprintf(digitStr, 2, "%u", digit);
  31. canvas_set_color(canvas, ColorBlack);
  32. canvas_draw_str(
  33. canvas, startingPosition, BARCODE_Y_START + BARCODE_HEIGHT + BARCODE_TEXT_OFFSET, digitStr);
  34. if(drawlines) {
  35. switch(rightHand) {
  36. case BarEncodingTypeLeft:
  37. case BarEncodingTypeRight:
  38. canvas_set_color(
  39. canvas, (rightHand == BarEncodingTypeRight) ? ColorBlack : ColorWhite);
  40. //int count = 0;
  41. for(int i = 0; i < 4; i++) {
  42. canvas_draw_box(
  43. canvas, startingPosition, BARCODE_Y_START, DIGITS[digit][i], BARCODE_HEIGHT);
  44. canvas_invert_color(canvas);
  45. startingPosition += DIGITS[digit][i];
  46. }
  47. break;
  48. case BarEncodingTypeG:
  49. canvas_set_color(canvas, ColorWhite);
  50. //int count = 0;
  51. for(int i = 3; i >= 0; i--) {
  52. canvas_draw_box(
  53. canvas, startingPosition, BARCODE_Y_START, DIGITS[digit][i], BARCODE_HEIGHT);
  54. canvas_invert_color(canvas);
  55. startingPosition += DIGITS[digit][i];
  56. }
  57. break;
  58. default:
  59. break;
  60. }
  61. }
  62. }
  63. int get_digit_position(int index, BarcodeType* type) {
  64. int pos = 0;
  65. switch(type->bartype) {
  66. case BarTypeEAN8:
  67. case BarTypeUPCA:
  68. pos = type->startPos + index * 7;
  69. if(index >= type->numberOfDigits / 2) {
  70. pos += 5;
  71. }
  72. break;
  73. case BarTypeEAN13:
  74. if(index == 0)
  75. pos = type->startPos - 10;
  76. else {
  77. pos = type->startPos + (index - 1) * 7;
  78. if((index - 1) >= type->numberOfDigits / 2) {
  79. pos += 5;
  80. }
  81. }
  82. break;
  83. default:
  84. break;
  85. }
  86. return pos;
  87. }
  88. int get_menu_text_location(int index) {
  89. return 20 + 10 * index;
  90. }
  91. int get_barcode_max_index(PluginState* plugin_state) {
  92. return plugin_state->barcode_state.doParityCalculation ?
  93. barcodeTypes[plugin_state->barcode_state.barcodeTypeIndex]->numberOfDigits - 1 :
  94. barcodeTypes[plugin_state->barcode_state.barcodeTypeIndex]->numberOfDigits;
  95. }
  96. int calculate_check_digit(PluginState* plugin_state, BarcodeType* type) {
  97. int checkDigit = 0;
  98. int checkDigitOdd = 0;
  99. int checkDigitEven = 0;
  100. //add all odd positions. Confusing because 0index
  101. for(int i = 0; i < type->numberOfDigits - 1; i += 2) {
  102. checkDigitOdd += plugin_state->barcode_state.barcodeNumeral[i];
  103. }
  104. //add all even positions to above. Confusing because 0index
  105. for(int i = 1; i < type->numberOfDigits - 1; i += 2) {
  106. checkDigitEven += plugin_state->barcode_state.barcodeNumeral[i];
  107. }
  108. if(type->bartype == BarTypeEAN13) {
  109. checkDigit = checkDigitEven * 3 + checkDigitOdd;
  110. } else {
  111. checkDigit = checkDigitOdd * 3 + checkDigitEven;
  112. }
  113. checkDigit = checkDigit % 10; //mod 10
  114. //if m = 0 then x12 = 0, otherwise x12 is 10 - m
  115. return (10 - checkDigit) % 10;
  116. }
  117. static void render_callback(Canvas* const canvas, void* ctx) {
  118. furi_assert(ctx);
  119. PluginState* plugin_state = ctx;
  120. furi_mutex_acquire(plugin_state->mutex, FuriWaitForever);
  121. if(plugin_state->mode == MenuMode) {
  122. canvas_set_color(canvas, ColorBlack);
  123. canvas_draw_str_aligned(canvas, 64, 6, AlignCenter, AlignCenter, "MENU");
  124. canvas_draw_frame(canvas, 50, 0, 29, 11); //box around Menu
  125. canvas_draw_str_aligned(
  126. canvas, 64, get_menu_text_location(0), AlignCenter, AlignCenter, "View");
  127. canvas_draw_str_aligned(
  128. canvas, 64, get_menu_text_location(1), AlignCenter, AlignCenter, "Edit");
  129. canvas_draw_str_aligned(
  130. canvas, 64, get_menu_text_location(2), AlignCenter, AlignCenter, "Parity?");
  131. canvas_draw_frame(canvas, 83, get_menu_text_location(2) - 3, 6, 6);
  132. if(plugin_state->barcode_state.doParityCalculation == true) {
  133. canvas_draw_box(canvas, 85, get_menu_text_location(2) - 1, 2, 2);
  134. }
  135. canvas_draw_str_aligned(
  136. canvas,
  137. 64,
  138. get_menu_text_location(3),
  139. AlignCenter,
  140. AlignCenter,
  141. (barcodeTypes[plugin_state->barcode_state.barcodeTypeIndex])->name);
  142. canvas_draw_disc(
  143. canvas,
  144. 40,
  145. get_menu_text_location(plugin_state->menuIndex) - 1,
  146. 2); //draw menu cursor
  147. } else {
  148. BarcodeType* type = barcodeTypes[plugin_state->barcode_state.barcodeTypeIndex];
  149. //start saftey
  150. canvas_set_color(canvas, ColorBlack);
  151. canvas_draw_box(canvas, type->startPos - 3, BARCODE_Y_START, 1, BARCODE_HEIGHT + 2);
  152. canvas_draw_box(canvas, (type->startPos - 1), BARCODE_Y_START, 1, BARCODE_HEIGHT + 2);
  153. int startpos = 0;
  154. int endpos = type->numberOfDigits;
  155. if(type->bartype == BarTypeEAN13) {
  156. startpos++;
  157. draw_digit(
  158. canvas,
  159. plugin_state->barcode_state.barcodeNumeral[0],
  160. BarEncodingTypeRight,
  161. get_digit_position(0, barcodeTypes[plugin_state->barcode_state.barcodeTypeIndex]),
  162. false);
  163. }
  164. if(plugin_state->barcode_state.doParityCalculation) { //calculate the check digit
  165. plugin_state->barcode_state.barcodeNumeral[type->numberOfDigits - 1] =
  166. calculate_check_digit(plugin_state, type);
  167. }
  168. for(int index = startpos; index < endpos; index++) {
  169. BarEncodingType barEncodingType = BarEncodingTypeLeft;
  170. if(type->bartype == BarTypeEAN13) {
  171. if(index - 1 >= (type->numberOfDigits - 1) / 2) {
  172. barEncodingType = BarEncodingTypeRight;
  173. } else {
  174. barEncodingType =
  175. (FURI_BIT(
  176. EAN13ENCODE[plugin_state->barcode_state.barcodeNumeral[0]],
  177. index - 1)) ?
  178. BarEncodingTypeG :
  179. BarEncodingTypeLeft;
  180. }
  181. } else {
  182. if(index >= type->numberOfDigits / 2) {
  183. barEncodingType = BarEncodingTypeRight;
  184. }
  185. }
  186. int digitPosition = get_digit_position(
  187. index, barcodeTypes[plugin_state->barcode_state.barcodeTypeIndex]);
  188. draw_digit(
  189. canvas,
  190. plugin_state->barcode_state.barcodeNumeral[index],
  191. barEncodingType,
  192. digitPosition,
  193. true);
  194. }
  195. //central separator
  196. canvas_set_color(canvas, ColorBlack);
  197. canvas_draw_box(canvas, 62, BARCODE_Y_START, 1, BARCODE_HEIGHT + 2);
  198. canvas_draw_box(canvas, 64, BARCODE_Y_START, 1, BARCODE_HEIGHT + 2);
  199. if(plugin_state->mode == EditMode) {
  200. canvas_set_color(canvas, ColorBlack);
  201. canvas_draw_box(
  202. canvas,
  203. get_digit_position(
  204. plugin_state->editingIndex,
  205. barcodeTypes[plugin_state->barcode_state.barcodeTypeIndex]) -
  206. 1,
  207. 63,
  208. 7,
  209. 1); //draw editing cursor
  210. }
  211. //end safety
  212. int endSafetyPosition = get_digit_position(type->numberOfDigits - 1, type) + 7;
  213. canvas_set_color(canvas, ColorBlack);
  214. canvas_draw_box(canvas, endSafetyPosition, BARCODE_Y_START, 1, BARCODE_HEIGHT + 2);
  215. canvas_draw_box(canvas, (endSafetyPosition + 2), BARCODE_Y_START, 1, BARCODE_HEIGHT + 2);
  216. }
  217. furi_mutex_release(plugin_state->mutex);
  218. }
  219. static void input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) {
  220. furi_assert(event_queue);
  221. PluginEvent event = {.type = EventTypeKey, .input = *input_event};
  222. furi_message_queue_put(event_queue, &event, FuriWaitForever);
  223. }
  224. static void barcode_generator_state_init(PluginState* plugin_state) {
  225. plugin_state->editingIndex = 0;
  226. plugin_state->mode = ViewMode;
  227. plugin_state->menuIndex = MENU_INDEX_VIEW;
  228. if(!LOAD_BARCODE_SETTINGS(&plugin_state->barcode_state)) {
  229. for(int i = 0; i < BARCODE_MAX_LENS; ++i) {
  230. plugin_state->barcode_state.barcodeNumeral[i] = i % 10;
  231. }
  232. plugin_state->barcode_state.doParityCalculation = true;
  233. plugin_state->barcode_state.barcodeTypeIndex = 0;
  234. }
  235. }
  236. static bool handle_key_press_view(InputKey key, PluginState* plugin_state) {
  237. switch(key) {
  238. case InputKeyOk:
  239. case InputKeyBack:
  240. plugin_state->mode = MenuMode;
  241. break;
  242. default:
  243. break;
  244. }
  245. return true;
  246. }
  247. static bool handle_key_press_edit(InputKey key, PluginState* plugin_state) {
  248. int barcodeMaxIndex = get_barcode_max_index(plugin_state);
  249. switch(key) {
  250. case InputKeyUp:
  251. plugin_state->barcode_state.barcodeNumeral[plugin_state->editingIndex] =
  252. (plugin_state->barcode_state.barcodeNumeral[plugin_state->editingIndex] + 1) % 10;
  253. break;
  254. case InputKeyDown:
  255. plugin_state->barcode_state.barcodeNumeral[plugin_state->editingIndex] =
  256. (plugin_state->barcode_state.barcodeNumeral[plugin_state->editingIndex] == 0) ?
  257. 9 :
  258. plugin_state->barcode_state.barcodeNumeral[plugin_state->editingIndex] - 1;
  259. break;
  260. case InputKeyRight:
  261. plugin_state->editingIndex = (plugin_state->editingIndex + 1) % barcodeMaxIndex;
  262. break;
  263. case InputKeyLeft:
  264. plugin_state->editingIndex = (plugin_state->editingIndex == 0) ?
  265. barcodeMaxIndex - 1 :
  266. plugin_state->editingIndex - 1;
  267. break;
  268. case InputKeyOk:
  269. case InputKeyBack:
  270. plugin_state->mode = MenuMode;
  271. break;
  272. default:
  273. break;
  274. }
  275. return true;
  276. }
  277. static bool handle_key_press_menu(InputKey key, PluginState* plugin_state) {
  278. switch(key) {
  279. case InputKeyUp:
  280. plugin_state->menuIndex = (plugin_state->menuIndex == MENU_INDEX_VIEW) ?
  281. MENU_INDEX_TYPE :
  282. plugin_state->menuIndex - 1;
  283. break;
  284. case InputKeyDown:
  285. plugin_state->menuIndex = (plugin_state->menuIndex + 1) % 4;
  286. break;
  287. case InputKeyRight:
  288. if(plugin_state->menuIndex == MENU_INDEX_TYPE) {
  289. plugin_state->barcode_state.barcodeTypeIndex =
  290. (plugin_state->barcode_state.barcodeTypeIndex == NUMBER_OF_BARCODE_TYPES - 1) ?
  291. 0 :
  292. plugin_state->barcode_state.barcodeTypeIndex + 1;
  293. } else if(plugin_state->menuIndex == MENU_INDEX_PARITY) {
  294. plugin_state->barcode_state.doParityCalculation =
  295. !plugin_state->barcode_state.doParityCalculation;
  296. }
  297. break;
  298. case InputKeyLeft:
  299. if(plugin_state->menuIndex == MENU_INDEX_TYPE) {
  300. plugin_state->barcode_state.barcodeTypeIndex =
  301. (plugin_state->barcode_state.barcodeTypeIndex == 0) ?
  302. NUMBER_OF_BARCODE_TYPES - 1 :
  303. plugin_state->barcode_state.barcodeTypeIndex - 1;
  304. } else if(plugin_state->menuIndex == MENU_INDEX_PARITY) {
  305. plugin_state->barcode_state.doParityCalculation =
  306. !plugin_state->barcode_state.doParityCalculation;
  307. }
  308. break;
  309. case InputKeyOk:
  310. if(plugin_state->menuIndex == MENU_INDEX_VIEW) {
  311. plugin_state->mode = ViewMode;
  312. } else if(plugin_state->menuIndex == MENU_INDEX_EDIT) {
  313. plugin_state->mode = EditMode;
  314. } else if(plugin_state->menuIndex == MENU_INDEX_PARITY) {
  315. plugin_state->barcode_state.doParityCalculation =
  316. !plugin_state->barcode_state.doParityCalculation;
  317. } else if(plugin_state->menuIndex == MENU_INDEX_TYPE) {
  318. plugin_state->barcode_state.barcodeTypeIndex =
  319. (plugin_state->barcode_state.barcodeTypeIndex == NUMBER_OF_BARCODE_TYPES - 1) ?
  320. 0 :
  321. plugin_state->barcode_state.barcodeTypeIndex + 1;
  322. }
  323. break;
  324. case InputKeyBack:
  325. return false;
  326. default:
  327. break;
  328. }
  329. int barcodeMaxIndex = get_barcode_max_index(plugin_state);
  330. if(plugin_state->editingIndex >= barcodeMaxIndex)
  331. plugin_state->editingIndex = barcodeMaxIndex - 1;
  332. return true;
  333. }
  334. int32_t barcode_generator_app(void* p) {
  335. UNUSED(p);
  336. init_types();
  337. FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(PluginEvent));
  338. PluginState* plugin_state = malloc(sizeof(PluginState));
  339. barcode_generator_state_init(plugin_state);
  340. plugin_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal);
  341. if(!plugin_state->mutex) {
  342. FURI_LOG_E("barcode_generator", "cannot create mutex\r\n");
  343. furi_message_queue_free(event_queue);
  344. free(plugin_state);
  345. return 255;
  346. }
  347. // Set system callbacks
  348. ViewPort* view_port = view_port_alloc();
  349. view_port_draw_callback_set(view_port, render_callback, plugin_state);
  350. view_port_input_callback_set(view_port, input_callback, event_queue);
  351. // Open GUI and register view_port
  352. Gui* gui = furi_record_open(RECORD_GUI);
  353. gui_add_view_port(gui, view_port, GuiLayerFullscreen);
  354. PluginEvent event;
  355. for(bool processing = true; processing;) {
  356. FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100);
  357. furi_mutex_acquire(plugin_state->mutex, FuriWaitForever);
  358. if(event_status == FuriStatusOk) {
  359. // press events
  360. if(event.type == EventTypeKey &&
  361. ((event.input.type == InputTypePress) || (event.input.type == InputTypeRepeat))) {
  362. switch(plugin_state->mode) {
  363. case ViewMode:
  364. processing = handle_key_press_view(event.input.key, plugin_state);
  365. break;
  366. case EditMode:
  367. processing = handle_key_press_edit(event.input.key, plugin_state);
  368. break;
  369. case MenuMode:
  370. processing = handle_key_press_menu(event.input.key, plugin_state);
  371. break;
  372. default:
  373. break;
  374. }
  375. }
  376. }
  377. view_port_update(view_port);
  378. furi_mutex_release(plugin_state->mutex);
  379. }
  380. view_port_enabled_set(view_port, false);
  381. gui_remove_view_port(gui, view_port);
  382. furi_record_close(RECORD_GUI);
  383. view_port_free(view_port);
  384. furi_message_queue_free(event_queue);
  385. furi_mutex_free(plugin_state->mutex);
  386. // save settings
  387. SAVE_BARCODE_SETTINGS(&plugin_state->barcode_state);
  388. free(plugin_state);
  389. return 0;
  390. }