unleashed-firmware/applications/plugins/barcode_generator/barcode_generator.c
MX 28eb4d1060
Massive plugins refactoring
Not full refactoring, only small issues is fixed and moved all plugins to furi mutex instead of valuemutex

Many small issues was found and fixed due mutex upgrade

OFW removed 60 lines of code and it was painful
2023-03-08 00:18:23 +03:00

447 lines
15 KiB
C

#include "barcode_generator.h"
static BarcodeType* barcodeTypes[NUMBER_OF_BARCODE_TYPES];
void init_types() {
BarcodeType* upcA = malloc(sizeof(BarcodeType));
upcA->name = "UPC-A";
upcA->numberOfDigits = 12;
upcA->startPos = 19;
upcA->bartype = BarTypeUPCA;
barcodeTypes[0] = upcA;
BarcodeType* ean8 = malloc(sizeof(BarcodeType));
ean8->name = "EAN-8";
ean8->numberOfDigits = 8;
ean8->startPos = 33;
ean8->bartype = BarTypeEAN8;
barcodeTypes[1] = ean8;
BarcodeType* ean13 = malloc(sizeof(BarcodeType));
ean13->name = "EAN-13";
ean13->numberOfDigits = 13;
ean13->startPos = 19;
ean13->bartype = BarTypeEAN13;
barcodeTypes[2] = ean13;
}
void draw_digit(
Canvas* canvas,
int digit,
BarEncodingType rightHand,
int startingPosition,
bool drawlines) {
char digitStr[2];
snprintf(digitStr, 2, "%u", digit);
canvas_set_color(canvas, ColorBlack);
canvas_draw_str(
canvas, startingPosition, BARCODE_Y_START + BARCODE_HEIGHT + BARCODE_TEXT_OFFSET, digitStr);
if(drawlines) {
switch(rightHand) {
case BarEncodingTypeLeft:
case BarEncodingTypeRight:
canvas_set_color(
canvas, (rightHand == BarEncodingTypeRight) ? ColorBlack : ColorWhite);
//int count = 0;
for(int i = 0; i < 4; i++) {
canvas_draw_box(
canvas, startingPosition, BARCODE_Y_START, DIGITS[digit][i], BARCODE_HEIGHT);
canvas_invert_color(canvas);
startingPosition += DIGITS[digit][i];
}
break;
case BarEncodingTypeG:
canvas_set_color(canvas, ColorWhite);
//int count = 0;
for(int i = 3; i >= 0; i--) {
canvas_draw_box(
canvas, startingPosition, BARCODE_Y_START, DIGITS[digit][i], BARCODE_HEIGHT);
canvas_invert_color(canvas);
startingPosition += DIGITS[digit][i];
}
break;
default:
break;
}
}
}
int get_digit_position(int index, BarcodeType* type) {
int pos = 0;
switch(type->bartype) {
case BarTypeEAN8:
case BarTypeUPCA:
pos = type->startPos + index * 7;
if(index >= type->numberOfDigits / 2) {
pos += 5;
}
break;
case BarTypeEAN13:
if(index == 0)
pos = type->startPos - 10;
else {
pos = type->startPos + (index - 1) * 7;
if((index - 1) >= type->numberOfDigits / 2) {
pos += 5;
}
}
break;
default:
break;
}
return pos;
}
int get_menu_text_location(int index) {
return 20 + 10 * index;
}
int get_barcode_max_index(PluginState* plugin_state) {
return plugin_state->barcode_state.doParityCalculation ?
barcodeTypes[plugin_state->barcode_state.barcodeTypeIndex]->numberOfDigits - 1 :
barcodeTypes[plugin_state->barcode_state.barcodeTypeIndex]->numberOfDigits;
}
int calculate_check_digit(PluginState* plugin_state, BarcodeType* type) {
int checkDigit = 0;
int checkDigitOdd = 0;
int checkDigitEven = 0;
//add all odd positions. Confusing because 0index
for(int i = 0; i < type->numberOfDigits - 1; i += 2) {
checkDigitOdd += plugin_state->barcode_state.barcodeNumeral[i];
}
//add all even positions to above. Confusing because 0index
for(int i = 1; i < type->numberOfDigits - 1; i += 2) {
checkDigitEven += plugin_state->barcode_state.barcodeNumeral[i];
}
if(type->bartype == BarTypeEAN13) {
checkDigit = checkDigitEven * 3 + checkDigitOdd;
} else {
checkDigit = checkDigitOdd * 3 + checkDigitEven;
}
checkDigit = checkDigit % 10; //mod 10
//if m = 0 then x12 = 0, otherwise x12 is 10 - m
return (10 - checkDigit) % 10;
}
static void render_callback(Canvas* const canvas, void* ctx) {
furi_assert(ctx);
PluginState* plugin_state = ctx;
furi_mutex_acquire(plugin_state->mutex, FuriWaitForever);
if(plugin_state->mode == MenuMode) {
canvas_set_color(canvas, ColorBlack);
canvas_draw_str_aligned(canvas, 64, 6, AlignCenter, AlignCenter, "MENU");
canvas_draw_frame(canvas, 50, 0, 29, 11); //box around Menu
canvas_draw_str_aligned(
canvas, 64, get_menu_text_location(0), AlignCenter, AlignCenter, "View");
canvas_draw_str_aligned(
canvas, 64, get_menu_text_location(1), AlignCenter, AlignCenter, "Edit");
canvas_draw_str_aligned(
canvas, 64, get_menu_text_location(2), AlignCenter, AlignCenter, "Parity?");
canvas_draw_frame(canvas, 83, get_menu_text_location(2) - 3, 6, 6);
if(plugin_state->barcode_state.doParityCalculation == true) {
canvas_draw_box(canvas, 85, get_menu_text_location(2) - 1, 2, 2);
}
canvas_draw_str_aligned(
canvas,
64,
get_menu_text_location(3),
AlignCenter,
AlignCenter,
(barcodeTypes[plugin_state->barcode_state.barcodeTypeIndex])->name);
canvas_draw_disc(
canvas,
40,
get_menu_text_location(plugin_state->menuIndex) - 1,
2); //draw menu cursor
} else {
BarcodeType* type = barcodeTypes[plugin_state->barcode_state.barcodeTypeIndex];
//start saftey
canvas_set_color(canvas, ColorBlack);
canvas_draw_box(canvas, type->startPos - 3, BARCODE_Y_START, 1, BARCODE_HEIGHT + 2);
canvas_draw_box(canvas, (type->startPos - 1), BARCODE_Y_START, 1, BARCODE_HEIGHT + 2);
int startpos = 0;
int endpos = type->numberOfDigits;
if(type->bartype == BarTypeEAN13) {
startpos++;
draw_digit(
canvas,
plugin_state->barcode_state.barcodeNumeral[0],
BarEncodingTypeRight,
get_digit_position(0, barcodeTypes[plugin_state->barcode_state.barcodeTypeIndex]),
false);
}
if(plugin_state->barcode_state.doParityCalculation) { //calculate the check digit
plugin_state->barcode_state.barcodeNumeral[type->numberOfDigits - 1] =
calculate_check_digit(plugin_state, type);
}
for(int index = startpos; index < endpos; index++) {
BarEncodingType barEncodingType = BarEncodingTypeLeft;
if(type->bartype == BarTypeEAN13) {
if(index - 1 >= (type->numberOfDigits - 1) / 2) {
barEncodingType = BarEncodingTypeRight;
} else {
barEncodingType =
(FURI_BIT(
EAN13ENCODE[plugin_state->barcode_state.barcodeNumeral[0]],
index - 1)) ?
BarEncodingTypeG :
BarEncodingTypeLeft;
}
} else {
if(index >= type->numberOfDigits / 2) {
barEncodingType = BarEncodingTypeRight;
}
}
int digitPosition = get_digit_position(
index, barcodeTypes[plugin_state->barcode_state.barcodeTypeIndex]);
draw_digit(
canvas,
plugin_state->barcode_state.barcodeNumeral[index],
barEncodingType,
digitPosition,
true);
}
//central separator
canvas_set_color(canvas, ColorBlack);
canvas_draw_box(canvas, 62, BARCODE_Y_START, 1, BARCODE_HEIGHT + 2);
canvas_draw_box(canvas, 64, BARCODE_Y_START, 1, BARCODE_HEIGHT + 2);
if(plugin_state->mode == EditMode) {
canvas_set_color(canvas, ColorBlack);
canvas_draw_box(
canvas,
get_digit_position(
plugin_state->editingIndex,
barcodeTypes[plugin_state->barcode_state.barcodeTypeIndex]) -
1,
63,
7,
1); //draw editing cursor
}
//end safety
int endSafetyPosition = get_digit_position(type->numberOfDigits - 1, type) + 7;
canvas_set_color(canvas, ColorBlack);
canvas_draw_box(canvas, endSafetyPosition, BARCODE_Y_START, 1, BARCODE_HEIGHT + 2);
canvas_draw_box(canvas, (endSafetyPosition + 2), BARCODE_Y_START, 1, BARCODE_HEIGHT + 2);
}
furi_mutex_release(plugin_state->mutex);
}
static void input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) {
furi_assert(event_queue);
PluginEvent event = {.type = EventTypeKey, .input = *input_event};
furi_message_queue_put(event_queue, &event, FuriWaitForever);
}
static void barcode_generator_state_init(PluginState* plugin_state) {
plugin_state->editingIndex = 0;
plugin_state->mode = ViewMode;
plugin_state->menuIndex = MENU_INDEX_VIEW;
if(!LOAD_BARCODE_SETTINGS(&plugin_state->barcode_state)) {
for(int i = 0; i < BARCODE_MAX_LENS; ++i) {
plugin_state->barcode_state.barcodeNumeral[i] = i % 10;
}
plugin_state->barcode_state.doParityCalculation = true;
plugin_state->barcode_state.barcodeTypeIndex = 0;
}
}
static bool handle_key_press_view(InputKey key, PluginState* plugin_state) {
switch(key) {
case InputKeyOk:
case InputKeyBack:
plugin_state->mode = MenuMode;
break;
default:
break;
}
return true;
}
static bool handle_key_press_edit(InputKey key, PluginState* plugin_state) {
int barcodeMaxIndex = get_barcode_max_index(plugin_state);
switch(key) {
case InputKeyUp:
plugin_state->barcode_state.barcodeNumeral[plugin_state->editingIndex] =
(plugin_state->barcode_state.barcodeNumeral[plugin_state->editingIndex] + 1) % 10;
break;
case InputKeyDown:
plugin_state->barcode_state.barcodeNumeral[plugin_state->editingIndex] =
(plugin_state->barcode_state.barcodeNumeral[plugin_state->editingIndex] == 0) ?
9 :
plugin_state->barcode_state.barcodeNumeral[plugin_state->editingIndex] - 1;
break;
case InputKeyRight:
plugin_state->editingIndex = (plugin_state->editingIndex + 1) % barcodeMaxIndex;
break;
case InputKeyLeft:
plugin_state->editingIndex = (plugin_state->editingIndex == 0) ?
barcodeMaxIndex - 1 :
plugin_state->editingIndex - 1;
break;
case InputKeyOk:
case InputKeyBack:
plugin_state->mode = MenuMode;
break;
default:
break;
}
return true;
}
static bool handle_key_press_menu(InputKey key, PluginState* plugin_state) {
switch(key) {
case InputKeyUp:
plugin_state->menuIndex = (plugin_state->menuIndex == MENU_INDEX_VIEW) ?
MENU_INDEX_TYPE :
plugin_state->menuIndex - 1;
break;
case InputKeyDown:
plugin_state->menuIndex = (plugin_state->menuIndex + 1) % 4;
break;
case InputKeyRight:
if(plugin_state->menuIndex == MENU_INDEX_TYPE) {
plugin_state->barcode_state.barcodeTypeIndex =
(plugin_state->barcode_state.barcodeTypeIndex == NUMBER_OF_BARCODE_TYPES - 1) ?
0 :
plugin_state->barcode_state.barcodeTypeIndex + 1;
} else if(plugin_state->menuIndex == MENU_INDEX_PARITY) {
plugin_state->barcode_state.doParityCalculation =
!plugin_state->barcode_state.doParityCalculation;
}
break;
case InputKeyLeft:
if(plugin_state->menuIndex == MENU_INDEX_TYPE) {
plugin_state->barcode_state.barcodeTypeIndex =
(plugin_state->barcode_state.barcodeTypeIndex == 0) ?
NUMBER_OF_BARCODE_TYPES - 1 :
plugin_state->barcode_state.barcodeTypeIndex - 1;
} else if(plugin_state->menuIndex == MENU_INDEX_PARITY) {
plugin_state->barcode_state.doParityCalculation =
!plugin_state->barcode_state.doParityCalculation;
}
break;
case InputKeyOk:
if(plugin_state->menuIndex == MENU_INDEX_VIEW) {
plugin_state->mode = ViewMode;
} else if(plugin_state->menuIndex == MENU_INDEX_EDIT) {
plugin_state->mode = EditMode;
} else if(plugin_state->menuIndex == MENU_INDEX_PARITY) {
plugin_state->barcode_state.doParityCalculation =
!plugin_state->barcode_state.doParityCalculation;
} else if(plugin_state->menuIndex == MENU_INDEX_TYPE) {
plugin_state->barcode_state.barcodeTypeIndex =
(plugin_state->barcode_state.barcodeTypeIndex == NUMBER_OF_BARCODE_TYPES - 1) ?
0 :
plugin_state->barcode_state.barcodeTypeIndex + 1;
}
break;
case InputKeyBack:
return false;
default:
break;
}
int barcodeMaxIndex = get_barcode_max_index(plugin_state);
if(plugin_state->editingIndex >= barcodeMaxIndex)
plugin_state->editingIndex = barcodeMaxIndex - 1;
return true;
}
int32_t barcode_generator_app(void* p) {
UNUSED(p);
init_types();
FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(PluginEvent));
PluginState* plugin_state = malloc(sizeof(PluginState));
barcode_generator_state_init(plugin_state);
plugin_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal);
if(!plugin_state->mutex) {
FURI_LOG_E("barcode_generator", "cannot create mutex\r\n");
furi_message_queue_free(event_queue);
free(plugin_state);
return 255;
}
// Set system callbacks
ViewPort* view_port = view_port_alloc();
view_port_draw_callback_set(view_port, render_callback, plugin_state);
view_port_input_callback_set(view_port, input_callback, event_queue);
// Open GUI and register view_port
Gui* gui = furi_record_open(RECORD_GUI);
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
PluginEvent event;
for(bool processing = true; processing;) {
FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100);
furi_mutex_acquire(plugin_state->mutex, FuriWaitForever);
if(event_status == FuriStatusOk) {
// press events
if(event.type == EventTypeKey &&
((event.input.type == InputTypePress) || (event.input.type == InputTypeRepeat))) {
switch(plugin_state->mode) {
case ViewMode:
processing = handle_key_press_view(event.input.key, plugin_state);
break;
case EditMode:
processing = handle_key_press_edit(event.input.key, plugin_state);
break;
case MenuMode:
processing = handle_key_press_menu(event.input.key, plugin_state);
break;
default:
break;
}
}
}
view_port_update(view_port);
furi_mutex_release(plugin_state->mutex);
}
view_port_enabled_set(view_port, false);
gui_remove_view_port(gui, view_port);
furi_record_close(RECORD_GUI);
view_port_free(view_port);
furi_message_queue_free(event_queue);
furi_mutex_free(plugin_state->mutex);
// save settings
SAVE_BARCODE_SETTINGS(&plugin_state->barcode_state);
free(plugin_state);
return 0;
}