This commit is contained in:
MX 2023-07-06 02:26:56 +03:00
parent cebc56dc23
commit 45f3a77548
No known key found for this signature in database
GPG key ID: 7CCC66B7DBDD1C83
31 changed files with 2908 additions and 580 deletions

View file

@ -145,7 +145,7 @@ You can support us by using links or addresses below:
- WiFi Scanner plugin [(by SequoiaSan)](https://github.com/SequoiaSan/FlipperZero-WiFi-Scanner_Module)
- MultiConverter plugin [(by theisolinearchip)](https://github.com/theisolinearchip/flipperzero_stuff)
- WAV Player [(OFW: DrZlo13)](https://github.com/flipperdevices/flipperzero-firmware/tree/zlo/wav-player) - Fixed and improved by [LTVA1](https://github.com/LTVA1/wav_player) -> Also outputs audio on `PA6` - `3(A6)` pin
- Barcode generator plugin [(original by McAzzaMan)](https://github.com/McAzzaMan/flipperzero-firmware/tree/UPC-A_Barcode_Generator/applications/barcode_generator) - [EAN-8 and refactoring](https://github.com/DarkFlippers/unleashed-firmware/pull/154) by @msvsergey
- Barcode Generator [(by Kingal1337)](https://github.com/Kingal1337/flipper-barcode-generator)
- GPIO: Sentry Safe plugin [(by H4ckd4ddy)](https://github.com/H4ckd4ddy/flipperzero-sentry-safe-plugin)
- ESP32: WiFi Marauder companion plugin [(by 0xchocolate)](https://github.com/0xchocolate/flipperzero-wifi-marauder) - Saving .pcap on flipper microSD [by tcpassos](https://github.com/tcpassos/flipperzero-firmware-with-wifi-marauder-companion) -> Only with custom marauder build (It is necessary to uncomment "#define WRITE_PACKETS_SERIAL" in configs.h (in marauder fw) and compile the firmware for the wifi board.) Or download precompiled build -> [Download esp32_marauder_ver_flipper_sd_serial.bin](https://github.com/justcallmekoko/ESP32Marauder/releases/latest)
- NRF24: Sniffer & MouseJacker (with changes) [(by mothball187)](https://github.com/mothball187/flipperzero-nrf24/tree/main/mousejacker)

View file

@ -0,0 +1,22 @@
MIT License
Copyright (c) 2023 Alan Tsui
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -0,0 +1,88 @@
<p align="center">
<h1 align="center">Barcode Generator</h1>
<p align="center">
A barcode generator for the Flipper Zero that supports **UPC-A**, **EAN-8**, **EAN-13**, **Code-39**, **Codabar**, and **Code-128**[1]
</p>
Note: Barcode save locations have been moved from `/barcodes` to `/apps_data/barcodes`
## Table of Contents
- [Table of Contents](#table-of-contents)
- [Installing](#installing)
- [Building](#building)
- [Usage](#usage)
- [Creating a barcode](#creating-a-barcode)
- [Editing a barcode](#editing-a-barcode)
- [Deleting a barcode](#deleting-a-barcode)
- [Viewing a barcode](#viewing-a-barcode)
- [Screenshots](#screenshots)
- [Credits](#credits)
## Installing
1) Download the `.zip` file from the release section
2) Extract/unzip the `.zip` file onto your computer
3) Open qFlipper and go to the file manager
4) Navigate to the `apps` folder
5) Drag & drop the `.fap` file into the `apps` folder
6) Navigate back to the root folder of the SD card and create the folder `apps_data`, if not already there
7) Navigate into `apps_data` and create another folder called `barcode_data`
8) Navigate into `barcode_data`
9) Drag & drop the encoding txts (`code39_encodings.txt`, `code128_encodings.txt` & `codabar_encodings.txt`) into the `barcode_data` folder
## Building
1) Clone the [flipperzero-firmware](https://github.com/flipperdevices/flipperzero-firmware) repository or a firmware of your choice
2) Clone this repository and put it in the `applications_user` folder
3) Build this app by using the command `./fbt fap_Barcode_App`
4) Copy the `.fap` from `build\f7-firmware-D\.extapps\Barcode_App.fap` to `apps\Misc` using the qFlipper app
5) While still in the qFlipper app, navigate to the root folder of the SD card and create the folder `apps_data`, if not already there
6) Navigate into `apps_data` and create another folder called `barcode_data`
7) Navigate into `barcode_data`
8) Drag & drop the encoding txts (`code39_encodings.txt`, `code128_encodings.txt` & `codabar_encodings.txt`) from the `encoding_tables` folder in this repository into the `barcode_data` folder
## Usage
### Creating a barcode
1) To create a barcode click on `Create Barcode`
2) Next select your type using the left and right arrows
3) Enter your filename and then your barcode data
4) Click save
**Note**: For Codabar barcodes, you must manually add the start and stop codes to the barcode data
Start/Stop codes can be A, B, C, or D
For example, if you wanted to represent `1234` as a barcode you will need to enter something like `A1234A`. (You can replace the letters A with either A, B, C, or D)
![Codabar Data Example](screenshots/Codabar%20Data%20Example.png "Codabar Data Example")
### Editing a barcode
1) To edit a barcode click on `Edit Barcode`
2) Next select the barcode file you want to edit
3) Edit the type, name, or data
4) Click save
### Deleting a barcode
1) To delete a barcode click on `Edit Barcode`
2) Next select the barcode file you want to delete
3) Scroll all the way to the bottom
4) Click delete
### Viewing a barcode
1) To view a barcode click on `Load Barcode`
2) Next select the barcode file you want to view
## Screenshots
![Barcode Create Screen](screenshots/Creating%20Barcode.png "Barcode Create Screen")
![Flipper Code-128 Barcode](screenshots/Flipper%20Barcode.png "Flipper Code-128 Barcode")
![Flipper Box EAN-13 Barcode](screenshots/Flipper%20Box%20Barcode.png "Flipper Box EAN-13 Barcode")
## Credits
- [Kingal1337](https://github.com/Kingal1337) - Developer
- [Z0wl](https://github.com/Z0wl) - Added Code128-C Support
- [@teeebor](https://github.com/teeebor) - Menu Code Snippet
[1] - supports Set B (only the characters from 0-94). Also supports Set C

View file

@ -0,0 +1,16 @@
App(
appid="barcode_app",
name="Barcode App",
apptype=FlipperAppType.EXTERNAL,
entry_point="barcode_main",
requires=["gui", "storage"],
stack_size=2 * 1024,
fap_category="Tools",
fap_icon="images/barcode_10.png",
fap_icon_assets="images",
fap_icon_assets_symbol="barcode_app",
fap_author="@Kingal1337",
fap_weburl="https://github.com/Kingal1337/flipper-barcode-generator",
fap_version="1.0",
fap_description="App allows you to display various barcodes on flipper screen",
)

View file

@ -0,0 +1,348 @@
#include "barcode_app.h"
#include "barcode_app_icons.h"
/**
* Opens a file browser dialog and returns the filepath of the selected file
*
* @param folder the folder to view when the browser opens
* @param file_path a string pointer for the file_path when a file is selected,
* file_path will be the folder path is nothing is selected
* @returns true if a file is selected
*/
static bool select_file(const char* folder, FuriString* file_path) {
DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS);
DialogsFileBrowserOptions browser_options;
dialog_file_browser_set_basic_options(&browser_options, "", &I_barcode_10);
browser_options.base_path = DEFAULT_USER_BARCODES;
furi_string_set(file_path, folder);
bool res = dialog_file_browser_show(dialogs, file_path, file_path, &browser_options);
furi_record_close(RECORD_DIALOGS);
return res;
}
/**
* Reads the data from a file and stores them in the FuriStrings raw_type and raw_data
*/
ErrorCode read_raw_data(FuriString* file_path, FuriString* raw_type, FuriString* raw_data) {
//Open Storage
Storage* storage = furi_record_open(RECORD_STORAGE);
FlipperFormat* ff = flipper_format_file_alloc(storage);
ErrorCode reason = OKCode;
if(!flipper_format_file_open_existing(ff, furi_string_get_cstr(file_path))) {
FURI_LOG_E(TAG, "Could not open file %s", furi_string_get_cstr(file_path));
reason = FileOpening;
} else {
if(!flipper_format_read_string(ff, "Type", raw_type)) {
FURI_LOG_E(TAG, "Could not read \"Type\" string");
reason = InvalidFileData;
}
if(!flipper_format_read_string(ff, "Data", raw_data)) {
FURI_LOG_E(TAG, "Could not read \"Data\" string");
reason = InvalidFileData;
}
}
//Close Storage
flipper_format_free(ff);
furi_record_close(RECORD_STORAGE);
return reason;
}
/**
* Gets the file name from a file path
* @param file_path the file path
* @param file_name the FuriString to store the file name
* @param remove_extension true if the extension should be removed, otherwise false
*/
bool get_file_name_from_path(FuriString* file_path, FuriString* file_name, bool remove_extension) {
if(file_path == NULL || file_name == NULL) {
return false;
}
uint32_t slash_index = furi_string_search_rchar(file_path, '/', 0);
if(slash_index == FURI_STRING_FAILURE || slash_index >= (furi_string_size(file_path) - 1)) {
return false;
}
furi_string_set(file_name, file_path);
furi_string_right(file_name, slash_index + 1);
if(remove_extension) {
uint32_t ext_index = furi_string_search_rchar(file_name, '.', 0);
if(ext_index != FURI_STRING_FAILURE && ext_index < (furi_string_size(file_path))) {
furi_string_left(file_name, ext_index);
}
}
return true;
}
/**
* Creates the barcode folder
*/
void init_folder() {
Storage* storage = furi_record_open(RECORD_STORAGE);
FURI_LOG_I(TAG, "Creating barcodes folder");
if(storage_simply_mkdir(storage, DEFAULT_USER_BARCODES)) {
FURI_LOG_I(TAG, "Barcodes folder successfully created!");
} else {
FURI_LOG_I(TAG, "Barcodes folder already exists.");
}
furi_record_close(RECORD_STORAGE);
}
void select_barcode_item(BarcodeApp* app) {
FuriString* file_path = furi_string_alloc();
FuriString* raw_type = furi_string_alloc();
FuriString* raw_data = furi_string_alloc();
//this determines if the data was read correctly or if the
bool loaded_success = true;
ErrorCode reason = OKCode;
bool file_selected = select_file(DEFAULT_USER_BARCODES, file_path);
if(file_selected) {
FURI_LOG_I(TAG, "The file selected is %s", furi_string_get_cstr(file_path));
Barcode* barcode = app->barcode_view;
reason = read_raw_data(file_path, raw_type, raw_data);
if(reason != OKCode) {
loaded_success = false;
FURI_LOG_E(TAG, "Could not read data correctly");
}
//Free the data from the previous barcode
barcode_free_model(barcode);
with_view_model(
barcode->view,
BarcodeModel * model,
{
model->file_path = furi_string_alloc_set(file_path);
model->data = malloc(sizeof(BarcodeData));
model->data->valid = loaded_success;
if(loaded_success) {
model->data->raw_data = furi_string_alloc_set(raw_data);
model->data->correct_data = furi_string_alloc();
model->data->type_obj = get_type(raw_type);
barcode_loader(model->data);
} else {
model->data->reason = reason;
}
},
true);
view_dispatcher_switch_to_view(app->view_dispatcher, BarcodeView);
}
furi_string_free(raw_type);
furi_string_free(raw_data);
furi_string_free(file_path);
}
void edit_barcode_item(BarcodeApp* app) {
FuriString* file_path = furi_string_alloc();
FuriString* file_name = furi_string_alloc();
FuriString* raw_type = furi_string_alloc();
FuriString* raw_data = furi_string_alloc();
//this determines if the data was read correctly or if the
ErrorCode reason = OKCode;
bool file_selected = select_file(DEFAULT_USER_BARCODES, file_path);
if(file_selected) {
FURI_LOG_I(TAG, "The file selected is %s", furi_string_get_cstr(file_path));
CreateView* create_view_object = app->create_view;
reason = read_raw_data(file_path, raw_type, raw_data);
if(reason != OKCode) {
FURI_LOG_E(TAG, "Could not read data correctly");
with_view_model(
app->message_view->view,
MessageViewModel * model,
{ model->message = get_error_code_message(reason); },
true);
view_dispatcher_switch_to_view(
create_view_object->barcode_app->view_dispatcher, MessageErrorView);
} else {
BarcodeTypeObj* type_obj = get_type(raw_type);
if(type_obj->type == UNKNOWN) {
type_obj = barcode_type_objs[0];
}
get_file_name_from_path(file_path, file_name, true);
create_view_free_model(create_view_object);
with_view_model(
create_view_object->view,
CreateViewModel * model,
{
model->selected_menu_item = 0;
model->barcode_type = type_obj;
model->file_path = furi_string_alloc_set(file_path);
model->file_name = furi_string_alloc_set(file_name);
model->barcode_data = furi_string_alloc_set(raw_data);
model->mode = EditMode;
},
true);
view_dispatcher_switch_to_view(app->view_dispatcher, CreateBarcodeView);
}
}
furi_string_free(raw_type);
furi_string_free(raw_data);
furi_string_free(file_name);
furi_string_free(file_path);
}
void create_barcode_item(BarcodeApp* app) {
CreateView* create_view_object = app->create_view;
create_view_free_model(create_view_object);
with_view_model(
create_view_object->view,
CreateViewModel * model,
{
model->selected_menu_item = 0;
model->barcode_type = barcode_type_objs[0];
model->file_path = furi_string_alloc();
model->file_name = furi_string_alloc();
model->barcode_data = furi_string_alloc();
model->mode = NewMode;
},
true);
view_dispatcher_switch_to_view(app->view_dispatcher, CreateBarcodeView);
}
void submenu_callback(void* context, uint32_t index) {
furi_assert(context);
BarcodeApp* app = context;
if(index == SelectBarcodeItem) {
select_barcode_item(app);
} else if(index == EditBarcodeItem) {
edit_barcode_item(app);
} else if(index == CreateBarcodeItem) {
create_barcode_item(app);
}
}
uint32_t create_view_callback(void* context) {
UNUSED(context);
return CreateBarcodeView;
}
uint32_t main_menu_callback(void* context) {
UNUSED(context);
return MainMenuView;
}
uint32_t exit_callback(void* context) {
UNUSED(context);
return VIEW_NONE;
}
void free_app(BarcodeApp* app) {
FURI_LOG_I(TAG, "Freeing Data");
init_folder();
free_types();
view_dispatcher_remove_view(app->view_dispatcher, TextInputView);
text_input_free(app->text_input);
view_dispatcher_remove_view(app->view_dispatcher, MessageErrorView);
message_view_free(app->message_view);
view_dispatcher_remove_view(app->view_dispatcher, MainMenuView);
submenu_free(app->main_menu);
view_dispatcher_remove_view(app->view_dispatcher, CreateBarcodeView);
create_view_free(app->create_view);
view_dispatcher_remove_view(app->view_dispatcher, BarcodeView);
barcode_free(app->barcode_view);
//free the dispatcher
view_dispatcher_free(app->view_dispatcher);
furi_message_queue_free(app->event_queue);
furi_record_close(RECORD_GUI);
app->gui = NULL;
free(app);
}
int32_t barcode_main(void* p) {
UNUSED(p);
BarcodeApp* app = malloc(sizeof(BarcodeApp));
init_types();
app->event_queue = furi_message_queue_alloc(8, sizeof(InputEvent));
// Register view port in GUI
app->gui = furi_record_open(RECORD_GUI);
app->view_dispatcher = view_dispatcher_alloc();
view_dispatcher_enable_queue(app->view_dispatcher);
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
app->main_menu = submenu_alloc();
submenu_add_item(app->main_menu, "Load Barcode", SelectBarcodeItem, submenu_callback, app);
view_set_previous_callback(submenu_get_view(app->main_menu), exit_callback);
view_dispatcher_add_view(app->view_dispatcher, MainMenuView, submenu_get_view(app->main_menu));
submenu_add_item(app->main_menu, "Edit Barcode", EditBarcodeItem, submenu_callback, app);
/*****************************
* Creating Text Input View
******************************/
app->text_input = text_input_alloc();
view_set_previous_callback(text_input_get_view(app->text_input), create_view_callback);
view_dispatcher_add_view(
app->view_dispatcher, TextInputView, text_input_get_view(app->text_input));
/*****************************
* Creating Message View
******************************/
app->message_view = message_view_allocate(app);
view_dispatcher_add_view(
app->view_dispatcher, MessageErrorView, message_get_view(app->message_view));
/*****************************
* Creating Create View
******************************/
app->create_view = create_view_allocate(app);
submenu_add_item(app->main_menu, "Create Barcode", CreateBarcodeItem, submenu_callback, app);
view_set_previous_callback(create_get_view(app->create_view), main_menu_callback);
view_dispatcher_add_view(
app->view_dispatcher, CreateBarcodeView, create_get_view(app->create_view));
/*****************************
* Creating Barcode View
******************************/
app->barcode_view = barcode_view_allocate(app);
view_set_previous_callback(barcode_get_view(app->barcode_view), main_menu_callback);
view_dispatcher_add_view(
app->view_dispatcher, BarcodeView, barcode_get_view(app->barcode_view));
//switch view to submenu and run dispatcher
view_dispatcher_switch_to_view(app->view_dispatcher, MainMenuView);
view_dispatcher_run(app->view_dispatcher);
free_app(app);
return 0;
}

View file

@ -0,0 +1,91 @@
#pragma once
#include <furi.h>
#include <furi_hal.h>
#include <gui/gui.h>
#include <input/input.h>
#include <dialogs/dialogs.h>
#include <gui/view_dispatcher.h>
#include <gui/modules/submenu.h>
#include <gui/modules/text_input.h>
#include <gui/modules/text_input.h>
#include <flipper_format/flipper_format.h>
#include "barcode_utils.h"
#define TAG "BARCODE"
#define VERSION "1.1"
#define FILE_VERSION "1"
#define TEXT_BUFFER_SIZE 128
#define BARCODE_HEIGHT 50
#define BARCODE_Y_START 3
//the folder where the encodings are located
#define BARCODE_DATA_FILE_DIR_PATH EXT_PATH("apps_data/barcode_data")
//the folder where the codabar encoding table is located
#define CODABAR_DICT_FILE_PATH BARCODE_DATA_FILE_DIR_PATH "/codabar_encodings.txt"
//the folder where the code 39 encoding table is located
#define CODE39_DICT_FILE_PATH BARCODE_DATA_FILE_DIR_PATH "/code39_encodings.txt"
//the folder where the code 128 encoding table is located
#define CODE128_DICT_FILE_PATH BARCODE_DATA_FILE_DIR_PATH "/code128_encodings.txt"
//the folder where the code 128 C encoding table is located
#define CODE128C_DICT_FILE_PATH BARCODE_DATA_FILE_DIR_PATH "/code128c_encodings.txt"
//the folder where the user stores their barcodes
#define DEFAULT_USER_BARCODES EXT_PATH("apps_data/barcodes")
//The extension barcode files use
#define BARCODE_EXTENSION ".txt"
#define BARCODE_EXTENSION_LENGTH 4
#include "views/barcode_view.h"
#include "views/create_view.h"
#include "views/message_view.h"
#include "barcode_validator.h"
typedef struct BarcodeApp BarcodeApp;
struct BarcodeApp {
Submenu* main_menu;
ViewDispatcher* view_dispatcher;
Gui* gui;
FuriMessageQueue* event_queue;
CreateView* create_view;
Barcode* barcode_view;
MessageView* message_view;
TextInput* text_input;
};
enum SubmenuItems {
SelectBarcodeItem,
EditBarcodeItem,
CreateBarcodeItem
};
enum Views {
TextInputView,
MessageErrorView,
MainMenuView,
CreateBarcodeView,
BarcodeView
};
void submenu_callback(void* context, uint32_t index);
uint32_t main_menu_callback(void* context);
uint32_t exit_callback(void* context);
int32_t barcode_main(void* p);

View file

@ -0,0 +1,147 @@
#include "barcode_utils.h"
BarcodeTypeObj* barcode_type_objs[NUMBER_OF_BARCODE_TYPES] = {NULL};
void init_types() {
BarcodeTypeObj* upc_a = malloc(sizeof(BarcodeTypeObj));
upc_a->name = "UPC-A";
upc_a->type = UPCA;
upc_a->min_digits = 11;
upc_a->max_digits = 12;
upc_a->start_pos = 16;
barcode_type_objs[UPCA] = upc_a;
BarcodeTypeObj* ean_8 = malloc(sizeof(BarcodeTypeObj));
ean_8->name = "EAN-8";
ean_8->type = EAN8;
ean_8->min_digits = 7;
ean_8->max_digits = 8;
ean_8->start_pos = 32;
barcode_type_objs[EAN8] = ean_8;
BarcodeTypeObj* ean_13 = malloc(sizeof(BarcodeTypeObj));
ean_13->name = "EAN-13";
ean_13->type = EAN13;
ean_13->min_digits = 12;
ean_13->max_digits = 13;
ean_13->start_pos = 16;
barcode_type_objs[EAN13] = ean_13;
BarcodeTypeObj* code_39 = malloc(sizeof(BarcodeTypeObj));
code_39->name = "CODE-39";
code_39->type = CODE39;
code_39->min_digits = 1;
code_39->max_digits = -1;
code_39->start_pos = 0;
barcode_type_objs[CODE39] = code_39;
BarcodeTypeObj* code_128 = malloc(sizeof(BarcodeTypeObj));
code_128->name = "CODE-128";
code_128->type = CODE128;
code_128->min_digits = 1;
code_128->max_digits = -1;
code_128->start_pos = 0;
barcode_type_objs[CODE128] = code_128;
BarcodeTypeObj* code_128c = malloc(sizeof(BarcodeTypeObj));
code_128c->name = "CODE-128C";
code_128c->type = CODE128C;
code_128c->min_digits = 2;
code_128c->max_digits = -1;
code_128c->start_pos = 0;
barcode_type_objs[CODE128C] = code_128c;
BarcodeTypeObj* codabar = malloc(sizeof(BarcodeTypeObj));
codabar->name = "Codabar";
codabar->type = CODABAR;
codabar->min_digits = 1;
codabar->max_digits = -1;
codabar->start_pos = 0;
barcode_type_objs[CODABAR] = codabar;
BarcodeTypeObj* unknown = malloc(sizeof(BarcodeTypeObj));
unknown->name = "Unknown";
unknown->type = UNKNOWN;
unknown->min_digits = 0;
unknown->max_digits = 0;
unknown->start_pos = 0;
barcode_type_objs[UNKNOWN] = unknown;
}
void free_types() {
for(int i = 0; i < NUMBER_OF_BARCODE_TYPES; i++) {
free(barcode_type_objs[i]);
}
}
BarcodeTypeObj* get_type(FuriString* type_string) {
if(furi_string_cmp_str(type_string, "UPC-A") == 0) {
return barcode_type_objs[UPCA];
}
if(furi_string_cmp_str(type_string, "EAN-8") == 0) {
return barcode_type_objs[EAN8];
}
if(furi_string_cmp_str(type_string, "EAN-13") == 0) {
return barcode_type_objs[EAN13];
}
if(furi_string_cmp_str(type_string, "CODE-39") == 0) {
return barcode_type_objs[CODE39];
}
if(furi_string_cmp_str(type_string, "CODE-128") == 0) {
return barcode_type_objs[CODE128];
}
if(furi_string_cmp_str(type_string, "CODE-128C") == 0) {
return barcode_type_objs[CODE128C];
}
if(furi_string_cmp_str(type_string, "Codabar") == 0) {
return barcode_type_objs[CODABAR];
}
return barcode_type_objs[UNKNOWN];
}
const char* get_error_code_name(ErrorCode error_code) {
switch(error_code) {
case WrongNumberOfDigits:
return "Wrong Number Of Digits";
case InvalidCharacters:
return "Invalid Characters";
case UnsupportedType:
return "Unsupported Type";
case FileOpening:
return "File Opening Error";
case InvalidFileData:
return "Invalid File Data";
case MissingEncodingTable:
return "Missing Encoding Table";
case EncodingTableError:
return "Encoding Table Error";
case OKCode:
return "OK";
default:
return "Unknown Code";
};
}
const char* get_error_code_message(ErrorCode error_code) {
switch(error_code) {
case WrongNumberOfDigits:
return "Wrong # of characters";
case InvalidCharacters:
return "Invalid characters";
case UnsupportedType:
return "Unsupported barcode type";
case FileOpening:
return "Could not open file";
case InvalidFileData:
return "Invalid file data";
case MissingEncodingTable:
return "Missing encoding table";
case EncodingTableError:
return "Encoding table error";
case OKCode:
return "OK";
default:
return "Could not read barcode data";
};
}

View file

@ -0,0 +1,55 @@
#pragma once
#include <furi.h>
#include <furi_hal.h>
#define NUMBER_OF_BARCODE_TYPES 8
typedef enum {
WrongNumberOfDigits, //There is too many or too few digits in the barcode
InvalidCharacters, //The barcode contains invalid characters
UnsupportedType, //the barcode type is not supported
FileOpening, //A problem occurred when opening the barcode data file
InvalidFileData, //One of the key in the file doesn't exist or there is a typo
MissingEncodingTable, //The encoding table txt for the barcode type is missing
EncodingTableError, //Something is wrong with the encoding table, probably missing data or typo
OKCode
} ErrorCode;
typedef enum {
UPCA,
EAN8,
EAN13,
CODE39,
CODE128,
CODE128C,
CODABAR,
UNKNOWN
} BarcodeType;
typedef struct {
char* name; //The name of the barcode type
BarcodeType type; //The barcode type enum
int min_digits; //the minimum number of digits
int max_digits; //the maximum number of digits
int start_pos; //where to start drawing the barcode, set to -1 to dynamically draw barcode
} BarcodeTypeObj;
typedef struct {
BarcodeTypeObj* type_obj;
int check_digit; //A place to store the check digit
FuriString* raw_data; //the data directly from the file
FuriString* correct_data; //the corrected/processed data
bool valid; //true if the raw data is correctly formatted, such as correct num of digits, valid characters, etc.
ErrorCode reason; //the reason why this barcode is invalid
} BarcodeData;
//All available barcode types
extern BarcodeTypeObj* barcode_type_objs[NUMBER_OF_BARCODE_TYPES];
void init_types();
void free_types();
BarcodeTypeObj* get_type(FuriString* type_string);
const char* get_error_code_name(ErrorCode error_code);
const char* get_error_code_message(ErrorCode error_code);

View file

@ -0,0 +1,532 @@
#include "barcode_validator.h"
void barcode_loader(BarcodeData* barcode_data) {
switch(barcode_data->type_obj->type) {
case UPCA:
case EAN8:
case EAN13:
ean_upc_loader(barcode_data);
break;
case CODE39:
code_39_loader(barcode_data);
break;
case CODE128:
code_128_loader(barcode_data);
break;
case CODE128C:
code_128c_loader(barcode_data);
break;
case CODABAR:
codabar_loader(barcode_data);
break;
case UNKNOWN:
barcode_data->reason = UnsupportedType;
barcode_data->valid = false;
default:
break;
}
}
/**
* Calculates the check digit of a barcode if they have one
* @param barcode_data the barcode data
* @returns a check digit or -1 for either an invalid
*/
int calculate_check_digit(BarcodeData* barcode_data) {
int check_digit = -1;
switch(barcode_data->type_obj->type) {
case UPCA:
case EAN8:
case EAN13:
check_digit = calculate_ean_upc_check_digit(barcode_data);
break;
case CODE39:
case CODE128:
case CODE128C:
case CODABAR:
case UNKNOWN:
default:
break;
}
return check_digit;
}
/**
* Calculates the check digit of barcode types UPC-A, EAN-8, & EAN-13
*/
int calculate_ean_upc_check_digit(BarcodeData* barcode_data) {
int check_digit = 0;
int odd = 0;
int even = 0;
int length = barcode_data->type_obj->min_digits;
//Get sum of odd digits
for(int i = 0; i < length; i += 2) {
odd += furi_string_get_char(barcode_data->raw_data, i) - '0';
}
//Get sum of even digits
for(int i = 1; i < length; i += 2) {
even += furi_string_get_char(barcode_data->raw_data, i) - '0';
}
if(barcode_data->type_obj->type == EAN13) {
check_digit = even * 3 + odd;
} else {
check_digit = odd * 3 + even;
}
check_digit = check_digit % 10;
return (10 - check_digit) % 10;
}
/**
* Loads and validates Barcode Types EAN-8, EAN-13, and UPC-A
* barcode_data and its strings should already be allocated;
*/
void ean_upc_loader(BarcodeData* barcode_data) {
int barcode_length = furi_string_size(barcode_data->raw_data);
int min_digits = barcode_data->type_obj->min_digits;
int max_digit = barcode_data->type_obj->max_digits;
//check the length of the barcode
if(barcode_length < min_digits || barcode_length > max_digit) {
barcode_data->reason = WrongNumberOfDigits;
barcode_data->valid = false;
return;
}
//checks if the barcode contains any characters that aren't a number
for(int i = 0; i < barcode_length; i++) {
char character = furi_string_get_char(barcode_data->raw_data, i);
int digit = character - '0'; //convert the number into an int (also the index)
if(digit < 0 || digit > 9) {
barcode_data->reason = InvalidCharacters;
barcode_data->valid = false;
return;
}
}
int check_digit = calculate_check_digit(barcode_data);
char check_digit_char = check_digit + '0';
barcode_data->check_digit = check_digit;
//if the barcode length is at max length then we will verify if the check digit is correct
if(barcode_length == max_digit) {
//append the raw_data to the correct data string
furi_string_cat(barcode_data->correct_data, barcode_data->raw_data);
//append the check digit to the correct data string
furi_string_set_char(barcode_data->correct_data, min_digits, check_digit_char);
}
//if the barcode length is at min length, we will calculate the check digit
if(barcode_length == min_digits) {
//append the raw_data to the correct data string
furi_string_cat(barcode_data->correct_data, barcode_data->raw_data);
//append the check digit to the correct data string
furi_string_push_back(barcode_data->correct_data, check_digit_char);
}
}
void code_39_loader(BarcodeData* barcode_data) {
int barcode_length = furi_string_size(barcode_data->raw_data);
int min_digits = barcode_data->type_obj->min_digits;
//check the length of the barcode, must contain atleast a character,
//this can have as many characters as it wants, it might not fit on the screen
if(barcode_length < min_digits) {
barcode_data->reason = WrongNumberOfDigits;
barcode_data->valid = false;
return;
}
FuriString* barcode_bits = furi_string_alloc();
FuriString* temp_string = furi_string_alloc();
//add starting and ending *
if(!furi_string_start_with(barcode_data->raw_data, "*")) {
furi_string_push_back(temp_string, '*');
furi_string_cat(temp_string, barcode_data->raw_data);
furi_string_set(barcode_data->raw_data, temp_string);
}
if(!furi_string_end_with(barcode_data->raw_data, "*")) {
furi_string_push_back(barcode_data->raw_data, '*');
}
furi_string_free(temp_string);
barcode_length = furi_string_size(barcode_data->raw_data);
//Open Storage
Storage* storage = furi_record_open(RECORD_STORAGE);
FlipperFormat* ff = flipper_format_file_alloc(storage);
if(!flipper_format_file_open_existing(ff, CODE39_DICT_FILE_PATH)) {
FURI_LOG_E(TAG, "Could not open file %s", CODE39_DICT_FILE_PATH);
barcode_data->reason = MissingEncodingTable;
barcode_data->valid = false;
} else {
FuriString* char_bits = furi_string_alloc();
for(int i = 0; i < barcode_length; i++) {
char barcode_char = toupper(furi_string_get_char(barcode_data->raw_data, i));
//convert a char into a string so it used in flipper_format_read_string
char current_character[2];
snprintf(current_character, 2, "%c", barcode_char);
if(!flipper_format_read_string(ff, current_character, char_bits)) {
FURI_LOG_E(TAG, "Could not read \"%c\" string", barcode_char);
barcode_data->reason = InvalidCharacters;
barcode_data->valid = false;
break;
} else {
FURI_LOG_I(
TAG, "\"%c\" string: %s", barcode_char, furi_string_get_cstr(char_bits));
furi_string_cat(barcode_bits, char_bits);
}
flipper_format_rewind(ff);
}
furi_string_free(char_bits);
}
//Close Storage
flipper_format_free(ff);
furi_record_close(RECORD_STORAGE);
furi_string_cat(barcode_data->correct_data, barcode_bits);
furi_string_free(barcode_bits);
}
/**
* Loads a code 128 barcode
*
* Only supports character set B
*/
void code_128_loader(BarcodeData* barcode_data) {
int barcode_length = furi_string_size(barcode_data->raw_data);
//the start code for character set B
int start_code_value = 104;
//The bits for the start code
const char* start_code_bits = "11010010000";
//The bits for the stop code
const char* stop_code_bits = "1100011101011";
int min_digits = barcode_data->type_obj->min_digits;
/**
* A sum of all of the characters values
* Ex:
* Barcode Data : ABC
* A has a value of 33
* B has a value of 34
* C has a value of 35
*
* the checksum_adder would be (33 * 1) + (34 * 2) + (35 * 3) + 104 = 310
*
* Add 104 since we are using set B
*/
int checksum_adder = start_code_value;
/**
* Checksum digits is the number of characters it has read so far
* In the above example the checksum_digits would be 3
*/
int checksum_digits = 0;
//the calculated check digit
int final_check_digit = 0;
//check the length of the barcode, must contain atleast a character,
//this can have as many characters as it wants, it might not fit on the screen
if(barcode_length < min_digits) {
barcode_data->reason = WrongNumberOfDigits;
barcode_data->valid = false;
return;
}
//Open Storage
Storage* storage = furi_record_open(RECORD_STORAGE);
FlipperFormat* ff = flipper_format_file_alloc(storage);
FuriString* barcode_bits = furi_string_alloc();
//add the start code
furi_string_cat(barcode_bits, start_code_bits);
if(!flipper_format_file_open_existing(ff, CODE128_DICT_FILE_PATH)) {
FURI_LOG_E(TAG, "Could not open file %s", CODE128_DICT_FILE_PATH);
barcode_data->reason = MissingEncodingTable;
barcode_data->valid = false;
} else {
FuriString* value = furi_string_alloc();
FuriString* char_bits = furi_string_alloc();
for(int i = 0; i < barcode_length; i++) {
char barcode_char = furi_string_get_char(barcode_data->raw_data, i);
//convert a char into a string so it used in flipper_format_read_string
char current_character[2];
snprintf(current_character, 2, "%c", barcode_char);
//get the value of the character
if(!flipper_format_read_string(ff, current_character, value)) {
FURI_LOG_E(TAG, "Could not read \"%c\" string", barcode_char);
barcode_data->reason = InvalidCharacters;
barcode_data->valid = false;
break;
}
//using the value of the character, get the characters bits
if(!flipper_format_read_string(ff, furi_string_get_cstr(value), char_bits)) {
FURI_LOG_E(TAG, "Could not read \"%c\" string", barcode_char);
barcode_data->reason = EncodingTableError;
barcode_data->valid = false;
break;
} else {
//add the bits to the full barcode
furi_string_cat(barcode_bits, char_bits);
//calculate the checksum
checksum_digits += 1;
checksum_adder += (atoi(furi_string_get_cstr(value)) * checksum_digits);
FURI_LOG_D(
TAG,
"\"%c\" string: %s : %s : %d : %d : %d",
barcode_char,
furi_string_get_cstr(char_bits),
furi_string_get_cstr(value),
checksum_digits,
(atoi(furi_string_get_cstr(value)) * checksum_digits),
checksum_adder);
}
//bring the file pointer back to the beginning
flipper_format_rewind(ff);
}
//calculate the check digit and convert it into a c string for lookup in the encoding table
final_check_digit = checksum_adder % 103;
int length = snprintf(NULL, 0, "%d", final_check_digit);
char* final_check_digit_string = malloc(length + 1);
snprintf(final_check_digit_string, length + 1, "%d", final_check_digit);
//after the checksum has been calculated, add the bits to the full barcode
if(!flipper_format_read_string(ff, final_check_digit_string, char_bits)) {
FURI_LOG_E(TAG, "Could not read \"%s\" string", final_check_digit_string);
barcode_data->reason = EncodingTableError;
barcode_data->valid = false;
} else {
//add the check digit bits to the full barcode
furi_string_cat(barcode_bits, char_bits);
FURI_LOG_D(
TAG,
"\"%s\" string: %s",
final_check_digit_string,
furi_string_get_cstr(char_bits));
}
free(final_check_digit_string);
furi_string_free(value);
furi_string_free(char_bits);
}
//add the stop code
furi_string_cat(barcode_bits, stop_code_bits);
//Close Storage
flipper_format_free(ff);
furi_record_close(RECORD_STORAGE);
furi_string_cat(barcode_data->correct_data, barcode_bits);
furi_string_free(barcode_bits);
}
/**
* Loads a code 128 C barcode
*/
void code_128c_loader(BarcodeData* barcode_data) {
int barcode_length = furi_string_size(barcode_data->raw_data);
//the start code for character set C
int start_code_value = 105;
//The bits for the start code
const char* start_code_bits = "11010011100";
//The bits for the stop code
const char* stop_code_bits = "1100011101011";
int min_digits = barcode_data->type_obj->min_digits;
int checksum_adder = start_code_value;
int checksum_digits = 0;
//the calculated check digit
int final_check_digit = 0;
// check the length of the barcode, must contain atleast 2 character,
// this can have as many characters as it wants, it might not fit on the screen
// code 128 C: the length must be even
if((barcode_length < min_digits) || (barcode_length & 1)) {
barcode_data->reason = WrongNumberOfDigits;
barcode_data->valid = false;
return;
}
//Open Storage
Storage* storage = furi_record_open(RECORD_STORAGE);
FlipperFormat* ff = flipper_format_file_alloc(storage);
FuriString* barcode_bits = furi_string_alloc();
//add the start code
furi_string_cat(barcode_bits, start_code_bits);
if(!flipper_format_file_open_existing(ff, CODE128C_DICT_FILE_PATH)) {
FURI_LOG_E(TAG, "c128c Could not open file %s", CODE128C_DICT_FILE_PATH);
barcode_data->reason = MissingEncodingTable;
barcode_data->valid = false;
} else {
FuriString* value = furi_string_alloc();
FuriString* char_bits = furi_string_alloc();
for(int i = 0; i < barcode_length; i += 2) {
char barcode_char1 = furi_string_get_char(barcode_data->raw_data, i);
char barcode_char2 = furi_string_get_char(barcode_data->raw_data, i + 1);
FURI_LOG_I(TAG, "c128c bc1='%c' bc2='%c'", barcode_char1, barcode_char2);
char current_chars[4];
snprintf(current_chars, 3, "%c%c", barcode_char1, barcode_char2);
FURI_LOG_I(TAG, "c128c current_chars='%s'", current_chars);
//using the value of the characters, get the characters bits
if(!flipper_format_read_string(ff, current_chars, char_bits)) {
FURI_LOG_E(TAG, "c128c Could not read \"%s\" string", current_chars);
barcode_data->reason = EncodingTableError;
barcode_data->valid = false;
break;
} else {
//add the bits to the full barcode
furi_string_cat(barcode_bits, char_bits);
// calculate the checksum
checksum_digits += 1;
checksum_adder += (atoi(current_chars) * checksum_digits);
FURI_LOG_I(
TAG,
"c128c \"%s\" string: %s : %s : %d : %d : %d",
current_chars,
furi_string_get_cstr(char_bits),
furi_string_get_cstr(value),
checksum_digits,
(atoi(furi_string_get_cstr(value)) * checksum_digits),
checksum_adder);
}
//bring the file pointer back to the begining
flipper_format_rewind(ff);
}
//calculate the check digit and convert it into a c string for lookup in the encoding table
final_check_digit = checksum_adder % 103;
FURI_LOG_I(TAG, "c128c finale_check_digit=%d", final_check_digit);
int length = snprintf(NULL, 0, "%d", final_check_digit);
if(final_check_digit < 100) length = 2;
char* final_check_digit_string = malloc(length + 1);
snprintf(final_check_digit_string, length + 1, "%02d", final_check_digit);
//after the checksum has been calculated, add the bits to the full barcode
if(!flipper_format_read_string(ff, final_check_digit_string, char_bits)) {
FURI_LOG_E(TAG, "c128c cksum Could not read \"%s\" string", final_check_digit_string);
barcode_data->reason = EncodingTableError;
barcode_data->valid = false;
} else {
//add the check digit bits to the full barcode
furi_string_cat(barcode_bits, char_bits);
FURI_LOG_I(
TAG,
"check digit \"%s\" string: %s",
final_check_digit_string,
furi_string_get_cstr(char_bits));
}
free(final_check_digit_string);
furi_string_free(value);
furi_string_free(char_bits);
}
//add the stop code
furi_string_cat(barcode_bits, stop_code_bits);
//Close Storage
flipper_format_free(ff);
furi_record_close(RECORD_STORAGE);
FURI_LOG_I(TAG, "c128c %s", furi_string_get_cstr(barcode_bits));
furi_string_cat(barcode_data->correct_data, barcode_bits);
furi_string_free(barcode_bits);
}
void codabar_loader(BarcodeData* barcode_data) {
int barcode_length = furi_string_size(barcode_data->raw_data);
int min_digits = barcode_data->type_obj->min_digits;
//check the length of the barcode, must contain atleast a character,
//this can have as many characters as it wants, it might not fit on the screen
if(barcode_length < min_digits) {
barcode_data->reason = WrongNumberOfDigits;
barcode_data->valid = false;
return;
}
FuriString* barcode_bits = furi_string_alloc();
barcode_length = furi_string_size(barcode_data->raw_data);
//Open Storage
Storage* storage = furi_record_open(RECORD_STORAGE);
FlipperFormat* ff = flipper_format_file_alloc(storage);
if(!flipper_format_file_open_existing(ff, CODABAR_DICT_FILE_PATH)) {
FURI_LOG_E(TAG, "Could not open file %s", CODABAR_DICT_FILE_PATH);
barcode_data->reason = MissingEncodingTable;
barcode_data->valid = false;
} else {
FuriString* char_bits = furi_string_alloc();
for(int i = 0; i < barcode_length; i++) {
char barcode_char = toupper(furi_string_get_char(barcode_data->raw_data, i));
//convert a char into a string so it used in flipper_format_read_string
char current_character[2];
snprintf(current_character, 2, "%c", barcode_char);
if(!flipper_format_read_string(ff, current_character, char_bits)) {
FURI_LOG_E(TAG, "Could not read \"%c\" string", barcode_char);
barcode_data->reason = InvalidCharacters;
barcode_data->valid = false;
break;
} else {
FURI_LOG_I(
TAG, "\"%c\" string: %s", barcode_char, furi_string_get_cstr(char_bits));
furi_string_cat(barcode_bits, char_bits);
}
flipper_format_rewind(ff);
}
furi_string_free(char_bits);
}
//Close Storage
flipper_format_free(ff);
furi_record_close(RECORD_STORAGE);
furi_string_cat(barcode_data->correct_data, barcode_bits);
furi_string_free(barcode_bits);
}

View file

@ -0,0 +1,15 @@
#pragma once
#include "barcode_app.h"
int calculate_check_digit(BarcodeData* barcode_data);
int calculate_ean_upc_check_digit(BarcodeData* barcode_data);
void ean_upc_loader(BarcodeData* barcode_data);
void upc_a_loader(BarcodeData* barcode_data);
void ean_8_loader(BarcodeData* barcode_data);
void ean_13_loader(BarcodeData* barcode_data);
void code_39_loader(BarcodeData* barcode_data);
void code_128_loader(BarcodeData* barcode_data);
void code_128c_loader(BarcodeData* barcode_data);
void codabar_loader(BarcodeData* barcode_data);
void barcode_loader(BarcodeData* barcode_data);

View file

@ -0,0 +1,52 @@
#include "encodings.h"
const char EAN_13_STRUCTURE_CODES[10][6] = {
"LLLLLL",
"LLGLGG",
"LLGGLG",
"LLGGGL",
"LGLLGG",
"LGGLLG",
"LGGGLL",
"LGLGLG",
"LGLGGL",
"LGGLGL"};
const char UPC_EAN_L_CODES[10][8] = {
"0001101", // 0
"0011001", // 1
"0010011", // 2
"0111101", // 3
"0100011", // 4
"0110001", // 5
"0101111", // 6
"0111011", // 7
"0110111", // 8
"0001011" // 9
};
const char EAN_G_CODES[10][8] = {
"0100111", // 0
"0110011", // 1
"0011011", // 2
"0100001", // 3
"0011101", // 4
"0111001", // 5
"0000101", // 6
"0010001", // 7
"0001001", // 8
"0010111" // 9
};
const char UPC_EAN_R_CODES[10][8] = {
"1110010", // 0
"1100110", // 1
"1101100", // 2
"1000010", // 3
"1011100", // 4
"1001110", // 5
"1010000", // 6
"1000100", // 7
"1001000", // 8
"1110100" // 9
};

View file

@ -0,0 +1,6 @@
#pragma once
extern const char EAN_13_STRUCTURE_CODES[10][6];
extern const char UPC_EAN_L_CODES[10][8];
extern const char EAN_G_CODES[10][8];
extern const char UPC_EAN_R_CODES[10][8];

Binary file not shown.

After

Width:  |  Height:  |  Size: 161 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -0,0 +1,510 @@
#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;
}

View file

@ -0,0 +1,23 @@
#pragma once
#include <gui/view.h>
typedef struct BarcodeApp BarcodeApp;
typedef struct {
View* view;
BarcodeApp* barcode_app;
} Barcode;
typedef struct {
FuriString* file_path;
BarcodeData* data;
} BarcodeModel;
Barcode* barcode_view_allocate(BarcodeApp* barcode_app);
void barcode_free_model(Barcode* barcode);
void barcode_free(Barcode* barcode);
View* barcode_get_view(Barcode* barcode);

View file

@ -0,0 +1,494 @@
#include "../barcode_app.h"
#include "create_view.h"
#include <math.h>
#define LINE_HEIGHT 16
#define TEXT_PADDING 4
#define TOTAL_MENU_ITEMS 5
typedef enum {
TypeMenuItem,
FileNameMenuItem,
BarcodeDataMenuItem,
SaveMenuButton,
DeleteMenuButton
} MenuItems;
/**
* Took this function from blackjack
* @author @teeebor
*/
void draw_menu_item(
Canvas* const canvas,
const char* text,
const char* value,
int y,
bool left_caret,
bool right_caret,
bool selected) {
UNUSED(selected);
if(y < 0 || y >= 64) {
return;
}
if(selected) {
canvas_set_color(canvas, ColorBlack);
canvas_draw_box(canvas, 0, y, 123, LINE_HEIGHT);
canvas_set_color(canvas, ColorWhite);
}
canvas_draw_str_aligned(canvas, 4, y + TEXT_PADDING, AlignLeft, AlignTop, text);
if(left_caret) {
canvas_draw_str_aligned(canvas, 60, y + TEXT_PADDING, AlignLeft, AlignTop, "<");
}
canvas_draw_str_aligned(canvas, 90, y + TEXT_PADDING, AlignCenter, AlignTop, value);
if(right_caret) {
canvas_draw_str_aligned(canvas, 120, y + TEXT_PADDING, AlignRight, AlignTop, ">");
}
canvas_set_color(canvas, ColorBlack);
}
void draw_button(Canvas* const canvas, const char* text, int y, bool selected) {
if(selected) {
canvas_set_color(canvas, ColorBlack);
canvas_draw_box(canvas, 0, y, 123, LINE_HEIGHT);
canvas_set_color(canvas, ColorWhite);
}
canvas_draw_str_aligned(canvas, 64, y + TEXT_PADDING, AlignCenter, AlignTop, text);
canvas_set_color(canvas, ColorBlack);
}
static void app_draw_callback(Canvas* canvas, void* ctx) {
furi_assert(ctx);
CreateViewModel* create_view_model = ctx;
BarcodeTypeObj* type_obj = create_view_model->barcode_type;
if(create_view_model->barcode_type == NULL) {
return;
}
BarcodeType selected_type = type_obj->type;
int selected_menu_item = create_view_model->selected_menu_item;
int total_menu_items = create_view_model->mode == EditMode ? TOTAL_MENU_ITEMS :
TOTAL_MENU_ITEMS - 1;
int startY = 0;
//the menu items index that is/would be in view
//int current_last_menu_item = selected_menu_item + 3;
if(selected_menu_item > 1) {
int offset = 2;
if(selected_menu_item + offset > total_menu_items) {
offset = 3;
}
startY -= (LINE_HEIGHT * (selected_menu_item - offset));
}
//ensure that the scroll height is atleast 1
int scrollHeight = ceil(64.0 / total_menu_items);
int scrollPos = scrollHeight * selected_menu_item;
canvas_set_color(canvas, ColorBlack);
//draw the scroll bar box
canvas_draw_box(canvas, 125, scrollPos, 3, scrollHeight);
//draw the scroll bar track
canvas_draw_box(canvas, 126, 0, 1, 64);
draw_menu_item(
canvas,
"Type",
type_obj->name,
TypeMenuItem * LINE_HEIGHT + startY,
selected_type > 0,
selected_type < NUMBER_OF_BARCODE_TYPES - 2,
selected_menu_item == TypeMenuItem);
draw_menu_item(
canvas,
"Name",
furi_string_empty(create_view_model->file_name) ?
"--" :
furi_string_get_cstr(create_view_model->file_name),
FileNameMenuItem * LINE_HEIGHT + startY,
false,
false,
selected_menu_item == FileNameMenuItem);
draw_menu_item(
canvas,
"Data",
furi_string_empty(create_view_model->barcode_data) ?
"--" :
furi_string_get_cstr(create_view_model->barcode_data),
BarcodeDataMenuItem * LINE_HEIGHT + startY,
false,
false,
selected_menu_item == BarcodeDataMenuItem);
draw_button(
canvas,
"Save",
SaveMenuButton * LINE_HEIGHT + startY,
selected_menu_item == SaveMenuButton);
if(create_view_model->mode == EditMode) {
draw_button(
canvas,
"Delete",
DeleteMenuButton * LINE_HEIGHT + startY,
selected_menu_item == DeleteMenuButton);
}
}
void text_input_callback(void* ctx) {
CreateView* create_view_object = ctx;
with_view_model(
create_view_object->view,
CreateViewModel * model,
{
if(create_view_object->setter == FileNameSetter) {
furi_string_set_str(model->file_name, create_view_object->input);
}
if(create_view_object->setter == BarcodeDataSetter) {
furi_string_set_str(model->barcode_data, create_view_object->input);
}
},
true);
view_dispatcher_switch_to_view(
create_view_object->barcode_app->view_dispatcher, CreateBarcodeView);
}
static bool app_input_callback(InputEvent* input_event, void* ctx) {
furi_assert(ctx);
if(input_event->key == InputKeyBack) {
return false;
}
CreateView* create_view_object = ctx;
//get the currently selected menu item from the model
int selected_menu_item = 0;
BarcodeTypeObj* barcode_type = NULL;
FuriString* file_name;
FuriString* barcode_data;
CreateMode mode;
with_view_model(
create_view_object->view,
CreateViewModel * model,
{
selected_menu_item = model->selected_menu_item;
barcode_type = model->barcode_type;
file_name = model->file_name;
barcode_data = model->barcode_data;
mode = model->mode;
},
true);
int total_menu_items = mode == EditMode ? TOTAL_MENU_ITEMS : TOTAL_MENU_ITEMS - 1;
if(input_event->type == InputTypePress) {
if(input_event->key == InputKeyUp && selected_menu_item > 0) {
selected_menu_item--;
} else if(input_event->key == InputKeyDown && selected_menu_item < total_menu_items - 1) {
selected_menu_item++;
} else if(input_event->key == InputKeyLeft) {
if(selected_menu_item == TypeMenuItem && barcode_type != NULL) { //Select Barcode Type
if(barcode_type->type > 0) {
barcode_type = barcode_type_objs[barcode_type->type - 1];
}
}
} else if(input_event->key == InputKeyRight) {
if(selected_menu_item == TypeMenuItem && barcode_type != NULL) { //Select Barcode Type
if(barcode_type->type < NUMBER_OF_BARCODE_TYPES - 2) {
barcode_type = barcode_type_objs[barcode_type->type + 1];
}
}
} else if(input_event->key == InputKeyOk) {
if(selected_menu_item == FileNameMenuItem && barcode_type != NULL) {
create_view_object->setter = FileNameSetter;
snprintf(
create_view_object->input,
sizeof(create_view_object->input),
"%s",
furi_string_get_cstr(file_name));
text_input_set_result_callback(
create_view_object->barcode_app->text_input,
text_input_callback,
create_view_object,
create_view_object->input,
TEXT_BUFFER_SIZE - BARCODE_EXTENSION_LENGTH, //remove the barcode length
//clear default text
false);
text_input_set_header_text(
create_view_object->barcode_app->text_input, "File Name");
view_dispatcher_switch_to_view(
create_view_object->barcode_app->view_dispatcher, TextInputView);
}
if(selected_menu_item == BarcodeDataMenuItem && barcode_type != NULL) {
create_view_object->setter = BarcodeDataSetter;
snprintf(
create_view_object->input,
sizeof(create_view_object->input),
"%s",
furi_string_get_cstr(barcode_data));
text_input_set_result_callback(
create_view_object->barcode_app->text_input,
text_input_callback,
create_view_object,
create_view_object->input,
TEXT_BUFFER_SIZE,
//clear default text
false);
text_input_set_header_text(
create_view_object->barcode_app->text_input, "Barcode Data");
view_dispatcher_switch_to_view(
create_view_object->barcode_app->view_dispatcher, TextInputView);
}
if(selected_menu_item == SaveMenuButton && barcode_type != NULL) {
save_barcode(create_view_object);
}
if(selected_menu_item == DeleteMenuButton && barcode_type != NULL) {
if(mode == EditMode) {
remove_barcode(create_view_object);
} else if(mode == NewMode) {
view_dispatcher_switch_to_view(
create_view_object->barcode_app->view_dispatcher, MainMenuView);
}
}
}
}
//change the currently selected menu item
with_view_model(
create_view_object->view,
CreateViewModel * model,
{
model->selected_menu_item = selected_menu_item;
model->barcode_type = barcode_type;
},
true);
return true;
}
CreateView* create_view_allocate(BarcodeApp* barcode_app) {
furi_assert(barcode_app);
CreateView* create_view_object = malloc(sizeof(CreateView));
create_view_object->view = view_alloc();
create_view_object->barcode_app = barcode_app;
view_set_context(create_view_object->view, create_view_object);
view_allocate_model(create_view_object->view, ViewModelTypeLocking, sizeof(CreateViewModel));
view_set_draw_callback(create_view_object->view, app_draw_callback);
view_set_input_callback(create_view_object->view, app_input_callback);
return create_view_object;
}
void create_view_free_model(CreateView* create_view_object) {
with_view_model(
create_view_object->view,
CreateViewModel * model,
{
if(model->file_path != NULL) {
furi_string_free(model->file_path);
}
if(model->file_name != NULL) {
furi_string_free(model->file_name);
}
if(model->barcode_data != NULL) {
furi_string_free(model->barcode_data);
}
},
true);
}
void remove_barcode(CreateView* create_view_object) {
Storage* storage = furi_record_open(RECORD_STORAGE);
bool success = false;
with_view_model(
create_view_object->view,
CreateViewModel * model,
{
FURI_LOG_I(TAG, "Attempting to remove file");
if(model->file_path != NULL) {
FURI_LOG_I(TAG, "Removing File: %s", furi_string_get_cstr(model->file_path));
if(storage_simply_remove(storage, furi_string_get_cstr(model->file_path))) {
FURI_LOG_I(
TAG,
"File: \"%s\" was successfully removed",
furi_string_get_cstr(model->file_path));
success = true;
} else {
FURI_LOG_E(TAG, "Unable to remove file!");
success = false;
}
} else {
FURI_LOG_E(TAG, "Could not remove barcode file");
success = false;
}
},
true);
furi_record_close(RECORD_STORAGE);
with_view_model(
create_view_object->barcode_app->message_view->view,
MessageViewModel * model,
{
if(success) {
model->message = "File Deleted";
} else {
model->message = "Could not delete file";
}
},
true);
view_dispatcher_switch_to_view(
create_view_object->barcode_app->view_dispatcher, MessageErrorView);
}
void save_barcode(CreateView* create_view_object) {
BarcodeTypeObj* barcode_type = NULL;
FuriString* file_path; //this may be empty
FuriString* file_name;
FuriString* barcode_data;
CreateMode mode;
with_view_model(
create_view_object->view,
CreateViewModel * model,
{
file_path = model->file_path;
file_name = model->file_name;
barcode_data = model->barcode_data;
barcode_type = model->barcode_type;
mode = model->mode;
},
true);
if(file_name == NULL || furi_string_empty(file_name)) {
FURI_LOG_E(TAG, "File Name cannot be empty");
return;
}
if(barcode_data == NULL || furi_string_empty(barcode_data)) {
FURI_LOG_E(TAG, "Barcode Data cannot be empty");
return;
}
if(barcode_type == NULL) {
FURI_LOG_E(TAG, "Type not defined");
return;
}
bool success = false;
FuriString* full_file_path = furi_string_alloc_set(DEFAULT_USER_BARCODES);
furi_string_push_back(full_file_path, '/');
furi_string_cat(full_file_path, file_name);
furi_string_cat_str(full_file_path, BARCODE_EXTENSION);
Storage* storage = furi_record_open(RECORD_STORAGE);
if(mode == EditMode) {
if(!furi_string_empty(file_path)) {
if(!furi_string_equal(file_path, full_file_path)) {
FS_Error error = storage_common_rename(
storage,
furi_string_get_cstr(file_path),
furi_string_get_cstr(full_file_path));
if(error != FSE_OK) {
FURI_LOG_E(TAG, "Rename error: %s", storage_error_get_desc(error));
} else {
FURI_LOG_I(TAG, "Rename Success");
}
}
}
}
FlipperFormat* ff = flipper_format_file_alloc(storage);
FURI_LOG_I(TAG, "Saving Barcode to: %s", furi_string_get_cstr(full_file_path));
bool file_opened_status = false;
if(mode == NewMode) {
file_opened_status =
flipper_format_file_open_new(ff, furi_string_get_cstr(full_file_path));
} else if(mode == EditMode) {
file_opened_status =
flipper_format_file_open_always(ff, furi_string_get_cstr(full_file_path));
}
if(file_opened_status) {
// Filetype: Barcode
// Version: 1
// # Types - UPC-A, EAN-8, EAN-13, CODE-39
// Type: CODE-39
// Data: AB
flipper_format_write_string_cstr(ff, "Filetype", "Barcode");
flipper_format_write_string_cstr(ff, "Version", FILE_VERSION);
flipper_format_write_comment_cstr(
ff, "Types - UPC-A, EAN-8, EAN-13, CODE-39, CODE-128, Codabar");
flipper_format_write_string_cstr(ff, "Type", barcode_type->name);
flipper_format_write_string_cstr(ff, "Data", furi_string_get_cstr(barcode_data));
success = true;
} else {
FURI_LOG_E(TAG, "Save error");
success = false;
}
furi_string_free(full_file_path);
flipper_format_free(ff);
furi_record_close(RECORD_STORAGE);
with_view_model(
create_view_object->barcode_app->message_view->view,
MessageViewModel * model,
{
if(success) {
model->message = "File Saved!";
} else {
model->message = "A saving error has occurred";
}
},
true);
view_dispatcher_switch_to_view(
create_view_object->barcode_app->view_dispatcher, MessageErrorView);
}
void create_view_free(CreateView* create_view_object) {
furi_assert(create_view_object);
create_view_free_model(create_view_object);
view_free(create_view_object->view);
free(create_view_object);
}
View* create_get_view(CreateView* create_view_object) {
furi_assert(create_view_object);
return create_view_object->view;
}

View file

@ -0,0 +1,46 @@
#pragma once
#include <gui/view.h>
typedef struct BarcodeApp BarcodeApp;
typedef enum {
FileNameSetter,
BarcodeDataSetter
} InputSetter; //what value to set for the text input view
typedef enum {
EditMode,
NewMode
} CreateMode;
typedef struct {
View* view;
BarcodeApp* barcode_app;
InputSetter setter;
char input[TEXT_BUFFER_SIZE];
} CreateView;
typedef struct {
int selected_menu_item;
CreateMode mode;
BarcodeTypeObj* barcode_type;
FuriString* file_path; //the current file that is opened
FuriString* file_name;
FuriString* barcode_data;
} CreateViewModel;
CreateView* create_view_allocate(BarcodeApp* barcode_app);
void remove_barcode(CreateView* create_view_object);
void save_barcode(CreateView* create_view_object);
void create_view_free_model(CreateView* create_view_object);
void create_view_free(CreateView* create_view_object);
View* create_get_view(CreateView* create_view_object);

View file

@ -0,0 +1,66 @@
#include "../barcode_app.h"
#include "message_view.h"
static void app_draw_callback(Canvas* canvas, void* ctx) {
furi_assert(ctx);
MessageViewModel* message_view_model = ctx;
canvas_clear(canvas);
if(message_view_model->message != NULL) {
canvas_draw_str_aligned(
canvas, 62, 30, AlignCenter, AlignCenter, message_view_model->message);
}
canvas_set_color(canvas, ColorBlack);
canvas_draw_box(canvas, 100, 52, 28, 12);
canvas_set_color(canvas, ColorWhite);
canvas_draw_str_aligned(canvas, 114, 58, AlignCenter, AlignCenter, "OK");
}
static bool app_input_callback(InputEvent* input_event, void* ctx) {
furi_assert(ctx);
MessageView* message_view_object = ctx;
if(input_event->key == InputKeyBack) {
view_dispatcher_switch_to_view(
message_view_object->barcode_app->view_dispatcher, MainMenuView);
}
if(input_event->type == InputTypeShort) {
if(input_event->key == InputKeyOk) {
view_dispatcher_switch_to_view(
message_view_object->barcode_app->view_dispatcher, MainMenuView);
}
}
return true;
}
MessageView* message_view_allocate(BarcodeApp* barcode_app) {
furi_assert(barcode_app);
MessageView* message_view_object = malloc(sizeof(MessageView));
message_view_object->view = view_alloc();
message_view_object->barcode_app = barcode_app;
view_set_context(message_view_object->view, message_view_object);
view_allocate_model(message_view_object->view, ViewModelTypeLocking, sizeof(MessageViewModel));
view_set_draw_callback(message_view_object->view, app_draw_callback);
view_set_input_callback(message_view_object->view, app_input_callback);
return message_view_object;
}
void message_view_free(MessageView* message_view_object) {
furi_assert(message_view_object);
view_free(message_view_object->view);
free(message_view_object);
}
View* message_get_view(MessageView* message_view_object) {
furi_assert(message_view_object);
return message_view_object->view;
}

View file

@ -0,0 +1,22 @@
#pragma once
#include <gui/view.h>
typedef struct BarcodeApp BarcodeApp;
typedef struct {
View* view;
BarcodeApp* barcode_app;
} MessageView;
typedef struct {
const char* message;
} MessageViewModel;
MessageView* message_view_allocate(BarcodeApp* barcode_app);
void message_view_free_model(MessageView* message_view_object);
void message_view_free(MessageView* message_view_object);
View* message_get_view(MessageView* message_view_object);

View file

@ -1,17 +0,0 @@
App(
appid="barcode_generator",
name="Barcode Generator",
apptype=FlipperAppType.EXTERNAL,
entry_point="barcode_generator_app",
requires=[
"gui",
"dialogs",
],
stack_size=1 * 1024,
order=50,
fap_icon="barcode_10px.png",
fap_category="Tools",
fap_author="@xMasterX & @msvsergey & @McAzzaMan",
fap_version="1.0",
fap_description="App displays Barcode on flipper screen and allows to edit it",
)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

View file

@ -1,447 +0,0 @@
#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;
}

View file

@ -1,115 +0,0 @@
#pragma once
#include <furi.h>
#include <gui/gui.h>
#include <input/input.h>
#include <stdlib.h>
#include <storage/storage.h>
#include <toolbox/saved_struct.h>
#define BARCODE_SETTINGS_FILE_NAME "apps/Tools/barcodegen.save"
#define BARCODE_SETTINGS_VER (1)
#define BARCODE_SETTINGS_PATH EXT_PATH(BARCODE_SETTINGS_FILE_NAME)
#define BARCODE_SETTINGS_MAGIC (0xC2)
#define SAVE_BARCODE_SETTINGS(x) \
saved_struct_save( \
BARCODE_SETTINGS_PATH, \
(x), \
sizeof(BarcodeState), \
BARCODE_SETTINGS_MAGIC, \
BARCODE_SETTINGS_VER)
#define LOAD_BARCODE_SETTINGS(x) \
saved_struct_load( \
BARCODE_SETTINGS_PATH, \
(x), \
sizeof(BarcodeState), \
BARCODE_SETTINGS_MAGIC, \
BARCODE_SETTINGS_VER)
#define BARCODE_HEIGHT 50
#define BARCODE_Y_START 3
#define BARCODE_TEXT_OFFSET 9
#define BARCODE_MAX_LENS 13
#define NUMBER_OF_BARCODE_TYPES 3
#define MENU_INDEX_VIEW 0
#define MENU_INDEX_EDIT 1
#define MENU_INDEX_PARITY 2
#define MENU_INDEX_TYPE 3
typedef enum {
EventTypeTick,
EventTypeKey,
} EventType;
typedef struct {
EventType type;
InputEvent input;
} PluginEvent;
typedef enum {
ViewMode,
EditMode,
MenuMode,
} Mode;
typedef enum {
BarEncodingTypeLeft,
BarEncodingTypeRight,
BarEncodingTypeG,
} BarEncodingType;
typedef enum {
BarTypeEAN8,
BarTypeUPCA,
BarTypeEAN13,
} BarType;
typedef struct {
char* name;
int numberOfDigits;
int startPos;
BarType bartype;
} BarcodeType;
typedef struct {
int barcodeNumeral[BARCODE_MAX_LENS]; //The current barcode number
bool doParityCalculation; //Should do parity check?
int barcodeTypeIndex;
} BarcodeState;
typedef struct {
FuriMutex* mutex;
BarcodeState barcode_state;
int editingIndex; //The index of the editing symbol
int menuIndex; //The index of the menu cursor
Mode mode; //View, edit or menu
} PluginState;
static const int DIGITS[10][4] = {
{3, 2, 1, 1},
{2, 2, 2, 1},
{2, 1, 2, 2},
{1, 4, 1, 1},
{1, 1, 3, 2},
{1, 2, 3, 1},
{1, 1, 1, 4},
{1, 3, 1, 2},
{1, 2, 1, 3},
{3, 1, 1, 2},
};
static const uint8_t EAN13ENCODE[10] = {
0b000000,
0b110100,
0b101100,
0b011100,
0b110010,
0b100110,
0b001110,
0b101010,
0b011010,
0b010110,
};

View file

@ -0,0 +1,22 @@
# alternates between bars and spaces, always begins with bar
# 0 for narrow, 1 for wide
0: 0000011
1: 0000110
2: 0001001
3: 1100000
4: 0010010
5: 1000010
6: 0100001
7: 0100100
8: 0110000
9: 1001000
-: 0001100
$: 0011000
:: 1000101
/: 1010001
.: 1010100
+: 0010101
A: 0011010
B: 0101001
C: 0001011
D: 0001110

View file

@ -0,0 +1,202 @@
: 00
!: 01
": 02
#: 03
$: 04
%: 05
&: 06
': 07
(: 08
): 09
*: 10
+: 11
,: 12
-: 13
.: 14
/: 15
0: 16
1: 17
2: 18
3: 19
4: 20
5: 21
6: 22
7: 23
8: 24
9: 25
:: 26
;: 27
<: 28
=: 29
>: 30
?: 31
@: 32
A: 33
B: 34
C: 35
D: 36
E: 37
F: 38
G: 39
H: 40
I: 41
J: 42
K: 43
L: 44
M: 45
N: 46
O: 47
P: 48
Q: 49
R: 50
S: 51
T: 52
U: 53
V: 54
W: 55
X: 56
Y: 57
Z: 58
[: 59
\: 60
]: 61
^: 62
_: 63
`: 64
a: 65
b: 66
c: 67
d: 68
e: 69
f: 70
g: 71
h: 72
i: 73
j: 74
k: 75
l: 76
m: 77
n: 78
o: 79
p: 80
q: 81
r: 82
s: 83
t: 84
u: 85
v: 86
w: 87
x: 88
y: 89
z: 90
{: 91
|: 92
}: 93
~: 94
00: 11011001100
01: 11001101100
02: 11001100110
03: 10010011000
04: 10010001100
05: 10001001100
06: 10011001000
07: 10011000100
08: 10001100100
09: 11001001000
10: 11001000100
11: 11000100100
12: 10110011100
13: 10011011100
14: 10011001110
15: 10111001100
16: 10011101100
17: 10011100110
18: 11001110010
19: 11001011100
20: 11001001110
21: 11011100100
22: 11001110100
23: 11101101110
24: 11101001100
25: 11100101100
26: 11100100110
27: 11101100100
28: 11100110100
29: 11100110010
30: 11011011000
31: 11011000110
32: 11000110110
33: 10100011000
34: 10001011000
35: 10001000110
36: 10110001000
37: 10001101000
38: 10001100010
39: 11010001000
40: 11000101000
41: 11000100010
42: 10110111000
43: 10110001110
44: 10001101110
45: 10111011000
46: 10111000110
47: 10001110110
48: 11101110110
49: 11010001110
50: 11000101110
51: 11011101000
52: 11011100010
53: 11011101110
54: 11101011000
55: 11101000110
56: 11100010110
57: 11101101000
58: 11101100010
59: 11100011010
60: 11101111010
61: 11001000010
62: 11110001010
63: 10100110000
64: 10100001100
65: 10010110000
66: 10010000110
67: 10000101100
68: 10000100110
69: 10110010000
70: 10110000100
71: 10011010000
72: 10011000010
73: 10000110100
74: 10000110010
75: 11000010010
76: 11001010000
77: 11110111010
78: 11000010100
79: 10001111010
80: 10100111100
81: 10010111100
82: 10010011110
83: 10111100100
84: 10011110100
85: 10011110010
86: 11110100100
87: 11110010100
88: 11110010010
89: 11011011110
90: 11011110110
91: 11110110110
92: 10101111000
93: 10100011110
94: 10001011110
95: 10111101000
96: 10111100010
97: 11110101000
98: 11110100010
99: 10111011110
100: 10111101110
101: 11101011110
102: 11110101110
103: 11010000100
104: 11010010000
105: 11010011100

View file

@ -0,0 +1,106 @@
00: 11011001100
01: 11001101100
02: 11001100110
03: 10010011000
04: 10010001100
05: 10001001100
06: 10011001000
07: 10011000100
08: 10001100100
09: 11001001000
10: 11001000100
11: 11000100100
12: 10110011100
13: 10011011100
14: 10011001110
15: 10111001100
16: 10011101100
17: 10011100110
18: 11001110010
19: 11001011100
20: 11001001110
21: 11011100100
22: 11001110100
23: 11101101110
24: 11101001100
25: 11100101100
26: 11100100110
27: 11101100100
28: 11100110100
29: 11100110010
30: 11011011000
31: 11011000110
32: 11000110110
33: 10100011000
34: 10001011000
35: 10001000110
36: 10110001000
37: 10001101000
38: 10001100010
39: 11010001000
40: 11000101000
41: 11000100010
42: 10110111000
43: 10110001110
44: 10001101110
45: 10111011000
46: 10111000110
47: 10001110110
48: 11101110110
49: 11010001110
50: 11000101110
51: 11011101000
52: 11011100010
53: 11011101110
54: 11101011000
55: 11101000110
56: 11100010110
57: 11101101000
58: 11101100010
59: 11100011010
60: 11101111010
61: 11001000010
62: 11110001010
63: 10100110000
64: 10100001100
65: 10010110000
66: 10010000110
67: 10000101100
68: 10000100110
69: 10110010000
70: 10110000100
71: 10011010000
72: 10011000010
73: 10000110100
74: 10000110010
75: 11000010010
76: 11001010000
77: 11110111010
78: 11000010100
79: 10001111010
80: 10100111100
81: 10010111100
82: 10010011110
83: 10111100100
84: 10011110100
85: 10011110010
86: 11110100100
87: 11110010100
88: 11110010010
89: 11011011110
90: 11011110110
91: 11110110110
92: 10101111000
93: 10100011110
94: 10001011110
95: 10111101000
96: 10111100010
97: 11110101000
98: 11110100010
99: 10111011110
100: 10111101110
101: 11101011110
102: 11110101110
103: 11010000100
104: 11010010000
105: 11010011100

View file

@ -0,0 +1,44 @@
0: 000110100
1: 100100001
2: 001100001
3: 101100000
4: 000110001
5: 100110000
6: 001110000
7: 000100101
8: 100100100
9: 001100100
A: 100001001
B: 001001001
C: 101001000
D: 000011001
E: 100011000
F: 001011000
G: 000001101
H: 100001100
I: 001001100
J: 000011100
K: 100000011
L: 001000011
M: 101000010
N: 000010011
O: 100010010
P: 001010010
Q: 000000111
R: 100000110
S: 001000110
T: 000010110
U: 110000001
V: 011000001
W: 111000000
X: 010010001
Y: 110010000
Z: 011010000
-: 010000101
.: 110000100
: 011000100
*: 010010100
$: 010101000
/: 010100010
+: 010001010
%: 000101010