diff --git a/ReadMe.md b/ReadMe.md
index 28c580a3c..b589e164e 100644
--- a/ReadMe.md
+++ b/ReadMe.md
@@ -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)
diff --git a/applications/external/barcode_gen/LICENSE b/applications/external/barcode_gen/LICENSE
new file mode 100644
index 000000000..4c02d8221
--- /dev/null
+++ b/applications/external/barcode_gen/LICENSE
@@ -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.
\ No newline at end of file
diff --git a/applications/external/barcode_gen/README.md b/applications/external/barcode_gen/README.md
new file mode 100644
index 000000000..ec944cb26
--- /dev/null
+++ b/applications/external/barcode_gen/README.md
@@ -0,0 +1,88 @@
+
+
Barcode Generator
+
+
+A barcode generator for the Flipper Zero that supports **UPC-A**, **EAN-8**, **EAN-13**, **Code-39**, **Codabar**, and **Code-128**[1]
+
+
+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)
+
+
+
+### 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
+
+
+
+
+
+
+## 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
diff --git a/applications/external/barcode_gen/application.fam b/applications/external/barcode_gen/application.fam
new file mode 100644
index 000000000..371e52c04
--- /dev/null
+++ b/applications/external/barcode_gen/application.fam
@@ -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",
+)
diff --git a/applications/external/barcode_gen/barcode_app.c b/applications/external/barcode_gen/barcode_app.c
new file mode 100644
index 000000000..99e5769d2
--- /dev/null
+++ b/applications/external/barcode_gen/barcode_app.c
@@ -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;
+}
diff --git a/applications/external/barcode_gen/barcode_app.h b/applications/external/barcode_gen/barcode_app.h
new file mode 100644
index 000000000..3150bff1f
--- /dev/null
+++ b/applications/external/barcode_gen/barcode_app.h
@@ -0,0 +1,91 @@
+#pragma once
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#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);
diff --git a/applications/external/barcode_gen/barcode_utils.c b/applications/external/barcode_gen/barcode_utils.c
new file mode 100644
index 000000000..31274c1fe
--- /dev/null
+++ b/applications/external/barcode_gen/barcode_utils.c
@@ -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";
+ };
+}
diff --git a/applications/external/barcode_gen/barcode_utils.h b/applications/external/barcode_gen/barcode_utils.h
new file mode 100644
index 000000000..0a27785cf
--- /dev/null
+++ b/applications/external/barcode_gen/barcode_utils.h
@@ -0,0 +1,55 @@
+
+#pragma once
+#include
+#include
+
+#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);
diff --git a/applications/external/barcode_gen/barcode_validator.c b/applications/external/barcode_gen/barcode_validator.c
new file mode 100644
index 000000000..cb493f3e9
--- /dev/null
+++ b/applications/external/barcode_gen/barcode_validator.c
@@ -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);
+}
diff --git a/applications/external/barcode_gen/barcode_validator.h b/applications/external/barcode_gen/barcode_validator.h
new file mode 100644
index 000000000..2138124dd
--- /dev/null
+++ b/applications/external/barcode_gen/barcode_validator.h
@@ -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);
diff --git a/applications/external/barcode_gen/encodings.c b/applications/external/barcode_gen/encodings.c
new file mode 100644
index 000000000..764fde796
--- /dev/null
+++ b/applications/external/barcode_gen/encodings.c
@@ -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
+};
\ No newline at end of file
diff --git a/applications/external/barcode_gen/encodings.h b/applications/external/barcode_gen/encodings.h
new file mode 100644
index 000000000..c5b8d61ff
--- /dev/null
+++ b/applications/external/barcode_gen/encodings.h
@@ -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];
\ No newline at end of file
diff --git a/applications/external/barcode_gen/images/barcode_10.png b/applications/external/barcode_gen/images/barcode_10.png
new file mode 100644
index 000000000..32d4971ad
Binary files /dev/null and b/applications/external/barcode_gen/images/barcode_10.png differ
diff --git a/applications/external/barcode_gen/screenshots/Codabar Data Example.png b/applications/external/barcode_gen/screenshots/Codabar Data Example.png
new file mode 100644
index 000000000..907dfd901
Binary files /dev/null and b/applications/external/barcode_gen/screenshots/Codabar Data Example.png differ
diff --git a/applications/external/barcode_gen/screenshots/Creating Barcode.png b/applications/external/barcode_gen/screenshots/Creating Barcode.png
new file mode 100644
index 000000000..e976b5682
Binary files /dev/null and b/applications/external/barcode_gen/screenshots/Creating Barcode.png differ
diff --git a/applications/external/barcode_gen/screenshots/Flipper Barcode.png b/applications/external/barcode_gen/screenshots/Flipper Barcode.png
new file mode 100644
index 000000000..a6758c621
Binary files /dev/null and b/applications/external/barcode_gen/screenshots/Flipper Barcode.png differ
diff --git a/applications/external/barcode_gen/screenshots/Flipper Box Barcode.png b/applications/external/barcode_gen/screenshots/Flipper Box Barcode.png
new file mode 100644
index 000000000..8dbd7d2a9
Binary files /dev/null and b/applications/external/barcode_gen/screenshots/Flipper Box Barcode.png differ
diff --git a/applications/external/barcode_gen/views/barcode_view.c b/applications/external/barcode_gen/views/barcode_view.c
new file mode 100644
index 000000000..55ab52046
--- /dev/null
+++ b/applications/external/barcode_gen/views/barcode_view.c
@@ -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;
+}
diff --git a/applications/external/barcode_gen/views/barcode_view.h b/applications/external/barcode_gen/views/barcode_view.h
new file mode 100644
index 000000000..828428c08
--- /dev/null
+++ b/applications/external/barcode_gen/views/barcode_view.h
@@ -0,0 +1,23 @@
+#pragma once
+
+#include
+
+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);
diff --git a/applications/external/barcode_gen/views/create_view.c b/applications/external/barcode_gen/views/create_view.c
new file mode 100644
index 000000000..e4e489113
--- /dev/null
+++ b/applications/external/barcode_gen/views/create_view.c
@@ -0,0 +1,494 @@
+#include "../barcode_app.h"
+#include "create_view.h"
+#include
+
+#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;
+}
\ No newline at end of file
diff --git a/applications/external/barcode_gen/views/create_view.h b/applications/external/barcode_gen/views/create_view.h
new file mode 100644
index 000000000..6063786d9
--- /dev/null
+++ b/applications/external/barcode_gen/views/create_view.h
@@ -0,0 +1,46 @@
+#pragma once
+
+#include
+
+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);
diff --git a/applications/external/barcode_gen/views/message_view.c b/applications/external/barcode_gen/views/message_view.c
new file mode 100644
index 000000000..3a9aa90b3
--- /dev/null
+++ b/applications/external/barcode_gen/views/message_view.c
@@ -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;
+}
\ No newline at end of file
diff --git a/applications/external/barcode_gen/views/message_view.h b/applications/external/barcode_gen/views/message_view.h
new file mode 100644
index 000000000..33acc3d0c
--- /dev/null
+++ b/applications/external/barcode_gen/views/message_view.h
@@ -0,0 +1,22 @@
+#pragma once
+
+#include
+
+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);
diff --git a/applications/external/barcode_generator/application.fam b/applications/external/barcode_generator/application.fam
deleted file mode 100644
index 9bb44915c..000000000
--- a/applications/external/barcode_generator/application.fam
+++ /dev/null
@@ -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",
-)
diff --git a/applications/external/barcode_generator/barcode_10px.png b/applications/external/barcode_generator/barcode_10px.png
deleted file mode 100644
index 7c19c6656..000000000
Binary files a/applications/external/barcode_generator/barcode_10px.png and /dev/null differ
diff --git a/applications/external/barcode_generator/barcode_generator.c b/applications/external/barcode_generator/barcode_generator.c
deleted file mode 100644
index 2645bbcea..000000000
--- a/applications/external/barcode_generator/barcode_generator.c
+++ /dev/null
@@ -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;
-}
diff --git a/applications/external/barcode_generator/barcode_generator.h b/applications/external/barcode_generator/barcode_generator.h
deleted file mode 100644
index 9f2e10c16..000000000
--- a/applications/external/barcode_generator/barcode_generator.h
+++ /dev/null
@@ -1,115 +0,0 @@
-#pragma once
-
-#include
-#include
-#include
-#include
-#include
-#include
-
-#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,
-};
\ No newline at end of file
diff --git a/assets/resources/apps_data/barcode_data/codabar_encodings.txt b/assets/resources/apps_data/barcode_data/codabar_encodings.txt
new file mode 100644
index 000000000..5f0684cbd
--- /dev/null
+++ b/assets/resources/apps_data/barcode_data/codabar_encodings.txt
@@ -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
\ No newline at end of file
diff --git a/assets/resources/apps_data/barcode_data/code128_encodings.txt b/assets/resources/apps_data/barcode_data/code128_encodings.txt
new file mode 100644
index 000000000..394a34520
--- /dev/null
+++ b/assets/resources/apps_data/barcode_data/code128_encodings.txt
@@ -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
\ No newline at end of file
diff --git a/assets/resources/apps_data/barcode_data/code128c_encodings.txt b/assets/resources/apps_data/barcode_data/code128c_encodings.txt
new file mode 100644
index 000000000..75cc71135
--- /dev/null
+++ b/assets/resources/apps_data/barcode_data/code128c_encodings.txt
@@ -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
diff --git a/assets/resources/apps_data/barcode_data/code39_encodings.txt b/assets/resources/apps_data/barcode_data/code39_encodings.txt
new file mode 100644
index 000000000..a41ad16e9
--- /dev/null
+++ b/assets/resources/apps_data/barcode_data/code39_encodings.txt
@@ -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
\ No newline at end of file