mirror of
https://github.com/DarkFlippers/unleashed-firmware
synced 2024-12-26 20:53:07 +00:00
511 lines
16 KiB
C
511 lines
16 KiB
C
|
#include "../barcode_app.h"
|
||
|
#include "barcode_view.h"
|
||
|
#include "../encodings.h"
|
||
|
|
||
|
/**
|
||
|
* @brief Draws a single bit from a barcode at a specified location
|
||
|
* @param canvas
|
||
|
* @param bit a 1 or a 0 to signify a bit of data
|
||
|
* @param x the top left x coordinate
|
||
|
* @param y the top left y coordinate
|
||
|
* @param width the width of the bit
|
||
|
* @param height the height of the bit
|
||
|
*/
|
||
|
static void draw_bit(Canvas* canvas, int bit, int x, int y, int width, int height) {
|
||
|
if(bit == 1) {
|
||
|
canvas_set_color(canvas, ColorBlack);
|
||
|
} else {
|
||
|
canvas_set_color(canvas, ColorWhite);
|
||
|
}
|
||
|
canvas_draw_box(canvas, x, y, width, height);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
*/
|
||
|
static void draw_error_str(Canvas* canvas, const char* error) {
|
||
|
canvas_clear(canvas);
|
||
|
canvas_draw_str_aligned(canvas, 62, 30, AlignCenter, AlignCenter, error);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param bits a string of 1's and 0's
|
||
|
* @returns the x coordinate after the bits have been drawn, useful for drawing the next section of bits
|
||
|
*/
|
||
|
static int draw_bits(Canvas* canvas, const char* bits, int x, int y, int width, int height) {
|
||
|
int bits_length = strlen(bits);
|
||
|
for(int i = 0; i < bits_length; i++) {
|
||
|
char c = bits[i];
|
||
|
int num = c - '0';
|
||
|
|
||
|
draw_bit(canvas, num, x, y, width, height);
|
||
|
|
||
|
x += width;
|
||
|
}
|
||
|
return x;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Draws an EAN-8 type barcode, does not check if the barcode is valid
|
||
|
* @param canvas the canvas
|
||
|
* @param barcode_digits the digits in the barcode, must be 8 characters long
|
||
|
*/
|
||
|
static void draw_ean_8(Canvas* canvas, BarcodeData* barcode_data) {
|
||
|
FuriString* barcode_digits = barcode_data->correct_data;
|
||
|
BarcodeTypeObj* type_obj = barcode_data->type_obj;
|
||
|
|
||
|
int barcode_length = furi_string_size(barcode_digits);
|
||
|
|
||
|
int x = type_obj->start_pos;
|
||
|
int y = BARCODE_Y_START;
|
||
|
int width = 1;
|
||
|
int height = BARCODE_HEIGHT;
|
||
|
|
||
|
//the guard patterns for the beginning, center, ending
|
||
|
const char* end_bits = "101";
|
||
|
const char* center_bits = "01010";
|
||
|
|
||
|
//draw the starting guard pattern
|
||
|
x = draw_bits(canvas, end_bits, x, y, width, height + 5);
|
||
|
|
||
|
FuriString* code_part = furi_string_alloc();
|
||
|
|
||
|
//loop through each digit, find the encoding, and draw it
|
||
|
for(int i = 0; i < barcode_length; i++) {
|
||
|
char current_digit = furi_string_get_char(barcode_digits, i);
|
||
|
|
||
|
//the actual number and the index of the bits
|
||
|
int index = current_digit - '0';
|
||
|
//use the L-codes for the first 4 digits and the R-Codes for the last 4 digits
|
||
|
if(i <= 3) {
|
||
|
furi_string_set_str(code_part, UPC_EAN_L_CODES[index]);
|
||
|
} else {
|
||
|
furi_string_set_str(code_part, UPC_EAN_R_CODES[index]);
|
||
|
}
|
||
|
|
||
|
//convert the current_digit char into a string so it can be printed
|
||
|
char current_digit_string[2];
|
||
|
snprintf(current_digit_string, 2, "%c", current_digit);
|
||
|
|
||
|
//set the canvas color to black to print the digit
|
||
|
canvas_set_color(canvas, ColorBlack);
|
||
|
canvas_draw_str(canvas, x + 1, y + height + 8, current_digit_string);
|
||
|
|
||
|
//draw the bits of the barcode
|
||
|
x = draw_bits(canvas, furi_string_get_cstr(code_part), x, y, width, height);
|
||
|
|
||
|
//if the index has reached 3, that means 4 digits have been drawn and now draw the center guard pattern
|
||
|
if(i == 3) {
|
||
|
x = draw_bits(canvas, center_bits, x, y, width, height + 5);
|
||
|
}
|
||
|
}
|
||
|
furi_string_free(code_part);
|
||
|
|
||
|
//draw the ending guard pattern
|
||
|
x = draw_bits(canvas, end_bits, x, y, width, height + 5);
|
||
|
}
|
||
|
|
||
|
static void draw_ean_13(Canvas* canvas, BarcodeData* barcode_data) {
|
||
|
FuriString* barcode_digits = barcode_data->correct_data;
|
||
|
BarcodeTypeObj* type_obj = barcode_data->type_obj;
|
||
|
|
||
|
int barcode_length = furi_string_size(barcode_digits);
|
||
|
|
||
|
int x = type_obj->start_pos;
|
||
|
int y = BARCODE_Y_START;
|
||
|
int width = 1;
|
||
|
int height = BARCODE_HEIGHT;
|
||
|
|
||
|
//the guard patterns for the beginning, center, ending
|
||
|
const char* end_bits = "101";
|
||
|
const char* center_bits = "01010";
|
||
|
|
||
|
//draw the starting guard pattern
|
||
|
x = draw_bits(canvas, end_bits, x, y, width, height + 5);
|
||
|
|
||
|
FuriString* left_structure = furi_string_alloc();
|
||
|
FuriString* code_part = furi_string_alloc();
|
||
|
|
||
|
//loop through each digit, find the encoding, and draw it
|
||
|
for(int i = 0; i < barcode_length; i++) {
|
||
|
char current_digit = furi_string_get_char(barcode_digits, i);
|
||
|
int index = current_digit - '0';
|
||
|
|
||
|
if(i == 0) {
|
||
|
furi_string_set_str(left_structure, EAN_13_STRUCTURE_CODES[index]);
|
||
|
|
||
|
//convert the current_digit char into a string so it can be printed
|
||
|
char current_digit_string[2];
|
||
|
snprintf(current_digit_string, 2, "%c", current_digit);
|
||
|
|
||
|
//set the canvas color to black to print the digit
|
||
|
canvas_set_color(canvas, ColorBlack);
|
||
|
canvas_draw_str(canvas, x - 10, y + height + 8, current_digit_string);
|
||
|
|
||
|
continue;
|
||
|
} else {
|
||
|
//use the L-codes for the first 6 digits and the R-Codes for the last 6 digits
|
||
|
if(i <= 6) {
|
||
|
//get the encoding type at the current barcode bit position
|
||
|
char encoding_type = furi_string_get_char(left_structure, i - 1);
|
||
|
if(encoding_type == 'L') {
|
||
|
furi_string_set_str(code_part, UPC_EAN_L_CODES[index]);
|
||
|
} else {
|
||
|
furi_string_set_str(code_part, EAN_G_CODES[index]);
|
||
|
}
|
||
|
} else {
|
||
|
furi_string_set_str(code_part, UPC_EAN_R_CODES[index]);
|
||
|
}
|
||
|
|
||
|
//convert the current_digit char into a string so it can be printed
|
||
|
char current_digit_string[2];
|
||
|
snprintf(current_digit_string, 2, "%c", current_digit);
|
||
|
|
||
|
//set the canvas color to black to print the digit
|
||
|
canvas_set_color(canvas, ColorBlack);
|
||
|
canvas_draw_str(canvas, x + 1, y + height + 8, current_digit_string);
|
||
|
|
||
|
//draw the bits of the barcode
|
||
|
x = draw_bits(canvas, furi_string_get_cstr(code_part), x, y, width, height);
|
||
|
|
||
|
//if the index has reached 6, that means 6 digits have been drawn and we now draw the center guard pattern
|
||
|
if(i == 6) {
|
||
|
x = draw_bits(canvas, center_bits, x, y, width, height + 5);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
furi_string_free(left_structure);
|
||
|
furi_string_free(code_part);
|
||
|
|
||
|
//draw the ending guard pattern
|
||
|
x = draw_bits(canvas, end_bits, x, y, width, height + 5);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Draw a UPC-A barcode
|
||
|
*/
|
||
|
static void draw_upc_a(Canvas* canvas, BarcodeData* barcode_data) {
|
||
|
FuriString* barcode_digits = barcode_data->correct_data;
|
||
|
BarcodeTypeObj* type_obj = barcode_data->type_obj;
|
||
|
|
||
|
int barcode_length = furi_string_size(barcode_digits);
|
||
|
|
||
|
int x = type_obj->start_pos;
|
||
|
int y = BARCODE_Y_START;
|
||
|
int width = 1;
|
||
|
int height = BARCODE_HEIGHT;
|
||
|
|
||
|
//the guard patterns for the beginning, center, ending
|
||
|
char* end_bits = "101";
|
||
|
char* center_bits = "01010";
|
||
|
|
||
|
//draw the starting guard pattern
|
||
|
x = draw_bits(canvas, end_bits, x, y, width, height + 5);
|
||
|
|
||
|
FuriString* code_part = furi_string_alloc();
|
||
|
|
||
|
//loop through each digit, find the encoding, and draw it
|
||
|
for(int i = 0; i < barcode_length; i++) {
|
||
|
char current_digit = furi_string_get_char(barcode_digits, i);
|
||
|
int index = current_digit - '0'; //convert the number into an int (also the index)
|
||
|
|
||
|
//use the L-codes for the first 6 digits and the R-Codes for the last 6 digits
|
||
|
if(i <= 5) {
|
||
|
furi_string_set_str(code_part, UPC_EAN_L_CODES[index]);
|
||
|
} else {
|
||
|
furi_string_set_str(code_part, UPC_EAN_R_CODES[index]);
|
||
|
}
|
||
|
|
||
|
//convert the current_digit char into a string so it can be printed
|
||
|
char current_digit_string[2];
|
||
|
snprintf(current_digit_string, 2, "%c", current_digit);
|
||
|
|
||
|
//set the canvas color to black to print the digit
|
||
|
canvas_set_color(canvas, ColorBlack);
|
||
|
canvas_draw_str(canvas, x + 1, y + height + 8, current_digit_string);
|
||
|
|
||
|
//draw the bits of the barcode
|
||
|
x = draw_bits(canvas, furi_string_get_cstr(code_part), x, y, width, height);
|
||
|
|
||
|
//if the index has reached 6, that means 6 digits have been drawn and we now draw the center guard pattern
|
||
|
if(i == 5) {
|
||
|
x = draw_bits(canvas, center_bits, x, y, width, height + 5);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
furi_string_free(code_part);
|
||
|
|
||
|
//draw the ending guard pattern
|
||
|
x = draw_bits(canvas, end_bits, x, y, width, height + 5);
|
||
|
}
|
||
|
|
||
|
static void draw_code_39(Canvas* canvas, BarcodeData* barcode_data) {
|
||
|
FuriString* raw_data = barcode_data->raw_data;
|
||
|
FuriString* barcode_digits = barcode_data->correct_data;
|
||
|
//BarcodeTypeObj* type_obj = barcode_data->type_obj;
|
||
|
|
||
|
int barcode_length = furi_string_size(barcode_digits);
|
||
|
int total_pixels = 0;
|
||
|
|
||
|
for(int i = 0; i < barcode_length; i++) {
|
||
|
//1 for wide, 0 for narrow
|
||
|
char wide_or_narrow = furi_string_get_char(barcode_digits, i);
|
||
|
int wn_digit = wide_or_narrow - '0'; //wide(1) or narrow(0) digit
|
||
|
|
||
|
if(wn_digit == 1) {
|
||
|
total_pixels += 3;
|
||
|
} else {
|
||
|
total_pixels += 1;
|
||
|
}
|
||
|
if((i + 1) % 9 == 0) {
|
||
|
total_pixels += 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int x = (128 - total_pixels) / 2;
|
||
|
int y = BARCODE_Y_START;
|
||
|
int width = 1;
|
||
|
int height = BARCODE_HEIGHT;
|
||
|
bool filled_in = true;
|
||
|
|
||
|
//set the canvas color to black to print the digit
|
||
|
canvas_set_color(canvas, ColorBlack);
|
||
|
// canvas_draw_str_aligned(canvas, 62, 30, AlignCenter, AlignCenter, error);
|
||
|
canvas_draw_str_aligned(
|
||
|
canvas, 62, y + height + 8, AlignCenter, AlignBottom, furi_string_get_cstr(raw_data));
|
||
|
|
||
|
for(int i = 0; i < barcode_length; i++) {
|
||
|
//1 for wide, 0 for narrow
|
||
|
char wide_or_narrow = furi_string_get_char(barcode_digits, i);
|
||
|
int wn_digit = wide_or_narrow - '0'; //wide(1) or narrow(0) digit
|
||
|
|
||
|
if(filled_in) {
|
||
|
if(wn_digit == 1) {
|
||
|
x = draw_bits(canvas, "111", x, y, width, height);
|
||
|
} else {
|
||
|
x = draw_bits(canvas, "1", x, y, width, height);
|
||
|
}
|
||
|
filled_in = false;
|
||
|
} else {
|
||
|
if(wn_digit == 1) {
|
||
|
x = draw_bits(canvas, "000", x, y, width, height);
|
||
|
} else {
|
||
|
x = draw_bits(canvas, "0", x, y, width, height);
|
||
|
}
|
||
|
filled_in = true;
|
||
|
}
|
||
|
if((i + 1) % 9 == 0) {
|
||
|
x = draw_bits(canvas, "0", x, y, width, height);
|
||
|
filled_in = true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void draw_code_128(Canvas* canvas, BarcodeData* barcode_data) {
|
||
|
FuriString* raw_data = barcode_data->raw_data;
|
||
|
FuriString* barcode_digits = barcode_data->correct_data;
|
||
|
|
||
|
int barcode_length = furi_string_size(barcode_digits);
|
||
|
|
||
|
int x = (128 - barcode_length) / 2;
|
||
|
int y = BARCODE_Y_START;
|
||
|
int width = 1;
|
||
|
int height = BARCODE_HEIGHT;
|
||
|
|
||
|
x = draw_bits(canvas, furi_string_get_cstr(barcode_digits), x, y, width, height);
|
||
|
|
||
|
//set the canvas color to black to print the digit
|
||
|
canvas_set_color(canvas, ColorBlack);
|
||
|
// canvas_draw_str_aligned(canvas, 62, 30, AlignCenter, AlignCenter, error);
|
||
|
canvas_draw_str_aligned(
|
||
|
canvas, 62, y + height + 8, AlignCenter, AlignBottom, furi_string_get_cstr(raw_data));
|
||
|
}
|
||
|
|
||
|
static void draw_codabar(Canvas* canvas, BarcodeData* barcode_data) {
|
||
|
FuriString* raw_data = barcode_data->raw_data;
|
||
|
FuriString* barcode_digits = barcode_data->correct_data;
|
||
|
//BarcodeTypeObj* type_obj = barcode_data->type_obj;
|
||
|
|
||
|
int barcode_length = furi_string_size(barcode_digits);
|
||
|
int total_pixels = 0;
|
||
|
|
||
|
for(int i = 0; i < barcode_length; i++) {
|
||
|
//1 for wide, 0 for narrow
|
||
|
char wide_or_narrow = furi_string_get_char(barcode_digits, i);
|
||
|
int wn_digit = wide_or_narrow - '0'; //wide(1) or narrow(0) digit
|
||
|
|
||
|
if(wn_digit == 1) {
|
||
|
total_pixels += 3;
|
||
|
} else {
|
||
|
total_pixels += 1;
|
||
|
}
|
||
|
if((i + 1) % 7 == 0) {
|
||
|
total_pixels += 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int x = (128 - total_pixels) / 2;
|
||
|
int y = BARCODE_Y_START;
|
||
|
int width = 1;
|
||
|
int height = BARCODE_HEIGHT;
|
||
|
bool filled_in = true;
|
||
|
|
||
|
//set the canvas color to black to print the digit
|
||
|
canvas_set_color(canvas, ColorBlack);
|
||
|
// canvas_draw_str_aligned(canvas, 62, 30, AlignCenter, AlignCenter, error);
|
||
|
canvas_draw_str_aligned(
|
||
|
canvas, 62, y + height + 8, AlignCenter, AlignBottom, furi_string_get_cstr(raw_data));
|
||
|
|
||
|
for(int i = 0; i < barcode_length; i++) {
|
||
|
//1 for wide, 0 for narrow
|
||
|
char wide_or_narrow = furi_string_get_char(barcode_digits, i);
|
||
|
int wn_digit = wide_or_narrow - '0'; //wide(1) or narrow(0) digit
|
||
|
|
||
|
if(filled_in) {
|
||
|
if(wn_digit == 1) {
|
||
|
x = draw_bits(canvas, "111", x, y, width, height);
|
||
|
} else {
|
||
|
x = draw_bits(canvas, "1", x, y, width, height);
|
||
|
}
|
||
|
filled_in = false;
|
||
|
} else {
|
||
|
if(wn_digit == 1) {
|
||
|
x = draw_bits(canvas, "000", x, y, width, height);
|
||
|
} else {
|
||
|
x = draw_bits(canvas, "0", x, y, width, height);
|
||
|
}
|
||
|
filled_in = true;
|
||
|
}
|
||
|
if((i + 1) % 7 == 0) {
|
||
|
x = draw_bits(canvas, "0", x, y, width, height);
|
||
|
filled_in = true;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void barcode_draw_callback(Canvas* canvas, void* ctx) {
|
||
|
furi_assert(ctx);
|
||
|
BarcodeModel* barcode_model = ctx;
|
||
|
BarcodeData* data = barcode_model->data;
|
||
|
// const char* barcode_digits =;
|
||
|
|
||
|
canvas_clear(canvas);
|
||
|
if(data->valid) {
|
||
|
switch(data->type_obj->type) {
|
||
|
case UPCA:
|
||
|
draw_upc_a(canvas, data);
|
||
|
break;
|
||
|
case EAN8:
|
||
|
draw_ean_8(canvas, data);
|
||
|
break;
|
||
|
case EAN13:
|
||
|
draw_ean_13(canvas, data);
|
||
|
break;
|
||
|
case CODE39:
|
||
|
draw_code_39(canvas, data);
|
||
|
break;
|
||
|
case CODE128:
|
||
|
case CODE128C:
|
||
|
draw_code_128(canvas, data);
|
||
|
break;
|
||
|
case CODABAR:
|
||
|
draw_codabar(canvas, data);
|
||
|
break;
|
||
|
case UNKNOWN:
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
} else {
|
||
|
switch(data->reason) {
|
||
|
case WrongNumberOfDigits:
|
||
|
draw_error_str(canvas, "Wrong # of characters");
|
||
|
break;
|
||
|
case InvalidCharacters:
|
||
|
draw_error_str(canvas, "Invalid characters");
|
||
|
break;
|
||
|
case UnsupportedType:
|
||
|
draw_error_str(canvas, "Unsupported barcode type");
|
||
|
break;
|
||
|
case FileOpening:
|
||
|
draw_error_str(canvas, "Could not open file");
|
||
|
break;
|
||
|
case InvalidFileData:
|
||
|
draw_error_str(canvas, "Invalid file data");
|
||
|
break;
|
||
|
case MissingEncodingTable:
|
||
|
draw_error_str(canvas, "Missing encoding table");
|
||
|
break;
|
||
|
case EncodingTableError:
|
||
|
draw_error_str(canvas, "Encoding table error");
|
||
|
break;
|
||
|
default:
|
||
|
draw_error_str(canvas, "Could not read barcode data");
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool barcode_input_callback(InputEvent* input_event, void* ctx) {
|
||
|
UNUSED(ctx);
|
||
|
//furi_assert(ctx);
|
||
|
|
||
|
//Barcode* test_view_object = ctx;
|
||
|
|
||
|
if(input_event->key == InputKeyBack) {
|
||
|
return false;
|
||
|
} else {
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Barcode* barcode_view_allocate(BarcodeApp* barcode_app) {
|
||
|
furi_assert(barcode_app);
|
||
|
|
||
|
Barcode* barcode = malloc(sizeof(Barcode));
|
||
|
|
||
|
barcode->view = view_alloc();
|
||
|
barcode->barcode_app = barcode_app;
|
||
|
|
||
|
view_set_context(barcode->view, barcode);
|
||
|
view_allocate_model(barcode->view, ViewModelTypeLocking, sizeof(BarcodeModel));
|
||
|
view_set_draw_callback(barcode->view, barcode_draw_callback);
|
||
|
view_set_input_callback(barcode->view, barcode_input_callback);
|
||
|
|
||
|
return barcode;
|
||
|
}
|
||
|
|
||
|
void barcode_free_model(Barcode* barcode) {
|
||
|
with_view_model(
|
||
|
barcode->view,
|
||
|
BarcodeModel * model,
|
||
|
{
|
||
|
if(model->file_path != NULL) {
|
||
|
furi_string_free(model->file_path);
|
||
|
}
|
||
|
if(model->data != NULL) {
|
||
|
if(model->data->raw_data != NULL) {
|
||
|
furi_string_free(model->data->raw_data);
|
||
|
}
|
||
|
if(model->data->correct_data != NULL) {
|
||
|
furi_string_free(model->data->correct_data);
|
||
|
}
|
||
|
free(model->data);
|
||
|
}
|
||
|
},
|
||
|
false);
|
||
|
}
|
||
|
|
||
|
void barcode_free(Barcode* barcode) {
|
||
|
furi_assert(barcode);
|
||
|
|
||
|
barcode_free_model(barcode);
|
||
|
view_free(barcode->view);
|
||
|
free(barcode);
|
||
|
}
|
||
|
|
||
|
View* barcode_get_view(Barcode* barcode) {
|
||
|
furi_assert(barcode);
|
||
|
return barcode->view;
|
||
|
}
|