mirror of
https://github.com/DarkFlippers/unleashed-firmware
synced 2024-12-24 11:43:09 +00:00
28eb4d1060
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
447 lines
15 KiB
C
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;
|
|
}
|