remove base apps pack
12
.gitmodules
vendored
@@ -26,12 +26,6 @@
|
|||||||
[submodule "lib/cxxheaderparser"]
|
[submodule "lib/cxxheaderparser"]
|
||||||
path = lib/cxxheaderparser
|
path = lib/cxxheaderparser
|
||||||
url = https://github.com/robotpy/cxxheaderparser.git
|
url = https://github.com/robotpy/cxxheaderparser.git
|
||||||
[submodule "applications/external/dap_link/lib/free-dap"]
|
|
||||||
path = applications/external/dap_link/lib/free-dap
|
|
||||||
url = https://github.com/ataradov/free-dap.git
|
|
||||||
[submodule "applications/external/subbrute"]
|
|
||||||
path = applications/external/subbrute
|
|
||||||
url = https://github.com/DarkFlippers/flipperzero-subbrute.git
|
|
||||||
[submodule "lib/heatshrink"]
|
[submodule "lib/heatshrink"]
|
||||||
path = lib/heatshrink
|
path = lib/heatshrink
|
||||||
url = https://github.com/flipperdevices/heatshrink.git
|
url = https://github.com/flipperdevices/heatshrink.git
|
||||||
@@ -44,9 +38,3 @@
|
|||||||
[submodule "lib/stm32wb_copro"]
|
[submodule "lib/stm32wb_copro"]
|
||||||
path = lib/stm32wb_copro
|
path = lib/stm32wb_copro
|
||||||
url = https://github.com/flipperdevices/stm32wb_copro.git
|
url = https://github.com/flipperdevices/stm32wb_copro.git
|
||||||
[submodule "applications/external/multi_fuzzer"]
|
|
||||||
path = applications/external/multi_fuzzer
|
|
||||||
url = https://github.com/DarkFlippers/Multi_Fuzzer.git
|
|
||||||
[submodule "applications/external/totp/lib/wolfssl"]
|
|
||||||
path = applications/external/totp/lib/wolfssl
|
|
||||||
url = https://github.com/wolfSSL/wolfssl.git
|
|
||||||
|
|||||||
6
applications/external/application.fam
vendored
@@ -1,6 +0,0 @@
|
|||||||
# Placeholder
|
|
||||||
App(
|
|
||||||
appid="external_apps",
|
|
||||||
name="External apps bundle",
|
|
||||||
apptype=FlipperAppType.METAPACKAGE,
|
|
||||||
)
|
|
||||||
14
applications/external/arkanoid/application.fam
vendored
@@ -1,14 +0,0 @@
|
|||||||
App(
|
|
||||||
appid="arkanoid",
|
|
||||||
name="Arkanoid",
|
|
||||||
apptype=FlipperAppType.EXTERNAL,
|
|
||||||
entry_point="arkanoid_game_app",
|
|
||||||
requires=["gui"],
|
|
||||||
stack_size=1 * 1024,
|
|
||||||
order=30,
|
|
||||||
fap_icon="arkanoid_10px.png",
|
|
||||||
fap_category="Games",
|
|
||||||
fap_author="@xMasterX & @gotnull",
|
|
||||||
fap_version="1.0",
|
|
||||||
fap_description="Arkanoid Game",
|
|
||||||
)
|
|
||||||
BIN
applications/external/arkanoid/arkanoid_10px.png
vendored
|
Before Width: | Height: | Size: 1.6 KiB |
479
applications/external/arkanoid/arkanoid_game.c
vendored
@@ -1,479 +0,0 @@
|
|||||||
#include <furi.h>
|
|
||||||
#include <gui/gui.h>
|
|
||||||
#include <input/input.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <gui/view.h>
|
|
||||||
#include <notification/notification.h>
|
|
||||||
#include <notification/notification_messages.h>
|
|
||||||
#include <dolphin/dolphin.h>
|
|
||||||
|
|
||||||
#define TAG "Arkanoid"
|
|
||||||
|
|
||||||
#define FLIPPER_LCD_WIDTH 128
|
|
||||||
#define FLIPPER_LCD_HEIGHT 64
|
|
||||||
#define MAX_SPEED 3
|
|
||||||
|
|
||||||
typedef enum { EventTypeTick, EventTypeKey } EventType;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
//Brick Bounds used in collision detection
|
|
||||||
int leftBrick;
|
|
||||||
int rightBrick;
|
|
||||||
int topBrick;
|
|
||||||
int bottomBrick;
|
|
||||||
bool isHit[4][13]; //Array of if bricks are hit or not
|
|
||||||
} BrickState;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
int dx; //Initial movement of ball
|
|
||||||
int dy; //Initial movement of ball
|
|
||||||
int xb; //Balls starting possition
|
|
||||||
int yb; //Balls starting possition
|
|
||||||
bool released; //If the ball has been released by the player
|
|
||||||
//Ball Bounds used in collision detection
|
|
||||||
int leftBall;
|
|
||||||
int rightBall;
|
|
||||||
int topBall;
|
|
||||||
int bottomBall;
|
|
||||||
} BallState;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
FuriMutex* mutex;
|
|
||||||
BallState ball_state;
|
|
||||||
BrickState brick_state;
|
|
||||||
NotificationApp* notify;
|
|
||||||
unsigned int COLUMNS; //Columns of bricks
|
|
||||||
unsigned int ROWS; //Rows of bricks
|
|
||||||
bool initialDraw; //If the inital draw has happened
|
|
||||||
int xPaddle; //X position of paddle
|
|
||||||
char text[16]; //General string buffer
|
|
||||||
bool bounced; //Used to fix double bounce glitch
|
|
||||||
int lives; //Amount of lives
|
|
||||||
int level; //Current level
|
|
||||||
unsigned int score; //Score for the game
|
|
||||||
unsigned int brickCount; //Amount of bricks hit
|
|
||||||
int tick; //Tick counter
|
|
||||||
bool gameStarted; // Did the game start?
|
|
||||||
int speed; // Ball speed
|
|
||||||
} ArkanoidState;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
EventType type;
|
|
||||||
InputEvent input;
|
|
||||||
} GameEvent;
|
|
||||||
|
|
||||||
static const NotificationSequence sequence_short_sound = {
|
|
||||||
&message_note_c5,
|
|
||||||
&message_delay_50,
|
|
||||||
&message_sound_off,
|
|
||||||
NULL,
|
|
||||||
};
|
|
||||||
|
|
||||||
// generate number in range [min,max)
|
|
||||||
int rand_range(int min, int max) {
|
|
||||||
return min + rand() % (max - min);
|
|
||||||
}
|
|
||||||
|
|
||||||
void move_ball(Canvas* canvas, ArkanoidState* st) {
|
|
||||||
st->tick++;
|
|
||||||
|
|
||||||
int current_speed = abs(st->speed - 1 - MAX_SPEED);
|
|
||||||
if(st->tick % current_speed != 0 && st->tick % (current_speed + 1) != 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(st->ball_state.released) {
|
|
||||||
//Move ball
|
|
||||||
if(abs(st->ball_state.dx) == 2) {
|
|
||||||
st->ball_state.xb += st->ball_state.dx / 2;
|
|
||||||
// 2x speed is really 1.5 speed
|
|
||||||
if((st->tick / current_speed) % 2 == 0) st->ball_state.xb += st->ball_state.dx / 2;
|
|
||||||
} else {
|
|
||||||
st->ball_state.xb += st->ball_state.dx;
|
|
||||||
}
|
|
||||||
st->ball_state.yb = st->ball_state.yb + st->ball_state.dy;
|
|
||||||
|
|
||||||
//Set bounds
|
|
||||||
st->ball_state.leftBall = st->ball_state.xb;
|
|
||||||
st->ball_state.rightBall = st->ball_state.xb + 2;
|
|
||||||
st->ball_state.topBall = st->ball_state.yb;
|
|
||||||
st->ball_state.bottomBall = st->ball_state.yb + 2;
|
|
||||||
|
|
||||||
//Bounce off top edge
|
|
||||||
if(st->ball_state.yb <= 0) {
|
|
||||||
st->ball_state.yb = 2;
|
|
||||||
st->ball_state.dy = -st->ball_state.dy;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Lose a life if bottom edge hit
|
|
||||||
if(st->ball_state.yb >= FLIPPER_LCD_HEIGHT) {
|
|
||||||
canvas_draw_frame(canvas, st->xPaddle, FLIPPER_LCD_HEIGHT - 1, 11, 1);
|
|
||||||
st->xPaddle = 54;
|
|
||||||
st->ball_state.yb = 60;
|
|
||||||
st->ball_state.released = false;
|
|
||||||
st->lives--;
|
|
||||||
st->gameStarted = false;
|
|
||||||
|
|
||||||
if(rand_range(0, 2) == 0) {
|
|
||||||
st->ball_state.dx = 1;
|
|
||||||
} else {
|
|
||||||
st->ball_state.dx = -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Bounce off left side
|
|
||||||
if(st->ball_state.xb <= 0) {
|
|
||||||
st->ball_state.xb = 2;
|
|
||||||
st->ball_state.dx = -st->ball_state.dx;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Bounce off right side
|
|
||||||
if(st->ball_state.xb >= FLIPPER_LCD_WIDTH - 2) {
|
|
||||||
st->ball_state.xb = FLIPPER_LCD_WIDTH - 4;
|
|
||||||
st->ball_state.dx = -st->ball_state.dx;
|
|
||||||
// arduboy.tunes.tone(523, 250);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Bounce off paddle
|
|
||||||
if(st->ball_state.xb + 1 >= st->xPaddle && st->ball_state.xb <= st->xPaddle + 12 &&
|
|
||||||
st->ball_state.yb + 2 >= FLIPPER_LCD_HEIGHT - 1 &&
|
|
||||||
st->ball_state.yb <= FLIPPER_LCD_HEIGHT) {
|
|
||||||
st->ball_state.dy = -st->ball_state.dy;
|
|
||||||
st->ball_state.dx =
|
|
||||||
((st->ball_state.xb - (st->xPaddle + 6)) / 3); //Applies spin on the ball
|
|
||||||
// prevent straight bounce, but not prevent roguuemaster from stealing
|
|
||||||
if(st->ball_state.dx == 0) {
|
|
||||||
st->ball_state.dx = (rand_range(0, 2) == 1) ? 1 : -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Bounce off Bricks
|
|
||||||
for(unsigned int row = 0; row < st->ROWS; row++) {
|
|
||||||
for(unsigned int column = 0; column < st->COLUMNS; column++) {
|
|
||||||
if(!st->brick_state.isHit[row][column]) {
|
|
||||||
//Sets Brick bounds
|
|
||||||
st->brick_state.leftBrick = 10 * column;
|
|
||||||
st->brick_state.rightBrick = 10 * column + 10;
|
|
||||||
st->brick_state.topBrick = 6 * row + 1;
|
|
||||||
st->brick_state.bottomBrick = 6 * row + 7;
|
|
||||||
|
|
||||||
//If A collison has occured
|
|
||||||
if(st->ball_state.topBall <= st->brick_state.bottomBrick &&
|
|
||||||
st->ball_state.bottomBall >= st->brick_state.topBrick &&
|
|
||||||
st->ball_state.leftBall <= st->brick_state.rightBrick &&
|
|
||||||
st->ball_state.rightBall >= st->brick_state.leftBrick) {
|
|
||||||
st->score += st->level;
|
|
||||||
// Blink led when we hit some brick
|
|
||||||
notification_message(st->notify, &sequence_short_sound);
|
|
||||||
//notification_message(st->notify, &sequence_blink_white_100);
|
|
||||||
|
|
||||||
st->brickCount++;
|
|
||||||
st->brick_state.isHit[row][column] = true;
|
|
||||||
canvas_draw_frame(canvas, 10 * column, 2 + 6 * row, 8, 4);
|
|
||||||
|
|
||||||
//Vertical collision
|
|
||||||
if(st->ball_state.bottomBall > st->brick_state.bottomBrick ||
|
|
||||||
st->ball_state.topBall < st->brick_state.topBrick) {
|
|
||||||
//Only bounce once each ball move
|
|
||||||
if(!st->bounced) {
|
|
||||||
st->ball_state.dy = -st->ball_state.dy;
|
|
||||||
st->ball_state.yb += st->ball_state.dy;
|
|
||||||
st->bounced = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Hoizontal collision
|
|
||||||
if(st->ball_state.leftBall < st->brick_state.leftBrick ||
|
|
||||||
st->ball_state.rightBall > st->brick_state.rightBrick) {
|
|
||||||
//Only bounce once brick each ball move
|
|
||||||
if(!st->bounced) {
|
|
||||||
st->ball_state.dx = -st->ball_state.dx;
|
|
||||||
st->ball_state.xb += st->ball_state.dx;
|
|
||||||
st->bounced = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Reset Bounce
|
|
||||||
st->bounced = false;
|
|
||||||
} else {
|
|
||||||
//Ball follows paddle
|
|
||||||
st->ball_state.xb = st->xPaddle + 5;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void draw_lives(Canvas* canvas, ArkanoidState* arkanoid_state) {
|
|
||||||
if(arkanoid_state->lives == 3) {
|
|
||||||
canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 7);
|
|
||||||
canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 7);
|
|
||||||
canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 8);
|
|
||||||
canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 8);
|
|
||||||
|
|
||||||
canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 11);
|
|
||||||
canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 11);
|
|
||||||
canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 12);
|
|
||||||
canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 12);
|
|
||||||
|
|
||||||
canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 15);
|
|
||||||
canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 15);
|
|
||||||
canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 16);
|
|
||||||
canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 16);
|
|
||||||
} else if(arkanoid_state->lives == 2) {
|
|
||||||
canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 7);
|
|
||||||
canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 7);
|
|
||||||
canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 8);
|
|
||||||
canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 8);
|
|
||||||
|
|
||||||
canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 11);
|
|
||||||
canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 11);
|
|
||||||
canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 12);
|
|
||||||
canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 12);
|
|
||||||
} else {
|
|
||||||
canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 7);
|
|
||||||
canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 7);
|
|
||||||
canvas_draw_dot(canvas, 4, FLIPPER_LCD_HEIGHT - 8);
|
|
||||||
canvas_draw_dot(canvas, 3, FLIPPER_LCD_HEIGHT - 8);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void draw_score(Canvas* canvas, ArkanoidState* arkanoid_state) {
|
|
||||||
snprintf(arkanoid_state->text, sizeof(arkanoid_state->text), "%u", arkanoid_state->score);
|
|
||||||
canvas_draw_str_aligned(
|
|
||||||
canvas,
|
|
||||||
FLIPPER_LCD_WIDTH - 2,
|
|
||||||
FLIPPER_LCD_HEIGHT - 6,
|
|
||||||
AlignRight,
|
|
||||||
AlignBottom,
|
|
||||||
arkanoid_state->text);
|
|
||||||
}
|
|
||||||
|
|
||||||
void draw_ball(Canvas* canvas, ArkanoidState* ast) {
|
|
||||||
canvas_draw_dot(canvas, ast->ball_state.xb, ast->ball_state.yb);
|
|
||||||
canvas_draw_dot(canvas, ast->ball_state.xb + 1, ast->ball_state.yb);
|
|
||||||
canvas_draw_dot(canvas, ast->ball_state.xb, ast->ball_state.yb + 1);
|
|
||||||
canvas_draw_dot(canvas, ast->ball_state.xb + 1, ast->ball_state.yb + 1);
|
|
||||||
|
|
||||||
move_ball(canvas, ast);
|
|
||||||
}
|
|
||||||
|
|
||||||
void draw_paddle(Canvas* canvas, ArkanoidState* arkanoid_state) {
|
|
||||||
canvas_draw_frame(canvas, arkanoid_state->xPaddle, FLIPPER_LCD_HEIGHT - 1, 11, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void reset_level(Canvas* canvas, ArkanoidState* arkanoid_state) {
|
|
||||||
//Undraw paddle
|
|
||||||
canvas_draw_frame(canvas, arkanoid_state->xPaddle, FLIPPER_LCD_HEIGHT - 1, 11, 1);
|
|
||||||
|
|
||||||
//Undraw ball
|
|
||||||
canvas_draw_dot(canvas, arkanoid_state->ball_state.xb, arkanoid_state->ball_state.yb);
|
|
||||||
canvas_draw_dot(canvas, arkanoid_state->ball_state.xb + 1, arkanoid_state->ball_state.yb);
|
|
||||||
canvas_draw_dot(canvas, arkanoid_state->ball_state.xb, arkanoid_state->ball_state.yb + 1);
|
|
||||||
canvas_draw_dot(canvas, arkanoid_state->ball_state.xb + 1, arkanoid_state->ball_state.yb + 1);
|
|
||||||
|
|
||||||
//Alter various variables to reset the game
|
|
||||||
arkanoid_state->xPaddle = 54;
|
|
||||||
arkanoid_state->ball_state.yb = 60;
|
|
||||||
arkanoid_state->brickCount = 0;
|
|
||||||
arkanoid_state->ball_state.released = false;
|
|
||||||
arkanoid_state->gameStarted = false;
|
|
||||||
|
|
||||||
// Reset all brick hit states
|
|
||||||
for(unsigned int row = 0; row < arkanoid_state->ROWS; row++) {
|
|
||||||
for(unsigned int column = 0; column < arkanoid_state->COLUMNS; column++) {
|
|
||||||
arkanoid_state->brick_state.isHit[row][column] = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void arkanoid_state_init(ArkanoidState* arkanoid_state) {
|
|
||||||
// Init notification
|
|
||||||
arkanoid_state->notify = furi_record_open(RECORD_NOTIFICATION);
|
|
||||||
|
|
||||||
// Set the initial game state
|
|
||||||
arkanoid_state->COLUMNS = 13;
|
|
||||||
arkanoid_state->ROWS = 4;
|
|
||||||
arkanoid_state->ball_state.dx = -1;
|
|
||||||
arkanoid_state->ball_state.dy = -1;
|
|
||||||
arkanoid_state->speed = 2;
|
|
||||||
arkanoid_state->bounced = false;
|
|
||||||
arkanoid_state->lives = 3;
|
|
||||||
arkanoid_state->level = 1;
|
|
||||||
arkanoid_state->score = 0;
|
|
||||||
arkanoid_state->COLUMNS = 13;
|
|
||||||
arkanoid_state->COLUMNS = 13;
|
|
||||||
|
|
||||||
// Reset initial state
|
|
||||||
arkanoid_state->initialDraw = false;
|
|
||||||
arkanoid_state->gameStarted = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void arkanoid_draw_callback(Canvas* const canvas, void* ctx) {
|
|
||||||
furi_assert(ctx);
|
|
||||||
ArkanoidState* arkanoid_state = ctx;
|
|
||||||
furi_mutex_acquire(arkanoid_state->mutex, FuriWaitForever);
|
|
||||||
|
|
||||||
//Initial level draw
|
|
||||||
if(!arkanoid_state->initialDraw) {
|
|
||||||
arkanoid_state->initialDraw = true;
|
|
||||||
|
|
||||||
// Set default font for text
|
|
||||||
canvas_set_font(canvas, FontSecondary);
|
|
||||||
|
|
||||||
//Draws the new level
|
|
||||||
reset_level(canvas, arkanoid_state);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Draws new bricks and resets their values
|
|
||||||
for(unsigned int row = 0; row < arkanoid_state->ROWS; row++) {
|
|
||||||
for(unsigned int column = 0; column < arkanoid_state->COLUMNS; column++) {
|
|
||||||
if(!arkanoid_state->brick_state.isHit[row][column]) {
|
|
||||||
canvas_draw_frame(canvas, 10 * column, 2 + 6 * row, 8, 4);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(arkanoid_state->lives > 0) {
|
|
||||||
draw_paddle(canvas, arkanoid_state);
|
|
||||||
draw_ball(canvas, arkanoid_state);
|
|
||||||
draw_score(canvas, arkanoid_state);
|
|
||||||
draw_lives(canvas, arkanoid_state);
|
|
||||||
|
|
||||||
if(arkanoid_state->brickCount == arkanoid_state->ROWS * arkanoid_state->COLUMNS) {
|
|
||||||
arkanoid_state->level++;
|
|
||||||
reset_level(canvas, arkanoid_state);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
reset_level(canvas, arkanoid_state);
|
|
||||||
arkanoid_state->initialDraw = false;
|
|
||||||
arkanoid_state->lives = 3;
|
|
||||||
arkanoid_state->score = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
furi_mutex_release(arkanoid_state->mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void arkanoid_input_callback(InputEvent* input_event, FuriMessageQueue* event_queue) {
|
|
||||||
furi_assert(event_queue);
|
|
||||||
|
|
||||||
GameEvent event = {.type = EventTypeKey, .input = *input_event};
|
|
||||||
furi_message_queue_put(event_queue, &event, FuriWaitForever);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void arkanoid_update_timer_callback(FuriMessageQueue* event_queue) {
|
|
||||||
furi_assert(event_queue);
|
|
||||||
|
|
||||||
GameEvent event = {.type = EventTypeTick};
|
|
||||||
furi_message_queue_put(event_queue, &event, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t arkanoid_game_app(void* p) {
|
|
||||||
UNUSED(p);
|
|
||||||
int32_t return_code = 0;
|
|
||||||
|
|
||||||
FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(GameEvent));
|
|
||||||
|
|
||||||
ArkanoidState* arkanoid_state = malloc(sizeof(ArkanoidState));
|
|
||||||
arkanoid_state_init(arkanoid_state);
|
|
||||||
|
|
||||||
arkanoid_state->mutex = furi_mutex_alloc(FuriMutexTypeNormal);
|
|
||||||
if(!arkanoid_state->mutex) {
|
|
||||||
FURI_LOG_E(TAG, "Cannot create mutex\r\n");
|
|
||||||
return_code = 255;
|
|
||||||
goto free_and_exit;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set system callbacks
|
|
||||||
ViewPort* view_port = view_port_alloc();
|
|
||||||
view_port_draw_callback_set(view_port, arkanoid_draw_callback, arkanoid_state);
|
|
||||||
view_port_input_callback_set(view_port, arkanoid_input_callback, event_queue);
|
|
||||||
|
|
||||||
FuriTimer* timer =
|
|
||||||
furi_timer_alloc(arkanoid_update_timer_callback, FuriTimerTypePeriodic, event_queue);
|
|
||||||
furi_timer_start(timer, furi_kernel_get_tick_frequency() / 22);
|
|
||||||
|
|
||||||
// Open GUI and register view_port
|
|
||||||
Gui* gui = furi_record_open(RECORD_GUI);
|
|
||||||
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
|
|
||||||
|
|
||||||
// Call dolphin deed on game start
|
|
||||||
dolphin_deed(DolphinDeedPluginGameStart);
|
|
||||||
|
|
||||||
GameEvent event;
|
|
||||||
for(bool processing = true; processing;) {
|
|
||||||
FuriStatus event_status = furi_message_queue_get(event_queue, &event, 100);
|
|
||||||
furi_mutex_acquire(arkanoid_state->mutex, FuriWaitForever);
|
|
||||||
|
|
||||||
if(event_status == FuriStatusOk) {
|
|
||||||
// Key events
|
|
||||||
if(event.type == EventTypeKey) {
|
|
||||||
if(event.input.type == InputTypePress || event.input.type == InputTypeLong ||
|
|
||||||
event.input.type == InputTypeRepeat) {
|
|
||||||
switch(event.input.key) {
|
|
||||||
case InputKeyBack:
|
|
||||||
processing = false;
|
|
||||||
break;
|
|
||||||
case InputKeyRight:
|
|
||||||
if(arkanoid_state->xPaddle < FLIPPER_LCD_WIDTH - 12) {
|
|
||||||
arkanoid_state->xPaddle += 8;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case InputKeyLeft:
|
|
||||||
if(arkanoid_state->xPaddle > 0) {
|
|
||||||
arkanoid_state->xPaddle -= 8;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case InputKeyUp:
|
|
||||||
if(arkanoid_state->speed < MAX_SPEED) {
|
|
||||||
arkanoid_state->speed++;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case InputKeyDown:
|
|
||||||
if(arkanoid_state->speed > 1) {
|
|
||||||
arkanoid_state->speed--;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case InputKeyOk:
|
|
||||||
if(arkanoid_state->gameStarted == false) {
|
|
||||||
//Release ball if FIRE pressed
|
|
||||||
arkanoid_state->ball_state.released = true;
|
|
||||||
|
|
||||||
//Apply random direction to ball on release
|
|
||||||
if(rand_range(0, 2) == 0) {
|
|
||||||
arkanoid_state->ball_state.dx = 1;
|
|
||||||
} else {
|
|
||||||
arkanoid_state->ball_state.dx = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Makes sure the ball heads upwards
|
|
||||||
arkanoid_state->ball_state.dy = -1;
|
|
||||||
//start the game flag
|
|
||||||
arkanoid_state->gameStarted = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
view_port_update(view_port);
|
|
||||||
furi_mutex_release(arkanoid_state->mutex);
|
|
||||||
}
|
|
||||||
furi_timer_free(timer);
|
|
||||||
view_port_enabled_set(view_port, false);
|
|
||||||
gui_remove_view_port(gui, view_port);
|
|
||||||
furi_record_close(RECORD_GUI);
|
|
||||||
furi_record_close(RECORD_NOTIFICATION);
|
|
||||||
view_port_free(view_port);
|
|
||||||
furi_mutex_free(arkanoid_state->mutex);
|
|
||||||
|
|
||||||
free_and_exit:
|
|
||||||
free(arkanoid_state);
|
|
||||||
furi_message_queue_free(event_queue);
|
|
||||||
|
|
||||||
return return_code;
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
App(
|
|
||||||
appid="avr_isp",
|
|
||||||
name="AVR Flasher",
|
|
||||||
apptype=FlipperAppType.EXTERNAL,
|
|
||||||
entry_point="avr_isp_app",
|
|
||||||
requires=["gui"],
|
|
||||||
stack_size=4 * 1024,
|
|
||||||
order=20,
|
|
||||||
fap_icon="avr_app_icon_10x10.png",
|
|
||||||
fap_category="GPIO",
|
|
||||||
fap_icon_assets="images",
|
|
||||||
fap_private_libs=[
|
|
||||||
Lib(
|
|
||||||
name="driver",
|
|
||||||
),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
Before Width: | Height: | Size: 3.5 KiB |
@@ -1,179 +0,0 @@
|
|||||||
#include "avr_isp_app_i.h"
|
|
||||||
|
|
||||||
static bool avr_isp_app_custom_event_callback(void* context, uint32_t event) {
|
|
||||||
furi_assert(context);
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
return scene_manager_handle_custom_event(app->scene_manager, event);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool avr_isp_app_back_event_callback(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
return scene_manager_handle_back_event(app->scene_manager);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void avr_isp_app_tick_event_callback(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
scene_manager_handle_tick_event(app->scene_manager);
|
|
||||||
}
|
|
||||||
|
|
||||||
AvrIspApp* avr_isp_app_alloc() {
|
|
||||||
AvrIspApp* app = malloc(sizeof(AvrIspApp));
|
|
||||||
|
|
||||||
app->file_path = furi_string_alloc();
|
|
||||||
furi_string_set(app->file_path, STORAGE_APP_DATA_PATH_PREFIX);
|
|
||||||
app->error = AvrIspErrorNoError;
|
|
||||||
|
|
||||||
// GUI
|
|
||||||
app->gui = furi_record_open(RECORD_GUI);
|
|
||||||
|
|
||||||
// View Dispatcher
|
|
||||||
app->view_dispatcher = view_dispatcher_alloc();
|
|
||||||
app->scene_manager = scene_manager_alloc(&avr_isp_scene_handlers, app);
|
|
||||||
view_dispatcher_enable_queue(app->view_dispatcher);
|
|
||||||
|
|
||||||
view_dispatcher_set_event_callback_context(app->view_dispatcher, app);
|
|
||||||
view_dispatcher_set_custom_event_callback(
|
|
||||||
app->view_dispatcher, avr_isp_app_custom_event_callback);
|
|
||||||
view_dispatcher_set_navigation_event_callback(
|
|
||||||
app->view_dispatcher, avr_isp_app_back_event_callback);
|
|
||||||
view_dispatcher_set_tick_event_callback(
|
|
||||||
app->view_dispatcher, avr_isp_app_tick_event_callback, 100);
|
|
||||||
|
|
||||||
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
|
|
||||||
|
|
||||||
// Open Notification record
|
|
||||||
app->notifications = furi_record_open(RECORD_NOTIFICATION);
|
|
||||||
|
|
||||||
// SubMenu
|
|
||||||
app->submenu = submenu_alloc();
|
|
||||||
view_dispatcher_add_view(
|
|
||||||
app->view_dispatcher, AvrIspViewSubmenu, submenu_get_view(app->submenu));
|
|
||||||
|
|
||||||
// Widget
|
|
||||||
app->widget = widget_alloc();
|
|
||||||
view_dispatcher_add_view(app->view_dispatcher, AvrIspViewWidget, widget_get_view(app->widget));
|
|
||||||
|
|
||||||
// Text Input
|
|
||||||
app->text_input = text_input_alloc();
|
|
||||||
view_dispatcher_add_view(
|
|
||||||
app->view_dispatcher, AvrIspViewTextInput, text_input_get_view(app->text_input));
|
|
||||||
|
|
||||||
// Popup
|
|
||||||
app->popup = popup_alloc();
|
|
||||||
view_dispatcher_add_view(app->view_dispatcher, AvrIspViewPopup, popup_get_view(app->popup));
|
|
||||||
|
|
||||||
//Dialog
|
|
||||||
app->dialogs = furi_record_open(RECORD_DIALOGS);
|
|
||||||
|
|
||||||
// Programmer view
|
|
||||||
app->avr_isp_programmer_view = avr_isp_programmer_view_alloc();
|
|
||||||
view_dispatcher_add_view(
|
|
||||||
app->view_dispatcher,
|
|
||||||
AvrIspViewProgrammer,
|
|
||||||
avr_isp_programmer_view_get_view(app->avr_isp_programmer_view));
|
|
||||||
|
|
||||||
// Reader view
|
|
||||||
app->avr_isp_reader_view = avr_isp_reader_view_alloc();
|
|
||||||
view_dispatcher_add_view(
|
|
||||||
app->view_dispatcher,
|
|
||||||
AvrIspViewReader,
|
|
||||||
avr_isp_reader_view_get_view(app->avr_isp_reader_view));
|
|
||||||
|
|
||||||
// Writer view
|
|
||||||
app->avr_isp_writer_view = avr_isp_writer_view_alloc();
|
|
||||||
view_dispatcher_add_view(
|
|
||||||
app->view_dispatcher,
|
|
||||||
AvrIspViewWriter,
|
|
||||||
avr_isp_writer_view_get_view(app->avr_isp_writer_view));
|
|
||||||
|
|
||||||
// Chip detect view
|
|
||||||
app->avr_isp_chip_detect_view = avr_isp_chip_detect_view_alloc();
|
|
||||||
view_dispatcher_add_view(
|
|
||||||
app->view_dispatcher,
|
|
||||||
AvrIspViewChipDetect,
|
|
||||||
avr_isp_chip_detect_view_get_view(app->avr_isp_chip_detect_view));
|
|
||||||
|
|
||||||
// Enable 5v power, multiple attempts to avoid issues with power chip protection false triggering
|
|
||||||
uint8_t attempts = 0;
|
|
||||||
while(!furi_hal_power_is_otg_enabled() && attempts++ < 5) {
|
|
||||||
furi_hal_power_enable_otg();
|
|
||||||
furi_delay_ms(10);
|
|
||||||
}
|
|
||||||
|
|
||||||
scene_manager_next_scene(app->scene_manager, AvrIspSceneStart);
|
|
||||||
|
|
||||||
return app;
|
|
||||||
} //-V773
|
|
||||||
|
|
||||||
void avr_isp_app_free(AvrIspApp* app) {
|
|
||||||
furi_assert(app);
|
|
||||||
|
|
||||||
// Disable 5v power
|
|
||||||
if(furi_hal_power_is_otg_enabled()) {
|
|
||||||
furi_hal_power_disable_otg();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Submenu
|
|
||||||
view_dispatcher_remove_view(app->view_dispatcher, AvrIspViewSubmenu);
|
|
||||||
submenu_free(app->submenu);
|
|
||||||
|
|
||||||
// Widget
|
|
||||||
view_dispatcher_remove_view(app->view_dispatcher, AvrIspViewWidget);
|
|
||||||
widget_free(app->widget);
|
|
||||||
|
|
||||||
// TextInput
|
|
||||||
view_dispatcher_remove_view(app->view_dispatcher, AvrIspViewTextInput);
|
|
||||||
text_input_free(app->text_input);
|
|
||||||
|
|
||||||
// Popup
|
|
||||||
view_dispatcher_remove_view(app->view_dispatcher, AvrIspViewPopup);
|
|
||||||
popup_free(app->popup);
|
|
||||||
|
|
||||||
//Dialog
|
|
||||||
furi_record_close(RECORD_DIALOGS);
|
|
||||||
|
|
||||||
// Programmer view
|
|
||||||
view_dispatcher_remove_view(app->view_dispatcher, AvrIspViewProgrammer);
|
|
||||||
avr_isp_programmer_view_free(app->avr_isp_programmer_view);
|
|
||||||
|
|
||||||
// Reader view
|
|
||||||
view_dispatcher_remove_view(app->view_dispatcher, AvrIspViewReader);
|
|
||||||
avr_isp_reader_view_free(app->avr_isp_reader_view);
|
|
||||||
|
|
||||||
// Writer view
|
|
||||||
view_dispatcher_remove_view(app->view_dispatcher, AvrIspViewWriter);
|
|
||||||
avr_isp_writer_view_free(app->avr_isp_writer_view);
|
|
||||||
|
|
||||||
// Chip detect view
|
|
||||||
view_dispatcher_remove_view(app->view_dispatcher, AvrIspViewChipDetect);
|
|
||||||
avr_isp_chip_detect_view_free(app->avr_isp_chip_detect_view);
|
|
||||||
|
|
||||||
// View dispatcher
|
|
||||||
view_dispatcher_free(app->view_dispatcher);
|
|
||||||
scene_manager_free(app->scene_manager);
|
|
||||||
|
|
||||||
// Notifications
|
|
||||||
furi_record_close(RECORD_NOTIFICATION);
|
|
||||||
app->notifications = NULL;
|
|
||||||
|
|
||||||
// Close records
|
|
||||||
furi_record_close(RECORD_GUI);
|
|
||||||
|
|
||||||
// Path strings
|
|
||||||
furi_string_free(app->file_path);
|
|
||||||
|
|
||||||
free(app);
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t avr_isp_app(void* p) {
|
|
||||||
UNUSED(p);
|
|
||||||
AvrIspApp* avr_isp_app = avr_isp_app_alloc();
|
|
||||||
|
|
||||||
view_dispatcher_run(avr_isp_app->view_dispatcher);
|
|
||||||
|
|
||||||
avr_isp_app_free(avr_isp_app);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
#include "avr_isp_app_i.h"
|
|
||||||
#include <lib/toolbox/path.h>
|
|
||||||
#include <flipper_format/flipper_format_i.h>
|
|
||||||
|
|
||||||
#define TAG "AvrIsp"
|
|
||||||
|
|
||||||
bool avr_isp_load_from_file(AvrIspApp* app) {
|
|
||||||
furi_assert(app);
|
|
||||||
|
|
||||||
FuriString* file_path = furi_string_alloc();
|
|
||||||
FuriString* file_name = furi_string_alloc();
|
|
||||||
|
|
||||||
DialogsFileBrowserOptions browser_options;
|
|
||||||
dialog_file_browser_set_basic_options(
|
|
||||||
&browser_options, AVR_ISP_APP_EXTENSION, &I_avr_app_icon_10x10);
|
|
||||||
browser_options.base_path = STORAGE_APP_DATA_PATH_PREFIX;
|
|
||||||
|
|
||||||
// Input events and views are managed by file_select
|
|
||||||
bool res = dialog_file_browser_show(app->dialogs, file_path, app->file_path, &browser_options);
|
|
||||||
|
|
||||||
if(res) {
|
|
||||||
path_extract_dirname(furi_string_get_cstr(file_path), app->file_path);
|
|
||||||
path_extract_filename(file_path, file_name, true);
|
|
||||||
strncpy(app->file_name_tmp, furi_string_get_cstr(file_name), AVR_ISP_MAX_LEN_NAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
furi_string_free(file_name);
|
|
||||||
furi_string_free(file_path);
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "helpers/avr_isp_types.h"
|
|
||||||
#include <avr_isp_icons.h>
|
|
||||||
|
|
||||||
#include "scenes/avr_isp_scene.h"
|
|
||||||
#include <gui/gui.h>
|
|
||||||
#include <gui/view_dispatcher.h>
|
|
||||||
#include <gui/scene_manager.h>
|
|
||||||
#include <gui/modules/submenu.h>
|
|
||||||
#include <gui/modules/widget.h>
|
|
||||||
#include <notification/notification_messages.h>
|
|
||||||
#include <gui/modules/text_input.h>
|
|
||||||
#include <dialogs/dialogs.h>
|
|
||||||
#include <storage/storage.h>
|
|
||||||
#include <gui/modules/popup.h>
|
|
||||||
|
|
||||||
#include "views/avr_isp_view_programmer.h"
|
|
||||||
#include "views/avr_isp_view_reader.h"
|
|
||||||
#include "views/avr_isp_view_writer.h"
|
|
||||||
#include "views/avr_isp_view_chip_detect.h"
|
|
||||||
|
|
||||||
#define AVR_ISP_MAX_LEN_NAME 64
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
Gui* gui;
|
|
||||||
ViewDispatcher* view_dispatcher;
|
|
||||||
SceneManager* scene_manager;
|
|
||||||
NotificationApp* notifications;
|
|
||||||
DialogsApp* dialogs;
|
|
||||||
Popup* popup;
|
|
||||||
Submenu* submenu;
|
|
||||||
Widget* widget;
|
|
||||||
TextInput* text_input;
|
|
||||||
FuriString* file_path;
|
|
||||||
char file_name_tmp[AVR_ISP_MAX_LEN_NAME];
|
|
||||||
AvrIspProgrammerView* avr_isp_programmer_view;
|
|
||||||
AvrIspReaderView* avr_isp_reader_view;
|
|
||||||
AvrIspWriterView* avr_isp_writer_view;
|
|
||||||
AvrIspChipDetectView* avr_isp_chip_detect_view;
|
|
||||||
AvrIspError error;
|
|
||||||
} AvrIspApp;
|
|
||||||
|
|
||||||
bool avr_isp_load_from_file(AvrIspApp* app);
|
|
||||||
@@ -1,496 +0,0 @@
|
|||||||
#include "avr_isp.h"
|
|
||||||
#include "../lib/driver/avr_isp_prog_cmd.h"
|
|
||||||
#include "../lib/driver/avr_isp_spi_sw.h"
|
|
||||||
|
|
||||||
#include <furi.h>
|
|
||||||
|
|
||||||
#define AVR_ISP_PROG_TX_RX_BUF_SIZE 320
|
|
||||||
#define TAG "AvrIsp"
|
|
||||||
|
|
||||||
struct AvrIsp {
|
|
||||||
AvrIspSpiSw* spi;
|
|
||||||
bool pmode;
|
|
||||||
AvrIspCallback callback;
|
|
||||||
void* context;
|
|
||||||
};
|
|
||||||
|
|
||||||
AvrIsp* avr_isp_alloc(void) {
|
|
||||||
AvrIsp* instance = malloc(sizeof(AvrIsp));
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_free(AvrIsp* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
if(instance->spi) avr_isp_end_pmode(instance);
|
|
||||||
free(instance);
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_set_tx_callback(AvrIsp* instance, AvrIspCallback callback, void* context) {
|
|
||||||
furi_assert(instance);
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
instance->callback = callback;
|
|
||||||
instance->context = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t avr_isp_spi_transaction(
|
|
||||||
AvrIsp* instance,
|
|
||||||
uint8_t cmd,
|
|
||||||
uint8_t addr_hi,
|
|
||||||
uint8_t addr_lo,
|
|
||||||
uint8_t data) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
avr_isp_spi_sw_txrx(instance->spi, cmd);
|
|
||||||
avr_isp_spi_sw_txrx(instance->spi, addr_hi);
|
|
||||||
avr_isp_spi_sw_txrx(instance->spi, addr_lo);
|
|
||||||
return avr_isp_spi_sw_txrx(instance->spi, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool avr_isp_set_pmode(AvrIsp* instance, uint8_t a, uint8_t b, uint8_t c, uint8_t d) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
uint8_t res = 0;
|
|
||||||
avr_isp_spi_sw_txrx(instance->spi, a);
|
|
||||||
avr_isp_spi_sw_txrx(instance->spi, b);
|
|
||||||
res = avr_isp_spi_sw_txrx(instance->spi, c);
|
|
||||||
avr_isp_spi_sw_txrx(instance->spi, d);
|
|
||||||
return res == 0x53;
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_end_pmode(AvrIsp* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
if(instance->pmode) {
|
|
||||||
avr_isp_spi_sw_res_set(instance->spi, true);
|
|
||||||
// We're about to take the target out of reset
|
|
||||||
// so configure SPI pins as input
|
|
||||||
if(instance->spi) avr_isp_spi_sw_free(instance->spi);
|
|
||||||
instance->spi = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
instance->pmode = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool avr_isp_start_pmode(AvrIsp* instance, AvrIspSpiSwSpeed spi_speed) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
// Reset target before driving PIN_SCK or PIN_MOSI
|
|
||||||
|
|
||||||
// SPI.begin() will configure SS as output,
|
|
||||||
// so SPI master mode is selected.
|
|
||||||
// We have defined RESET as pin 10,
|
|
||||||
// which for many arduino's is not the SS pin.
|
|
||||||
// So we have to configure RESET as output here,
|
|
||||||
// (reset_target() first sets the correct level)
|
|
||||||
if(instance->spi) avr_isp_spi_sw_free(instance->spi);
|
|
||||||
instance->spi = avr_isp_spi_sw_init(spi_speed);
|
|
||||||
|
|
||||||
avr_isp_spi_sw_res_set(instance->spi, false);
|
|
||||||
// See avr datasheets, chapter "SERIAL_PRG Programming Algorithm":
|
|
||||||
|
|
||||||
// Pulse RESET after PIN_SCK is low:
|
|
||||||
avr_isp_spi_sw_sck_set(instance->spi, false);
|
|
||||||
|
|
||||||
// discharge PIN_SCK, value arbitrally chosen
|
|
||||||
furi_delay_ms(20);
|
|
||||||
avr_isp_spi_sw_res_set(instance->spi, true);
|
|
||||||
|
|
||||||
// Pulse must be minimum 2 target CPU speed cycles
|
|
||||||
// so 100 usec is ok for CPU speeds above 20KHz
|
|
||||||
furi_delay_ms(1);
|
|
||||||
|
|
||||||
avr_isp_spi_sw_res_set(instance->spi, false);
|
|
||||||
|
|
||||||
// Send the enable programming command:
|
|
||||||
// datasheet: must be > 20 msec
|
|
||||||
furi_delay_ms(50);
|
|
||||||
if(avr_isp_set_pmode(instance, AVR_ISP_SET_PMODE)) {
|
|
||||||
instance->pmode = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool avr_isp_auto_set_spi_speed_start_pmode(AvrIsp* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
AvrIspSpiSwSpeed spi_speed[] = {
|
|
||||||
AvrIspSpiSwSpeed1Mhz,
|
|
||||||
AvrIspSpiSwSpeed400Khz,
|
|
||||||
AvrIspSpiSwSpeed250Khz,
|
|
||||||
AvrIspSpiSwSpeed125Khz,
|
|
||||||
AvrIspSpiSwSpeed60Khz,
|
|
||||||
AvrIspSpiSwSpeed40Khz,
|
|
||||||
AvrIspSpiSwSpeed20Khz,
|
|
||||||
AvrIspSpiSwSpeed10Khz,
|
|
||||||
AvrIspSpiSwSpeed5Khz,
|
|
||||||
AvrIspSpiSwSpeed1Khz,
|
|
||||||
};
|
|
||||||
for(uint8_t i = 0; i < COUNT_OF(spi_speed); i++) {
|
|
||||||
if(avr_isp_start_pmode(instance, spi_speed[i])) {
|
|
||||||
AvrIspSignature sig = avr_isp_read_signature(instance);
|
|
||||||
AvrIspSignature sig_examination = avr_isp_read_signature(instance); //-V656
|
|
||||||
uint8_t y = 0;
|
|
||||||
while(y < 8) {
|
|
||||||
if(memcmp((uint8_t*)&sig, (uint8_t*)&sig_examination, sizeof(AvrIspSignature)) !=
|
|
||||||
0)
|
|
||||||
break;
|
|
||||||
sig_examination = avr_isp_read_signature(instance);
|
|
||||||
y++;
|
|
||||||
}
|
|
||||||
if(y == 8) {
|
|
||||||
if(spi_speed[i] > AvrIspSpiSwSpeed1Mhz) {
|
|
||||||
if(i < (COUNT_OF(spi_speed) - 1)) {
|
|
||||||
avr_isp_end_pmode(instance);
|
|
||||||
i++;
|
|
||||||
return avr_isp_start_pmode(instance, spi_speed[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(instance->spi) {
|
|
||||||
avr_isp_spi_sw_free(instance->spi);
|
|
||||||
instance->spi = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void avr_isp_commit(AvrIsp* instance, uint16_t addr, uint8_t data) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
avr_isp_spi_transaction(instance, AVR_ISP_COMMIT(addr));
|
|
||||||
/* polling flash */
|
|
||||||
if(data == 0xFF) {
|
|
||||||
furi_delay_ms(5);
|
|
||||||
} else {
|
|
||||||
/* polling flash */
|
|
||||||
uint32_t starttime = furi_get_tick();
|
|
||||||
while((furi_get_tick() - starttime) < 30) {
|
|
||||||
if(avr_isp_spi_transaction(instance, AVR_ISP_READ_FLASH_HI(addr)) != 0xFF) {
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint16_t avr_isp_current_page(AvrIsp* instance, uint32_t addr, uint16_t page_size) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
uint16_t page = 0;
|
|
||||||
switch(page_size) {
|
|
||||||
case 32:
|
|
||||||
page = addr & 0xFFFFFFF0;
|
|
||||||
break;
|
|
||||||
case 64:
|
|
||||||
page = addr & 0xFFFFFFE0;
|
|
||||||
break;
|
|
||||||
case 128:
|
|
||||||
page = addr & 0xFFFFFFC0;
|
|
||||||
break;
|
|
||||||
case 256:
|
|
||||||
page = addr & 0xFFFFFF80;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
page = addr;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return page;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool avr_isp_flash_write_pages(
|
|
||||||
AvrIsp* instance,
|
|
||||||
uint16_t addr,
|
|
||||||
uint16_t page_size,
|
|
||||||
uint8_t* data,
|
|
||||||
uint32_t data_size) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
size_t x = 0;
|
|
||||||
uint16_t page = avr_isp_current_page(instance, addr, page_size);
|
|
||||||
|
|
||||||
while(x < data_size) {
|
|
||||||
if(page != avr_isp_current_page(instance, addr, page_size)) {
|
|
||||||
avr_isp_commit(instance, page, data[x - 1]);
|
|
||||||
page = avr_isp_current_page(instance, addr, page_size);
|
|
||||||
}
|
|
||||||
avr_isp_spi_transaction(instance, AVR_ISP_WRITE_FLASH_LO(addr, data[x++]));
|
|
||||||
avr_isp_spi_transaction(instance, AVR_ISP_WRITE_FLASH_HI(addr, data[x++]));
|
|
||||||
addr++;
|
|
||||||
}
|
|
||||||
avr_isp_commit(instance, page, data[x - 1]);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool avr_isp_erase_chip(AvrIsp* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
bool ret = false;
|
|
||||||
if(!instance->pmode) avr_isp_auto_set_spi_speed_start_pmode(instance);
|
|
||||||
if(instance->pmode) {
|
|
||||||
avr_isp_spi_transaction(instance, AVR_ISP_ERASE_CHIP);
|
|
||||||
furi_delay_ms(100);
|
|
||||||
avr_isp_end_pmode(instance);
|
|
||||||
ret = true;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
avr_isp_eeprom_write(AvrIsp* instance, uint16_t addr, uint8_t* data, uint32_t data_size) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
for(uint16_t i = 0; i < data_size; i++) {
|
|
||||||
avr_isp_spi_transaction(instance, AVR_ISP_WRITE_EEPROM(addr, data[i]));
|
|
||||||
furi_delay_ms(10);
|
|
||||||
addr++;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool avr_isp_write_page(
|
|
||||||
AvrIsp* instance,
|
|
||||||
uint32_t mem_type,
|
|
||||||
uint32_t mem_size,
|
|
||||||
uint16_t addr,
|
|
||||||
uint16_t page_size,
|
|
||||||
uint8_t* data,
|
|
||||||
uint32_t data_size) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
bool ret = false;
|
|
||||||
switch(mem_type) {
|
|
||||||
case STK_SET_FLASH_TYPE:
|
|
||||||
if((addr + data_size / 2) <= mem_size) {
|
|
||||||
ret = avr_isp_flash_write_pages(instance, addr, page_size, data, data_size);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case STK_SET_EEPROM_TYPE:
|
|
||||||
if((addr + data_size) <= mem_size) {
|
|
||||||
ret = avr_isp_eeprom_write(instance, addr, data, data_size);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
furi_crash(TAG " Incorrect mem type.");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool avr_isp_flash_read_page(
|
|
||||||
AvrIsp* instance,
|
|
||||||
uint16_t addr,
|
|
||||||
uint16_t page_size,
|
|
||||||
uint8_t* data,
|
|
||||||
uint32_t data_size) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
if(page_size > data_size) return false;
|
|
||||||
for(uint16_t i = 0; i < page_size; i += 2) {
|
|
||||||
data[i] = avr_isp_spi_transaction(instance, AVR_ISP_READ_FLASH_LO(addr));
|
|
||||||
data[i + 1] = avr_isp_spi_transaction(instance, AVR_ISP_READ_FLASH_HI(addr));
|
|
||||||
addr++;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool avr_isp_eeprom_read_page(
|
|
||||||
AvrIsp* instance,
|
|
||||||
uint16_t addr,
|
|
||||||
uint16_t page_size,
|
|
||||||
uint8_t* data,
|
|
||||||
uint32_t data_size) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
if(page_size > data_size) return false;
|
|
||||||
for(uint16_t i = 0; i < page_size; i++) {
|
|
||||||
data[i] = avr_isp_spi_transaction(instance, AVR_ISP_READ_EEPROM(addr));
|
|
||||||
addr++;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool avr_isp_read_page(
|
|
||||||
AvrIsp* instance,
|
|
||||||
uint32_t mem_type,
|
|
||||||
uint16_t addr,
|
|
||||||
uint16_t page_size,
|
|
||||||
uint8_t* data,
|
|
||||||
uint32_t data_size) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
bool res = false;
|
|
||||||
if(mem_type == STK_SET_FLASH_TYPE)
|
|
||||||
res = avr_isp_flash_read_page(instance, addr, page_size, data, data_size);
|
|
||||||
if(mem_type == STK_SET_EEPROM_TYPE)
|
|
||||||
res = avr_isp_eeprom_read_page(instance, addr, page_size, data, data_size);
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
AvrIspSignature avr_isp_read_signature(AvrIsp* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
AvrIspSignature signature;
|
|
||||||
signature.vendor = avr_isp_spi_transaction(instance, AVR_ISP_READ_VENDOR);
|
|
||||||
signature.part_family = avr_isp_spi_transaction(instance, AVR_ISP_READ_PART_FAMILY);
|
|
||||||
signature.part_number = avr_isp_spi_transaction(instance, AVR_ISP_READ_PART_NUMBER);
|
|
||||||
return signature;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t avr_isp_read_lock_byte(AvrIsp* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
uint8_t data = 0;
|
|
||||||
uint32_t starttime = furi_get_tick();
|
|
||||||
while((furi_get_tick() - starttime) < 300) {
|
|
||||||
data = avr_isp_spi_transaction(instance, AVR_ISP_READ_LOCK_BYTE);
|
|
||||||
if(avr_isp_spi_transaction(instance, AVR_ISP_READ_LOCK_BYTE) == data) {
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
data = 0x00;
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool avr_isp_write_lock_byte(AvrIsp* instance, uint8_t lock) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
bool ret = false;
|
|
||||||
if(avr_isp_read_lock_byte(instance) == lock) {
|
|
||||||
ret = true;
|
|
||||||
} else {
|
|
||||||
avr_isp_spi_transaction(instance, AVR_ISP_WRITE_LOCK_BYTE(lock));
|
|
||||||
/* polling lock byte */
|
|
||||||
uint32_t starttime = furi_get_tick();
|
|
||||||
while((furi_get_tick() - starttime) < 30) {
|
|
||||||
if(avr_isp_spi_transaction(instance, AVR_ISP_READ_LOCK_BYTE) == lock) {
|
|
||||||
ret = true;
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t avr_isp_read_fuse_low(AvrIsp* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
uint8_t data = 0;
|
|
||||||
uint32_t starttime = furi_get_tick();
|
|
||||||
while((furi_get_tick() - starttime) < 300) {
|
|
||||||
data = avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_LOW);
|
|
||||||
if(avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_LOW) == data) {
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
data = 0x00;
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool avr_isp_write_fuse_low(AvrIsp* instance, uint8_t lfuse) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
bool ret = false;
|
|
||||||
if(avr_isp_read_fuse_low(instance) == lfuse) {
|
|
||||||
ret = true;
|
|
||||||
} else {
|
|
||||||
avr_isp_spi_transaction(instance, AVR_ISP_WRITE_FUSE_LOW(lfuse));
|
|
||||||
/* polling fuse */
|
|
||||||
uint32_t starttime = furi_get_tick();
|
|
||||||
while((furi_get_tick() - starttime) < 30) {
|
|
||||||
if(avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_LOW) == lfuse) {
|
|
||||||
ret = true;
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t avr_isp_read_fuse_high(AvrIsp* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
uint8_t data = 0;
|
|
||||||
uint32_t starttime = furi_get_tick();
|
|
||||||
while((furi_get_tick() - starttime) < 300) {
|
|
||||||
data = avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_HIGH);
|
|
||||||
if(avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_HIGH) == data) {
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
data = 0x00;
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool avr_isp_write_fuse_high(AvrIsp* instance, uint8_t hfuse) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
bool ret = false;
|
|
||||||
if(avr_isp_read_fuse_high(instance) == hfuse) {
|
|
||||||
ret = true;
|
|
||||||
} else {
|
|
||||||
avr_isp_spi_transaction(instance, AVR_ISP_WRITE_FUSE_HIGH(hfuse));
|
|
||||||
/* polling fuse */
|
|
||||||
uint32_t starttime = furi_get_tick();
|
|
||||||
while((furi_get_tick() - starttime) < 30) {
|
|
||||||
if(avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_HIGH) == hfuse) {
|
|
||||||
ret = true;
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t avr_isp_read_fuse_extended(AvrIsp* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
uint8_t data = 0;
|
|
||||||
uint32_t starttime = furi_get_tick();
|
|
||||||
while((furi_get_tick() - starttime) < 300) {
|
|
||||||
data = avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_EXTENDED);
|
|
||||||
if(avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_EXTENDED) == data) {
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
data = 0x00;
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool avr_isp_write_fuse_extended(AvrIsp* instance, uint8_t efuse) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
bool ret = false;
|
|
||||||
if(avr_isp_read_fuse_extended(instance) == efuse) {
|
|
||||||
ret = true;
|
|
||||||
} else {
|
|
||||||
avr_isp_spi_transaction(instance, AVR_ISP_WRITE_FUSE_EXTENDED(efuse));
|
|
||||||
/* polling fuse */
|
|
||||||
uint32_t starttime = furi_get_tick();
|
|
||||||
while((furi_get_tick() - starttime) < 30) {
|
|
||||||
if(avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_EXTENDED) == efuse) {
|
|
||||||
ret = true;
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_write_extended_addr(AvrIsp* instance, uint8_t extended_addr) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
avr_isp_spi_transaction(instance, AVR_ISP_EXTENDED_ADDR(extended_addr));
|
|
||||||
furi_delay_ms(10);
|
|
||||||
}
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <furi_hal.h>
|
|
||||||
|
|
||||||
typedef struct AvrIsp AvrIsp;
|
|
||||||
typedef void (*AvrIspCallback)(void* context);
|
|
||||||
|
|
||||||
struct AvrIspSignature {
|
|
||||||
uint8_t vendor;
|
|
||||||
uint8_t part_family;
|
|
||||||
uint8_t part_number;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct AvrIspSignature AvrIspSignature;
|
|
||||||
|
|
||||||
AvrIsp* avr_isp_alloc(void);
|
|
||||||
|
|
||||||
void avr_isp_free(AvrIsp* instance);
|
|
||||||
|
|
||||||
void avr_isp_set_tx_callback(AvrIsp* instance, AvrIspCallback callback, void* context);
|
|
||||||
|
|
||||||
bool avr_isp_auto_set_spi_speed_start_pmode(AvrIsp* instance);
|
|
||||||
|
|
||||||
AvrIspSignature avr_isp_read_signature(AvrIsp* instance);
|
|
||||||
|
|
||||||
void avr_isp_end_pmode(AvrIsp* instance);
|
|
||||||
|
|
||||||
bool avr_isp_erase_chip(AvrIsp* instance);
|
|
||||||
|
|
||||||
uint8_t avr_isp_spi_transaction(
|
|
||||||
AvrIsp* instance,
|
|
||||||
uint8_t cmd,
|
|
||||||
uint8_t addr_hi,
|
|
||||||
uint8_t addr_lo,
|
|
||||||
uint8_t data);
|
|
||||||
|
|
||||||
bool avr_isp_read_page(
|
|
||||||
AvrIsp* instance,
|
|
||||||
uint32_t memtype,
|
|
||||||
uint16_t addr,
|
|
||||||
uint16_t page_size,
|
|
||||||
uint8_t* data,
|
|
||||||
uint32_t data_size);
|
|
||||||
|
|
||||||
bool avr_isp_write_page(
|
|
||||||
AvrIsp* instance,
|
|
||||||
uint32_t mem_type,
|
|
||||||
uint32_t mem_size,
|
|
||||||
uint16_t addr,
|
|
||||||
uint16_t page_size,
|
|
||||||
uint8_t* data,
|
|
||||||
uint32_t data_size);
|
|
||||||
|
|
||||||
uint8_t avr_isp_read_lock_byte(AvrIsp* instance);
|
|
||||||
|
|
||||||
bool avr_isp_write_lock_byte(AvrIsp* instance, uint8_t lock);
|
|
||||||
|
|
||||||
uint8_t avr_isp_read_fuse_low(AvrIsp* instance);
|
|
||||||
|
|
||||||
bool avr_isp_write_fuse_low(AvrIsp* instance, uint8_t lfuse);
|
|
||||||
|
|
||||||
uint8_t avr_isp_read_fuse_high(AvrIsp* instance);
|
|
||||||
|
|
||||||
bool avr_isp_write_fuse_high(AvrIsp* instance, uint8_t hfuse);
|
|
||||||
|
|
||||||
uint8_t avr_isp_read_fuse_extended(AvrIsp* instance);
|
|
||||||
|
|
||||||
bool avr_isp_write_fuse_extended(AvrIsp* instance, uint8_t efuse);
|
|
||||||
|
|
||||||
void avr_isp_write_extended_addr(AvrIsp* instance, uint8_t extended_addr);
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
//SubmenuIndex
|
|
||||||
SubmenuIndexAvrIspProgrammer = 10,
|
|
||||||
SubmenuIndexAvrIspReader,
|
|
||||||
SubmenuIndexAvrIspWriter,
|
|
||||||
SubmenuIndexAvrIsWiring,
|
|
||||||
SubmenuIndexAvrIspAbout,
|
|
||||||
|
|
||||||
//AvrIspCustomEvent
|
|
||||||
AvrIspCustomEventSceneChipDetectOk = 100,
|
|
||||||
AvrIspCustomEventSceneReadingOk,
|
|
||||||
AvrIspCustomEventSceneWritingOk,
|
|
||||||
AvrIspCustomEventSceneErrorVerification,
|
|
||||||
AvrIspCustomEventSceneErrorReading,
|
|
||||||
AvrIspCustomEventSceneErrorWriting,
|
|
||||||
AvrIspCustomEventSceneErrorWritingFuse,
|
|
||||||
AvrIspCustomEventSceneInputName,
|
|
||||||
AvrIspCustomEventSceneSuccess,
|
|
||||||
AvrIspCustomEventSceneExit,
|
|
||||||
AvrIspCustomEventSceneExitStartMenu,
|
|
||||||
} AvrIspCustomEvent;
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <furi.h>
|
|
||||||
#include <furi_hal.h>
|
|
||||||
|
|
||||||
#define AVR_ISP_VERSION_APP "0.1"
|
|
||||||
#define AVR_ISP_DEVELOPED "SkorP"
|
|
||||||
#define AVR_ISP_GITHUB "https://github.com/flipperdevices/flipperzero-firmware"
|
|
||||||
|
|
||||||
#define AVR_ISP_APP_FILE_VERSION 1
|
|
||||||
#define AVR_ISP_APP_FILE_TYPE "Flipper Dump AVR"
|
|
||||||
#define AVR_ISP_APP_EXTENSION ".avr"
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
//AvrIspViewVariableItemList,
|
|
||||||
AvrIspViewSubmenu,
|
|
||||||
AvrIspViewProgrammer,
|
|
||||||
AvrIspViewReader,
|
|
||||||
AvrIspViewWriter,
|
|
||||||
AvrIspViewWidget,
|
|
||||||
AvrIspViewPopup,
|
|
||||||
AvrIspViewTextInput,
|
|
||||||
AvrIspViewChipDetect,
|
|
||||||
} AvrIspView;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
AvrIspErrorNoError,
|
|
||||||
AvrIspErrorReading,
|
|
||||||
AvrIspErrorWriting,
|
|
||||||
AvrIspErrorVerification,
|
|
||||||
AvrIspErrorWritingFuse,
|
|
||||||
} AvrIspError;
|
|
||||||
@@ -1,266 +0,0 @@
|
|||||||
#include "avr_isp_worker.h"
|
|
||||||
#include <furi_hal_pwm.h>
|
|
||||||
#include "../lib/driver/avr_isp_prog.h"
|
|
||||||
#include "../lib/driver/avr_isp_prog_cmd.h"
|
|
||||||
#include "../lib/driver/avr_isp_chip_arr.h"
|
|
||||||
|
|
||||||
#include <furi.h>
|
|
||||||
|
|
||||||
#define TAG "AvrIspWorker"
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
AvrIspWorkerEvtStop = (1 << 0),
|
|
||||||
|
|
||||||
AvrIspWorkerEvtRx = (1 << 1),
|
|
||||||
AvrIspWorkerEvtTxCoplete = (1 << 2),
|
|
||||||
AvrIspWorkerEvtTx = (1 << 3),
|
|
||||||
AvrIspWorkerEvtState = (1 << 4),
|
|
||||||
|
|
||||||
//AvrIspWorkerEvtCfg = (1 << 5),
|
|
||||||
|
|
||||||
} AvrIspWorkerEvt;
|
|
||||||
|
|
||||||
struct AvrIspWorker {
|
|
||||||
FuriThread* thread;
|
|
||||||
volatile bool worker_running;
|
|
||||||
uint8_t connect_usb;
|
|
||||||
AvrIspWorkerCallback callback;
|
|
||||||
void* context;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define AVR_ISP_WORKER_PROG_ALL_EVENTS (AvrIspWorkerEvtStop)
|
|
||||||
#define AVR_ISP_WORKER_ALL_EVENTS \
|
|
||||||
(AvrIspWorkerEvtTx | AvrIspWorkerEvtTxCoplete | AvrIspWorkerEvtRx | AvrIspWorkerEvtStop | \
|
|
||||||
AvrIspWorkerEvtState)
|
|
||||||
|
|
||||||
//########################/* VCP CDC */#############################################
|
|
||||||
#include "usb_cdc.h"
|
|
||||||
#include <cli/cli_vcp.h>
|
|
||||||
#include <cli/cli.h>
|
|
||||||
#include <furi_hal_usb_cdc.h>
|
|
||||||
|
|
||||||
#define AVR_ISP_VCP_CDC_CH 1
|
|
||||||
#define AVR_ISP_VCP_CDC_PKT_LEN CDC_DATA_SZ
|
|
||||||
#define AVR_ISP_VCP_UART_RX_BUF_SIZE (AVR_ISP_VCP_CDC_PKT_LEN * 5)
|
|
||||||
|
|
||||||
static void vcp_on_cdc_tx_complete(void* context);
|
|
||||||
static void vcp_on_cdc_rx(void* context);
|
|
||||||
static void vcp_state_callback(void* context, uint8_t state);
|
|
||||||
static void vcp_on_cdc_control_line(void* context, uint8_t state);
|
|
||||||
static void vcp_on_line_config(void* context, struct usb_cdc_line_coding* config);
|
|
||||||
|
|
||||||
static const CdcCallbacks cdc_cb = {
|
|
||||||
vcp_on_cdc_tx_complete,
|
|
||||||
vcp_on_cdc_rx,
|
|
||||||
vcp_state_callback,
|
|
||||||
vcp_on_cdc_control_line,
|
|
||||||
vcp_on_line_config,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* VCP callbacks */
|
|
||||||
|
|
||||||
static void vcp_on_cdc_tx_complete(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
AvrIspWorker* instance = context;
|
|
||||||
furi_thread_flags_set(furi_thread_get_id(instance->thread), AvrIspWorkerEvtTxCoplete);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void vcp_on_cdc_rx(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
AvrIspWorker* instance = context;
|
|
||||||
furi_thread_flags_set(furi_thread_get_id(instance->thread), AvrIspWorkerEvtRx);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void vcp_state_callback(void* context, uint8_t state) {
|
|
||||||
UNUSED(context);
|
|
||||||
|
|
||||||
AvrIspWorker* instance = context;
|
|
||||||
instance->connect_usb = state;
|
|
||||||
furi_thread_flags_set(furi_thread_get_id(instance->thread), AvrIspWorkerEvtState);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void vcp_on_cdc_control_line(void* context, uint8_t state) {
|
|
||||||
UNUSED(context);
|
|
||||||
UNUSED(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void vcp_on_line_config(void* context, struct usb_cdc_line_coding* config) {
|
|
||||||
UNUSED(context);
|
|
||||||
UNUSED(config);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void avr_isp_worker_vcp_cdc_init(void* context) {
|
|
||||||
furi_hal_usb_unlock();
|
|
||||||
Cli* cli = furi_record_open(RECORD_CLI);
|
|
||||||
//close cli
|
|
||||||
cli_session_close(cli);
|
|
||||||
//disable callbacks VCP_CDC=0
|
|
||||||
furi_hal_cdc_set_callbacks(0, NULL, NULL);
|
|
||||||
//set 2 cdc
|
|
||||||
furi_check(furi_hal_usb_set_config(&usb_cdc_dual, NULL) == true);
|
|
||||||
//open cli VCP_CDC=0
|
|
||||||
cli_session_open(cli, &cli_vcp);
|
|
||||||
furi_record_close(RECORD_CLI);
|
|
||||||
|
|
||||||
furi_hal_cdc_set_callbacks(AVR_ISP_VCP_CDC_CH, (CdcCallbacks*)&cdc_cb, context);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void avr_isp_worker_vcp_cdc_deinit(void) {
|
|
||||||
//disable callbacks AVR_ISP_VCP_CDC_CH
|
|
||||||
furi_hal_cdc_set_callbacks(AVR_ISP_VCP_CDC_CH, NULL, NULL);
|
|
||||||
|
|
||||||
Cli* cli = furi_record_open(RECORD_CLI);
|
|
||||||
//close cli
|
|
||||||
cli_session_close(cli);
|
|
||||||
furi_hal_usb_unlock();
|
|
||||||
//set 1 cdc
|
|
||||||
furi_check(furi_hal_usb_set_config(&usb_cdc_single, NULL) == true);
|
|
||||||
//open cli VCP_CDC=0
|
|
||||||
cli_session_open(cli, &cli_vcp);
|
|
||||||
furi_record_close(RECORD_CLI);
|
|
||||||
}
|
|
||||||
|
|
||||||
//#################################################################################
|
|
||||||
|
|
||||||
static int32_t avr_isp_worker_prog_thread(void* context) {
|
|
||||||
AvrIspProg* prog = context;
|
|
||||||
FURI_LOG_D(TAG, "AvrIspProgWorker Start");
|
|
||||||
while(1) {
|
|
||||||
if(furi_thread_flags_get() & AvrIspWorkerEvtStop) break;
|
|
||||||
avr_isp_prog_avrisp(prog);
|
|
||||||
}
|
|
||||||
FURI_LOG_D(TAG, "AvrIspProgWorker Stop");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void avr_isp_worker_prog_tx_data(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
AvrIspWorker* instance = context;
|
|
||||||
furi_thread_flags_set(furi_thread_get_id(instance->thread), AvrIspWorkerEvtTx);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Worker thread
|
|
||||||
*
|
|
||||||
* @param context
|
|
||||||
* @return exit code
|
|
||||||
*/
|
|
||||||
static int32_t avr_isp_worker_thread(void* context) {
|
|
||||||
AvrIspWorker* instance = context;
|
|
||||||
avr_isp_worker_vcp_cdc_init(instance);
|
|
||||||
|
|
||||||
/* start PWM on &gpio_ext_pa4 */
|
|
||||||
furi_hal_pwm_start(FuriHalPwmOutputIdLptim2PA4, 4000000, 50);
|
|
||||||
|
|
||||||
AvrIspProg* prog = avr_isp_prog_init();
|
|
||||||
avr_isp_prog_set_tx_callback(prog, avr_isp_worker_prog_tx_data, instance);
|
|
||||||
|
|
||||||
uint8_t buf[AVR_ISP_VCP_UART_RX_BUF_SIZE];
|
|
||||||
size_t len = 0;
|
|
||||||
|
|
||||||
FuriThread* prog_thread =
|
|
||||||
furi_thread_alloc_ex("AvrIspProgWorker", 1024, avr_isp_worker_prog_thread, prog);
|
|
||||||
furi_thread_start(prog_thread);
|
|
||||||
|
|
||||||
FURI_LOG_D(TAG, "Start");
|
|
||||||
|
|
||||||
while(instance->worker_running) {
|
|
||||||
uint32_t events =
|
|
||||||
furi_thread_flags_wait(AVR_ISP_WORKER_ALL_EVENTS, FuriFlagWaitAny, FuriWaitForever);
|
|
||||||
|
|
||||||
if(events & AvrIspWorkerEvtRx) {
|
|
||||||
if(avr_isp_prog_spaces_rx(prog) >= AVR_ISP_VCP_CDC_PKT_LEN) {
|
|
||||||
len = furi_hal_cdc_receive(AVR_ISP_VCP_CDC_CH, buf, AVR_ISP_VCP_CDC_PKT_LEN);
|
|
||||||
// for(uint8_t i = 0; i < len; i++) {
|
|
||||||
// FURI_LOG_I(TAG, "--> %X", buf[i]);
|
|
||||||
// }
|
|
||||||
avr_isp_prog_rx(prog, buf, len);
|
|
||||||
} else {
|
|
||||||
furi_thread_flags_set(furi_thread_get_id(instance->thread), AvrIspWorkerEvtRx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if((events & AvrIspWorkerEvtTxCoplete) || (events & AvrIspWorkerEvtTx)) {
|
|
||||||
len = avr_isp_prog_tx(prog, buf, AVR_ISP_VCP_CDC_PKT_LEN);
|
|
||||||
|
|
||||||
// for(uint8_t i = 0; i < len; i++) {
|
|
||||||
// FURI_LOG_I(TAG, "<-- %X", buf[i]);
|
|
||||||
// }
|
|
||||||
|
|
||||||
if(len > 0) furi_hal_cdc_send(AVR_ISP_VCP_CDC_CH, buf, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(events & AvrIspWorkerEvtStop) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(events & AvrIspWorkerEvtState) {
|
|
||||||
if(instance->callback)
|
|
||||||
instance->callback(instance->context, (bool)instance->connect_usb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FURI_LOG_D(TAG, "Stop");
|
|
||||||
|
|
||||||
furi_thread_flags_set(furi_thread_get_id(prog_thread), AvrIspWorkerEvtStop);
|
|
||||||
avr_isp_prog_exit(prog);
|
|
||||||
furi_delay_ms(10);
|
|
||||||
furi_thread_join(prog_thread);
|
|
||||||
furi_thread_free(prog_thread);
|
|
||||||
|
|
||||||
avr_isp_prog_free(prog);
|
|
||||||
furi_hal_pwm_stop(FuriHalPwmOutputIdLptim2PA4);
|
|
||||||
avr_isp_worker_vcp_cdc_deinit();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
AvrIspWorker* avr_isp_worker_alloc(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
UNUSED(context);
|
|
||||||
AvrIspWorker* instance = malloc(sizeof(AvrIspWorker));
|
|
||||||
|
|
||||||
instance->thread = furi_thread_alloc_ex("AvrIspWorker", 2048, avr_isp_worker_thread, instance);
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_worker_free(AvrIspWorker* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
furi_check(!instance->worker_running);
|
|
||||||
furi_thread_free(instance->thread);
|
|
||||||
free(instance);
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_worker_set_callback(
|
|
||||||
AvrIspWorker* instance,
|
|
||||||
AvrIspWorkerCallback callback,
|
|
||||||
void* context) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
instance->callback = callback;
|
|
||||||
instance->context = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_worker_start(AvrIspWorker* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
furi_assert(!instance->worker_running);
|
|
||||||
|
|
||||||
instance->worker_running = true;
|
|
||||||
|
|
||||||
furi_thread_start(instance->thread);
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_worker_stop(AvrIspWorker* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
furi_assert(instance->worker_running);
|
|
||||||
|
|
||||||
instance->worker_running = false;
|
|
||||||
furi_thread_flags_set(furi_thread_get_id(instance->thread), AvrIspWorkerEvtStop);
|
|
||||||
|
|
||||||
furi_thread_join(instance->thread);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool avr_isp_worker_is_running(AvrIspWorker* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
return instance->worker_running;
|
|
||||||
}
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <furi_hal.h>
|
|
||||||
|
|
||||||
typedef struct AvrIspWorker AvrIspWorker;
|
|
||||||
|
|
||||||
typedef void (*AvrIspWorkerCallback)(void* context, bool connect_usb);
|
|
||||||
|
|
||||||
/** Allocate AvrIspWorker
|
|
||||||
*
|
|
||||||
* @param context AvrIsp* context
|
|
||||||
* @return AvrIspWorker*
|
|
||||||
*/
|
|
||||||
AvrIspWorker* avr_isp_worker_alloc(void* context);
|
|
||||||
|
|
||||||
/** Free AvrIspWorker
|
|
||||||
*
|
|
||||||
* @param instance AvrIspWorker instance
|
|
||||||
*/
|
|
||||||
void avr_isp_worker_free(AvrIspWorker* instance);
|
|
||||||
|
|
||||||
/** Callback AvrIspWorker
|
|
||||||
*
|
|
||||||
* @param instance AvrIspWorker instance
|
|
||||||
* @param callback AvrIspWorkerOverrunCallback callback
|
|
||||||
* @param context
|
|
||||||
*/
|
|
||||||
void avr_isp_worker_set_callback(
|
|
||||||
AvrIspWorker* instance,
|
|
||||||
AvrIspWorkerCallback callback,
|
|
||||||
void* context);
|
|
||||||
|
|
||||||
/** Start AvrIspWorker
|
|
||||||
*
|
|
||||||
* @param instance AvrIspWorker instance
|
|
||||||
*/
|
|
||||||
void avr_isp_worker_start(AvrIspWorker* instance);
|
|
||||||
|
|
||||||
/** Stop AvrIspWorker
|
|
||||||
*
|
|
||||||
* @param instance AvrIspWorker instance
|
|
||||||
*/
|
|
||||||
void avr_isp_worker_stop(AvrIspWorker* instance);
|
|
||||||
|
|
||||||
/** Check if worker is running
|
|
||||||
* @param instance AvrIspWorker instance
|
|
||||||
* @return bool - true if running
|
|
||||||
*/
|
|
||||||
bool avr_isp_worker_is_running(AvrIspWorker* instance);
|
|
||||||
@@ -1,99 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <furi_hal.h>
|
|
||||||
|
|
||||||
typedef struct AvrIspWorkerRW AvrIspWorkerRW;
|
|
||||||
|
|
||||||
typedef void (*AvrIspWorkerRWCallback)(
|
|
||||||
void* context,
|
|
||||||
const char* name,
|
|
||||||
bool detect_chip,
|
|
||||||
uint32_t flash_size);
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
AvrIspWorkerRWStatusILDE = 0,
|
|
||||||
AvrIspWorkerRWStatusEndReading = 1,
|
|
||||||
AvrIspWorkerRWStatusEndVerification = 2,
|
|
||||||
AvrIspWorkerRWStatusEndWriting = 3,
|
|
||||||
AvrIspWorkerRWStatusEndWritingFuse = 4,
|
|
||||||
|
|
||||||
AvrIspWorkerRWStatusErrorReading = (-1),
|
|
||||||
AvrIspWorkerRWStatusErrorVerification = (-2),
|
|
||||||
AvrIspWorkerRWStatusErrorWriting = (-3),
|
|
||||||
AvrIspWorkerRWStatusErrorWritingFuse = (-4),
|
|
||||||
|
|
||||||
AvrIspWorkerRWStatusReserved = 0x7FFFFFFF, ///< Prevents enum down-size compiler optimization.
|
|
||||||
} AvrIspWorkerRWStatus;
|
|
||||||
|
|
||||||
typedef void (*AvrIspWorkerRWStatusCallback)(void* context, AvrIspWorkerRWStatus status);
|
|
||||||
|
|
||||||
AvrIspWorkerRW* avr_isp_worker_rw_alloc(void* context);
|
|
||||||
|
|
||||||
void avr_isp_worker_rw_free(AvrIspWorkerRW* instance);
|
|
||||||
|
|
||||||
void avr_isp_worker_rw_start(AvrIspWorkerRW* instance);
|
|
||||||
|
|
||||||
void avr_isp_worker_rw_stop(AvrIspWorkerRW* instance);
|
|
||||||
|
|
||||||
bool avr_isp_worker_rw_is_running(AvrIspWorkerRW* instance);
|
|
||||||
|
|
||||||
void avr_isp_worker_rw_set_callback(
|
|
||||||
AvrIspWorkerRW* instance,
|
|
||||||
AvrIspWorkerRWCallback callback,
|
|
||||||
void* context);
|
|
||||||
|
|
||||||
void avr_isp_worker_rw_set_callback_status(
|
|
||||||
AvrIspWorkerRW* instance,
|
|
||||||
AvrIspWorkerRWStatusCallback callback_status,
|
|
||||||
void* context_status);
|
|
||||||
|
|
||||||
bool avr_isp_worker_rw_detect_chip(AvrIspWorkerRW* instance);
|
|
||||||
|
|
||||||
float avr_isp_worker_rw_get_progress_flash(AvrIspWorkerRW* instance);
|
|
||||||
|
|
||||||
float avr_isp_worker_rw_get_progress_eeprom(AvrIspWorkerRW* instance);
|
|
||||||
|
|
||||||
bool avr_isp_worker_rw_read_dump(
|
|
||||||
AvrIspWorkerRW* instance,
|
|
||||||
const char* file_path,
|
|
||||||
const char* file_name);
|
|
||||||
|
|
||||||
void avr_isp_worker_rw_read_dump_start(
|
|
||||||
AvrIspWorkerRW* instance,
|
|
||||||
const char* file_path,
|
|
||||||
const char* file_name);
|
|
||||||
|
|
||||||
bool avr_isp_worker_rw_verification(
|
|
||||||
AvrIspWorkerRW* instance,
|
|
||||||
const char* file_path,
|
|
||||||
const char* file_name);
|
|
||||||
|
|
||||||
void avr_isp_worker_rw_verification_start(
|
|
||||||
AvrIspWorkerRW* instance,
|
|
||||||
const char* file_path,
|
|
||||||
const char* file_name);
|
|
||||||
|
|
||||||
bool avr_isp_worker_rw_check_hex(
|
|
||||||
AvrIspWorkerRW* instance,
|
|
||||||
const char* file_path,
|
|
||||||
const char* file_name);
|
|
||||||
|
|
||||||
bool avr_isp_worker_rw_write_dump(
|
|
||||||
AvrIspWorkerRW* instance,
|
|
||||||
const char* file_path,
|
|
||||||
const char* file_name);
|
|
||||||
|
|
||||||
void avr_isp_worker_rw_write_dump_start(
|
|
||||||
AvrIspWorkerRW* instance,
|
|
||||||
const char* file_path,
|
|
||||||
const char* file_name);
|
|
||||||
|
|
||||||
bool avr_isp_worker_rw_write_fuse(
|
|
||||||
AvrIspWorkerRW* instance,
|
|
||||||
const char* file_path,
|
|
||||||
const char* file_name);
|
|
||||||
|
|
||||||
void avr_isp_worker_rw_write_fuse_start(
|
|
||||||
AvrIspWorkerRW* instance,
|
|
||||||
const char* file_path,
|
|
||||||
const char* file_name);
|
|
||||||
@@ -1,321 +0,0 @@
|
|||||||
#include "flipper_i32hex_file.h"
|
|
||||||
#include <string.h>
|
|
||||||
#include <storage/storage.h>
|
|
||||||
#include <toolbox/stream/stream.h>
|
|
||||||
#include <toolbox/stream/file_stream.h>
|
|
||||||
#include <toolbox/hex.h>
|
|
||||||
|
|
||||||
//https://en.wikipedia.org/wiki/Intel_HEX
|
|
||||||
|
|
||||||
#define TAG "FlipperI32HexFile"
|
|
||||||
|
|
||||||
#define COUNT_BYTE_PAYLOAD 32 //how much payload will be used
|
|
||||||
|
|
||||||
#define I32HEX_TYPE_DATA 0x00
|
|
||||||
#define I32HEX_TYPE_END_OF_FILE 0x01
|
|
||||||
#define I32HEX_TYPE_EXT_LINEAR_ADDR 0x04
|
|
||||||
#define I32HEX_TYPE_START_LINEAR_ADDR 0x05
|
|
||||||
|
|
||||||
struct FlipperI32HexFile {
|
|
||||||
uint32_t addr;
|
|
||||||
uint32_t addr_last;
|
|
||||||
Storage* storage;
|
|
||||||
Stream* stream;
|
|
||||||
FuriString* str_data;
|
|
||||||
FlipperI32HexFileStatus file_open;
|
|
||||||
};
|
|
||||||
|
|
||||||
FlipperI32HexFile* flipper_i32hex_file_open_write(const char* name, uint32_t start_addr) {
|
|
||||||
furi_assert(name);
|
|
||||||
|
|
||||||
FlipperI32HexFile* instance = malloc(sizeof(FlipperI32HexFile));
|
|
||||||
instance->addr = start_addr;
|
|
||||||
instance->addr_last = 0;
|
|
||||||
instance->storage = furi_record_open(RECORD_STORAGE);
|
|
||||||
instance->stream = file_stream_alloc(instance->storage);
|
|
||||||
|
|
||||||
if(file_stream_open(instance->stream, name, FSAM_WRITE, FSOM_CREATE_ALWAYS)) {
|
|
||||||
instance->file_open = FlipperI32HexFileStatusOpenFileWrite;
|
|
||||||
FURI_LOG_D(TAG, "Open write file %s", name);
|
|
||||||
} else {
|
|
||||||
FURI_LOG_E(TAG, "Failed to open file %s", name);
|
|
||||||
instance->file_open = FlipperI32HexFileStatusErrorNoOpenFile;
|
|
||||||
}
|
|
||||||
instance->str_data = furi_string_alloc(instance->storage);
|
|
||||||
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
FlipperI32HexFile* flipper_i32hex_file_open_read(const char* name) {
|
|
||||||
furi_assert(name);
|
|
||||||
|
|
||||||
FlipperI32HexFile* instance = malloc(sizeof(FlipperI32HexFile));
|
|
||||||
instance->addr = 0;
|
|
||||||
instance->addr_last = 0;
|
|
||||||
instance->storage = furi_record_open(RECORD_STORAGE);
|
|
||||||
instance->stream = file_stream_alloc(instance->storage);
|
|
||||||
|
|
||||||
if(file_stream_open(instance->stream, name, FSAM_READ, FSOM_OPEN_EXISTING)) {
|
|
||||||
instance->file_open = FlipperI32HexFileStatusOpenFileRead;
|
|
||||||
FURI_LOG_D(TAG, "Open read file %s", name);
|
|
||||||
} else {
|
|
||||||
FURI_LOG_E(TAG, "Failed to open file %s", name);
|
|
||||||
instance->file_open = FlipperI32HexFileStatusErrorNoOpenFile;
|
|
||||||
}
|
|
||||||
instance->str_data = furi_string_alloc(instance->storage);
|
|
||||||
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
void flipper_i32hex_file_close(FlipperI32HexFile* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
furi_string_free(instance->str_data);
|
|
||||||
file_stream_close(instance->stream);
|
|
||||||
stream_free(instance->stream);
|
|
||||||
furi_record_close(RECORD_STORAGE);
|
|
||||||
}
|
|
||||||
|
|
||||||
FlipperI32HexFileRet flipper_i32hex_file_bin_to_i32hex_set_data(
|
|
||||||
FlipperI32HexFile* instance,
|
|
||||||
uint8_t* data,
|
|
||||||
uint32_t data_size) {
|
|
||||||
furi_assert(instance);
|
|
||||||
furi_assert(data);
|
|
||||||
|
|
||||||
FlipperI32HexFileRet ret = {.status = FlipperI32HexFileStatusOK, .data_size = 0};
|
|
||||||
if(instance->file_open != FlipperI32HexFileStatusOpenFileWrite) {
|
|
||||||
ret.status = FlipperI32HexFileStatusErrorFileWrite;
|
|
||||||
}
|
|
||||||
uint8_t count_byte = 0;
|
|
||||||
uint32_t ind = 0;
|
|
||||||
uint8_t crc = 0;
|
|
||||||
|
|
||||||
furi_string_reset(instance->str_data);
|
|
||||||
|
|
||||||
if((instance->addr_last & 0xFF0000) < (instance->addr & 0xFF0000)) {
|
|
||||||
crc = 0x02 + 0x04 + ((instance->addr >> 24) & 0xFF) + ((instance->addr >> 16) & 0xFF);
|
|
||||||
crc = 0x01 + ~crc;
|
|
||||||
//I32HEX_TYPE_EXT_LINEAR_ADDR
|
|
||||||
furi_string_cat_printf(
|
|
||||||
instance->str_data, ":02000004%04lX%02X\r\n", (instance->addr >> 16), crc);
|
|
||||||
instance->addr_last = instance->addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
while(ind < data_size) {
|
|
||||||
if((ind + COUNT_BYTE_PAYLOAD) > data_size) {
|
|
||||||
count_byte = data_size - ind;
|
|
||||||
} else {
|
|
||||||
count_byte = COUNT_BYTE_PAYLOAD;
|
|
||||||
}
|
|
||||||
//I32HEX_TYPE_DATA
|
|
||||||
furi_string_cat_printf(
|
|
||||||
instance->str_data, ":%02X%04lX00", count_byte, (instance->addr & 0xFFFF));
|
|
||||||
crc = count_byte + ((instance->addr >> 8) & 0xFF) + (instance->addr & 0xFF);
|
|
||||||
|
|
||||||
for(uint32_t i = 0; i < count_byte; i++) {
|
|
||||||
furi_string_cat_printf(instance->str_data, "%02X", *data);
|
|
||||||
crc += *data++;
|
|
||||||
}
|
|
||||||
crc = 0x01 + ~crc;
|
|
||||||
furi_string_cat_printf(instance->str_data, "%02X\r\n", crc);
|
|
||||||
|
|
||||||
ind += count_byte;
|
|
||||||
instance->addr += count_byte;
|
|
||||||
}
|
|
||||||
if(instance->file_open) stream_write_string(instance->stream, instance->str_data);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
FlipperI32HexFileRet flipper_i32hex_file_bin_to_i32hex_set_end_line(FlipperI32HexFile* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
FlipperI32HexFileRet ret = {.status = FlipperI32HexFileStatusOK, .data_size = 0};
|
|
||||||
if(instance->file_open != FlipperI32HexFileStatusOpenFileWrite) {
|
|
||||||
ret.status = FlipperI32HexFileStatusErrorFileWrite;
|
|
||||||
}
|
|
||||||
furi_string_reset(instance->str_data);
|
|
||||||
//I32HEX_TYPE_END_OF_FILE
|
|
||||||
furi_string_cat_printf(instance->str_data, ":00000001FF\r\n");
|
|
||||||
if(instance->file_open) stream_write_string(instance->stream, instance->str_data);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void flipper_i32hex_file_bin_to_i32hex_set_addr(FlipperI32HexFile* instance, uint32_t addr) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
instance->addr = addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* flipper_i32hex_file_get_string(FlipperI32HexFile* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
return furi_string_get_cstr(instance->str_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static FlipperI32HexFileRet flipper_i32hex_file_parse_line(
|
|
||||||
FlipperI32HexFile* instance,
|
|
||||||
const char* str,
|
|
||||||
uint8_t* data,
|
|
||||||
uint32_t data_size) {
|
|
||||||
furi_assert(instance);
|
|
||||||
furi_assert(data);
|
|
||||||
|
|
||||||
char* str1;
|
|
||||||
uint32_t data_wrire_ind = 0;
|
|
||||||
uint32_t data_len = 0;
|
|
||||||
FlipperI32HexFileRet ret = {.status = FlipperI32HexFileStatusErrorData, .data_size = 0};
|
|
||||||
|
|
||||||
//Search for start of data I32HEX
|
|
||||||
str1 = strstr(str, ":");
|
|
||||||
do {
|
|
||||||
if(str1 == NULL) {
|
|
||||||
ret.status = FlipperI32HexFileStatusErrorData;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
str1++;
|
|
||||||
if(!hex_char_to_uint8(*str1, str1[1], data + data_wrire_ind)) {
|
|
||||||
ret.status = FlipperI32HexFileStatusErrorData;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
str1++;
|
|
||||||
if(++data_wrire_ind > data_size) {
|
|
||||||
ret.status = FlipperI32HexFileStatusErrorOverflow;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
data_len = 5 + data[0]; // +5 bytes per header and crc
|
|
||||||
while(data_len > data_wrire_ind) {
|
|
||||||
str1++;
|
|
||||||
if(!hex_char_to_uint8(*str1, str1[1], data + data_wrire_ind)) {
|
|
||||||
ret.status = FlipperI32HexFileStatusErrorData;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
str1++;
|
|
||||||
if(++data_wrire_ind > data_size) {
|
|
||||||
ret.status = FlipperI32HexFileStatusErrorOverflow;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ret.status = FlipperI32HexFileStatusOK;
|
|
||||||
ret.data_size = data_wrire_ind;
|
|
||||||
|
|
||||||
} while(0);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool flipper_i32hex_file_check_data(uint8_t* data, uint32_t data_size) {
|
|
||||||
furi_assert(data);
|
|
||||||
|
|
||||||
uint8_t crc = 0;
|
|
||||||
uint32_t data_read_ind = 0;
|
|
||||||
if(data[0] > data_size) return false;
|
|
||||||
while(data_read_ind < data_size - 1) {
|
|
||||||
crc += data[data_read_ind++];
|
|
||||||
}
|
|
||||||
return data[data_size - 1] == ((1 + ~crc) & 0xFF);
|
|
||||||
}
|
|
||||||
|
|
||||||
static FlipperI32HexFileRet flipper_i32hex_file_parse(
|
|
||||||
FlipperI32HexFile* instance,
|
|
||||||
const char* str,
|
|
||||||
uint8_t* data,
|
|
||||||
uint32_t data_size) {
|
|
||||||
furi_assert(instance);
|
|
||||||
furi_assert(data);
|
|
||||||
|
|
||||||
FlipperI32HexFileRet ret = flipper_i32hex_file_parse_line(instance, str, data, data_size);
|
|
||||||
|
|
||||||
if((ret.status == FlipperI32HexFileStatusOK) && (ret.data_size > 4)) {
|
|
||||||
switch(data[3]) {
|
|
||||||
case I32HEX_TYPE_DATA:
|
|
||||||
if(flipper_i32hex_file_check_data(data, ret.data_size)) {
|
|
||||||
ret.data_size -= 5;
|
|
||||||
memcpy(data, data + 4, ret.data_size);
|
|
||||||
ret.status = FlipperI32HexFileStatusData;
|
|
||||||
} else {
|
|
||||||
ret.status = FlipperI32HexFileStatusErrorCrc;
|
|
||||||
ret.data_size = 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case I32HEX_TYPE_END_OF_FILE:
|
|
||||||
if(flipper_i32hex_file_check_data(data, ret.data_size)) {
|
|
||||||
ret.status = FlipperI32HexFileStatusEofFile;
|
|
||||||
ret.data_size = 0;
|
|
||||||
} else {
|
|
||||||
ret.status = FlipperI32HexFileStatusErrorCrc;
|
|
||||||
ret.data_size = 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case I32HEX_TYPE_EXT_LINEAR_ADDR:
|
|
||||||
if(flipper_i32hex_file_check_data(data, ret.data_size)) {
|
|
||||||
data[0] = data[4];
|
|
||||||
data[1] = data[5];
|
|
||||||
data[3] = 0;
|
|
||||||
data[4] = 0;
|
|
||||||
ret.status = FlipperI32HexFileStatusUdateAddr;
|
|
||||||
ret.data_size = 4;
|
|
||||||
} else {
|
|
||||||
ret.status = FlipperI32HexFileStatusErrorCrc;
|
|
||||||
ret.data_size = 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case I32HEX_TYPE_START_LINEAR_ADDR:
|
|
||||||
ret.status = FlipperI32HexFileStatusErrorUnsupportedCommand;
|
|
||||||
ret.data_size = 0;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ret.status = FlipperI32HexFileStatusErrorUnsupportedCommand;
|
|
||||||
ret.data_size = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ret.status = FlipperI32HexFileStatusErrorData;
|
|
||||||
ret.data_size = 0;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool flipper_i32hex_file_check(FlipperI32HexFile* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
uint32_t data_size = 280;
|
|
||||||
uint8_t data[280] = {0};
|
|
||||||
bool ret = true;
|
|
||||||
|
|
||||||
if(instance->file_open != FlipperI32HexFileStatusOpenFileRead) {
|
|
||||||
FURI_LOG_E(TAG, "File is not open");
|
|
||||||
ret = false;
|
|
||||||
} else {
|
|
||||||
stream_rewind(instance->stream);
|
|
||||||
|
|
||||||
while(stream_read_line(instance->stream, instance->str_data)) {
|
|
||||||
FlipperI32HexFileRet parse_ret = flipper_i32hex_file_parse(
|
|
||||||
instance, furi_string_get_cstr(instance->str_data), data, data_size);
|
|
||||||
|
|
||||||
if(parse_ret.status < 0) {
|
|
||||||
ret = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stream_rewind(instance->stream);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
FlipperI32HexFileRet flipper_i32hex_file_i32hex_to_bin_get_data(
|
|
||||||
FlipperI32HexFile* instance,
|
|
||||||
uint8_t* data,
|
|
||||||
uint32_t data_size) {
|
|
||||||
furi_assert(instance);
|
|
||||||
furi_assert(data);
|
|
||||||
|
|
||||||
FlipperI32HexFileRet ret = {.status = FlipperI32HexFileStatusOK, .data_size = 0};
|
|
||||||
if(instance->file_open != FlipperI32HexFileStatusOpenFileRead) {
|
|
||||||
ret.status = FlipperI32HexFileStatusErrorFileRead;
|
|
||||||
} else {
|
|
||||||
stream_read_line(instance->stream, instance->str_data);
|
|
||||||
ret = flipper_i32hex_file_parse(
|
|
||||||
instance, furi_string_get_cstr(instance->str_data), data, data_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <furi_hal.h>
|
|
||||||
|
|
||||||
typedef struct FlipperI32HexFile FlipperI32HexFile;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
FlipperI32HexFileStatusOK = 0,
|
|
||||||
FlipperI32HexFileStatusData = 2,
|
|
||||||
FlipperI32HexFileStatusUdateAddr = 3,
|
|
||||||
FlipperI32HexFileStatusEofFile = 4,
|
|
||||||
FlipperI32HexFileStatusOpenFileWrite = 5,
|
|
||||||
FlipperI32HexFileStatusOpenFileRead = 6,
|
|
||||||
|
|
||||||
// Errors
|
|
||||||
FlipperI32HexFileStatusErrorCrc = (-1),
|
|
||||||
FlipperI32HexFileStatusErrorOverflow = (-2),
|
|
||||||
FlipperI32HexFileStatusErrorData = (-3),
|
|
||||||
FlipperI32HexFileStatusErrorUnsupportedCommand = (-4),
|
|
||||||
FlipperI32HexFileStatusErrorNoOpenFile = (-5),
|
|
||||||
FlipperI32HexFileStatusErrorFileWrite = (-6),
|
|
||||||
FlipperI32HexFileStatusErrorFileRead = (-7),
|
|
||||||
|
|
||||||
FlipperI32HexFileStatusReserved =
|
|
||||||
0x7FFFFFFF, ///< Prevents enum down-size compiler optimization.
|
|
||||||
} FlipperI32HexFileStatus;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
FlipperI32HexFileStatus status;
|
|
||||||
uint32_t data_size;
|
|
||||||
} FlipperI32HexFileRet;
|
|
||||||
|
|
||||||
FlipperI32HexFile* flipper_i32hex_file_open_write(const char* name, uint32_t start_addr);
|
|
||||||
|
|
||||||
FlipperI32HexFile* flipper_i32hex_file_open_read(const char* name);
|
|
||||||
|
|
||||||
void flipper_i32hex_file_close(FlipperI32HexFile* instance);
|
|
||||||
|
|
||||||
FlipperI32HexFileRet flipper_i32hex_file_bin_to_i32hex_set_data(
|
|
||||||
FlipperI32HexFile* instance,
|
|
||||||
uint8_t* data,
|
|
||||||
uint32_t data_size);
|
|
||||||
|
|
||||||
FlipperI32HexFileRet flipper_i32hex_file_bin_to_i32hex_set_end_line(FlipperI32HexFile* instance);
|
|
||||||
|
|
||||||
const char* flipper_i32hex_file_get_string(FlipperI32HexFile* instance);
|
|
||||||
|
|
||||||
void flipper_i32hex_file_bin_to_i32hex_set_addr(FlipperI32HexFile* instance, uint32_t addr);
|
|
||||||
|
|
||||||
bool flipper_i32hex_file_check(FlipperI32HexFile* instance);
|
|
||||||
|
|
||||||
FlipperI32HexFileRet flipper_i32hex_file_i32hex_to_bin_get_data(
|
|
||||||
FlipperI32HexFile* instance,
|
|
||||||
uint8_t* data,
|
|
||||||
uint32_t data_size);
|
|
||||||
|
Before Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 3.8 KiB |
@@ -1,386 +0,0 @@
|
|||||||
#include "avr_isp_chip_arr.h"
|
|
||||||
|
|
||||||
#include <furi.h>
|
|
||||||
|
|
||||||
//https://github.com/avrdudes/avrdude/blob/master/src/avrintel.c
|
|
||||||
|
|
||||||
const AvrIspChipArr avr_isp_chip_arr[] = { // Value of -1 typically means unknown
|
|
||||||
//{mcu_name, mcuid, family, {sig, na, ture}, flstart, flsize, pgsiz, nb, bootsz, eestart, eesize, ep, rambeg, ramsiz, nf, nl, ni}, // Source
|
|
||||||
{"ATtiny4", 0, F_AVR8L, {0x1E, 0x8F, 0x0A}, 0, 0x00200, 0x010, 0, 0, 0, 0, 0, 0x0040, 0x0020, 1, 1, 10}, // atdf, avr-gcc 12.2.0, avrdude, boot size (manual)
|
|
||||||
{"ATtiny5", 1, F_AVR8L, {0x1E, 0x8F, 0x09}, 0, 0x00200, 0x010, 0, 0, 0, 0, 0, 0x0040, 0x0020, 1, 1, 11}, // atdf, avr-gcc 12.2.0, avrdude, boot size (manual)
|
|
||||||
{"ATtiny9", 2, F_AVR8L, {0x1E, 0x90, 0x08}, 0, 0x00400, 0x010, 0, 0, 0, 0, 0, 0x0040, 0x0020, 1, 1, 10}, // atdf, avr-gcc 12.2.0, avrdude, boot size (manual)
|
|
||||||
{"ATtiny10", 3, F_AVR8L, {0x1E, 0x90, 0x03}, 0, 0x00400, 0x010, 0, 0, 0, 0, 0, 0x0040, 0x0020, 1, 1, 11}, // atdf, avr-gcc 12.2.0, avrdude, boot size (manual)
|
|
||||||
{"ATtiny20", 4, F_AVR8L, {0x1E, 0x91, 0x0F}, 0, 0x00800, 0x020, 0, 0, 0, 0, 0, 0x0040, 0x0080, 1, 1, 17}, // atdf, avr-gcc 12.2.0, avrdude, boot size (manual)
|
|
||||||
{"ATtiny40", 5, F_AVR8L, {0x1E, 0x92, 0x0E}, 0, 0x01000, 0x040, 0, 0, 0, 0, 0, 0x0040, 0x0100, 1, 1, 18}, // atdf, avr-gcc 12.2.0, avrdude, boot size (manual)
|
|
||||||
{"ATtiny102", 6, F_AVR8L, {0x1E, 0x90, 0x0C}, 0, 0x00400, 0x010, 0, 0, 0, 0, 0, 0x0040, 0x0020, 1, 1, 16}, // atdf, avrdude, boot size (manual)
|
|
||||||
{"ATtiny104", 7, F_AVR8L, {0x1E, 0x90, 0x0B}, 0, 0x00400, 0x010, 0, 0, 0, 0, 0, 0x0040, 0x0020, 1, 1, 16}, // atdf, avrdude, boot size (manual)
|
|
||||||
|
|
||||||
{"ATtiny11", 8, F_AVR8, {0x1E, 0x90, 0x04}, 0, 0x00400, 0x001, 0, 0, 0, 0x0040, 1, 0x0060, 0x0020, 1, 1, 5}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny12", 9, F_AVR8, {0x1E, 0x90, 0x05}, 0, 0x00400, 0x001, 0, 0, 0, 0x0040, 2, 0x0060, 0x0020, 1, 1, 6}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny13", 10, F_AVR8, {0x1E, 0x90, 0x07}, 0, 0x00400, 0x020, 0, 0, 0, 0x0040, 4, 0x0060, 0x0040, 2, 1, 10}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny13A", 11, F_AVR8, {0x1E, 0x90, 0x07}, 0, 0x00400, 0x020, 0, 0, 0, 0x0040, 4, 0x0060, 0x0040, 2, 1, 10}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny15", 12, F_AVR8, {0x1E, 0x90, 0x06}, 0, 0x00400, 0x001, 0, 0, 0, 0x0040, 2, 0x0060, 0x0020, 1, 1, 9}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny22", 13, F_AVR8, {0x1E, 0x91, 0x06}, 0, 0x00800, -1, 0, 0, -1, -1, -1, 0x0060, 0x0080, 1, 1, 3}, // avr-gcc 12.2.0, boot size (manual)
|
|
||||||
{"ATtiny24", 14, F_AVR8, {0x1E, 0x91, 0x0B}, 0, 0x00800, 0x020, 0, 0, 0, 0x0080, 4, 0x0060, 0x0080, 3, 1, 17}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny24A", 15, F_AVR8, {0x1E, 0x91, 0x0B}, 0, 0x00800, 0x020, 0, 0, 0, 0x0080, 4, 0x0060, 0x0080, 3, 1, 17}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny25", 16, F_AVR8, {0x1E, 0x91, 0x08}, 0, 0x00800, 0x020, 0, 0, 0, 0x0080, 4, 0x0060, 0x0080, 3, 1, 15}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny26", 17, F_AVR8, {0x1E, 0x91, 0x09}, 0, 0x00800, 0x020, 0, 0, 0, 0x0080, 4, 0x0060, 0x0080, 2, 1, 12}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny28", 18, F_AVR8, {0x1E, 0x91, 0x07}, 0, 0x00800, 0x002, 0, 0, 0, 0, 0, 0x0060, 0x0020, 1, 1, 6}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny43U", 19, F_AVR8, {0x1E, 0x92, 0x0C}, 0, 0x01000, 0x040, 0, 0, 0, 0x0040, 4, 0x0060, 0x0100, 3, 1, 16}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny44", 20, F_AVR8, {0x1E, 0x92, 0x07}, 0, 0x01000, 0x040, 0, 0, 0, 0x0100, 4, 0x0060, 0x0100, 3, 1, 17}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny44A", 21, F_AVR8, {0x1E, 0x92, 0x07}, 0, 0x01000, 0x040, 0, 0, 0, 0x0100, 4, 0x0060, 0x0100, 3, 1, 17}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny45", 22, F_AVR8, {0x1E, 0x92, 0x06}, 0, 0x01000, 0x040, 0, 0, 0, 0x0100, 4, 0x0060, 0x0100, 3, 1, 15}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny48", 23, F_AVR8, {0x1E, 0x92, 0x09}, 0, 0x01000, 0x040, 0, 0, 0, 0x0040, 4, 0x0100, 0x0100, 3, 1, 20}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny84", 24, F_AVR8, {0x1E, 0x93, 0x0C}, 0, 0x02000, 0x040, 0, 0, 0, 0x0200, 4, 0x0060, 0x0200, 3, 1, 17}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny84A", 25, F_AVR8, {0x1E, 0x93, 0x0C}, 0, 0x02000, 0x040, 0, 0, 0, 0x0200, 4, 0x0060, 0x0200, 3, 1, 17}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny85", 26, F_AVR8, {0x1E, 0x93, 0x0B}, 0, 0x02000, 0x040, 0, 0, 0, 0x0200, 4, 0x0060, 0x0200, 3, 1, 15}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny87", 27, F_AVR8, {0x1E, 0x93, 0x87}, 0, 0x02000, 0x080, 0, 0, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 20}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny88", 28, F_AVR8, {0x1E, 0x93, 0x11}, 0, 0x02000, 0x040, 0, 0, 0, 0x0040, 4, 0x0100, 0x0200, 3, 1, 20}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny167", 29, F_AVR8, {0x1E, 0x94, 0x87}, 0, 0x04000, 0x080, 0, 0, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 20}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny261", 30, F_AVR8, {0x1E, 0x91, 0x0C}, 0, 0x00800, 0x020, 0, 0, 0, 0x0080, 4, 0x0060, 0x0080, 3, 1, 19}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny261A", 31, F_AVR8, {0x1E, 0x91, 0x0C}, 0, 0x00800, 0x020, 0, 0, 0, 0x0080, 4, 0x0060, 0x0080, 3, 1, 19}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny441", 32, F_AVR8, {0x1E, 0x92, 0x15}, 0, 0x01000, 0x010, 0, 0, 0, 0x0100, 4, 0x0100, 0x0100, 3, 1, 30}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny461", 33, F_AVR8, {0x1E, 0x92, 0x08}, 0, 0x01000, 0x040, 0, 0, 0, 0x0100, 4, 0x0060, 0x0100, 3, 1, 19}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny461A", 34, F_AVR8, {0x1E, 0x92, 0x08}, 0, 0x01000, 0x040, 0, 0, 0, 0x0100, 4, 0x0060, 0x0100, 3, 1, 19}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny828", 35, F_AVR8, {0x1E, 0x93, 0x14}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0100, 4, 0x0100, 0x0200, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny828R", 36, F_AVR8, {0x1E, 0x93, 0x14}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0100, 4, 0x0100, 0x0200, 3, 1, 26}, // avrdude, from ATtiny828
|
|
||||||
{"ATtiny841", 37, F_AVR8, {0x1E, 0x93, 0x15}, 0, 0x02000, 0x010, 0, 0, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 30}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny861", 38, F_AVR8, {0x1E, 0x93, 0x0D}, 0, 0x02000, 0x040, 0, 0, 0, 0x0200, 4, 0x0060, 0x0200, 3, 1, 19}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny861A", 39, F_AVR8, {0x1E, 0x93, 0x0D}, 0, 0x02000, 0x040, 0, 0, 0, 0x0200, 4, 0x0060, 0x0200, 3, 1, 19}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny1634", 40, F_AVR8, {0x1E, 0x94, 0x12}, 0, 0x04000, 0x020, 0, 0, 0, 0x0100, 4, 0x0100, 0x0400, 3, 1, 28}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny1634R", 41, F_AVR8, {0x1E, 0x94, 0x12}, 0, 0x04000, 0x020, 0, 0, 0, 0x0100, 4, 0x0100, 0x0400, 3, 1, 28}, // avrdude, from ATtiny1634
|
|
||||||
{"ATtiny2313", 42, F_AVR8, {0x1E, 0x91, 0x0A}, 0, 0x00800, 0x020, 0, 0, 0, 0x0080, 4, 0x0060, 0x0080, 3, 1, 19}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny2313A", 43, F_AVR8, {0x1E, 0x91, 0x0A}, 0, 0x00800, 0x020, 0, 0, 0, 0x0080, 4, 0x0060, 0x0080, 3, 1, 21}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny4313", 44, F_AVR8, {0x1E, 0x92, 0x0D}, 0, 0x01000, 0x040, 0, 0, 0, 0x0100, 4, 0x0060, 0x0100, 3, 1, 21}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega8", 45, F_AVR8, {0x1E, 0x93, 0x07}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0060, 0x0400, 2, 1, 19}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega8A", 46, F_AVR8, {0x1E, 0x93, 0x07}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0060, 0x0400, 2, 1, 19}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega8HVA", 47, F_AVR8, {0x1E, 0x93, 0x10}, 0, 0x02000, 0x080, 0, 0, 0, 0x0100, 4, 0x0100, 0x0200, 1, 1, 21}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"ATmega8U2", 48, F_AVR8, {0x1E, 0x93, 0x89}, 0, 0x02000, 0x080, 4, 0x0200, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 29}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega16", 49, F_AVR8, {0x1E, 0x94, 0x03}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0060, 0x0400, 2, 1, 21}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega16A", 50, F_AVR8, {0x1E, 0x94, 0x03}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0060, 0x0400, 2, 1, 21}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega16HVA", 51, F_AVR8, {0x1E, 0x94, 0x0C}, 0, 0x04000, 0x080, 0, 0, 0, 0x0100, 4, 0x0100, 0x0200, 1, 1, 21}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"ATmega16HVB", 52, F_AVR8, {0x1E, 0x94, 0x0D}, 0, 0x04000, 0x080, 4, 0x0200, 0, 0x0200, 4, 0x0100, 0x0400, 2, 1, 29}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"ATmega16HVBrevB", 53, F_AVR8, {0x1E, 0x94, 0x0D}, 0, 0x04000, 0x080, 4, 0x0200, 0, 0x0200, 4, 0x0100, 0x0400, 2, 1, 29}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"ATmega16M1", 54, F_AVR8, {0x1E, 0x94, 0x84}, 0, 0x04000, 0x080, 4, 0x0200, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 31}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"ATmega16HVA2", 55, F_AVR8, {0x1E, 0x94, 0x0E}, 0, 0x04000, 0x080, -1, -1, -1, -1, -1, 0x0100, 0x0400, 2, 1, 22}, // avr-gcc 12.2.0
|
|
||||||
{"ATmega16U2", 56, F_AVR8, {0x1E, 0x94, 0x89}, 0, 0x04000, 0x080, 4, 0x0200, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 29}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega16U4", 57, F_AVR8, {0x1E, 0x94, 0x88}, 0, 0x04000, 0x080, 4, 0x0200, 0, 0x0200, 4, 0x0100, 0x0500, 3, 1, 43}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega32", 58, F_AVR8, {0x1E, 0x95, 0x02}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0060, 0x0800, 2, 1, 21}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega32A", 59, F_AVR8, {0x1E, 0x95, 0x02}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0060, 0x0800, 2, 1, 21}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega32HVB", 60, F_AVR8, {0x1E, 0x95, 0x10}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 2, 1, 29}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"ATmega32HVBrevB", 61, F_AVR8, {0x1E, 0x95, 0x10}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 2, 1, 29}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"ATmega32C1", 62, F_AVR8, {0x1E, 0x95, 0x86}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 31}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"ATmega32M1", 63, F_AVR8, {0x1E, 0x95, 0x84}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega32U2", 64, F_AVR8, {0x1E, 0x95, 0x8A}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0400, 3, 1, 29}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega32U4", 65, F_AVR8, {0x1E, 0x95, 0x87}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0a00, 3, 1, 43}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega32U6", 66, F_AVR8, {0x1E, 0x95, 0x88}, 0, 0x08000, 0x080, 4, 0x0200, -1, -1, -1, 0x0100, 0x0a00, 3, 1, 38}, // avr-gcc 12.2.0, boot size (manual)
|
|
||||||
{"ATmega48", 67, F_AVR8, {0x1E, 0x92, 0x05}, 0, 0x01000, 0x040, 0, 0, 0, 0x0100, 4, 0x0100, 0x0200, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega48A", 68, F_AVR8, {0x1E, 0x92, 0x05}, 0, 0x01000, 0x040, 0, 0, 0, 0x0100, 4, 0x0100, 0x0200, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega48P", 69, F_AVR8, {0x1E, 0x92, 0x0A}, 0, 0x01000, 0x040, 0, 0, 0, 0x0100, 4, 0x0100, 0x0200, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega48PA", 70, F_AVR8, {0x1E, 0x92, 0x0A}, 0, 0x01000, 0x040, 0, 0, 0, 0x0100, 4, 0x0100, 0x0200, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega48PB", 71, F_AVR8, {0x1E, 0x92, 0x10}, 0, 0x01000, 0x040, 0, 0, 0, 0x0100, 4, 0x0100, 0x0200, 3, 1, 27}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega64", 72, F_AVR8, {0x1E, 0x96, 0x02}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 35}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega64A", 73, F_AVR8, {0x1E, 0x96, 0x02}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 35}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega64HVE", 74, F_AVR8, {0x1E, 0x96, 0x10}, 0, 0x10000, 0x080, 4, 0x0400, -1, -1, -1, 0x0100, 0x1000, 2, 1, 25}, // avr-gcc 12.2.0, boot size (manual)
|
|
||||||
{"ATmega64C1", 75, F_AVR8, {0x1E, 0x96, 0x86}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 31}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"ATmega64M1", 76, F_AVR8, {0x1E, 0x96, 0x84}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega64HVE2", 77, F_AVR8, {0x1E, 0x96, 0x10}, 0, 0x10000, 0x080, 4, 0x0400, 0, 0x0400, 4, 0x0100, 0x1000, 2, 1, 25}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"ATmega64RFR2", 78, F_AVR8, {0x1E, 0xA6, 0x02}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0200, 0x2000, 3, 1, 77}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega88", 79, F_AVR8, {0x1E, 0x93, 0x0A}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega88A", 80, F_AVR8, {0x1E, 0x93, 0x0A}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega88P", 81, F_AVR8, {0x1E, 0x93, 0x0F}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega88PA", 82, F_AVR8, {0x1E, 0x93, 0x0F}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega88PB", 83, F_AVR8, {0x1E, 0x93, 0x16}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 27}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega103", 84, F_AVR8, {0x1E, 0x97, 0x01}, 0, 0x20000, 0x100, 0, 0, 0, 0x1000, 1, 0x0060, 0x0fa0, 1, 1, 24}, // avr-gcc 12.2.0, avrdude, boot size (manual)
|
|
||||||
{"ATmega128", 85, F_AVR8, {0x1E, 0x97, 0x02}, 0, 0x20000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0100, 0x1000, 3, 1, 35}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega128A", 86, F_AVR8, {0x1E, 0x97, 0x02}, 0, 0x20000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0100, 0x1000, 3, 1, 35}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega128RFA1", 87, F_AVR8, {0x1E, 0xA7, 0x01}, 0, 0x20000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0200, 0x4000, 3, 1, 72}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega128RFR2", 88, F_AVR8, {0x1E, 0xA7, 0x02}, 0, 0x20000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0200, 0x4000, 3, 1, 77}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega161", 89, F_AVR8, {0x1E, 0x94, 0x01}, 0, 0x04000, 0x080, 1, 0x0400, 0, 0x0200, 1, 0x0060, 0x0400, 1, 1, 21}, // avr-gcc 12.2.0, avrdude, boot size (manual)
|
|
||||||
{"ATmega162", 90, F_AVR8, {0x1E, 0x94, 0x04}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 28}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega163", 91, F_AVR8, {0x1E, 0x94, 0x02}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 1, 0x0060, 0x0400, 2, 1, 18}, // avr-gcc 12.2.0, avrdude, boot size (manual)
|
|
||||||
{"ATmega164A", 92, F_AVR8, {0x1E, 0x94, 0x0F}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega164P", 93, F_AVR8, {0x1E, 0x94, 0x0A}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega164PA", 94, F_AVR8, {0x1E, 0x94, 0x0A}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega165", 95, F_AVR8, {0x1E, 0x94, 0x10}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 22}, // avr-gcc 12.2.0, avrdude, boot size (manual)
|
|
||||||
{"ATmega165A", 96, F_AVR8, {0x1E, 0x94, 0x10}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 22}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega165P", 97, F_AVR8, {0x1E, 0x94, 0x07}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 22}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega165PA", 98, F_AVR8, {0x1E, 0x94, 0x07}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 22}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega168", 99, F_AVR8, {0x1E, 0x94, 0x06}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega168A", 100, F_AVR8, {0x1E, 0x94, 0x06}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega168P", 101, F_AVR8, {0x1E, 0x94, 0x0B}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega168PA", 102, F_AVR8, {0x1E, 0x94, 0x0B}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega168PB", 103, F_AVR8, {0x1E, 0x94, 0x15}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 27}, // atdf, avr-gcc 7.3.0, avrdude
|
|
||||||
{"ATmega169", 104, F_AVR8, {0x1E, 0x94, 0x05}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 23}, // avr-gcc 12.2.0, avrdude, boot size (manual)
|
|
||||||
{"ATmega169A", 105, F_AVR8, {0x1E, 0x94, 0x11}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 23}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega169P", 106, F_AVR8, {0x1E, 0x94, 0x05}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 23}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega169PA", 107, F_AVR8, {0x1E, 0x94, 0x05}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 23}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega256RFR2", 108, F_AVR8, {0x1E, 0xA8, 0x02}, 0, 0x40000, 0x100, 4, 0x0400, 0, 0x2000, 8, 0x0200, 0x8000, 3, 1, 77}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega323", 109, F_AVR8, {0x1E, 0x95, 0x01}, 0, 0x08000, 0x080, 4, 0x0200, -1, -1, -1, 0x0060, 0x0800, 2, 1, 21}, // avr-gcc 12.2.0, boot size (manual)
|
|
||||||
{"ATmega324A", 110, F_AVR8, {0x1E, 0x95, 0x15}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega324P", 111, F_AVR8, {0x1E, 0x95, 0x08}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega324PA", 112, F_AVR8, {0x1E, 0x95, 0x11}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega324PB", 113, F_AVR8, {0x1E, 0x95, 0x17}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 51}, // atdf, avrdude
|
|
||||||
{"ATmega325", 114, F_AVR8, {0x1E, 0x95, 0x05}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 22}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega325A", 115, F_AVR8, {0x1E, 0x95, 0x05}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 22}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega325P", 116, F_AVR8, {0x1E, 0x95, 0x0D}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 22}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega325PA", 117, F_AVR8, {0x1E, 0x95, 0x0D}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 22}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega328", 118, F_AVR8, {0x1E, 0x95, 0x14}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega328P", 119, F_AVR8, {0x1E, 0x95, 0x0F}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega328PB", 120, F_AVR8, {0x1E, 0x95, 0x16}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 45}, // atdf, avr-gcc 7.3.0, avrdude
|
|
||||||
{"ATmega329", 121, F_AVR8, {0x1E, 0x95, 0x03}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 23}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega329A", 122, F_AVR8, {0x1E, 0x95, 0x03}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 23}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega329P", 123, F_AVR8, {0x1E, 0x95, 0x0B}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 23}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega329PA", 124, F_AVR8, {0x1E, 0x95, 0x0B}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 23}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega406", 125, F_AVR8, {0x1E, 0x95, 0x07}, 0, 0x0a000, 0x080, 4, 0x0200, 0, 0x0200, 4, 0x0100, 0x0800, 2, 1, 23}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega640", 126, F_AVR8, {0x1E, 0x96, 0x08}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0200, 0x2000, 3, 1, 57}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega644", 127, F_AVR8, {0x1E, 0x96, 0x09}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 28}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega644A", 128, F_AVR8, {0x1E, 0x96, 0x09}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega644P", 129, F_AVR8, {0x1E, 0x96, 0x0A}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega644PA", 130, F_AVR8, {0x1E, 0x96, 0x0A}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega644RFR2", 131, F_AVR8, {0x1E, 0xA6, 0x03}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0200, 0x2000, 3, 1, 77}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega645", 132, F_AVR8, {0x1E, 0x96, 0x05}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 22}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega645A", 133, F_AVR8, {0x1E, 0x96, 0x05}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 22}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega645P", 134, F_AVR8, {0x1E, 0x96, 0x0D}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 22}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega649", 135, F_AVR8, {0x1E, 0x96, 0x03}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 23}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega649A", 136, F_AVR8, {0x1E, 0x96, 0x03}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 23}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega649P", 137, F_AVR8, {0x1E, 0x96, 0x0B}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 23}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega1280", 138, F_AVR8, {0x1E, 0x97, 0x03}, 0, 0x20000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0200, 0x2000, 3, 1, 57}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega1281", 139, F_AVR8, {0x1E, 0x97, 0x04}, 0, 0x20000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0200, 0x2000, 3, 1, 57}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega1284", 140, F_AVR8, {0x1E, 0x97, 0x06}, 0, 0x20000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0100, 0x4000, 3, 1, 35}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega1284P", 141, F_AVR8, {0x1E, 0x97, 0x05}, 0, 0x20000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0100, 0x4000, 3, 1, 35}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega1284RFR2", 142, F_AVR8, {0x1E, 0xA7, 0x03}, 0, 0x20000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0200, 0x4000, 3, 1, 77}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega2560", 143, F_AVR8, {0x1E, 0x98, 0x01}, 0, 0x40000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0200, 0x2000, 3, 1, 57}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega2561", 144, F_AVR8, {0x1E, 0x98, 0x02}, 0, 0x40000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0200, 0x2000, 3, 1, 57}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega2564RFR2", 145, F_AVR8, {0x1E, 0xA8, 0x03}, 0, 0x40000, 0x100, 4, 0x0400, 0, 0x2000, 8, 0x0200, 0x8000, 3, 1, 77}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega3250", 146, F_AVR8, {0x1E, 0x95, 0x06}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega3250A", 147, F_AVR8, {0x1E, 0x95, 0x06}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega3250P", 148, F_AVR8, {0x1E, 0x95, 0x0E}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega3250PA", 149, F_AVR8, {0x1E, 0x95, 0x0E}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega3290", 150, F_AVR8, {0x1E, 0x95, 0x04}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega3290A", 151, F_AVR8, {0x1E, 0x95, 0x04}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega3290P", 152, F_AVR8, {0x1E, 0x95, 0x0C}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega3290PA", 153, F_AVR8, {0x1E, 0x95, 0x0C}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega6450", 154, F_AVR8, {0x1E, 0x96, 0x06}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega6450A", 155, F_AVR8, {0x1E, 0x96, 0x06}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega6450P", 156, F_AVR8, {0x1E, 0x96, 0x0E}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega6490", 157, F_AVR8, {0x1E, 0x96, 0x04}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega6490A", 158, F_AVR8, {0x1E, 0x96, 0x04}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega6490P", 159, F_AVR8, {0x1E, 0x96, 0x0C}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega8515", 160, F_AVR8, {0x1E, 0x93, 0x06}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0060, 0x0200, 2, 1, 17}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega8535", 161, F_AVR8, {0x1E, 0x93, 0x08}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0060, 0x0200, 2, 1, 21}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"AT43USB320", 162, F_AVR8, {0xff, -1, -1}, 0, 0x10000, -1, -1, -1, -1, -1, -1, 0x0060, 0x0200, -1, -1, 0}, // avr-gcc 12.2.0
|
|
||||||
{"AT43USB355", 163, F_AVR8, {0xff, -1, -1}, 0, 0x06000, -1, -1, -1, -1, -1, -1, 0x0060, 0x0400, -1, -1, 0}, // avr-gcc 12.2.0
|
|
||||||
{"AT76C711", 164, F_AVR8, {0xff, -1, -1}, 0, 0x04000, -1, -1, -1, -1, -1, -1, 0x0060, 0x07a0, -1, -1, 0}, // avr-gcc 12.2.0
|
|
||||||
{"AT86RF401", 165, F_AVR8, {0x1E, 0x91, 0x81}, 0, 0x00800, -1, -1, -1, -1, -1, -1, 0x0060, 0x0080, 0, 1, 3}, // avr-gcc 12.2.0
|
|
||||||
{"AT90PWM1", 166, F_AVR8, {0x1E, 0x93, 0x83}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 32}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"AT90PWM2", 167, F_AVR8, {0x1E, 0x93, 0x81}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 32}, // avr-gcc 12.2.0, avrdude, boot size (manual)
|
|
||||||
{"AT90PWM2B", 168, F_AVR8, {0x1E, 0x93, 0x83}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 32}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"AT90PWM3", 169, F_AVR8, {0x1E, 0x93, 0x81}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 32}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"AT90PWM3B", 170, F_AVR8, {0x1E, 0x93, 0x83}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 32}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"AT90CAN32", 171, F_AVR8, {0x1E, 0x95, 0x81}, 0, 0x08000, 0x100, 4, 0x0400, 0, 0x0400, 8, 0x0100, 0x0800, 3, 1, 37}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"AT90CAN64", 172, F_AVR8, {0x1E, 0x96, 0x81}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 37}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"AT90PWM81", 173, F_AVR8, {0x1E, 0x93, 0x88}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0100, 3, 1, 20}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"AT90USB82", 174, F_AVR8, {0x1E, 0x93, 0x82}, 0, 0x02000, 0x080, 4, 0x0200, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 29}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"AT90SCR100", 175, F_AVR8, {0x1E, 0x96, 0xC1}, 0, 0x10000, 0x100, 4, 0x0200, -1, -1, -1, 0x0100, 0x1000, 3, 1, 38}, // avr-gcc 12.2.0, boot size (manual)
|
|
||||||
{"AT90CAN128", 176, F_AVR8, {0x1E, 0x97, 0x81}, 0, 0x20000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0100, 0x1000, 3, 1, 37}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"AT90PWM161", 177, F_AVR8, {0x1E, 0x94, 0x8B}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 20}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"AT90USB162", 178, F_AVR8, {0x1E, 0x94, 0x82}, 0, 0x04000, 0x080, 4, 0x0200, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 29}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"AT90PWM216", 179, F_AVR8, {0x1E, 0x94, 0x83}, 0, 0x04000, 0x080, 4, 0x0200, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 32}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"AT90PWM316", 180, F_AVR8, {0x1E, 0x94, 0x83}, 0, 0x04000, 0x080, 4, 0x0200, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 32}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"AT90USB646", 181, F_AVR8, {0x1E, 0x96, 0x82}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 38}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"AT90USB647", 182, F_AVR8, {0x1E, 0x96, 0x82}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 38}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"AT90S1200", 183, F_AVR8, {0x1E, 0x90, 0x01}, 0, 0x00400, 0x001, 0, 0, 0, 0x0040, 1, 0x0060, 0x0020, 1, 1, 4}, // avr-gcc 12.2.0, avrdude, boot size (manual)
|
|
||||||
{"AT90USB1286", 184, F_AVR8, {0x1E, 0x97, 0x82}, 0, 0x20000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0100, 0x2000, 3, 1, 38}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"AT90USB1287", 185, F_AVR8, {0x1E, 0x97, 0x82}, 0, 0x20000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0100, 0x2000, 3, 1, 38}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"AT90S2313", 186, F_AVR8, {0x1E, 0x91, 0x01}, 0, 0x00800, 0x001, 0, 0, 0, 0x0080, 1, 0x0060, 0x0080, 1, 1, 11}, // avr-gcc 12.2.0, avrdude, boot size (manual)
|
|
||||||
{"AT90S2323", 187, F_AVR8, {0x1E, 0x91, 0x02}, 0, 0x00800, -1, 0, 0, -1, -1, -1, 0x0060, 0x0080, 1, 1, 3}, // avr-gcc 12.2.0, boot size (manual)
|
|
||||||
{"AT90S2333", 188, F_AVR8, {0x1E, 0x91, 0x05}, 0, 0x00800, 0x001, 0, 0, 0, 0x0080, 1, 0x0060, 0x0080, -1, -1, 14}, // avr-gcc 12.2.0, avrdude, boot size (manual)
|
|
||||||
{"AT90S2343", 189, F_AVR8, {0x1E, 0x91, 0x03}, 0, 0x00800, 0x001, 0, 0, 0, 0x0080, 1, 0x0060, 0x0080, 1, 1, 3}, // avr-gcc 12.2.0, avrdude, boot size (manual)
|
|
||||||
{"AT90S4414", 190, F_AVR8, {0x1E, 0x92, 0x01}, 0, 0x01000, 0x001, 0, 0, 0, 0x0100, 1, 0x0060, 0x0100, 1, 1, 13}, // avr-gcc 12.2.0, avrdude, boot size (manual)
|
|
||||||
{"AT90S4433", 191, F_AVR8, {0x1E, 0x92, 0x03}, 0, 0x01000, 0x001, 0, 0, 0, 0x0100, 1, 0x0060, 0x0080, 1, 1, 14}, // avr-gcc 12.2.0, avrdude, boot size (manual)
|
|
||||||
{"AT90S4434", 192, F_AVR8, {0x1E, 0x92, 0x02}, 0, 0x01000, 0x001, 0, 0, 0, 0x0100, 1, 0x0060, 0x0100, 1, 1, 17}, // avr-gcc 12.2.0, avrdude, boot size (manual)
|
|
||||||
{"AT90S8515", 193, F_AVR8, {0x1E, 0x93, 0x01}, 0, 0x02000, 0x001, 0, 0, 0, 0x0200, 1, 0x0060, 0x0200, 1, 1, 13}, // avr-gcc 12.2.0, avrdude, boot size (manual)
|
|
||||||
{"AT90C8534", 194, F_AVR8, {0xff, -1, -1}, 0, 0x02000, -1, -1, -1, -1, -1, -1, 0x0060, 0x0100, -1, -1, 0}, // avr-gcc 12.2.0
|
|
||||||
{"AT90S8535", 195, F_AVR8, {0x1E, 0x93, 0x03}, 0, 0x02000, 0x001, 0, 0, 0, 0x0200, 1, 0x0060, 0x0200, 1, 1, 17}, // avr-gcc 12.2.0, avrdude, boot size (manual)
|
|
||||||
{"AT94K", 196, F_AVR8, {0xff, -1, -1}, 0, 0x08000, -1, -1, -1, -1, -1, -1, 0x0060, 0x0fa0, -1, -1, 0}, // avr-gcc 12.2.0
|
|
||||||
{"ATA5272", 197, F_AVR8, {0x1E, 0x93, 0x87}, 0, 0x02000, 0x080, 0, 0, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 37}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"ATA5505", 198, F_AVR8, {0x1E, 0x94, 0x87}, 0, 0x04000, 0x080, 0, 0, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 20}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"ATA5700M322", 199, F_AVR8, {0x1E, 0x95, 0x67}, 0x08000, 0x08000, 0x040, 0, 0, 0, 0x0880, 16, 0x0200, 0x0400, 1, 1, 51}, // atdf
|
|
||||||
{"ATA5702M322", 200, F_AVR8, {0x1E, 0x95, 0x69}, 0x08000, 0x08000, 0x040, 0, 0, 0, 0x0880, 16, 0x0200, 0x0400, 1, 1, 51}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"ATA5781", 201, F_AVR8, {0x1E, 0x95, 0x64}, -1, -1, -1, 0, 0, 0, 0x0400, 16, 0x0200, 0x0400, 1, 1, 42}, // atdf
|
|
||||||
{"ATA5782", 202, F_AVR8, {0x1E, 0x95, 0x65}, 0x08000, 0x05000, 0x040, 1, 0x5000, 0, 0x0400, 16, 0x0200, 0x0400, 1, 1, 42}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"ATA5783", 203, F_AVR8, {0x1E, 0x95, 0x66}, -1, -1, -1, 0, 0, 0, 0x0400, 16, 0x0200, 0x0400, 1, 1, 42}, // atdf
|
|
||||||
{"ATA5787", 204, F_AVR8, {0x1E, 0x94, 0x6C}, 0x08000, 0x05200, 0x040, 0, 0, 0, 0x0400, 16, 0x0200, 0x0800, 1, 1, 44}, // atdf
|
|
||||||
{"ATA5790", 205, F_AVR8, {0x1E, 0x94, 0x61}, 0, 0x04000, 0x080, 1, 0x0800, 0, 0x0800, 16, 0x0100, 0x0200, 1, 1, 30}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"ATA5790N", 206, F_AVR8, {0x1E, 0x94, 0x62}, 0, 0x04000, 0x080, 1, 0x0800, 0, 0x0800, 16, 0x0100, 0x0200, 1, 1, 31}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"ATA5791", 207, F_AVR8, {0x1E, 0x94, 0x62}, 0, 0x04000, 0x080, 1, 0x0800, 0, 0x0800, 16, 0x0100, 0x0200, 1, 1, 31}, // atdf, avr-gcc 7.3.0
|
|
||||||
{"ATA5795", 208, F_AVR8, {0x1E, 0x93, 0x61}, 0, 0x02000, 0x040, 1, 0x0800, 0, 0x0800, 16, 0x0100, 0x0200, 1, 1, 23}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"ATA5831", 209, F_AVR8, {0x1E, 0x95, 0x61}, 0x08000, 0x05000, 0x040, 1, 0x5000, 0, 0x0400, 16, 0x0200, 0x0400, 1, 1, 42}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"ATA5832", 210, F_AVR8, {0x1E, 0x95, 0x62}, -1, -1, -1, 0, 0, 0, 0x0400, 16, 0x0200, 0x0400, 1, 1, 42}, // atdf
|
|
||||||
{"ATA5833", 211, F_AVR8, {0x1E, 0x95, 0x63}, -1, -1, -1, 0, 0, 0, 0x0400, 16, 0x0200, 0x0400, 1, 1, 42}, // atdf
|
|
||||||
{"ATA5835", 212, F_AVR8, {0x1E, 0x94, 0x6B}, 0x08000, 0x05200, 0x040, 0, 0, 0, 0x0400, 16, 0x0200, 0x0800, 1, 1, 44}, // atdf
|
|
||||||
{"ATA6285", 213, F_AVR8, {0x1E, 0x93, 0x82}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0140, 4, 0x0100, 0x0200, 2, 1, 27}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"ATA6286", 214, F_AVR8, {0x1E, 0x93, 0x82}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0140, 4, 0x0100, 0x0200, 2, 1, 27}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"ATA6289", 215, F_AVR8, {0x1E, 0x93, 0x82}, 0, 0x02000, 0x040, 4, 0x0100, -1, -1, -1, 0x0100, 0x0200, 2, 1, 27}, // avr-gcc 12.2.0, boot size (manual)
|
|
||||||
{"ATA6612C", 216, F_AVR8, {0x1E, 0x93, 0x0A}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"ATA6613C", 217, F_AVR8, {0x1E, 0x94, 0x06}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"ATA6614Q", 218, F_AVR8, {0x1E, 0x95, 0x0F}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 26}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"ATA6616C", 219, F_AVR8, {0x1E, 0x93, 0x87}, 0, 0x02000, 0x080, 0, 0, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 20}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"ATA6617C", 220, F_AVR8, {0x1E, 0x94, 0x87}, 0, 0x04000, 0x080, 0, 0, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 20}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"ATA8210", 221, F_AVR8, {0x1E, 0x95, 0x65}, 0x08000, 0x05000, 0x040, 1, 0x5000, 0, 0x0400, 16, 0x0200, 0x0400, 1, 1, 42}, // atdf, avr-gcc 7.3.0
|
|
||||||
{"ATA8215", 222, F_AVR8, {0x1E, 0x95, 0x64}, -1, -1, -1, 0, 0, 0, 0x0400, 16, 0x0200, 0x0400, 1, 1, 42}, // atdf
|
|
||||||
{"ATA8510", 223, F_AVR8, {0x1E, 0x95, 0x61}, 0x08000, 0x05000, 0x040, 1, 0x5000, 0, 0x0400, 16, 0x0200, 0x0400, 1, 1, 42}, // atdf, avr-gcc 7.3.0
|
|
||||||
{"ATA8515", 224, F_AVR8, {0x1E, 0x95, 0x63}, -1, -1, -1, 0, 0, 0, 0x0400, 16, 0x0200, 0x0400, 1, 1, 42}, // atdf
|
|
||||||
{"ATA664251", 225, F_AVR8, {0x1E, 0x94, 0x87}, 0, 0x04000, 0x080, 0, 0, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 20}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"M3000", 226, F_AVR8, {0xff, -1, -1}, 0, 0x10000, -1, -1, -1, -1, -1, -1, 0x1000, 0x1000, -1, -1, 0}, // avr-gcc 12.2.0
|
|
||||||
{"LGT8F88P", 227, F_AVR8, {0x1E, 0x93, 0x0F}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // avrdude, from ATmega88
|
|
||||||
{"LGT8F168P", 228, F_AVR8, {0x1E, 0x94, 0x0B}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // avrdude, from ATmega168P
|
|
||||||
{"LGT8F328P", 229, F_AVR8, {0x1E, 0x95, 0x0F}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 26}, // avrdude, from ATmega328P
|
|
||||||
|
|
||||||
{"ATxmega8E5", 230, F_XMEGA, {0x1E, 0x93, 0x41}, 0, 0x02800, 0x080, 1, 0x0800, 0, 0x0200, 32, 0x2000, 0x0400, 7, 1, 43}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega16A4", 231, F_XMEGA, {0x1E, 0x94, 0x41}, 0, 0x05000, 0x100, 1, 0x1000, 0, 0x0400, 32, 0x2000, 0x0800, 6, 1, 94}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega16A4U", 232, F_XMEGA, {0x1E, 0x94, 0x41}, 0, 0x05000, 0x100, 1, 0x1000, 0, 0x0400, 32, 0x2000, 0x0800, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega16C4", 233, F_XMEGA, {0x1E, 0x94, 0x43}, 0, 0x05000, 0x100, 1, 0x1000, 0, 0x0400, 32, 0x2000, 0x0800, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega16D4", 234, F_XMEGA, {0x1E, 0x94, 0x42}, 0, 0x05000, 0x100, 1, 0x1000, 0, 0x0400, 32, 0x2000, 0x0800, 6, 1, 91}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega16E5", 235, F_XMEGA, {0x1E, 0x94, 0x45}, 0, 0x05000, 0x080, 1, 0x1000, 0, 0x0200, 32, 0x2000, 0x0800, 7, 1, 43}, // atdf, avr-gcc 7.3.0, avrdude
|
|
||||||
{"ATxmega32C3", 236, F_XMEGA, {0x1E, 0x95, 0x49}, 0, 0x09000, 0x100, 1, 0x1000, 0, 0x0400, 32, 0x2000, 0x1000, 6, 1, 127}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"ATxmega32D3", 237, F_XMEGA, {0x1E, 0x95, 0x4A}, 0, 0x09000, 0x100, 1, 0x1000, 0, 0x0400, 32, 0x2000, 0x1000, 6, 1, 114}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"ATxmega32A4", 238, F_XMEGA, {0x1E, 0x95, 0x41}, 0, 0x09000, 0x100, 1, 0x1000, 0, 0x0400, 32, 0x2000, 0x1000, 6, 1, 94}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega32A4U", 239, F_XMEGA, {0x1E, 0x95, 0x41}, 0, 0x09000, 0x100, 1, 0x1000, 0, 0x0400, 32, 0x2000, 0x1000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega32C4", 240, F_XMEGA, {0x1E, 0x95, 0x44}, 0, 0x09000, 0x100, 1, 0x1000, 0, 0x0400, 32, 0x2000, 0x1000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega32D4", 241, F_XMEGA, {0x1E, 0x95, 0x42}, 0, 0x09000, 0x100, 1, 0x1000, 0, 0x0400, 32, 0x2000, 0x1000, 6, 1, 91}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega32E5", 242, F_XMEGA, {0x1E, 0x95, 0x4C}, 0, 0x09000, 0x080, 1, 0x1000, 0, 0x0400, 32, 0x2000, 0x1000, 7, 1, 43}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega64A1", 243, F_XMEGA, {0x1E, 0x96, 0x4E}, 0, 0x11000, 0x100, 1, 0x1000, 0, 0x0800, 32, 0x2000, 0x1000, 6, 1, 125}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega64A1U", 244, F_XMEGA, {0x1E, 0x96, 0x4E}, 0, 0x11000, 0x100, 1, 0x1000, 0, 0x0800, 32, 0x2000, 0x1000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega64B1", 245, F_XMEGA, {0x1E, 0x96, 0x52}, 0, 0x11000, 0x100, 1, 0x1000, 0, 0x0800, 32, 0x2000, 0x1000, 6, 1, 81}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega64A3", 246, F_XMEGA, {0x1E, 0x96, 0x42}, 0, 0x11000, 0x100, 1, 0x1000, 0, 0x0800, 32, 0x2000, 0x1000, 6, 1, 122}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega64A3U", 247, F_XMEGA, {0x1E, 0x96, 0x42}, 0, 0x11000, 0x100, 1, 0x1000, 0, 0x0800, 32, 0x2000, 0x1000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega64B3", 248, F_XMEGA, {0x1E, 0x96, 0x51}, 0, 0x11000, 0x100, 1, 0x1000, 0, 0x0800, 32, 0x2000, 0x1000, 6, 1, 54}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega64C3", 249, F_XMEGA, {0x1E, 0x96, 0x49}, 0, 0x11000, 0x100, 1, 0x1000, 0, 0x0800, 32, 0x2000, 0x1000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega64D3", 250, F_XMEGA, {0x1E, 0x96, 0x4A}, 0, 0x11000, 0x100, 1, 0x1000, 0, 0x0800, 32, 0x2000, 0x1000, 6, 1, 114}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega64A4", 251, F_XMEGA, {0x1E, 0x96, 0x46}, 0, 0x11000, 0x100, -1, -1, 0, 0x0800, 32, -1, -1, -1, -1, 0}, // avrdude
|
|
||||||
{"ATxmega64A4U", 252, F_XMEGA, {0x1E, 0x96, 0x46}, 0, 0x11000, 0x100, 1, 0x1000, 0, 0x0800, 32, 0x2000, 0x1000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega64D4", 253, F_XMEGA, {0x1E, 0x96, 0x47}, 0, 0x11000, 0x100, 1, 0x1000, 0, 0x0800, 32, 0x2000, 0x1000, 6, 1, 91}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega128A1", 254, F_XMEGA, {0x1E, 0x97, 0x4C}, 0, 0x22000, 0x200, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x2000, 6, 1, 125}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega128A1revD", 255, F_XMEGA, {0x1E, 0x97, 0x41}, 0, 0x22000, 0x200, -1, -1, 0, 0x0800, 32, -1, -1, -1, -1, 0}, // avrdude
|
|
||||||
{"ATxmega128A1U", 256, F_XMEGA, {0x1E, 0x97, 0x4C}, 0, 0x22000, 0x200, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x2000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega128B1", 257, F_XMEGA, {0x1E, 0x97, 0x4D}, 0, 0x22000, 0x100, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x2000, 6, 1, 81}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega128A3", 258, F_XMEGA, {0x1E, 0x97, 0x42}, 0, 0x22000, 0x200, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x2000, 6, 1, 122}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega128A3U", 259, F_XMEGA, {0x1E, 0x97, 0x42}, 0, 0x22000, 0x200, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x2000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega128B3", 260, F_XMEGA, {0x1E, 0x97, 0x4B}, 0, 0x22000, 0x100, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x2000, 6, 1, 54}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega128C3", 261, F_XMEGA, {0x1E, 0x97, 0x52}, 0, 0x22000, 0x200, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x2000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega128D3", 262, F_XMEGA, {0x1E, 0x97, 0x48}, 0, 0x22000, 0x200, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x2000, 6, 1, 114}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega128A4", 263, F_XMEGA, {0x1E, 0x97, 0x46}, 0, 0x22000, 0x200, -1, -1, 0, 0x0800, 32, -1, -1, -1, -1, 0}, // avrdude
|
|
||||||
{"ATxmega128A4U", 264, F_XMEGA, {0x1E, 0x97, 0x46}, 0, 0x22000, 0x100, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x2000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega128D4", 265, F_XMEGA, {0x1E, 0x97, 0x47}, 0, 0x22000, 0x100, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x2000, 6, 1, 91}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega192A1", 266, F_XMEGA, {0x1E, 0x97, 0x4E}, 0, 0x32000, 0x200, -1, -1, 0, 0x0800, 32, -1, -1, -1, -1, 0}, // avrdude
|
|
||||||
{"ATxmega192A3", 267, F_XMEGA, {0x1E, 0x97, 0x44}, 0, 0x32000, 0x200, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x4000, 6, 1, 122}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega192A3U", 268, F_XMEGA, {0x1E, 0x97, 0x44}, 0, 0x32000, 0x200, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x4000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega192C3", 269, F_XMEGA, {0x1E, 0x97, 0x51}, 0, 0x32000, 0x200, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x4000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega192D3", 270, F_XMEGA, {0x1E, 0x97, 0x49}, 0, 0x32000, 0x200, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x4000, 6, 1, 114}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega256A1", 271, F_XMEGA, {0x1E, 0x98, 0x46}, 0, 0x42000, 0x200, -1, -1, 0, 0x1000, 32, -1, -1, -1, -1, 0}, // avrdude
|
|
||||||
{"ATxmega256A3", 272, F_XMEGA, {0x1E, 0x98, 0x42}, 0, 0x42000, 0x200, 1, 0x2000, 0, 0x1000, 32, 0x2000, 0x4000, 6, 1, 122}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega256A3B", 273, F_XMEGA, {0x1E, 0x98, 0x43}, 0, 0x42000, 0x200, 1, 0x2000, 0, 0x1000, 32, 0x2000, 0x4000, 6, 1, 122}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega256A3BU", 274, F_XMEGA, {0x1E, 0x98, 0x43}, 0, 0x42000, 0x200, 1, 0x2000, 0, 0x1000, 32, 0x2000, 0x4000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega256A3U", 275, F_XMEGA, {0x1E, 0x98, 0x42}, 0, 0x42000, 0x200, 1, 0x2000, 0, 0x1000, 32, 0x2000, 0x4000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega256C3", 276, F_XMEGA, {0x1E, 0x98, 0x46}, 0, 0x42000, 0x200, 1, 0x2000, 0, 0x1000, 32, 0x2000, 0x4000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega256D3", 277, F_XMEGA, {0x1E, 0x98, 0x44}, 0, 0x42000, 0x200, 1, 0x2000, 0, 0x1000, 32, 0x2000, 0x4000, 6, 1, 114}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega384C3", 278, F_XMEGA, {0x1E, 0x98, 0x45}, 0, 0x62000, 0x200, 1, 0x2000, 0, 0x1000, 32, 0x2000, 0x8000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega384D3", 279, F_XMEGA, {0x1E, 0x98, 0x47}, 0, 0x62000, 0x200, 1, 0x2000, 0, 0x1000, 32, 0x2000, 0x8000, 6, 1, 114}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
|
|
||||||
{"ATtiny202", 280, F_AVR8X, {0x1E, 0x91, 0x23}, 0, 0x00800, 0x040, 1, 0, 0x01400, 0x0040, 32, 0x3f80, 0x0080, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny204", 281, F_AVR8X, {0x1E, 0x91, 0x22}, 0, 0x00800, 0x040, 1, 0, 0x01400, 0x0040, 32, 0x3f80, 0x0080, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny212", 282, F_AVR8X, {0x1E, 0x91, 0x21}, 0, 0x00800, 0x040, 1, 0, 0x01400, 0x0040, 32, 0x3f80, 0x0080, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny214", 283, F_AVR8X, {0x1E, 0x91, 0x20}, 0, 0x00800, 0x040, 1, 0, 0x01400, 0x0040, 32, 0x3f80, 0x0080, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny402", 284, F_AVR8X, {0x1E, 0x92, 0x27}, 0, 0x01000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3f00, 0x0100, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny404", 285, F_AVR8X, {0x1E, 0x92, 0x26}, 0, 0x01000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3f00, 0x0100, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny406", 286, F_AVR8X, {0x1E, 0x92, 0x25}, 0, 0x01000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3f00, 0x0100, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny412", 287, F_AVR8X, {0x1E, 0x92, 0x23}, 0, 0x01000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3f00, 0x0100, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny414", 288, F_AVR8X, {0x1E, 0x92, 0x22}, 0, 0x01000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3f00, 0x0100, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny416", 289, F_AVR8X, {0x1E, 0x92, 0x21}, 0, 0x01000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3f00, 0x0100, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny416auto", 290, F_AVR8X, {0x1E, 0x92, 0x28}, 0, 0x01000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3f00, 0x0100, 10, 1, 26}, // atdf
|
|
||||||
{"ATtiny417", 291, F_AVR8X, {0x1E, 0x92, 0x20}, 0, 0x01000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3f00, 0x0100, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny424", 292, F_AVR8X, {0x1E, 0x92, 0x2C}, 0, 0x01000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3e00, 0x0200, 10, 1, 30}, // atdf, avrdude
|
|
||||||
{"ATtiny426", 293, F_AVR8X, {0x1E, 0x92, 0x2B}, 0, 0x01000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3e00, 0x0200, 10, 1, 30}, // atdf, avrdude
|
|
||||||
{"ATtiny427", 294, F_AVR8X, {0x1E, 0x92, 0x2A}, 0, 0x01000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3e00, 0x0200, 10, 1, 30}, // atdf, avrdude
|
|
||||||
{"ATtiny804", 295, F_AVR8X, {0x1E, 0x93, 0x25}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3e00, 0x0200, 10, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny806", 296, F_AVR8X, {0x1E, 0x93, 0x24}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3e00, 0x0200, 10, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny807", 297, F_AVR8X, {0x1E, 0x93, 0x23}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3e00, 0x0200, 10, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny814", 298, F_AVR8X, {0x1E, 0x93, 0x22}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3e00, 0x0200, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny816", 299, F_AVR8X, {0x1E, 0x93, 0x21}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3e00, 0x0200, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny817", 300, F_AVR8X, {0x1E, 0x93, 0x20}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3e00, 0x0200, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny824", 301, F_AVR8X, {0x1E, 0x93, 0x29}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3c00, 0x0400, 10, 1, 30}, // atdf, avrdude
|
|
||||||
{"ATtiny826", 302, F_AVR8X, {0x1E, 0x93, 0x28}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3c00, 0x0400, 10, 1, 30}, // atdf, avrdude
|
|
||||||
{"ATtiny827", 303, F_AVR8X, {0x1E, 0x93, 0x27}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3c00, 0x0400, 10, 1, 30}, // atdf, avrdude
|
|
||||||
{"ATtiny1604", 304, F_AVR8X, {0x1E, 0x94, 0x25}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3c00, 0x0400, 10, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny1606", 305, F_AVR8X, {0x1E, 0x94, 0x24}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3c00, 0x0400, 10, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny1607", 306, F_AVR8X, {0x1E, 0x94, 0x23}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3c00, 0x0400, 10, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny1614", 307, F_AVR8X, {0x1E, 0x94, 0x22}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3800, 0x0800, 10, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny1616", 308, F_AVR8X, {0x1E, 0x94, 0x21}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3800, 0x0800, 10, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny1617", 309, F_AVR8X, {0x1E, 0x94, 0x20}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3800, 0x0800, 10, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny1624", 310, F_AVR8X, {0x1E, 0x94, 0x2A}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3800, 0x0800, 10, 1, 30}, // atdf, avrdude
|
|
||||||
{"ATtiny1626", 311, F_AVR8X, {0x1E, 0x94, 0x29}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3800, 0x0800, 10, 1, 30}, // atdf, avrdude
|
|
||||||
{"ATtiny1627", 312, F_AVR8X, {0x1E, 0x94, 0x28}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3800, 0x0800, 10, 1, 30}, // atdf, avrdude
|
|
||||||
{"ATtiny3214", 313, F_AVR8X, {0x1E, 0x95, 0x20}, 0, 0x08000, 0x080, 1, 0, 0x01400, 0x0100, 64, 0x3800, 0x0800, 10, 1, 31}, // avr-gcc 12.2.0
|
|
||||||
{"ATtiny3216", 314, F_AVR8X, {0x1E, 0x95, 0x21}, 0, 0x08000, 0x080, 1, 0, 0x01400, 0x0100, 64, 0x3800, 0x0800, 10, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny3217", 315, F_AVR8X, {0x1E, 0x95, 0x22}, 0, 0x08000, 0x080, 1, 0, 0x01400, 0x0100, 64, 0x3800, 0x0800, 10, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny3224", 316, F_AVR8X, {0x1E, 0x95, 0x28}, 0, 0x08000, 0x080, 1, 0, 0x01400, 0x0100, 64, 0x3400, 0x0c00, 10, 1, 30}, // atdf, avrdude
|
|
||||||
{"ATtiny3226", 317, F_AVR8X, {0x1E, 0x95, 0x27}, 0, 0x08000, 0x080, 1, 0, 0x01400, 0x0100, 64, 0x3400, 0x0c00, 10, 1, 30}, // atdf, avrdude
|
|
||||||
{"ATtiny3227", 318, F_AVR8X, {0x1E, 0x95, 0x26}, 0, 0x08000, 0x080, 1, 0, 0x01400, 0x0100, 64, 0x3400, 0x0c00, 10, 1, 30}, // atdf, avrdude
|
|
||||||
{"ATmega808", 319, F_AVR8X, {0x1E, 0x93, 0x26}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3c00, 0x0400, 10, 1, 36}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega809", 320, F_AVR8X, {0x1E, 0x93, 0x2A}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3c00, 0x0400, 10, 1, 40}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega1608", 321, F_AVR8X, {0x1E, 0x94, 0x27}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3800, 0x0800, 10, 1, 36}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega1609", 322, F_AVR8X, {0x1E, 0x94, 0x26}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3800, 0x0800, 10, 1, 40}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega3208", 323, F_AVR8X, {0x1E, 0x95, 0x30}, 0, 0x08000, 0x080, 1, 0, 0x01400, 0x0100, 64, 0x3000, 0x1000, 10, 1, 36}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega3209", 324, F_AVR8X, {0x1E, 0x95, 0x31}, 0, 0x08000, 0x080, 1, 0, 0x01400, 0x0100, 64, 0x3000, 0x1000, 10, 1, 40}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega4808", 325, F_AVR8X, {0x1E, 0x96, 0x50}, 0, 0x0c000, 0x080, 1, 0, 0x01400, 0x0100, 64, 0x2800, 0x1800, 10, 1, 36}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega4809", 326, F_AVR8X, {0x1E, 0x96, 0x51}, 0, 0x0c000, 0x080, 1, 0, 0x01400, 0x0100, 64, 0x2800, 0x1800, 10, 1, 40}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"AVR8EA28", 327, F_AVR8X, {0x1E, 0x93, 0x2C}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0200, 8, -1, -1, -1, -1, 0}, // avrdude
|
|
||||||
{"AVR8EA32", 328, F_AVR8X, {0x1E, 0x93, 0x2B}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0200, 8, -1, -1, -1, -1, 0}, // avrdude
|
|
||||||
{"AVR16DD14", 329, F_AVR8X, {0x1E, 0x94, 0x34}, 0, 0x04000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x7800, 0x0800, 16, 4, 36}, // atdf, avrdude
|
|
||||||
{"AVR16DD20", 330, F_AVR8X, {0x1E, 0x94, 0x33}, 0, 0x04000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x7800, 0x0800, 16, 4, 36}, // atdf, avrdude
|
|
||||||
{"AVR16DD28", 331, F_AVR8X, {0x1E, 0x94, 0x32}, 0, 0x04000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x7800, 0x0800, 16, 4, 36}, // atdf, avrdude
|
|
||||||
{"AVR16EA28", 332, F_AVR8X, {0x1E, 0x94, 0x37}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0200, 8, -1, -1, -1, -1, 0}, // avrdude
|
|
||||||
{"AVR16DD32", 333, F_AVR8X, {0x1E, 0x94, 0x31}, 0, 0x04000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x7800, 0x0800, 16, 4, 36}, // atdf, avrdude
|
|
||||||
{"AVR16EA32", 334, F_AVR8X, {0x1E, 0x94, 0x36}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0200, 8, -1, -1, -1, -1, 0}, // avrdude
|
|
||||||
{"AVR16EA48", 335, F_AVR8X, {0x1E, 0x94, 0x35}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0200, 8, -1, -1, -1, -1, 0}, // avrdude
|
|
||||||
{"AVR32DD14", 336, F_AVR8X, {0x1E, 0x95, 0x3B}, 0, 0x08000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x7000, 0x1000, 16, 4, 36}, // atdf, avrdude
|
|
||||||
{"AVR32DD20", 337, F_AVR8X, {0x1E, 0x95, 0x3A}, 0, 0x08000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x7000, 0x1000, 16, 4, 36}, // atdf, avrdude
|
|
||||||
{"AVR32DA28", 338, F_AVR8X, {0x1E, 0x95, 0x34}, 0, 0x08000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x7000, 0x1000, 16, 4, 41}, // atdf, avrdude
|
|
||||||
{"AVR32DB28", 339, F_AVR8X, {0x1E, 0x95, 0x37}, 0, 0x08000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x7000, 0x1000, 16, 4, 42}, // atdf, avrdude
|
|
||||||
{"AVR32DD28", 340, F_AVR8X, {0x1E, 0x95, 0x39}, 0, 0x08000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x7000, 0x1000, 16, 4, 36}, // atdf, avrdude
|
|
||||||
{"AVR32EA28", 341, F_AVR8X, {0x1E, 0x95, 0x3E}, 0, 0x08000, 0x040, 1, 0, 0x01400, 0x0200, 8, -1, -1, -1, -1, 0}, // avrdude
|
|
||||||
{"AVR32DA32", 342, F_AVR8X, {0x1E, 0x95, 0x33}, 0, 0x08000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x7000, 0x1000, 16, 4, 44}, // atdf, avrdude
|
|
||||||
{"AVR32DB32", 343, F_AVR8X, {0x1E, 0x95, 0x36}, 0, 0x08000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x7000, 0x1000, 16, 4, 44}, // atdf, avrdude
|
|
||||||
{"AVR32DD32", 344, F_AVR8X, {0x1E, 0x95, 0x38}, 0, 0x08000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x7000, 0x1000, 16, 4, 36}, // atdf, avrdude
|
|
||||||
{"AVR32EA32", 345, F_AVR8X, {0x1E, 0x95, 0x3D}, 0, 0x08000, 0x040, 1, 0, 0x01400, 0x0200, 8, -1, -1, -1, -1, 0}, // avrdude
|
|
||||||
{"AVR32DA48", 346, F_AVR8X, {0x1E, 0x95, 0x32}, 0, 0x08000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x7000, 0x1000, 16, 4, 58}, // atdf, avrdude
|
|
||||||
{"AVR32DB48", 347, F_AVR8X, {0x1E, 0x95, 0x35}, 0, 0x08000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x7000, 0x1000, 16, 4, 61}, // atdf, avrdude
|
|
||||||
{"AVR32EA48", 348, F_AVR8X, {0x1E, 0x95, 0x3C}, 0, 0x08000, 0x040, 1, 0, 0x01400, 0x0200, 8, -1, -1, -1, -1, 0}, // avrdude
|
|
||||||
{"AVR64DD14", 349, F_AVR8X, {0x1E, 0x96, 0x1D}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x6000, 0x2000, 16, 4, 36}, // atdf, avrdude
|
|
||||||
{"AVR64DD20", 350, F_AVR8X, {0x1E, 0x96, 0x1C}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x6000, 0x2000, 16, 4, 36}, // atdf, avrdude
|
|
||||||
{"AVR64DA28", 351, F_AVR8X, {0x1E, 0x96, 0x15}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x6000, 0x2000, 16, 4, 41}, // atdf, avrdude
|
|
||||||
{"AVR64DB28", 352, F_AVR8X, {0x1E, 0x96, 0x19}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x6000, 0x2000, 16, 4, 42}, // atdf, avrdude
|
|
||||||
{"AVR64DD28", 353, F_AVR8X, {0x1E, 0x96, 0x1B}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x6000, 0x2000, 16, 4, 36}, // atdf, avrdude
|
|
||||||
{"AVR64EA28", 354, F_AVR8X, {0x1E, 0x96, 0x20}, 0, 0x10000, 0x080, 1, 0, 0x01400, 0x0200, 8, 0x6800, 0x1800, 16, 4, 37}, // atdf, avrdude
|
|
||||||
{"AVR64DA32", 355, F_AVR8X, {0x1E, 0x96, 0x14}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x6000, 0x2000, 16, 4, 44}, // atdf, avrdude
|
|
||||||
{"AVR64DB32", 356, F_AVR8X, {0x1E, 0x96, 0x18}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x6000, 0x2000, 16, 4, 44}, // atdf, avrdude
|
|
||||||
{"AVR64DD32", 357, F_AVR8X, {0x1E, 0x96, 0x1A}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x6000, 0x2000, 16, 4, 36}, // atdf, avrdude
|
|
||||||
{"AVR64EA32", 358, F_AVR8X, {0x1E, 0x96, 0x1F}, 0, 0x10000, 0x080, 1, 0, 0x01400, 0x0200, 8, 0x6800, 0x1800, 16, 4, 37}, // atdf, avrdude
|
|
||||||
{"AVR64DA48", 359, F_AVR8X, {0x1E, 0x96, 0x13}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x6000, 0x2000, 16, 4, 58}, // atdf, avrdude
|
|
||||||
{"AVR64DB48", 360, F_AVR8X, {0x1E, 0x96, 0x17}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x6000, 0x2000, 16, 4, 61}, // atdf, avrdude
|
|
||||||
{"AVR64EA48", 361, F_AVR8X, {0x1E, 0x96, 0x1E}, 0, 0x10000, 0x080, 1, 0, 0x01400, 0x0200, 8, 0x6800, 0x1800, 16, 4, 45}, // atdf, avrdude
|
|
||||||
{"AVR64DA64", 362, F_AVR8X, {0x1E, 0x96, 0x12}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x6000, 0x2000, 16, 4, 64}, // atdf, avrdude
|
|
||||||
{"AVR64DB64", 363, F_AVR8X, {0x1E, 0x96, 0x16}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x6000, 0x2000, 16, 4, 65}, // atdf, avrdude
|
|
||||||
{"AVR128DA28", 364, F_AVR8X, {0x1E, 0x97, 0x0A}, 0, 0x20000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x4000, 0x4000, 16, 4, 41}, // atdf, avrdude
|
|
||||||
{"AVR128DB28", 365, F_AVR8X, {0x1E, 0x97, 0x0E}, 0, 0x20000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x4000, 0x4000, 16, 4, 42}, // atdf, avrdude
|
|
||||||
{"AVR128DA32", 366, F_AVR8X, {0x1E, 0x97, 0x09}, 0, 0x20000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x4000, 0x4000, 16, 4, 44}, // atdf, avrdude
|
|
||||||
{"AVR128DB32", 367, F_AVR8X, {0x1E, 0x97, 0x0D}, 0, 0x20000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x4000, 0x4000, 16, 4, 44}, // atdf, avrdude
|
|
||||||
{"AVR128DA48", 368, F_AVR8X, {0x1E, 0x97, 0x08}, 0, 0x20000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x4000, 0x4000, 16, 4, 58}, // atdf, avrdude
|
|
||||||
{"AVR128DB48", 369, F_AVR8X, {0x1E, 0x97, 0x0C}, 0, 0x20000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x4000, 0x4000, 16, 4, 61}, // atdf, avrdude
|
|
||||||
{"AVR128DA64", 370, F_AVR8X, {0x1E, 0x97, 0x07}, 0, 0x20000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x4000, 0x4000, 16, 4, 64}, // atdf, avrdude
|
|
||||||
{"AVR128DB64", 371, F_AVR8X, {0x1E, 0x97, 0x0B}, 0, 0x20000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x4000, 0x4000, 16, 4, 65}, // atdf, avrdude
|
|
||||||
};
|
|
||||||
|
|
||||||
const size_t avr_isp_chip_arr_size = COUNT_OF(avr_isp_chip_arr);
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <furi_hal.h>
|
|
||||||
|
|
||||||
#define F_AVR8L 1 // TPI programming, ATtiny(4|5|9|10|20|40|102|104)
|
|
||||||
#define F_AVR8 2 // ISP programming with SPI, "classic" AVRs
|
|
||||||
#define F_XMEGA 4 // PDI programming, ATxmega family
|
|
||||||
#define F_AVR8X 8 // UPDI programming, newer 8-bit MCUs
|
|
||||||
|
|
||||||
struct AvrIspChipArr { // Value of -1 typically means unknown
|
|
||||||
const char* name; // Name of part
|
|
||||||
uint16_t mcuid; // ID of MCU in 0..2039
|
|
||||||
uint8_t avrarch; // F_AVR8L, F_AVR8, F_XMEGA or F_AVR8X
|
|
||||||
uint8_t sigs[3]; // Signature bytes
|
|
||||||
int32_t flashoffset; // Flash offset
|
|
||||||
int32_t flashsize; // Flash size
|
|
||||||
int16_t pagesize; // Flash page size
|
|
||||||
int8_t nboots; // Number of supported boot sectors
|
|
||||||
int16_t bootsize; // Size of (smallest) boot sector
|
|
||||||
int32_t eepromoffset; // EEPROM offset
|
|
||||||
int32_t eepromsize; // EEPROM size
|
|
||||||
int32_t eeprompagesize; // EEPROM page size
|
|
||||||
int32_t sramstart; // SRAM offset
|
|
||||||
int32_t sramsize; // SRAM size
|
|
||||||
int8_t nfuses; // Number of fuse bytes
|
|
||||||
int8_t nlocks; // Number of lock bytes
|
|
||||||
uint8_t ninterrupts; // Number of vectors in interrupt vector table
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct AvrIspChipArr AvrIspChipArr;
|
|
||||||
|
|
||||||
extern const AvrIspChipArr avr_isp_chip_arr[];
|
|
||||||
extern const size_t avr_isp_chip_arr_size;
|
|
||||||
@@ -1,639 +0,0 @@
|
|||||||
#include "avr_isp_prog.h"
|
|
||||||
#include "avr_isp_prog_cmd.h"
|
|
||||||
|
|
||||||
#include <furi.h>
|
|
||||||
|
|
||||||
#define AVR_ISP_PROG_TX_RX_BUF_SIZE 320
|
|
||||||
#define TAG "AvrIspProg"
|
|
||||||
|
|
||||||
struct AvrIspProgSignature {
|
|
||||||
uint8_t vendor;
|
|
||||||
uint8_t part_family;
|
|
||||||
uint8_t part_number;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct AvrIspProgSignature AvrIspProgSignature;
|
|
||||||
|
|
||||||
struct AvrIspProgCfgDevice {
|
|
||||||
uint8_t devicecode;
|
|
||||||
uint8_t revision;
|
|
||||||
uint8_t progtype;
|
|
||||||
uint8_t parmode;
|
|
||||||
uint8_t polling;
|
|
||||||
uint8_t selftimed;
|
|
||||||
uint8_t lockbytes;
|
|
||||||
uint8_t fusebytes;
|
|
||||||
uint8_t flashpoll;
|
|
||||||
uint16_t eeprompoll;
|
|
||||||
uint16_t pagesize;
|
|
||||||
uint16_t eepromsize;
|
|
||||||
uint32_t flashsize;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct AvrIspProgCfgDevice AvrIspProgCfgDevice;
|
|
||||||
|
|
||||||
struct AvrIspProg {
|
|
||||||
AvrIspSpiSw* spi;
|
|
||||||
AvrIspProgCfgDevice* cfg;
|
|
||||||
FuriStreamBuffer* stream_rx;
|
|
||||||
FuriStreamBuffer* stream_tx;
|
|
||||||
|
|
||||||
uint16_t error;
|
|
||||||
uint16_t addr;
|
|
||||||
bool pmode;
|
|
||||||
bool exit;
|
|
||||||
bool rst_active_high;
|
|
||||||
uint8_t buff[AVR_ISP_PROG_TX_RX_BUF_SIZE];
|
|
||||||
|
|
||||||
AvrIspProgCallback callback;
|
|
||||||
void* context;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void avr_isp_prog_end_pmode(AvrIspProg* instance);
|
|
||||||
|
|
||||||
AvrIspProg* avr_isp_prog_init(void) {
|
|
||||||
AvrIspProg* instance = malloc(sizeof(AvrIspProg));
|
|
||||||
instance->cfg = malloc(sizeof(AvrIspProgCfgDevice));
|
|
||||||
instance->stream_rx =
|
|
||||||
furi_stream_buffer_alloc(sizeof(int8_t) * AVR_ISP_PROG_TX_RX_BUF_SIZE, sizeof(int8_t));
|
|
||||||
instance->stream_tx =
|
|
||||||
furi_stream_buffer_alloc(sizeof(int8_t) * AVR_ISP_PROG_TX_RX_BUF_SIZE, sizeof(int8_t));
|
|
||||||
instance->rst_active_high = false;
|
|
||||||
instance->exit = false;
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_prog_free(AvrIspProg* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
if(instance->spi) avr_isp_prog_end_pmode(instance);
|
|
||||||
furi_stream_buffer_free(instance->stream_tx);
|
|
||||||
furi_stream_buffer_free(instance->stream_rx);
|
|
||||||
free(instance->cfg);
|
|
||||||
free(instance);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t avr_isp_prog_spaces_rx(AvrIspProg* instance) {
|
|
||||||
return furi_stream_buffer_spaces_available(instance->stream_rx);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool avr_isp_prog_rx(AvrIspProg* instance, uint8_t* data, size_t len) {
|
|
||||||
furi_assert(instance);
|
|
||||||
furi_assert(data);
|
|
||||||
furi_assert(len != 0);
|
|
||||||
size_t ret = furi_stream_buffer_send(instance->stream_rx, data, sizeof(uint8_t) * len, 0);
|
|
||||||
return ret == sizeof(uint8_t) * len;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t avr_isp_prog_tx(AvrIspProg* instance, uint8_t* data, size_t max_len) {
|
|
||||||
furi_assert(instance);
|
|
||||||
return furi_stream_buffer_receive(instance->stream_tx, data, sizeof(int8_t) * max_len, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_prog_exit(AvrIspProg* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
instance->exit = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_prog_set_tx_callback(AvrIspProg* instance, AvrIspProgCallback callback, void* context) {
|
|
||||||
furi_assert(instance);
|
|
||||||
furi_assert(context);
|
|
||||||
instance->callback = callback;
|
|
||||||
instance->context = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void avr_isp_prog_tx_ch(AvrIspProg* instance, uint8_t data) {
|
|
||||||
furi_assert(instance);
|
|
||||||
furi_stream_buffer_send(instance->stream_tx, &data, sizeof(uint8_t), FuriWaitForever);
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t avr_isp_prog_getch(AvrIspProg* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
uint8_t data[1] = {0};
|
|
||||||
while(furi_stream_buffer_receive(instance->stream_rx, &data, sizeof(int8_t), 30) == 0) {
|
|
||||||
if(instance->exit) break;
|
|
||||||
};
|
|
||||||
return data[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
static void avr_isp_prog_fill(AvrIspProg* instance, size_t len) {
|
|
||||||
furi_assert(instance);
|
|
||||||
for(size_t x = 0; x < len; x++) {
|
|
||||||
instance->buff[x] = avr_isp_prog_getch(instance);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void avr_isp_prog_reset_target(AvrIspProg* instance, bool reset) {
|
|
||||||
furi_assert(instance);
|
|
||||||
avr_isp_spi_sw_res_set(instance->spi, (reset == instance->rst_active_high) ? true : false);
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t avr_isp_prog_spi_transaction(
|
|
||||||
AvrIspProg* instance,
|
|
||||||
uint8_t cmd,
|
|
||||||
uint8_t addr_hi,
|
|
||||||
uint8_t addr_lo,
|
|
||||||
uint8_t data) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
avr_isp_spi_sw_txrx(instance->spi, cmd);
|
|
||||||
avr_isp_spi_sw_txrx(instance->spi, addr_hi);
|
|
||||||
avr_isp_spi_sw_txrx(instance->spi, addr_lo);
|
|
||||||
return avr_isp_spi_sw_txrx(instance->spi, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void avr_isp_prog_empty_reply(AvrIspProg* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
if(avr_isp_prog_getch(instance) == CRC_EOP) {
|
|
||||||
avr_isp_prog_tx_ch(instance, STK_INSYNC);
|
|
||||||
avr_isp_prog_tx_ch(instance, STK_OK);
|
|
||||||
} else {
|
|
||||||
instance->error++;
|
|
||||||
avr_isp_prog_tx_ch(instance, STK_NOSYNC);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void avr_isp_prog_breply(AvrIspProg* instance, uint8_t data) {
|
|
||||||
furi_assert(instance);
|
|
||||||
if(avr_isp_prog_getch(instance) == CRC_EOP) {
|
|
||||||
avr_isp_prog_tx_ch(instance, STK_INSYNC);
|
|
||||||
avr_isp_prog_tx_ch(instance, data);
|
|
||||||
avr_isp_prog_tx_ch(instance, STK_OK);
|
|
||||||
} else {
|
|
||||||
instance->error++;
|
|
||||||
avr_isp_prog_tx_ch(instance, STK_NOSYNC);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void avr_isp_prog_get_version(AvrIspProg* instance, uint8_t data) {
|
|
||||||
furi_assert(instance);
|
|
||||||
switch(data) {
|
|
||||||
case STK_HW_VER:
|
|
||||||
avr_isp_prog_breply(instance, AVR_ISP_HWVER);
|
|
||||||
break;
|
|
||||||
case STK_SW_MAJOR:
|
|
||||||
avr_isp_prog_breply(instance, AVR_ISP_SWMAJ);
|
|
||||||
break;
|
|
||||||
case STK_SW_MINOR:
|
|
||||||
avr_isp_prog_breply(instance, AVR_ISP_SWMIN);
|
|
||||||
break;
|
|
||||||
case AVP_ISP_CONNECT_TYPE:
|
|
||||||
avr_isp_prog_breply(instance, AVP_ISP_SERIAL_CONNECT_TYPE);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
avr_isp_prog_breply(instance, AVR_ISP_RESP_0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void avr_isp_prog_set_cfg(AvrIspProg* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
// call this after reading cfg packet into buff[]
|
|
||||||
instance->cfg->devicecode = instance->buff[0];
|
|
||||||
instance->cfg->revision = instance->buff[1];
|
|
||||||
instance->cfg->progtype = instance->buff[2];
|
|
||||||
instance->cfg->parmode = instance->buff[3];
|
|
||||||
instance->cfg->polling = instance->buff[4];
|
|
||||||
instance->cfg->selftimed = instance->buff[5];
|
|
||||||
instance->cfg->lockbytes = instance->buff[6];
|
|
||||||
instance->cfg->fusebytes = instance->buff[7];
|
|
||||||
instance->cfg->flashpoll = instance->buff[8];
|
|
||||||
// ignore (instance->buff[9] == instance->buff[8]) //FLASH polling value. Same as <20>flashpoll<6C>
|
|
||||||
instance->cfg->eeprompoll = instance->buff[10] << 8 | instance->buff[11];
|
|
||||||
instance->cfg->pagesize = instance->buff[12] << 8 | instance->buff[13];
|
|
||||||
instance->cfg->eepromsize = instance->buff[14] << 8 | instance->buff[15];
|
|
||||||
instance->cfg->flashsize = instance->buff[16] << 24 | instance->buff[17] << 16 |
|
|
||||||
instance->buff[18] << 8 | instance->buff[19];
|
|
||||||
|
|
||||||
// avr devices have active low reset, at89sx are active high
|
|
||||||
instance->rst_active_high = (instance->cfg->devicecode >= 0xe0);
|
|
||||||
}
|
|
||||||
static bool
|
|
||||||
avr_isp_prog_set_pmode(AvrIspProg* instance, uint8_t a, uint8_t b, uint8_t c, uint8_t d) {
|
|
||||||
furi_assert(instance);
|
|
||||||
uint8_t res = 0;
|
|
||||||
avr_isp_spi_sw_txrx(instance->spi, a);
|
|
||||||
avr_isp_spi_sw_txrx(instance->spi, b);
|
|
||||||
res = avr_isp_spi_sw_txrx(instance->spi, c);
|
|
||||||
avr_isp_spi_sw_txrx(instance->spi, d);
|
|
||||||
return res == 0x53;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void avr_isp_prog_end_pmode(AvrIspProg* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
if(instance->pmode) {
|
|
||||||
avr_isp_prog_reset_target(instance, false);
|
|
||||||
// We're about to take the target out of reset
|
|
||||||
// so configure SPI pins as input
|
|
||||||
|
|
||||||
if(instance->spi) avr_isp_spi_sw_free(instance->spi);
|
|
||||||
instance->spi = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
instance->pmode = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool avr_isp_prog_start_pmode(AvrIspProg* instance, AvrIspSpiSwSpeed spi_speed) {
|
|
||||||
furi_assert(instance);
|
|
||||||
// Reset target before driving PIN_SCK or PIN_MOSI
|
|
||||||
|
|
||||||
// SPI.begin() will configure SS as output,
|
|
||||||
// so SPI master mode is selected.
|
|
||||||
// We have defined RESET as pin 10,
|
|
||||||
// which for many arduino's is not the SS pin.
|
|
||||||
// So we have to configure RESET as output here,
|
|
||||||
// (reset_target() first sets the correct level)
|
|
||||||
if(instance->spi) avr_isp_spi_sw_free(instance->spi);
|
|
||||||
instance->spi = avr_isp_spi_sw_init(spi_speed);
|
|
||||||
|
|
||||||
avr_isp_prog_reset_target(instance, true);
|
|
||||||
// See avr datasheets, chapter "SERIAL_PRG Programming Algorithm":
|
|
||||||
|
|
||||||
// Pulse RESET after PIN_SCK is low:
|
|
||||||
avr_isp_spi_sw_sck_set(instance->spi, false);
|
|
||||||
|
|
||||||
// discharge PIN_SCK, value arbitrally chosen
|
|
||||||
furi_delay_ms(20);
|
|
||||||
avr_isp_prog_reset_target(instance, false);
|
|
||||||
|
|
||||||
// Pulse must be minimum 2 target CPU speed cycles
|
|
||||||
// so 100 usec is ok for CPU speeds above 20KHz
|
|
||||||
furi_delay_ms(1);
|
|
||||||
|
|
||||||
avr_isp_prog_reset_target(instance, true);
|
|
||||||
|
|
||||||
// Send the enable programming command:
|
|
||||||
// datasheet: must be > 20 msec
|
|
||||||
furi_delay_ms(50);
|
|
||||||
if(avr_isp_prog_set_pmode(instance, AVR_ISP_SET_PMODE)) {
|
|
||||||
instance->pmode = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static AvrIspProgSignature avr_isp_prog_check_signature(AvrIspProg* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
AvrIspProgSignature signature;
|
|
||||||
signature.vendor = avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_VENDOR);
|
|
||||||
signature.part_family = avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_PART_FAMILY);
|
|
||||||
signature.part_number = avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_PART_NUMBER);
|
|
||||||
return signature;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool avr_isp_prog_auto_set_spi_speed_start_pmode(AvrIspProg* instance) {
|
|
||||||
AvrIspSpiSwSpeed spi_speed[] = {
|
|
||||||
AvrIspSpiSwSpeed1Mhz,
|
|
||||||
AvrIspSpiSwSpeed400Khz,
|
|
||||||
AvrIspSpiSwSpeed250Khz,
|
|
||||||
AvrIspSpiSwSpeed125Khz,
|
|
||||||
AvrIspSpiSwSpeed60Khz,
|
|
||||||
AvrIspSpiSwSpeed40Khz,
|
|
||||||
AvrIspSpiSwSpeed20Khz,
|
|
||||||
AvrIspSpiSwSpeed10Khz,
|
|
||||||
AvrIspSpiSwSpeed5Khz,
|
|
||||||
AvrIspSpiSwSpeed1Khz,
|
|
||||||
};
|
|
||||||
for(uint8_t i = 0; i < COUNT_OF(spi_speed); i++) {
|
|
||||||
if(avr_isp_prog_start_pmode(instance, spi_speed[i])) {
|
|
||||||
AvrIspProgSignature sig = avr_isp_prog_check_signature(instance);
|
|
||||||
AvrIspProgSignature sig_examination = avr_isp_prog_check_signature(instance); //-V656
|
|
||||||
uint8_t y = 0;
|
|
||||||
while(y < 8) {
|
|
||||||
if(memcmp(
|
|
||||||
(uint8_t*)&sig, (uint8_t*)&sig_examination, sizeof(AvrIspProgSignature)) !=
|
|
||||||
0)
|
|
||||||
break;
|
|
||||||
sig_examination = avr_isp_prog_check_signature(instance);
|
|
||||||
y++;
|
|
||||||
}
|
|
||||||
if(y == 8) {
|
|
||||||
if(spi_speed[i] > AvrIspSpiSwSpeed1Mhz) {
|
|
||||||
if(i < (COUNT_OF(spi_speed) - 1)) {
|
|
||||||
avr_isp_prog_end_pmode(instance);
|
|
||||||
i++;
|
|
||||||
return avr_isp_prog_start_pmode(instance, spi_speed[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(instance->spi) {
|
|
||||||
avr_isp_spi_sw_free(instance->spi);
|
|
||||||
instance->spi = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void avr_isp_prog_universal(AvrIspProg* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
uint8_t data;
|
|
||||||
|
|
||||||
avr_isp_prog_fill(instance, 4);
|
|
||||||
data = avr_isp_prog_spi_transaction(
|
|
||||||
instance, instance->buff[0], instance->buff[1], instance->buff[2], instance->buff[3]);
|
|
||||||
avr_isp_prog_breply(instance, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void avr_isp_prog_commit(AvrIspProg* instance, uint16_t addr, uint8_t data) {
|
|
||||||
furi_assert(instance);
|
|
||||||
avr_isp_prog_spi_transaction(instance, AVR_ISP_COMMIT(addr));
|
|
||||||
/* polling flash */
|
|
||||||
if(data == 0xFF) {
|
|
||||||
furi_delay_ms(5);
|
|
||||||
} else {
|
|
||||||
/* polling flash */
|
|
||||||
uint32_t starttime = furi_get_tick();
|
|
||||||
while((furi_get_tick() - starttime) < 30) {
|
|
||||||
if(avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_FLASH_HI(addr)) != 0xFF) {
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint16_t avr_isp_prog_current_page(AvrIspProg* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
uint16_t page = 0;
|
|
||||||
switch(instance->cfg->pagesize) {
|
|
||||||
case 32:
|
|
||||||
page = instance->addr & 0xFFFFFFF0;
|
|
||||||
break;
|
|
||||||
case 64:
|
|
||||||
page = instance->addr & 0xFFFFFFE0;
|
|
||||||
break;
|
|
||||||
case 128:
|
|
||||||
page = instance->addr & 0xFFFFFFC0;
|
|
||||||
break;
|
|
||||||
case 256:
|
|
||||||
page = instance->addr & 0xFFFFFF80;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
page = instance->addr;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return page;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t avr_isp_prog_write_flash_pages(AvrIspProg* instance, size_t length) {
|
|
||||||
furi_assert(instance);
|
|
||||||
size_t x = 0;
|
|
||||||
uint16_t page = avr_isp_prog_current_page(instance);
|
|
||||||
while(x < length) {
|
|
||||||
if(page != avr_isp_prog_current_page(instance)) {
|
|
||||||
--x;
|
|
||||||
avr_isp_prog_commit(instance, page, instance->buff[x++]);
|
|
||||||
page = avr_isp_prog_current_page(instance);
|
|
||||||
}
|
|
||||||
avr_isp_prog_spi_transaction(
|
|
||||||
instance, AVR_ISP_WRITE_FLASH_LO(instance->addr, instance->buff[x++]));
|
|
||||||
|
|
||||||
avr_isp_prog_spi_transaction(
|
|
||||||
instance, AVR_ISP_WRITE_FLASH_HI(instance->addr, instance->buff[x++]));
|
|
||||||
instance->addr++;
|
|
||||||
}
|
|
||||||
|
|
||||||
avr_isp_prog_commit(instance, page, instance->buff[--x]);
|
|
||||||
return STK_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void avr_isp_prog_write_flash(AvrIspProg* instance, size_t length) {
|
|
||||||
furi_assert(instance);
|
|
||||||
avr_isp_prog_fill(instance, length);
|
|
||||||
if(avr_isp_prog_getch(instance) == CRC_EOP) {
|
|
||||||
avr_isp_prog_tx_ch(instance, STK_INSYNC);
|
|
||||||
avr_isp_prog_tx_ch(instance, avr_isp_prog_write_flash_pages(instance, length));
|
|
||||||
} else {
|
|
||||||
instance->error++;
|
|
||||||
avr_isp_prog_tx_ch(instance, STK_NOSYNC);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// write (length) bytes, (start) is a byte address
|
|
||||||
static uint8_t
|
|
||||||
avr_isp_prog_write_eeprom_chunk(AvrIspProg* instance, uint16_t start, uint16_t length) {
|
|
||||||
furi_assert(instance);
|
|
||||||
// this writes byte-by-byte,
|
|
||||||
// page writing may be faster (4 bytes at a time)
|
|
||||||
avr_isp_prog_fill(instance, length);
|
|
||||||
for(uint16_t x = 0; x < length; x++) {
|
|
||||||
uint16_t addr = start + x;
|
|
||||||
avr_isp_prog_spi_transaction(instance, AVR_ISP_WRITE_EEPROM(addr, instance->buff[x]));
|
|
||||||
furi_delay_ms(10);
|
|
||||||
}
|
|
||||||
return STK_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t avr_isp_prog_write_eeprom(AvrIspProg* instance, size_t length) {
|
|
||||||
furi_assert(instance);
|
|
||||||
// here is a word address, get the byte address
|
|
||||||
uint16_t start = instance->addr * 2;
|
|
||||||
uint16_t remaining = length;
|
|
||||||
if(length > instance->cfg->eepromsize) {
|
|
||||||
instance->error++;
|
|
||||||
return STK_FAILED;
|
|
||||||
}
|
|
||||||
while(remaining > AVR_ISP_EECHUNK) {
|
|
||||||
avr_isp_prog_write_eeprom_chunk(instance, start, AVR_ISP_EECHUNK);
|
|
||||||
start += AVR_ISP_EECHUNK;
|
|
||||||
remaining -= AVR_ISP_EECHUNK;
|
|
||||||
}
|
|
||||||
avr_isp_prog_write_eeprom_chunk(instance, start, remaining);
|
|
||||||
return STK_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void avr_isp_prog_program_page(AvrIspProg* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
uint8_t result = STK_FAILED;
|
|
||||||
uint16_t length = avr_isp_prog_getch(instance) << 8 | avr_isp_prog_getch(instance);
|
|
||||||
uint8_t memtype = avr_isp_prog_getch(instance);
|
|
||||||
// flash memory @addr, (length) bytes
|
|
||||||
if(memtype == STK_SET_FLASH_TYPE) {
|
|
||||||
avr_isp_prog_write_flash(instance, length);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(memtype == STK_SET_EEPROM_TYPE) {
|
|
||||||
result = avr_isp_prog_write_eeprom(instance, length);
|
|
||||||
if(avr_isp_prog_getch(instance) == CRC_EOP) {
|
|
||||||
avr_isp_prog_tx_ch(instance, STK_INSYNC);
|
|
||||||
avr_isp_prog_tx_ch(instance, result);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
instance->error++;
|
|
||||||
avr_isp_prog_tx_ch(instance, STK_NOSYNC);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
avr_isp_prog_tx_ch(instance, STK_FAILED);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t avr_isp_prog_flash_read_page(AvrIspProg* instance, uint16_t length) {
|
|
||||||
furi_assert(instance);
|
|
||||||
for(uint16_t x = 0; x < length; x += 2) {
|
|
||||||
avr_isp_prog_tx_ch(
|
|
||||||
instance,
|
|
||||||
avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_FLASH_LO(instance->addr)));
|
|
||||||
avr_isp_prog_tx_ch(
|
|
||||||
instance,
|
|
||||||
avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_FLASH_HI(instance->addr)));
|
|
||||||
instance->addr++;
|
|
||||||
}
|
|
||||||
return STK_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t avr_isp_prog_eeprom_read_page(AvrIspProg* instance, uint16_t length) {
|
|
||||||
furi_assert(instance);
|
|
||||||
// here again we have a word address
|
|
||||||
uint16_t start = instance->addr * 2;
|
|
||||||
for(uint16_t x = 0; x < length; x++) {
|
|
||||||
uint16_t addr = start + x;
|
|
||||||
avr_isp_prog_tx_ch(
|
|
||||||
instance, avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_EEPROM(addr)));
|
|
||||||
}
|
|
||||||
return STK_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void avr_isp_prog_read_page(AvrIspProg* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
uint8_t result = STK_FAILED;
|
|
||||||
uint16_t length = avr_isp_prog_getch(instance) << 8 | avr_isp_prog_getch(instance);
|
|
||||||
uint8_t memtype = avr_isp_prog_getch(instance);
|
|
||||||
if(avr_isp_prog_getch(instance) != CRC_EOP) {
|
|
||||||
instance->error++;
|
|
||||||
avr_isp_prog_tx_ch(instance, STK_NOSYNC);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
avr_isp_prog_tx_ch(instance, STK_INSYNC);
|
|
||||||
if(memtype == STK_SET_FLASH_TYPE) result = avr_isp_prog_flash_read_page(instance, length);
|
|
||||||
if(memtype == STK_SET_EEPROM_TYPE) result = avr_isp_prog_eeprom_read_page(instance, length);
|
|
||||||
avr_isp_prog_tx_ch(instance, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void avr_isp_prog_read_signature(AvrIspProg* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
if(avr_isp_prog_getch(instance) != CRC_EOP) {
|
|
||||||
instance->error++;
|
|
||||||
avr_isp_prog_tx_ch(instance, STK_NOSYNC);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
avr_isp_prog_tx_ch(instance, STK_INSYNC);
|
|
||||||
|
|
||||||
avr_isp_prog_tx_ch(instance, avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_VENDOR));
|
|
||||||
avr_isp_prog_tx_ch(instance, avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_PART_FAMILY));
|
|
||||||
avr_isp_prog_tx_ch(instance, avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_PART_NUMBER));
|
|
||||||
|
|
||||||
avr_isp_prog_tx_ch(instance, STK_OK);
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_prog_avrisp(AvrIspProg* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
uint8_t ch = avr_isp_prog_getch(instance);
|
|
||||||
|
|
||||||
switch(ch) {
|
|
||||||
case STK_GET_SYNC:
|
|
||||||
FURI_LOG_D(TAG, "cmd STK_GET_SYNC");
|
|
||||||
instance->error = 0;
|
|
||||||
avr_isp_prog_empty_reply(instance);
|
|
||||||
break;
|
|
||||||
case STK_GET_SIGN_ON:
|
|
||||||
FURI_LOG_D(TAG, "cmd STK_GET_SIGN_ON");
|
|
||||||
if(avr_isp_prog_getch(instance) == CRC_EOP) {
|
|
||||||
avr_isp_prog_tx_ch(instance, STK_INSYNC);
|
|
||||||
|
|
||||||
avr_isp_prog_tx_ch(instance, 'A');
|
|
||||||
avr_isp_prog_tx_ch(instance, 'V');
|
|
||||||
avr_isp_prog_tx_ch(instance, 'R');
|
|
||||||
avr_isp_prog_tx_ch(instance, ' ');
|
|
||||||
avr_isp_prog_tx_ch(instance, 'I');
|
|
||||||
avr_isp_prog_tx_ch(instance, 'S');
|
|
||||||
avr_isp_prog_tx_ch(instance, 'P');
|
|
||||||
|
|
||||||
avr_isp_prog_tx_ch(instance, STK_OK);
|
|
||||||
} else {
|
|
||||||
instance->error++;
|
|
||||||
avr_isp_prog_tx_ch(instance, STK_NOSYNC);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case STK_GET_PARAMETER:
|
|
||||||
FURI_LOG_D(TAG, "cmd STK_GET_PARAMETER");
|
|
||||||
avr_isp_prog_get_version(instance, avr_isp_prog_getch(instance));
|
|
||||||
break;
|
|
||||||
case STK_SET_DEVICE:
|
|
||||||
FURI_LOG_D(TAG, "cmd STK_SET_DEVICE");
|
|
||||||
avr_isp_prog_fill(instance, 20);
|
|
||||||
avr_isp_prog_set_cfg(instance);
|
|
||||||
avr_isp_prog_empty_reply(instance);
|
|
||||||
break;
|
|
||||||
case STK_SET_DEVICE_EXT: // ignore for now
|
|
||||||
FURI_LOG_D(TAG, "cmd STK_SET_DEVICE_EXT");
|
|
||||||
avr_isp_prog_fill(instance, 5);
|
|
||||||
avr_isp_prog_empty_reply(instance);
|
|
||||||
break;
|
|
||||||
case STK_ENTER_PROGMODE:
|
|
||||||
FURI_LOG_D(TAG, "cmd STK_ENTER_PROGMODE");
|
|
||||||
if(!instance->pmode) avr_isp_prog_auto_set_spi_speed_start_pmode(instance);
|
|
||||||
avr_isp_prog_empty_reply(instance);
|
|
||||||
break;
|
|
||||||
case STK_LOAD_ADDRESS:
|
|
||||||
FURI_LOG_D(TAG, "cmd STK_LOAD_ADDRESS");
|
|
||||||
instance->addr = avr_isp_prog_getch(instance) | avr_isp_prog_getch(instance) << 8;
|
|
||||||
avr_isp_prog_empty_reply(instance);
|
|
||||||
break;
|
|
||||||
case STK_PROG_FLASH: // ignore for now
|
|
||||||
FURI_LOG_D(TAG, "cmd STK_PROG_FLASH");
|
|
||||||
avr_isp_prog_getch(instance);
|
|
||||||
avr_isp_prog_getch(instance);
|
|
||||||
avr_isp_prog_empty_reply(instance);
|
|
||||||
break;
|
|
||||||
case STK_PROG_DATA: // ignore for now
|
|
||||||
FURI_LOG_D(TAG, "cmd STK_PROG_DATA");
|
|
||||||
avr_isp_prog_getch(instance);
|
|
||||||
avr_isp_prog_empty_reply(instance);
|
|
||||||
break;
|
|
||||||
case STK_PROG_PAGE:
|
|
||||||
FURI_LOG_D(TAG, "cmd STK_PROG_PAGE");
|
|
||||||
avr_isp_prog_program_page(instance);
|
|
||||||
break;
|
|
||||||
case STK_READ_PAGE:
|
|
||||||
FURI_LOG_D(TAG, "cmd STK_READ_PAGE");
|
|
||||||
avr_isp_prog_read_page(instance);
|
|
||||||
break;
|
|
||||||
case STK_UNIVERSAL:
|
|
||||||
FURI_LOG_D(TAG, "cmd STK_UNIVERSAL");
|
|
||||||
avr_isp_prog_universal(instance);
|
|
||||||
break;
|
|
||||||
case STK_LEAVE_PROGMODE:
|
|
||||||
FURI_LOG_D(TAG, "cmd STK_LEAVE_PROGMODE");
|
|
||||||
instance->error = 0;
|
|
||||||
if(instance->pmode) avr_isp_prog_end_pmode(instance);
|
|
||||||
avr_isp_prog_empty_reply(instance);
|
|
||||||
break;
|
|
||||||
case STK_READ_SIGN:
|
|
||||||
FURI_LOG_D(TAG, "cmd STK_READ_SIGN");
|
|
||||||
avr_isp_prog_read_signature(instance);
|
|
||||||
break;
|
|
||||||
// expecting a command, not CRC_EOP
|
|
||||||
// this is how we can get back in sync
|
|
||||||
case CRC_EOP:
|
|
||||||
FURI_LOG_D(TAG, "cmd CRC_EOP");
|
|
||||||
instance->error++;
|
|
||||||
avr_isp_prog_tx_ch(instance, STK_NOSYNC);
|
|
||||||
break;
|
|
||||||
// anything else we will return STK_UNKNOWN
|
|
||||||
default:
|
|
||||||
FURI_LOG_D(TAG, "cmd STK_ERROR_CMD");
|
|
||||||
instance->error++;
|
|
||||||
if(avr_isp_prog_getch(instance) == CRC_EOP)
|
|
||||||
avr_isp_prog_tx_ch(instance, STK_UNKNOWN);
|
|
||||||
else
|
|
||||||
avr_isp_prog_tx_ch(instance, STK_NOSYNC);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(instance->callback) {
|
|
||||||
instance->callback(instance->context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "avr_isp_spi_sw.h"
|
|
||||||
#include <furi_hal.h>
|
|
||||||
|
|
||||||
typedef struct AvrIspProg AvrIspProg;
|
|
||||||
typedef void (*AvrIspProgCallback)(void* context);
|
|
||||||
|
|
||||||
AvrIspProg* avr_isp_prog_init(void);
|
|
||||||
void avr_isp_prog_free(AvrIspProg* instance);
|
|
||||||
size_t avr_isp_prog_spaces_rx(AvrIspProg* instance) ;
|
|
||||||
bool avr_isp_prog_rx(AvrIspProg* instance, uint8_t* data, size_t len);
|
|
||||||
size_t avr_isp_prog_tx(AvrIspProg* instance, uint8_t* data, size_t max_len);
|
|
||||||
void avr_isp_prog_avrisp(AvrIspProg* instance);
|
|
||||||
void avr_isp_prog_exit(AvrIspProg* instance);
|
|
||||||
void avr_isp_prog_set_tx_callback(AvrIspProg* instance, AvrIspProgCallback callback, void* context);
|
|
||||||
@@ -1,97 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
// http://ww1.microchip.com/downloads/en/appnotes/atmel-0943-in-system-programming_applicationnote_avr910.pdf
|
|
||||||
// AVR ISP Definitions
|
|
||||||
#define AVR_ISP_HWVER 0X02
|
|
||||||
#define AVR_ISP_SWMAJ 0X01
|
|
||||||
#define AVR_ISP_SWMIN 0X12
|
|
||||||
#define AVP_ISP_SERIAL_CONNECT_TYPE 0X53
|
|
||||||
#define AVP_ISP_CONNECT_TYPE 0x93
|
|
||||||
#define AVR_ISP_RESP_0 0X00
|
|
||||||
|
|
||||||
#define AVR_ISP_SET_PMODE 0xAC, 0x53, 0x00, 0x00
|
|
||||||
#define AVR_ISP_READ_VENDOR 0x30, 0x00, 0x00, 0x00
|
|
||||||
#define AVR_ISP_READ_PART_FAMILY 0x30, 0x00, 0x01, 0x00
|
|
||||||
#define AVR_ISP_READ_PART_NUMBER 0x30, 0x00, 0x02, 0x00
|
|
||||||
#define AVR_ISP_ERASE_CHIP \
|
|
||||||
0xAC, 0x80, 0x00, 0x00 //Erase Chip, Wait N ms, Release RESET to end the erase.
|
|
||||||
//The only way to end a Chip Erase cycle is by temporarily releasing the Reset line
|
|
||||||
|
|
||||||
#define AVR_ISP_EXTENDED_ADDR(data) 0x4D, 0x00, data, 0x00
|
|
||||||
#define AVR_ISP_WRITE_FLASH_LO(add, data) 0x40, (add >> 8) & 0xFF, add & 0xFF, data
|
|
||||||
#define AVR_ISP_WRITE_FLASH_HI(add, data) 0x48, (add >> 8) & 0xFF, add & 0xFF, data
|
|
||||||
#define AVR_ISP_READ_FLASH_LO(add) 0x20, (add >> 8) & 0xFF, add & 0xFF, 0x00
|
|
||||||
#define AVR_ISP_READ_FLASH_HI(add) 0x28, (add >> 8) & 0xFF, add & 0xFF, 0x00
|
|
||||||
|
|
||||||
#define AVR_ISP_WRITE_EEPROM(add, data) \
|
|
||||||
0xC0, (add >> 8) & 0xFF, add & 0xFF, data //Send cmd, Wait N ms
|
|
||||||
#define AVR_ISP_READ_EEPROM(add) 0xA0, (add >> 8) & 0xFF, add & 0xFF, 0xFF
|
|
||||||
|
|
||||||
#define AVR_ISP_COMMIT(add) \
|
|
||||||
0x4C, (add >> 8) & 0xFF, add & 0xFF, 0x00 //Send cmd, polling read last addr page
|
|
||||||
|
|
||||||
#define AVR_ISP_OSCCAL(add) 0x38, 0x00, add, 0x00
|
|
||||||
|
|
||||||
#define AVR_ISP_WRITE_LOCK_BYTE(data) 0xAC, 0xE0, 0x00, data //Send cmd, Wait N ms
|
|
||||||
#define AVR_ISP_READ_LOCK_BYTE 0x58, 0x00, 0x00, 0x00
|
|
||||||
#define AVR_ISP_WRITE_FUSE_LOW(data) 0xAC, 0xA0, 0x00, data //Send cmd, Wait N ms
|
|
||||||
#define AVR_ISP_READ_FUSE_LOW 0x50, 0x00, 0x00, 0x00
|
|
||||||
#define AVR_ISP_WRITE_FUSE_HIGH(data) 0xAC, 0xA8, 0x00, data //Send cmd, Wait N ms
|
|
||||||
#define AVR_ISP_READ_FUSE_HIGH 0x58, 0x08, 0x00, 0x00
|
|
||||||
#define AVR_ISP_WRITE_FUSE_EXTENDED(data) 0xAC, 0xA4, 0x00, data //Send cmd, Wait N ms (~write)
|
|
||||||
#define AVR_ISP_READ_FUSE_EXTENDED 0x50, 0x08, 0x00, 0x00
|
|
||||||
|
|
||||||
#define AVR_ISP_EECHUNK 0x20
|
|
||||||
|
|
||||||
// https://www.microchip.com/content/dam/mchp/documents/OTH/ApplicationNotes/ApplicationNotes/doc2525.pdf
|
|
||||||
// STK Definitions
|
|
||||||
#define STK_OK 0x10
|
|
||||||
#define STK_FAILED 0x11
|
|
||||||
#define STK_UNKNOWN 0x12
|
|
||||||
#define STK_INSYNC 0x14
|
|
||||||
#define STK_NOSYNC 0x15
|
|
||||||
#define CRC_EOP 0x20
|
|
||||||
|
|
||||||
#define STK_GET_SYNC 0x30
|
|
||||||
#define STK_GET_SIGN_ON 0x31
|
|
||||||
#define STK_SET_PARAMETER 0x40
|
|
||||||
#define STK_GET_PARAMETER 0x41
|
|
||||||
#define STK_SET_DEVICE 0x42
|
|
||||||
#define STK_SET_DEVICE_EXT 0x45
|
|
||||||
#define STK_ENTER_PROGMODE 0x50
|
|
||||||
#define STK_LEAVE_PROGMODE 0x51
|
|
||||||
#define STK_CHIP_ERASE 0x52
|
|
||||||
#define STK_CHECK_AUTOINC 0x53
|
|
||||||
#define STK_LOAD_ADDRESS 0x55
|
|
||||||
#define STK_UNIVERSAL 0x56
|
|
||||||
#define STK_UNIVERSAL_MULTI 0x57
|
|
||||||
#define STK_PROG_FLASH 0x60
|
|
||||||
#define STK_PROG_DATA 0x61
|
|
||||||
#define STK_PROG_FUSE 0x62
|
|
||||||
#define STK_PROG_FUSE_EXT 0x65
|
|
||||||
#define STK_PROG_LOCK 0x63
|
|
||||||
#define STK_PROG_PAGE 0x64
|
|
||||||
#define STK_READ_FLASH 0x70
|
|
||||||
#define STK_READ_DATA 0x71
|
|
||||||
#define STK_READ_FUSE 0x72
|
|
||||||
#define STK_READ_LOCK 0x73
|
|
||||||
#define STK_READ_PAGE 0x74
|
|
||||||
#define STK_READ_SIGN 0x75
|
|
||||||
#define STK_READ_OSCCAL 0x76
|
|
||||||
#define STK_READ_FUSE_EXT 0x77
|
|
||||||
#define STK_READ_OSCCAL_EXT 0x78
|
|
||||||
#define STK_HW_VER 0x80
|
|
||||||
#define STK_SW_MAJOR 0x81
|
|
||||||
#define STK_SW_MINOR 0x82
|
|
||||||
#define STK_LEDS 0x83
|
|
||||||
#define STK_VTARGET 0x84
|
|
||||||
#define STK_VADJUST 0x85
|
|
||||||
#define STK_OSC_PSCALE 0x86
|
|
||||||
#define STK_OSC_CMATCH 0x87
|
|
||||||
#define STK_SCK_DURATION 0x89
|
|
||||||
#define STK_BUFSIZEL 0x90
|
|
||||||
#define STK_BUFSIZEH 0x91
|
|
||||||
#define STK_STK500_TOPCARD_DETECT 0x98
|
|
||||||
|
|
||||||
#define STK_SET_EEPROM_TYPE 0X45
|
|
||||||
#define STK_SET_FLASH_TYPE 0X46
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
#include "avr_isp_spi_sw.h"
|
|
||||||
|
|
||||||
#include <furi.h>
|
|
||||||
|
|
||||||
#define AVR_ISP_SPI_SW_MISO &gpio_ext_pa6
|
|
||||||
#define AVR_ISP_SPI_SW_MOSI &gpio_ext_pa7
|
|
||||||
#define AVR_ISP_SPI_SW_SCK &gpio_ext_pb3
|
|
||||||
#define AVR_ISP_RESET &gpio_ext_pb2
|
|
||||||
|
|
||||||
struct AvrIspSpiSw {
|
|
||||||
AvrIspSpiSwSpeed speed_wait_time;
|
|
||||||
const GpioPin* miso;
|
|
||||||
const GpioPin* mosi;
|
|
||||||
const GpioPin* sck;
|
|
||||||
const GpioPin* res;
|
|
||||||
};
|
|
||||||
|
|
||||||
AvrIspSpiSw* avr_isp_spi_sw_init(AvrIspSpiSwSpeed speed) {
|
|
||||||
AvrIspSpiSw* instance = malloc(sizeof(AvrIspSpiSw));
|
|
||||||
instance->speed_wait_time = speed;
|
|
||||||
instance->miso = AVR_ISP_SPI_SW_MISO;
|
|
||||||
instance->mosi = AVR_ISP_SPI_SW_MOSI;
|
|
||||||
instance->sck = AVR_ISP_SPI_SW_SCK;
|
|
||||||
instance->res = AVR_ISP_RESET;
|
|
||||||
|
|
||||||
furi_hal_gpio_init(instance->miso, GpioModeInput, GpioPullNo, GpioSpeedVeryHigh);
|
|
||||||
furi_hal_gpio_write(instance->mosi, false);
|
|
||||||
furi_hal_gpio_init(instance->mosi, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
|
|
||||||
furi_hal_gpio_write(instance->sck, false);
|
|
||||||
furi_hal_gpio_init(instance->sck, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
|
|
||||||
furi_hal_gpio_init(instance->res, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
|
|
||||||
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_spi_sw_free(AvrIspSpiSw* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
furi_hal_gpio_init(instance->res, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
|
||||||
furi_hal_gpio_init(instance->miso, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
|
||||||
furi_hal_gpio_init(instance->mosi, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
|
||||||
furi_hal_gpio_init(instance->sck, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
|
||||||
free(instance);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t avr_isp_spi_sw_txrx(AvrIspSpiSw* instance, uint8_t data) {
|
|
||||||
furi_assert(instance);
|
|
||||||
for(uint8_t i = 0; i < 8; ++i) {
|
|
||||||
furi_hal_gpio_write(instance->mosi, (data & 0x80) ? true : false);
|
|
||||||
|
|
||||||
furi_hal_gpio_write(instance->sck, true);
|
|
||||||
if(instance->speed_wait_time != AvrIspSpiSwSpeed1Mhz)
|
|
||||||
furi_delay_us(instance->speed_wait_time - 1);
|
|
||||||
|
|
||||||
data = (data << 1) | furi_hal_gpio_read(instance->miso); //-V792
|
|
||||||
|
|
||||||
furi_hal_gpio_write(instance->sck, false);
|
|
||||||
if(instance->speed_wait_time != AvrIspSpiSwSpeed1Mhz)
|
|
||||||
furi_delay_us(instance->speed_wait_time - 1);
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_spi_sw_res_set(AvrIspSpiSw* instance, bool state) {
|
|
||||||
furi_assert(instance);
|
|
||||||
furi_hal_gpio_write(instance->res, state);
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_spi_sw_sck_set(AvrIspSpiSw* instance, bool state) {
|
|
||||||
furi_assert(instance);
|
|
||||||
furi_hal_gpio_write(instance->sck, state);
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <furi_hal.h>
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
AvrIspSpiSwSpeed1Mhz = 0,
|
|
||||||
AvrIspSpiSwSpeed400Khz = 1,
|
|
||||||
AvrIspSpiSwSpeed250Khz = 2,
|
|
||||||
AvrIspSpiSwSpeed125Khz = 4,
|
|
||||||
AvrIspSpiSwSpeed60Khz = 8,
|
|
||||||
AvrIspSpiSwSpeed40Khz = 12,
|
|
||||||
AvrIspSpiSwSpeed20Khz = 24,
|
|
||||||
AvrIspSpiSwSpeed10Khz = 48,
|
|
||||||
AvrIspSpiSwSpeed5Khz = 96,
|
|
||||||
AvrIspSpiSwSpeed1Khz = 480,
|
|
||||||
} AvrIspSpiSwSpeed;
|
|
||||||
|
|
||||||
typedef struct AvrIspSpiSw AvrIspSpiSw;
|
|
||||||
|
|
||||||
AvrIspSpiSw* avr_isp_spi_sw_init(AvrIspSpiSwSpeed speed);
|
|
||||||
void avr_isp_spi_sw_free(AvrIspSpiSw* instance);
|
|
||||||
uint8_t avr_isp_spi_sw_txrx(AvrIspSpiSw* instance, uint8_t data);
|
|
||||||
void avr_isp_spi_sw_res_set(AvrIspSpiSw* instance, bool state);
|
|
||||||
void avr_isp_spi_sw_sck_set(AvrIspSpiSw* instance, bool state);
|
|
||||||
|
Before Width: | Height: | Size: 3.6 KiB |
@@ -1,30 +0,0 @@
|
|||||||
#include "../avr_isp_app_i.h"
|
|
||||||
|
|
||||||
// Generate scene on_enter handlers array
|
|
||||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
|
|
||||||
void (*const avr_isp_scene_on_enter_handlers[])(void*) = {
|
|
||||||
#include "avr_isp_scene_config.h"
|
|
||||||
};
|
|
||||||
#undef ADD_SCENE
|
|
||||||
|
|
||||||
// Generate scene on_event handlers array
|
|
||||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event,
|
|
||||||
bool (*const avr_isp_scene_on_event_handlers[])(void* context, SceneManagerEvent event) = {
|
|
||||||
#include "avr_isp_scene_config.h"
|
|
||||||
};
|
|
||||||
#undef ADD_SCENE
|
|
||||||
|
|
||||||
// Generate scene on_exit handlers array
|
|
||||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit,
|
|
||||||
void (*const avr_isp_scene_on_exit_handlers[])(void* context) = {
|
|
||||||
#include "avr_isp_scene_config.h"
|
|
||||||
};
|
|
||||||
#undef ADD_SCENE
|
|
||||||
|
|
||||||
// Initialize scene handlers configuration structure
|
|
||||||
const SceneManagerHandlers avr_isp_scene_handlers = {
|
|
||||||
.on_enter_handlers = avr_isp_scene_on_enter_handlers,
|
|
||||||
.on_event_handlers = avr_isp_scene_on_event_handlers,
|
|
||||||
.on_exit_handlers = avr_isp_scene_on_exit_handlers,
|
|
||||||
.scene_num = AvrIspSceneNum,
|
|
||||||
};
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <gui/scene_manager.h>
|
|
||||||
|
|
||||||
// Generate scene id and total number
|
|
||||||
#define ADD_SCENE(prefix, name, id) AvrIspScene##id,
|
|
||||||
typedef enum {
|
|
||||||
#include "avr_isp_scene_config.h"
|
|
||||||
AvrIspSceneNum,
|
|
||||||
} AvrIspScene;
|
|
||||||
#undef ADD_SCENE
|
|
||||||
|
|
||||||
extern const SceneManagerHandlers avr_isp_scene_handlers;
|
|
||||||
|
|
||||||
// Generate scene on_enter handlers declaration
|
|
||||||
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*);
|
|
||||||
#include "avr_isp_scene_config.h"
|
|
||||||
#undef ADD_SCENE
|
|
||||||
|
|
||||||
// Generate scene on_event handlers declaration
|
|
||||||
#define ADD_SCENE(prefix, name, id) \
|
|
||||||
bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event);
|
|
||||||
#include "avr_isp_scene_config.h"
|
|
||||||
#undef ADD_SCENE
|
|
||||||
|
|
||||||
// Generate scene on_exit handlers declaration
|
|
||||||
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context);
|
|
||||||
#include "avr_isp_scene_config.h"
|
|
||||||
#undef ADD_SCENE
|
|
||||||
@@ -1,99 +0,0 @@
|
|||||||
#include "../avr_isp_app_i.h"
|
|
||||||
#include "../helpers/avr_isp_types.h"
|
|
||||||
|
|
||||||
void avr_isp_scene_about_widget_callback(GuiButtonType result, InputType type, void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
if(type == InputTypeShort) {
|
|
||||||
view_dispatcher_send_custom_event(app->view_dispatcher, result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_scene_about_on_enter(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
FuriString* temp_str = furi_string_alloc();
|
|
||||||
furi_string_printf(temp_str, "\e#%s\n", "Information");
|
|
||||||
|
|
||||||
furi_string_cat_printf(temp_str, "Version: %s\n", AVR_ISP_VERSION_APP);
|
|
||||||
furi_string_cat_printf(temp_str, "Developed by: %s\n", AVR_ISP_DEVELOPED);
|
|
||||||
furi_string_cat_printf(temp_str, "Github: %s\n\n", AVR_ISP_GITHUB);
|
|
||||||
|
|
||||||
furi_string_cat_printf(temp_str, "\e#%s\n", "Description");
|
|
||||||
furi_string_cat_printf(
|
|
||||||
temp_str,
|
|
||||||
"This application is an AVR in-system programmer based on stk500mk1. It is compatible with AVR-based"
|
|
||||||
" microcontrollers including Arduino. You can also use it to repair the chip if you accidentally"
|
|
||||||
" corrupt the bootloader.\n\n");
|
|
||||||
|
|
||||||
furi_string_cat_printf(temp_str, "\e#%s\n", "What it can do:");
|
|
||||||
furi_string_cat_printf(temp_str, "- Create a dump of your chip on an SD card\n");
|
|
||||||
furi_string_cat_printf(temp_str, "- Flash your chip firmware from the SD card\n");
|
|
||||||
furi_string_cat_printf(temp_str, "- Act as a wired USB ISP using avrdude software\n\n");
|
|
||||||
|
|
||||||
furi_string_cat_printf(temp_str, "\e#%s\n", "Supported chip series:");
|
|
||||||
furi_string_cat_printf(
|
|
||||||
temp_str,
|
|
||||||
"Example command for avrdude flashing: avrdude.exe -p m328p -c stk500v1 -P COMxx -U flash:r:"
|
|
||||||
"X:\\sketch_sample.hex"
|
|
||||||
":i\n");
|
|
||||||
furi_string_cat_printf(
|
|
||||||
temp_str,
|
|
||||||
"Where: "
|
|
||||||
"-p m328p"
|
|
||||||
" brand of your chip, "
|
|
||||||
"-P COMxx"
|
|
||||||
" com port number in the system when "
|
|
||||||
"ISP Programmer"
|
|
||||||
" is enabled\n\n");
|
|
||||||
|
|
||||||
furi_string_cat_printf(temp_str, "\e#%s\n", "Info");
|
|
||||||
furi_string_cat_printf(
|
|
||||||
temp_str,
|
|
||||||
"ATtinyXXXX\nATmegaXXXX\nAT43Uxxx\nAT76C711\nAT86RF401\nAT90xxxxx\nAT94K\n"
|
|
||||||
"ATAxxxxx\nATA664251\nM3000\nLGT8F88P\nLGT8F168P\nLGT8F328P\n");
|
|
||||||
|
|
||||||
furi_string_cat_printf(
|
|
||||||
temp_str, "For a more detailed list of supported chips, see AVRDude help\n");
|
|
||||||
|
|
||||||
widget_add_text_box_element(
|
|
||||||
app->widget,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
128,
|
|
||||||
14,
|
|
||||||
AlignCenter,
|
|
||||||
AlignBottom,
|
|
||||||
"\e#\e! \e!\n",
|
|
||||||
false);
|
|
||||||
widget_add_text_box_element(
|
|
||||||
app->widget,
|
|
||||||
0,
|
|
||||||
2,
|
|
||||||
128,
|
|
||||||
14,
|
|
||||||
AlignCenter,
|
|
||||||
AlignBottom,
|
|
||||||
"\e#\e! ISP Programmer \e!\n",
|
|
||||||
false);
|
|
||||||
widget_add_text_scroll_element(app->widget, 0, 16, 128, 50, furi_string_get_cstr(temp_str));
|
|
||||||
furi_string_free(temp_str);
|
|
||||||
|
|
||||||
view_dispatcher_switch_to_view(app->view_dispatcher, AvrIspViewWidget);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool avr_isp_scene_about_on_event(void* context, SceneManagerEvent event) {
|
|
||||||
UNUSED(context);
|
|
||||||
UNUSED(event);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_scene_about_on_exit(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
// Clear views
|
|
||||||
widget_reset(app->widget);
|
|
||||||
}
|
|
||||||
@@ -1,72 +0,0 @@
|
|||||||
#include "../avr_isp_app_i.h"
|
|
||||||
|
|
||||||
void avr_isp_scene_chip_detect_callback(AvrIspCustomEvent event, void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
view_dispatcher_send_custom_event(app->view_dispatcher, event);
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_scene_chip_detect_on_enter(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
switch(app->error) {
|
|
||||||
case AvrIspErrorReading:
|
|
||||||
case AvrIspErrorWriting:
|
|
||||||
case AvrIspErrorWritingFuse:
|
|
||||||
avr_isp_chip_detect_set_state(
|
|
||||||
app->avr_isp_chip_detect_view, AvrIspChipDetectViewStateErrorOccured);
|
|
||||||
break;
|
|
||||||
case AvrIspErrorVerification:
|
|
||||||
avr_isp_chip_detect_set_state(
|
|
||||||
app->avr_isp_chip_detect_view, AvrIspChipDetectViewStateErrorVerification);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
avr_isp_chip_detect_set_state(
|
|
||||||
app->avr_isp_chip_detect_view, AvrIspChipDetectViewStateNoDetect);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
app->error = AvrIspErrorNoError;
|
|
||||||
avr_isp_chip_detect_view_set_callback(
|
|
||||||
app->avr_isp_chip_detect_view, avr_isp_scene_chip_detect_callback, app);
|
|
||||||
|
|
||||||
view_dispatcher_switch_to_view(app->view_dispatcher, AvrIspViewChipDetect);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool avr_isp_scene_chip_detect_on_event(void* context, SceneManagerEvent event) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
bool consumed = false;
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
|
||||||
switch(event.event) {
|
|
||||||
case AvrIspCustomEventSceneChipDetectOk:
|
|
||||||
|
|
||||||
if(scene_manager_get_scene_state(app->scene_manager, AvrIspSceneChipDetect) ==
|
|
||||||
AvrIspViewProgrammer) {
|
|
||||||
scene_manager_next_scene(app->scene_manager, AvrIspSceneProgrammer);
|
|
||||||
} else if(
|
|
||||||
scene_manager_get_scene_state(app->scene_manager, AvrIspSceneChipDetect) ==
|
|
||||||
AvrIspViewReader) {
|
|
||||||
scene_manager_next_scene(app->scene_manager, AvrIspSceneInputName);
|
|
||||||
} else if(
|
|
||||||
scene_manager_get_scene_state(app->scene_manager, AvrIspSceneChipDetect) ==
|
|
||||||
AvrIspViewWriter) {
|
|
||||||
scene_manager_next_scene(app->scene_manager, AvrIspSceneLoad);
|
|
||||||
}
|
|
||||||
|
|
||||||
consumed = true;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else if(event.type == SceneManagerEventTypeTick) {
|
|
||||||
}
|
|
||||||
return consumed;
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_scene_chip_detect_on_exit(void* context) {
|
|
||||||
UNUSED(context);
|
|
||||||
}
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
ADD_SCENE(avr_isp, start, Start)
|
|
||||||
ADD_SCENE(avr_isp, about, About)
|
|
||||||
ADD_SCENE(avr_isp, programmer, Programmer)
|
|
||||||
ADD_SCENE(avr_isp, reader, Reader)
|
|
||||||
ADD_SCENE(avr_isp, input_name, InputName)
|
|
||||||
ADD_SCENE(avr_isp, load, Load)
|
|
||||||
ADD_SCENE(avr_isp, writer, Writer)
|
|
||||||
ADD_SCENE(avr_isp, wiring, Wiring)
|
|
||||||
ADD_SCENE(avr_isp, chip_detect, ChipDetect)
|
|
||||||
ADD_SCENE(avr_isp, success, Success)
|
|
||||||
@@ -1,89 +0,0 @@
|
|||||||
#include "../avr_isp_app_i.h"
|
|
||||||
#include <gui/modules/validators.h>
|
|
||||||
|
|
||||||
#define MAX_TEXT_INPUT_LEN 22
|
|
||||||
|
|
||||||
void avr_isp_scene_input_name_text_callback(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
view_dispatcher_send_custom_event(app->view_dispatcher, AvrIspCustomEventSceneInputName);
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_scene_input_name_get_timefilename(FuriString* name) {
|
|
||||||
FuriHalRtcDateTime datetime = {0};
|
|
||||||
furi_hal_rtc_get_datetime(&datetime);
|
|
||||||
furi_string_printf(
|
|
||||||
name,
|
|
||||||
"AVR_dump-%.4d%.2d%.2d-%.2d%.2d%.2d",
|
|
||||||
datetime.year,
|
|
||||||
datetime.month,
|
|
||||||
datetime.day,
|
|
||||||
datetime.hour,
|
|
||||||
datetime.minute,
|
|
||||||
datetime.second);
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_scene_input_name_on_enter(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
// Setup view
|
|
||||||
TextInput* text_input = app->text_input;
|
|
||||||
bool dev_name_empty = false;
|
|
||||||
|
|
||||||
FuriString* file_name = furi_string_alloc();
|
|
||||||
|
|
||||||
avr_isp_scene_input_name_get_timefilename(file_name);
|
|
||||||
furi_string_set(app->file_path, STORAGE_APP_DATA_PATH_PREFIX);
|
|
||||||
//highlighting the entire filename by default
|
|
||||||
dev_name_empty = true;
|
|
||||||
|
|
||||||
strncpy(app->file_name_tmp, furi_string_get_cstr(file_name), AVR_ISP_MAX_LEN_NAME);
|
|
||||||
text_input_set_header_text(text_input, "Name dump");
|
|
||||||
text_input_set_result_callback(
|
|
||||||
text_input,
|
|
||||||
avr_isp_scene_input_name_text_callback,
|
|
||||||
app,
|
|
||||||
app->file_name_tmp,
|
|
||||||
MAX_TEXT_INPUT_LEN, // buffer size
|
|
||||||
dev_name_empty);
|
|
||||||
|
|
||||||
ValidatorIsFile* validator_is_file =
|
|
||||||
validator_is_file_alloc_init(STORAGE_APP_DATA_PATH_PREFIX, AVR_ISP_APP_EXTENSION, "");
|
|
||||||
text_input_set_validator(text_input, validator_is_file_callback, validator_is_file);
|
|
||||||
|
|
||||||
furi_string_free(file_name);
|
|
||||||
|
|
||||||
view_dispatcher_switch_to_view(app->view_dispatcher, AvrIspViewTextInput);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool avr_isp_scene_input_name_on_event(void* context, SceneManagerEvent event) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
if(event.type == SceneManagerEventTypeBack) {
|
|
||||||
scene_manager_previous_scene(app->scene_manager);
|
|
||||||
return true;
|
|
||||||
} else if(event.type == SceneManagerEventTypeCustom) {
|
|
||||||
if(event.event == AvrIspCustomEventSceneInputName) {
|
|
||||||
if(strcmp(app->file_name_tmp, "") != 0) {
|
|
||||||
scene_manager_next_scene(app->scene_manager, AvrIspSceneReader);
|
|
||||||
} else {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_scene_input_name_on_exit(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
// Clear validator
|
|
||||||
void* validator_context = text_input_get_validator_callback_context(app->text_input);
|
|
||||||
text_input_set_validator(app->text_input, NULL, NULL);
|
|
||||||
validator_is_file_free(validator_context);
|
|
||||||
// Clear view
|
|
||||||
text_input_reset(app->text_input);
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
#include "../avr_isp_app_i.h"
|
|
||||||
|
|
||||||
void avr_isp_scene_load_on_enter(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
if(avr_isp_load_from_file(app)) {
|
|
||||||
scene_manager_next_scene(app->scene_manager, AvrIspSceneWriter);
|
|
||||||
} else {
|
|
||||||
scene_manager_previous_scene(app->scene_manager);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool avr_isp_scene_load_on_event(void* context, SceneManagerEvent event) {
|
|
||||||
UNUSED(context);
|
|
||||||
UNUSED(event);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_scene_load_on_exit(void* context) {
|
|
||||||
UNUSED(context);
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
#include "../avr_isp_app_i.h"
|
|
||||||
|
|
||||||
void avr_isp_scene_programmer_callback(AvrIspCustomEvent event, void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
view_dispatcher_send_custom_event(app->view_dispatcher, event);
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_scene_programmer_on_enter(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
avr_isp_programmer_view_set_callback(
|
|
||||||
app->avr_isp_programmer_view, avr_isp_scene_programmer_callback, app);
|
|
||||||
|
|
||||||
view_dispatcher_switch_to_view(app->view_dispatcher, AvrIspViewProgrammer);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool avr_isp_scene_programmer_on_event(void* context, SceneManagerEvent event) {
|
|
||||||
UNUSED(context);
|
|
||||||
UNUSED(event);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_scene_programmer_on_exit(void* context) {
|
|
||||||
UNUSED(context);
|
|
||||||
}
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
#include "../avr_isp_app_i.h"
|
|
||||||
|
|
||||||
void avr_isp_scene_reader_callback(AvrIspCustomEvent event, void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
view_dispatcher_send_custom_event(app->view_dispatcher, event);
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_scene_reader_on_enter(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
avr_isp_reader_set_file_path(
|
|
||||||
app->avr_isp_reader_view, furi_string_get_cstr(app->file_path), app->file_name_tmp);
|
|
||||||
avr_isp_reader_view_set_callback(app->avr_isp_reader_view, avr_isp_scene_reader_callback, app);
|
|
||||||
|
|
||||||
view_dispatcher_switch_to_view(app->view_dispatcher, AvrIspViewReader);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool avr_isp_scene_reader_on_event(void* context, SceneManagerEvent event) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
UNUSED(app);
|
|
||||||
bool consumed = false;
|
|
||||||
if(event.type == SceneManagerEventTypeBack) {
|
|
||||||
//do not handle exit on "Back"
|
|
||||||
consumed = true;
|
|
||||||
} else if(event.type == SceneManagerEventTypeCustom) {
|
|
||||||
switch(event.event) {
|
|
||||||
case AvrIspCustomEventSceneReadingOk:
|
|
||||||
scene_manager_next_scene(app->scene_manager, AvrIspSceneSuccess);
|
|
||||||
consumed = true;
|
|
||||||
break;
|
|
||||||
case AvrIspCustomEventSceneExit:
|
|
||||||
scene_manager_search_and_switch_to_previous_scene(
|
|
||||||
app->scene_manager, AvrIspSceneChipDetect);
|
|
||||||
consumed = true;
|
|
||||||
break;
|
|
||||||
case AvrIspCustomEventSceneErrorVerification:
|
|
||||||
app->error = AvrIspErrorVerification;
|
|
||||||
scene_manager_search_and_switch_to_previous_scene(
|
|
||||||
app->scene_manager, AvrIspSceneChipDetect);
|
|
||||||
consumed = true;
|
|
||||||
break;
|
|
||||||
case AvrIspCustomEventSceneErrorReading:
|
|
||||||
app->error = AvrIspErrorReading;
|
|
||||||
scene_manager_search_and_switch_to_previous_scene(
|
|
||||||
app->scene_manager, AvrIspSceneChipDetect);
|
|
||||||
consumed = true;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else if(event.type == SceneManagerEventTypeTick) {
|
|
||||||
avr_isp_reader_update_progress(app->avr_isp_reader_view);
|
|
||||||
}
|
|
||||||
return consumed;
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_scene_reader_on_exit(void* context) {
|
|
||||||
UNUSED(context);
|
|
||||||
}
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
#include "../avr_isp_app_i.h"
|
|
||||||
|
|
||||||
void avr_isp_scene_start_submenu_callback(void* context, uint32_t index) {
|
|
||||||
furi_assert(context);
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
|
|
||||||
view_dispatcher_send_custom_event(app->view_dispatcher, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_scene_start_on_enter(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
Submenu* submenu = app->submenu;
|
|
||||||
submenu_add_item(
|
|
||||||
submenu, "Dump AVR", SubmenuIndexAvrIspReader, avr_isp_scene_start_submenu_callback, app);
|
|
||||||
submenu_add_item(
|
|
||||||
submenu, "Flash AVR", SubmenuIndexAvrIspWriter, avr_isp_scene_start_submenu_callback, app);
|
|
||||||
submenu_add_item(
|
|
||||||
submenu,
|
|
||||||
"ISP Programmer",
|
|
||||||
SubmenuIndexAvrIspProgrammer,
|
|
||||||
avr_isp_scene_start_submenu_callback,
|
|
||||||
app);
|
|
||||||
submenu_add_item(
|
|
||||||
submenu, "Wiring", SubmenuIndexAvrIsWiring, avr_isp_scene_start_submenu_callback, app);
|
|
||||||
submenu_add_item(
|
|
||||||
submenu, "About", SubmenuIndexAvrIspAbout, avr_isp_scene_start_submenu_callback, app);
|
|
||||||
|
|
||||||
submenu_set_selected_item(
|
|
||||||
submenu, scene_manager_get_scene_state(app->scene_manager, AvrIspSceneStart));
|
|
||||||
|
|
||||||
view_dispatcher_switch_to_view(app->view_dispatcher, AvrIspViewSubmenu);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool avr_isp_scene_start_on_event(void* context, SceneManagerEvent event) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
bool consumed = false;
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
|
||||||
if(event.event == SubmenuIndexAvrIspAbout) {
|
|
||||||
scene_manager_next_scene(app->scene_manager, AvrIspSceneAbout);
|
|
||||||
consumed = true;
|
|
||||||
} else if(event.event == SubmenuIndexAvrIspProgrammer) {
|
|
||||||
scene_manager_set_scene_state(
|
|
||||||
app->scene_manager, AvrIspSceneChipDetect, AvrIspViewProgrammer);
|
|
||||||
scene_manager_next_scene(app->scene_manager, AvrIspSceneChipDetect);
|
|
||||||
consumed = true;
|
|
||||||
} else if(event.event == SubmenuIndexAvrIspReader) {
|
|
||||||
scene_manager_set_scene_state(
|
|
||||||
app->scene_manager, AvrIspSceneChipDetect, AvrIspViewReader);
|
|
||||||
scene_manager_next_scene(app->scene_manager, AvrIspSceneChipDetect);
|
|
||||||
consumed = true;
|
|
||||||
} else if(event.event == SubmenuIndexAvrIspWriter) {
|
|
||||||
scene_manager_set_scene_state(
|
|
||||||
app->scene_manager, AvrIspSceneChipDetect, AvrIspViewWriter);
|
|
||||||
scene_manager_next_scene(app->scene_manager, AvrIspSceneChipDetect);
|
|
||||||
consumed = true;
|
|
||||||
} else if(event.event == SubmenuIndexAvrIsWiring) {
|
|
||||||
scene_manager_next_scene(app->scene_manager, AvrIspSceneWiring);
|
|
||||||
consumed = true;
|
|
||||||
}
|
|
||||||
scene_manager_set_scene_state(app->scene_manager, AvrIspSceneStart, event.event);
|
|
||||||
}
|
|
||||||
|
|
||||||
return consumed;
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_scene_start_on_exit(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
submenu_reset(app->submenu);
|
|
||||||
}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
#include "../avr_isp_app_i.h"
|
|
||||||
|
|
||||||
void avr_isp_scene_success_popup_callback(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
view_dispatcher_send_custom_event(app->view_dispatcher, AvrIspCustomEventSceneSuccess);
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_scene_success_on_enter(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
Popup* popup = app->popup;
|
|
||||||
popup_set_icon(popup, 32, 5, &I_dolphin_nice_96x59);
|
|
||||||
popup_set_header(popup, "Success!", 8, 22, AlignLeft, AlignBottom);
|
|
||||||
popup_set_timeout(popup, 1500);
|
|
||||||
popup_set_context(popup, app);
|
|
||||||
popup_set_callback(popup, avr_isp_scene_success_popup_callback);
|
|
||||||
popup_enable_timeout(popup);
|
|
||||||
view_dispatcher_switch_to_view(app->view_dispatcher, AvrIspViewPopup);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool avr_isp_scene_success_on_event(void* context, SceneManagerEvent event) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
|
||||||
if(event.event == AvrIspCustomEventSceneSuccess) {
|
|
||||||
scene_manager_search_and_switch_to_previous_scene(
|
|
||||||
app->scene_manager, AvrIspSceneStart);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_scene_success_on_exit(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
Popup* popup = app->popup;
|
|
||||||
popup_reset(popup);
|
|
||||||
}
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
#include "../avr_isp_app_i.h"
|
|
||||||
|
|
||||||
void avr_isp_scene_wiring_on_enter(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
widget_add_icon_element(app->widget, 0, 0, &I_avr_wiring);
|
|
||||||
view_dispatcher_switch_to_view(app->view_dispatcher, AvrIspViewWidget);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool avr_isp_scene_wiring_on_event(void* context, SceneManagerEvent event) {
|
|
||||||
UNUSED(context);
|
|
||||||
UNUSED(event);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
void avr_isp_scene_wiring_on_exit(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
widget_reset(app->widget);
|
|
||||||
}
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
#include "../avr_isp_app_i.h"
|
|
||||||
|
|
||||||
void avr_isp_scene_writer_callback(AvrIspCustomEvent event, void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
view_dispatcher_send_custom_event(app->view_dispatcher, event);
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_scene_writer_on_enter(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
avr_isp_writer_set_file_path(
|
|
||||||
app->avr_isp_writer_view, furi_string_get_cstr(app->file_path), app->file_name_tmp);
|
|
||||||
avr_isp_writer_view_set_callback(app->avr_isp_writer_view, avr_isp_scene_writer_callback, app);
|
|
||||||
view_dispatcher_switch_to_view(app->view_dispatcher, AvrIspViewWriter);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool avr_isp_scene_writer_on_event(void* context, SceneManagerEvent event) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
bool consumed = false;
|
|
||||||
if(event.type == SceneManagerEventTypeBack) {
|
|
||||||
//do not handle exit on "Back"
|
|
||||||
consumed = true;
|
|
||||||
} else if(event.type == SceneManagerEventTypeCustom) {
|
|
||||||
switch(event.event) {
|
|
||||||
case AvrIspCustomEventSceneExitStartMenu:
|
|
||||||
scene_manager_search_and_switch_to_previous_scene(
|
|
||||||
app->scene_manager, AvrIspSceneStart);
|
|
||||||
consumed = true;
|
|
||||||
break;
|
|
||||||
case AvrIspCustomEventSceneExit:
|
|
||||||
scene_manager_search_and_switch_to_previous_scene(
|
|
||||||
app->scene_manager, AvrIspSceneChipDetect);
|
|
||||||
consumed = true;
|
|
||||||
break;
|
|
||||||
case AvrIspCustomEventSceneErrorVerification:
|
|
||||||
app->error = AvrIspErrorVerification;
|
|
||||||
scene_manager_search_and_switch_to_previous_scene(
|
|
||||||
app->scene_manager, AvrIspSceneChipDetect);
|
|
||||||
consumed = true;
|
|
||||||
break;
|
|
||||||
case AvrIspCustomEventSceneErrorWriting:
|
|
||||||
app->error = AvrIspErrorWriting;
|
|
||||||
scene_manager_search_and_switch_to_previous_scene(
|
|
||||||
app->scene_manager, AvrIspSceneChipDetect);
|
|
||||||
consumed = true;
|
|
||||||
break;
|
|
||||||
case AvrIspCustomEventSceneErrorWritingFuse:
|
|
||||||
app->error = AvrIspErrorWritingFuse;
|
|
||||||
scene_manager_search_and_switch_to_previous_scene(
|
|
||||||
app->scene_manager, AvrIspSceneChipDetect);
|
|
||||||
consumed = true;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else if(event.type == SceneManagerEventTypeTick) {
|
|
||||||
avr_isp_writer_update_progress(app->avr_isp_writer_view);
|
|
||||||
}
|
|
||||||
return consumed;
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_scene_writer_on_exit(void* context) {
|
|
||||||
UNUSED(context);
|
|
||||||
}
|
|
||||||
@@ -1,213 +0,0 @@
|
|||||||
#include "avr_isp_view_chip_detect.h"
|
|
||||||
#include <avr_isp_icons.h>
|
|
||||||
#include <gui/elements.h>
|
|
||||||
|
|
||||||
#include "../helpers/avr_isp_worker_rw.h"
|
|
||||||
|
|
||||||
struct AvrIspChipDetectView {
|
|
||||||
View* view;
|
|
||||||
AvrIspWorkerRW* avr_isp_worker_rw;
|
|
||||||
AvrIspChipDetectViewCallback callback;
|
|
||||||
void* context;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint16_t idx;
|
|
||||||
const char* name_chip;
|
|
||||||
uint32_t flash_size;
|
|
||||||
AvrIspChipDetectViewState state;
|
|
||||||
} AvrIspChipDetectViewModel;
|
|
||||||
|
|
||||||
void avr_isp_chip_detect_view_set_callback(
|
|
||||||
AvrIspChipDetectView* instance,
|
|
||||||
AvrIspChipDetectViewCallback callback,
|
|
||||||
void* context) {
|
|
||||||
furi_assert(instance);
|
|
||||||
furi_assert(callback);
|
|
||||||
|
|
||||||
instance->callback = callback;
|
|
||||||
instance->context = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_chip_detect_set_state(AvrIspChipDetectView* instance, AvrIspChipDetectViewState state) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
with_view_model(
|
|
||||||
instance->view, AvrIspChipDetectViewModel * model, { model->state = state; }, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_chip_detect_view_draw(Canvas* canvas, AvrIspChipDetectViewModel* model) {
|
|
||||||
canvas_clear(canvas);
|
|
||||||
|
|
||||||
char str_buf[64] = {0};
|
|
||||||
canvas_set_font(canvas, FontPrimary);
|
|
||||||
|
|
||||||
switch(model->state) {
|
|
||||||
case AvrIspChipDetectViewStateDetected:
|
|
||||||
canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "AVR chip detected!");
|
|
||||||
canvas_draw_icon(canvas, 29, 14, &I_chip_long_70x22);
|
|
||||||
canvas_set_font(canvas, FontSecondary);
|
|
||||||
snprintf(str_buf, sizeof(str_buf), "%ld Kb", model->flash_size / 1024);
|
|
||||||
canvas_draw_str_aligned(canvas, 64, 25, AlignCenter, AlignCenter, str_buf);
|
|
||||||
canvas_draw_str_aligned(canvas, 64, 45, AlignCenter, AlignCenter, model->name_chip);
|
|
||||||
elements_button_right(canvas, "Next");
|
|
||||||
break;
|
|
||||||
case AvrIspChipDetectViewStateErrorOccured:
|
|
||||||
canvas_draw_str_aligned(
|
|
||||||
canvas, 64, 5, AlignCenter, AlignCenter, "Error occured, try again!");
|
|
||||||
canvas_draw_icon(canvas, 29, 14, &I_chip_error_70x22);
|
|
||||||
canvas_set_font(canvas, FontSecondary);
|
|
||||||
canvas_draw_str_aligned(
|
|
||||||
canvas, 64, 45, AlignCenter, AlignCenter, "Check the wiring and retry");
|
|
||||||
break;
|
|
||||||
case AvrIspChipDetectViewStateErrorVerification:
|
|
||||||
canvas_draw_str_aligned(
|
|
||||||
canvas, 64, 5, AlignCenter, AlignCenter, "Data verification failed");
|
|
||||||
canvas_draw_icon(canvas, 29, 14, &I_chip_error_70x22);
|
|
||||||
canvas_set_font(canvas, FontSecondary);
|
|
||||||
canvas_draw_str_aligned(
|
|
||||||
canvas, 64, 45, AlignCenter, AlignCenter, "Try to restart the process");
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
//AvrIspChipDetectViewStateNoDetect
|
|
||||||
canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "AVR chip not found!");
|
|
||||||
canvas_draw_icon(canvas, 29, 12, &I_chif_not_found_83x37);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
canvas_set_font(canvas, FontSecondary);
|
|
||||||
elements_button_left(canvas, "Retry");
|
|
||||||
}
|
|
||||||
|
|
||||||
bool avr_isp_chip_detect_view_input(InputEvent* event, void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspChipDetectView* instance = context;
|
|
||||||
|
|
||||||
if(event->type == InputTypeShort) {
|
|
||||||
if(event->key == InputKeyBack) {
|
|
||||||
return false;
|
|
||||||
} else if(event->key == InputKeyRight) {
|
|
||||||
with_view_model(
|
|
||||||
instance->view,
|
|
||||||
AvrIspChipDetectViewModel * model,
|
|
||||||
{
|
|
||||||
if(model->state == AvrIspChipDetectViewStateDetected) {
|
|
||||||
if(instance->callback)
|
|
||||||
instance->callback(
|
|
||||||
AvrIspCustomEventSceneChipDetectOk, instance->context);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
false);
|
|
||||||
|
|
||||||
} else if(event->key == InputKeyLeft) {
|
|
||||||
bool detect_chip = false;
|
|
||||||
with_view_model(
|
|
||||||
instance->view,
|
|
||||||
AvrIspChipDetectViewModel * model,
|
|
||||||
{
|
|
||||||
if(model->state != AvrIspChipDetectViewStateDetecting) {
|
|
||||||
model->state = AvrIspChipDetectViewStateDetecting;
|
|
||||||
detect_chip = true;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
false);
|
|
||||||
if(detect_chip) avr_isp_worker_rw_detect_chip(instance->avr_isp_worker_rw);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void avr_isp_chip_detect_detect_chip_callback(
|
|
||||||
void* context,
|
|
||||||
const char* name,
|
|
||||||
bool detect_chip,
|
|
||||||
uint32_t flash_size) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspChipDetectView* instance = context;
|
|
||||||
with_view_model(
|
|
||||||
instance->view,
|
|
||||||
AvrIspChipDetectViewModel * model,
|
|
||||||
{
|
|
||||||
model->name_chip = name;
|
|
||||||
model->flash_size = flash_size;
|
|
||||||
if(detect_chip) {
|
|
||||||
model->state = AvrIspChipDetectViewStateDetected;
|
|
||||||
} else {
|
|
||||||
model->state = AvrIspChipDetectViewStateNoDetect;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
true);
|
|
||||||
}
|
|
||||||
void avr_isp_chip_detect_view_enter(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspChipDetectView* instance = context;
|
|
||||||
bool detect_chip = false;
|
|
||||||
with_view_model(
|
|
||||||
instance->view,
|
|
||||||
AvrIspChipDetectViewModel * model,
|
|
||||||
{
|
|
||||||
if(model->state == AvrIspChipDetectViewStateNoDetect ||
|
|
||||||
model->state == AvrIspChipDetectViewStateDetected) {
|
|
||||||
detect_chip = true;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
false);
|
|
||||||
|
|
||||||
//Start avr_isp_worker_rw
|
|
||||||
instance->avr_isp_worker_rw = avr_isp_worker_rw_alloc(instance->context);
|
|
||||||
|
|
||||||
avr_isp_worker_rw_set_callback(
|
|
||||||
instance->avr_isp_worker_rw, avr_isp_chip_detect_detect_chip_callback, instance);
|
|
||||||
|
|
||||||
if(detect_chip) avr_isp_worker_rw_detect_chip(instance->avr_isp_worker_rw);
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_chip_detect_view_exit(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspChipDetectView* instance = context;
|
|
||||||
|
|
||||||
avr_isp_worker_rw_set_callback(instance->avr_isp_worker_rw, NULL, NULL);
|
|
||||||
avr_isp_worker_rw_free(instance->avr_isp_worker_rw);
|
|
||||||
}
|
|
||||||
|
|
||||||
AvrIspChipDetectView* avr_isp_chip_detect_view_alloc() {
|
|
||||||
AvrIspChipDetectView* instance = malloc(sizeof(AvrIspChipDetectView));
|
|
||||||
|
|
||||||
// View allocation and configuration
|
|
||||||
instance->view = view_alloc();
|
|
||||||
|
|
||||||
view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(AvrIspChipDetectViewModel));
|
|
||||||
view_set_context(instance->view, instance);
|
|
||||||
view_set_draw_callback(instance->view, (ViewDrawCallback)avr_isp_chip_detect_view_draw);
|
|
||||||
view_set_input_callback(instance->view, avr_isp_chip_detect_view_input);
|
|
||||||
view_set_enter_callback(instance->view, avr_isp_chip_detect_view_enter);
|
|
||||||
view_set_exit_callback(instance->view, avr_isp_chip_detect_view_exit);
|
|
||||||
|
|
||||||
with_view_model(
|
|
||||||
instance->view,
|
|
||||||
AvrIspChipDetectViewModel * model,
|
|
||||||
{ model->state = AvrIspChipDetectViewStateNoDetect; },
|
|
||||||
false);
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_chip_detect_view_free(AvrIspChipDetectView* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
view_free(instance->view);
|
|
||||||
free(instance);
|
|
||||||
}
|
|
||||||
|
|
||||||
View* avr_isp_chip_detect_view_get_view(AvrIspChipDetectView* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
return instance->view;
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <gui/view.h>
|
|
||||||
#include "../helpers/avr_isp_types.h"
|
|
||||||
#include "../helpers/avr_isp_event.h"
|
|
||||||
|
|
||||||
typedef struct AvrIspChipDetectView AvrIspChipDetectView;
|
|
||||||
|
|
||||||
typedef void (*AvrIspChipDetectViewCallback)(AvrIspCustomEvent event, void* context);
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
AvrIspChipDetectViewStateNoDetect,
|
|
||||||
AvrIspChipDetectViewStateDetecting,
|
|
||||||
AvrIspChipDetectViewStateDetected,
|
|
||||||
AvrIspChipDetectViewStateErrorOccured,
|
|
||||||
AvrIspChipDetectViewStateErrorVerification,
|
|
||||||
} AvrIspChipDetectViewState;
|
|
||||||
|
|
||||||
void avr_isp_chip_detect_view_set_callback(
|
|
||||||
AvrIspChipDetectView* instance,
|
|
||||||
AvrIspChipDetectViewCallback callback,
|
|
||||||
void* context);
|
|
||||||
|
|
||||||
void avr_isp_chip_detect_set_state(AvrIspChipDetectView* instance, AvrIspChipDetectViewState state);
|
|
||||||
|
|
||||||
AvrIspChipDetectView* avr_isp_chip_detect_view_alloc();
|
|
||||||
|
|
||||||
void avr_isp_chip_detect_view_free(AvrIspChipDetectView* instance);
|
|
||||||
|
|
||||||
View* avr_isp_chip_detect_view_get_view(AvrIspChipDetectView* instance);
|
|
||||||
|
|
||||||
void avr_isp_chip_detect_view_exit(void* context);
|
|
||||||
@@ -1,134 +0,0 @@
|
|||||||
#include "avr_isp_view_programmer.h"
|
|
||||||
#include <avr_isp_icons.h>
|
|
||||||
|
|
||||||
#include "../helpers/avr_isp_worker.h"
|
|
||||||
#include <gui/elements.h>
|
|
||||||
|
|
||||||
struct AvrIspProgrammerView {
|
|
||||||
View* view;
|
|
||||||
AvrIspWorker* worker;
|
|
||||||
AvrIspProgrammerViewCallback callback;
|
|
||||||
void* context;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
AvrIspProgrammerViewStatus status;
|
|
||||||
} AvrIspProgrammerViewModel;
|
|
||||||
|
|
||||||
void avr_isp_programmer_view_set_callback(
|
|
||||||
AvrIspProgrammerView* instance,
|
|
||||||
AvrIspProgrammerViewCallback callback,
|
|
||||||
void* context) {
|
|
||||||
furi_assert(instance);
|
|
||||||
furi_assert(callback);
|
|
||||||
|
|
||||||
instance->callback = callback;
|
|
||||||
instance->context = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_programmer_view_draw(Canvas* canvas, AvrIspProgrammerViewModel* model) {
|
|
||||||
canvas_clear(canvas);
|
|
||||||
|
|
||||||
if(model->status == AvrIspProgrammerViewStatusUSBConnect) {
|
|
||||||
canvas_set_font(canvas, FontPrimary);
|
|
||||||
canvas_draw_icon(canvas, 0, 0, &I_isp_active_128x53);
|
|
||||||
elements_multiline_text(canvas, 45, 10, "ISP mode active");
|
|
||||||
} else {
|
|
||||||
canvas_set_font(canvas, FontSecondary);
|
|
||||||
canvas_draw_icon(canvas, 51, 6, &I_link_waiting_77x56);
|
|
||||||
elements_multiline_text(canvas, 0, 25, "Waiting for\nsoftware\nconnection");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool avr_isp_programmer_view_input(InputEvent* event, void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
UNUSED(context);
|
|
||||||
|
|
||||||
if(event->key == InputKeyBack || event->type != InputTypeShort) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void avr_isp_programmer_usb_connect_callback(void* context, bool status_connect) {
|
|
||||||
furi_assert(context);
|
|
||||||
AvrIspProgrammerView* instance = context;
|
|
||||||
|
|
||||||
with_view_model(
|
|
||||||
instance->view,
|
|
||||||
AvrIspProgrammerViewModel * model,
|
|
||||||
{
|
|
||||||
if(status_connect) {
|
|
||||||
model->status = AvrIspProgrammerViewStatusUSBConnect;
|
|
||||||
} else {
|
|
||||||
model->status = AvrIspProgrammerViewStatusNoUSBConnect;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_programmer_view_enter(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspProgrammerView* instance = context;
|
|
||||||
with_view_model(
|
|
||||||
instance->view,
|
|
||||||
AvrIspProgrammerViewModel * model,
|
|
||||||
{ model->status = AvrIspProgrammerViewStatusNoUSBConnect; },
|
|
||||||
true);
|
|
||||||
|
|
||||||
//Start worker
|
|
||||||
instance->worker = avr_isp_worker_alloc(instance->context);
|
|
||||||
|
|
||||||
avr_isp_worker_set_callback(
|
|
||||||
instance->worker, avr_isp_programmer_usb_connect_callback, instance);
|
|
||||||
|
|
||||||
avr_isp_worker_start(instance->worker);
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_programmer_view_exit(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspProgrammerView* instance = context;
|
|
||||||
//Stop worker
|
|
||||||
if(avr_isp_worker_is_running(instance->worker)) {
|
|
||||||
avr_isp_worker_stop(instance->worker);
|
|
||||||
}
|
|
||||||
avr_isp_worker_set_callback(instance->worker, NULL, NULL);
|
|
||||||
avr_isp_worker_free(instance->worker);
|
|
||||||
}
|
|
||||||
|
|
||||||
AvrIspProgrammerView* avr_isp_programmer_view_alloc() {
|
|
||||||
AvrIspProgrammerView* instance = malloc(sizeof(AvrIspProgrammerView));
|
|
||||||
|
|
||||||
// View allocation and configuration
|
|
||||||
instance->view = view_alloc();
|
|
||||||
|
|
||||||
view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(AvrIspProgrammerViewModel));
|
|
||||||
view_set_context(instance->view, instance);
|
|
||||||
view_set_draw_callback(instance->view, (ViewDrawCallback)avr_isp_programmer_view_draw);
|
|
||||||
view_set_input_callback(instance->view, avr_isp_programmer_view_input);
|
|
||||||
view_set_enter_callback(instance->view, avr_isp_programmer_view_enter);
|
|
||||||
view_set_exit_callback(instance->view, avr_isp_programmer_view_exit);
|
|
||||||
|
|
||||||
with_view_model(
|
|
||||||
instance->view,
|
|
||||||
AvrIspProgrammerViewModel * model,
|
|
||||||
{ model->status = AvrIspProgrammerViewStatusNoUSBConnect; },
|
|
||||||
false);
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_programmer_view_free(AvrIspProgrammerView* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
view_free(instance->view);
|
|
||||||
free(instance);
|
|
||||||
}
|
|
||||||
|
|
||||||
View* avr_isp_programmer_view_get_view(AvrIspProgrammerView* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
return instance->view;
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <gui/view.h>
|
|
||||||
#include "../helpers/avr_isp_types.h"
|
|
||||||
#include "../helpers/avr_isp_event.h"
|
|
||||||
|
|
||||||
typedef struct AvrIspProgrammerView AvrIspProgrammerView;
|
|
||||||
|
|
||||||
typedef void (*AvrIspProgrammerViewCallback)(AvrIspCustomEvent event, void* context);
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
AvrIspProgrammerViewStatusNoUSBConnect,
|
|
||||||
AvrIspProgrammerViewStatusUSBConnect,
|
|
||||||
} AvrIspProgrammerViewStatus;
|
|
||||||
|
|
||||||
void avr_isp_programmer_view_set_callback(
|
|
||||||
AvrIspProgrammerView* instance,
|
|
||||||
AvrIspProgrammerViewCallback callback,
|
|
||||||
void* context);
|
|
||||||
|
|
||||||
AvrIspProgrammerView* avr_isp_programmer_view_alloc();
|
|
||||||
|
|
||||||
void avr_isp_programmer_view_free(AvrIspProgrammerView* instance);
|
|
||||||
|
|
||||||
View* avr_isp_programmer_view_get_view(AvrIspProgrammerView* instance);
|
|
||||||
|
|
||||||
void avr_isp_programmer_view_exit(void* context);
|
|
||||||
@@ -1,215 +0,0 @@
|
|||||||
#include "avr_isp_view_reader.h"
|
|
||||||
#include <gui/elements.h>
|
|
||||||
|
|
||||||
#include "../helpers/avr_isp_worker_rw.h"
|
|
||||||
|
|
||||||
struct AvrIspReaderView {
|
|
||||||
View* view;
|
|
||||||
AvrIspWorkerRW* avr_isp_worker_rw;
|
|
||||||
const char* file_path;
|
|
||||||
const char* file_name;
|
|
||||||
AvrIspReaderViewCallback callback;
|
|
||||||
void* context;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
AvrIspReaderViewStatus status;
|
|
||||||
float progress_flash;
|
|
||||||
float progress_eeprom;
|
|
||||||
} AvrIspReaderViewModel;
|
|
||||||
|
|
||||||
void avr_isp_reader_update_progress(AvrIspReaderView* instance) {
|
|
||||||
with_view_model(
|
|
||||||
instance->view,
|
|
||||||
AvrIspReaderViewModel * model,
|
|
||||||
{
|
|
||||||
model->progress_flash =
|
|
||||||
avr_isp_worker_rw_get_progress_flash(instance->avr_isp_worker_rw);
|
|
||||||
model->progress_eeprom =
|
|
||||||
avr_isp_worker_rw_get_progress_eeprom(instance->avr_isp_worker_rw);
|
|
||||||
},
|
|
||||||
true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_reader_view_set_callback(
|
|
||||||
AvrIspReaderView* instance,
|
|
||||||
AvrIspReaderViewCallback callback,
|
|
||||||
void* context) {
|
|
||||||
furi_assert(instance);
|
|
||||||
furi_assert(callback);
|
|
||||||
|
|
||||||
instance->callback = callback;
|
|
||||||
instance->context = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_reader_set_file_path(
|
|
||||||
AvrIspReaderView* instance,
|
|
||||||
const char* file_path,
|
|
||||||
const char* file_name) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
instance->file_path = file_path;
|
|
||||||
instance->file_name = file_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_reader_view_draw(Canvas* canvas, AvrIspReaderViewModel* model) {
|
|
||||||
canvas_clear(canvas);
|
|
||||||
char str_buf[64] = {0};
|
|
||||||
|
|
||||||
canvas_set_font(canvas, FontPrimary);
|
|
||||||
switch(model->status) {
|
|
||||||
case AvrIspReaderViewStatusIDLE:
|
|
||||||
canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "Press start to dump");
|
|
||||||
canvas_set_font(canvas, FontSecondary);
|
|
||||||
elements_button_center(canvas, "Start");
|
|
||||||
break;
|
|
||||||
case AvrIspReaderViewStatusReading:
|
|
||||||
canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "Reading dump");
|
|
||||||
break;
|
|
||||||
case AvrIspReaderViewStatusVerification:
|
|
||||||
canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "Verifyng dump");
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
canvas_set_font(canvas, FontSecondary);
|
|
||||||
canvas_draw_str(canvas, 0, 27, "Flash");
|
|
||||||
snprintf(str_buf, sizeof(str_buf), "%d%%", (uint8_t)(model->progress_flash * 100));
|
|
||||||
elements_progress_bar_with_text(canvas, 44, 17, 84, model->progress_flash, str_buf);
|
|
||||||
canvas_draw_str(canvas, 0, 43, "EEPROM");
|
|
||||||
snprintf(str_buf, sizeof(str_buf), "%d%%", (uint8_t)(model->progress_eeprom * 100));
|
|
||||||
elements_progress_bar_with_text(canvas, 44, 34, 84, model->progress_eeprom, str_buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool avr_isp_reader_view_input(InputEvent* event, void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
AvrIspReaderView* instance = context;
|
|
||||||
|
|
||||||
bool ret = true;
|
|
||||||
if(event->key == InputKeyBack && event->type == InputTypeShort) {
|
|
||||||
with_view_model(
|
|
||||||
instance->view,
|
|
||||||
AvrIspReaderViewModel * model,
|
|
||||||
{
|
|
||||||
if(model->status == AvrIspReaderViewStatusIDLE) {
|
|
||||||
if(instance->callback)
|
|
||||||
instance->callback(AvrIspCustomEventSceneExit, instance->context);
|
|
||||||
ret = false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
false);
|
|
||||||
} else if(event->key == InputKeyOk && event->type == InputTypeShort) {
|
|
||||||
with_view_model(
|
|
||||||
instance->view,
|
|
||||||
AvrIspReaderViewModel * model,
|
|
||||||
{
|
|
||||||
if(model->status == AvrIspReaderViewStatusIDLE) {
|
|
||||||
model->status = AvrIspReaderViewStatusReading;
|
|
||||||
avr_isp_worker_rw_read_dump_start(
|
|
||||||
instance->avr_isp_worker_rw, instance->file_path, instance->file_name);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
false);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void avr_isp_reader_callback_status(void* context, AvrIspWorkerRWStatus status) {
|
|
||||||
furi_assert(context);
|
|
||||||
AvrIspReaderView* instance = context;
|
|
||||||
|
|
||||||
with_view_model(
|
|
||||||
instance->view,
|
|
||||||
AvrIspReaderViewModel * model,
|
|
||||||
{
|
|
||||||
switch(status) {
|
|
||||||
case AvrIspWorkerRWStatusEndReading:
|
|
||||||
model->status = AvrIspReaderViewStatusVerification;
|
|
||||||
avr_isp_worker_rw_verification_start(
|
|
||||||
instance->avr_isp_worker_rw, instance->file_path, instance->file_name);
|
|
||||||
model->status = AvrIspReaderViewStatusVerification;
|
|
||||||
break;
|
|
||||||
case AvrIspWorkerRWStatusEndVerification:
|
|
||||||
if(instance->callback)
|
|
||||||
instance->callback(AvrIspCustomEventSceneReadingOk, instance->context);
|
|
||||||
break;
|
|
||||||
case AvrIspWorkerRWStatusErrorVerification:
|
|
||||||
if(instance->callback)
|
|
||||||
instance->callback(AvrIspCustomEventSceneErrorVerification, instance->context);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
//AvrIspWorkerRWStatusErrorReading;
|
|
||||||
if(instance->callback)
|
|
||||||
instance->callback(AvrIspCustomEventSceneErrorReading, instance->context);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_reader_view_enter(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
AvrIspReaderView* instance = context;
|
|
||||||
|
|
||||||
with_view_model(
|
|
||||||
instance->view,
|
|
||||||
AvrIspReaderViewModel * model,
|
|
||||||
{
|
|
||||||
model->status = AvrIspReaderViewStatusIDLE;
|
|
||||||
model->progress_flash = 0.0f;
|
|
||||||
model->progress_eeprom = 0.0f;
|
|
||||||
},
|
|
||||||
true);
|
|
||||||
|
|
||||||
//Start avr_isp_worker_rw
|
|
||||||
instance->avr_isp_worker_rw = avr_isp_worker_rw_alloc(instance->context);
|
|
||||||
|
|
||||||
avr_isp_worker_rw_set_callback_status(
|
|
||||||
instance->avr_isp_worker_rw, avr_isp_reader_callback_status, instance);
|
|
||||||
|
|
||||||
avr_isp_worker_rw_start(instance->avr_isp_worker_rw);
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_reader_view_exit(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspReaderView* instance = context;
|
|
||||||
//Stop avr_isp_worker_rw
|
|
||||||
if(avr_isp_worker_rw_is_running(instance->avr_isp_worker_rw)) {
|
|
||||||
avr_isp_worker_rw_stop(instance->avr_isp_worker_rw);
|
|
||||||
}
|
|
||||||
|
|
||||||
avr_isp_worker_rw_free(instance->avr_isp_worker_rw);
|
|
||||||
}
|
|
||||||
|
|
||||||
AvrIspReaderView* avr_isp_reader_view_alloc() {
|
|
||||||
AvrIspReaderView* instance = malloc(sizeof(AvrIspReaderView));
|
|
||||||
|
|
||||||
// View allocation and configuration
|
|
||||||
instance->view = view_alloc();
|
|
||||||
|
|
||||||
view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(AvrIspReaderViewModel));
|
|
||||||
view_set_context(instance->view, instance);
|
|
||||||
view_set_draw_callback(instance->view, (ViewDrawCallback)avr_isp_reader_view_draw);
|
|
||||||
view_set_input_callback(instance->view, avr_isp_reader_view_input);
|
|
||||||
view_set_enter_callback(instance->view, avr_isp_reader_view_enter);
|
|
||||||
view_set_exit_callback(instance->view, avr_isp_reader_view_exit);
|
|
||||||
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_reader_view_free(AvrIspReaderView* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
view_free(instance->view);
|
|
||||||
free(instance);
|
|
||||||
}
|
|
||||||
|
|
||||||
View* avr_isp_reader_view_get_view(AvrIspReaderView* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
return instance->view;
|
|
||||||
}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <gui/view.h>
|
|
||||||
#include "../helpers/avr_isp_types.h"
|
|
||||||
#include "../helpers/avr_isp_event.h"
|
|
||||||
|
|
||||||
typedef struct AvrIspReaderView AvrIspReaderView;
|
|
||||||
|
|
||||||
typedef void (*AvrIspReaderViewCallback)(AvrIspCustomEvent event, void* context);
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
AvrIspReaderViewStatusIDLE,
|
|
||||||
AvrIspReaderViewStatusReading,
|
|
||||||
AvrIspReaderViewStatusVerification,
|
|
||||||
} AvrIspReaderViewStatus;
|
|
||||||
|
|
||||||
void avr_isp_reader_update_progress(AvrIspReaderView* instance);
|
|
||||||
|
|
||||||
void avr_isp_reader_set_file_path(
|
|
||||||
AvrIspReaderView* instance,
|
|
||||||
const char* file_path,
|
|
||||||
const char* file_name);
|
|
||||||
|
|
||||||
void avr_isp_reader_view_set_callback(
|
|
||||||
AvrIspReaderView* instance,
|
|
||||||
AvrIspReaderViewCallback callback,
|
|
||||||
void* context);
|
|
||||||
|
|
||||||
AvrIspReaderView* avr_isp_reader_view_alloc();
|
|
||||||
|
|
||||||
void avr_isp_reader_view_free(AvrIspReaderView* instance);
|
|
||||||
|
|
||||||
View* avr_isp_reader_view_get_view(AvrIspReaderView* instance);
|
|
||||||
|
|
||||||
void avr_isp_reader_view_exit(void* context);
|
|
||||||
@@ -1,268 +0,0 @@
|
|||||||
#include "avr_isp_view_writer.h"
|
|
||||||
#include <gui/elements.h>
|
|
||||||
|
|
||||||
#include "../helpers/avr_isp_worker_rw.h"
|
|
||||||
#include <float_tools.h>
|
|
||||||
|
|
||||||
struct AvrIspWriterView {
|
|
||||||
View* view;
|
|
||||||
AvrIspWorkerRW* avr_isp_worker_rw;
|
|
||||||
const char* file_path;
|
|
||||||
const char* file_name;
|
|
||||||
AvrIspWriterViewCallback callback;
|
|
||||||
void* context;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
AvrIspWriterViewStatus status;
|
|
||||||
float progress_flash;
|
|
||||||
float progress_eeprom;
|
|
||||||
} AvrIspWriterViewModel;
|
|
||||||
|
|
||||||
void avr_isp_writer_update_progress(AvrIspWriterView* instance) {
|
|
||||||
with_view_model(
|
|
||||||
instance->view,
|
|
||||||
AvrIspWriterViewModel * model,
|
|
||||||
{
|
|
||||||
model->progress_flash =
|
|
||||||
avr_isp_worker_rw_get_progress_flash(instance->avr_isp_worker_rw);
|
|
||||||
model->progress_eeprom =
|
|
||||||
avr_isp_worker_rw_get_progress_eeprom(instance->avr_isp_worker_rw);
|
|
||||||
},
|
|
||||||
true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_writer_view_set_callback(
|
|
||||||
AvrIspWriterView* instance,
|
|
||||||
AvrIspWriterViewCallback callback,
|
|
||||||
void* context) {
|
|
||||||
furi_assert(instance);
|
|
||||||
furi_assert(callback);
|
|
||||||
|
|
||||||
instance->callback = callback;
|
|
||||||
instance->context = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_writer_set_file_path(
|
|
||||||
AvrIspWriterView* instance,
|
|
||||||
const char* file_path,
|
|
||||||
const char* file_name) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
instance->file_path = file_path;
|
|
||||||
instance->file_name = file_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_writer_view_draw(Canvas* canvas, AvrIspWriterViewModel* model) {
|
|
||||||
canvas_clear(canvas);
|
|
||||||
char str_flash[32] = {0};
|
|
||||||
char str_eeprom[32] = {0};
|
|
||||||
|
|
||||||
canvas_set_font(canvas, FontPrimary);
|
|
||||||
|
|
||||||
switch(model->status) {
|
|
||||||
case AvrIspWriterViewStatusIDLE:
|
|
||||||
canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "Press start to write");
|
|
||||||
canvas_set_font(canvas, FontSecondary);
|
|
||||||
elements_button_center(canvas, "Start");
|
|
||||||
snprintf(str_flash, sizeof(str_flash), "%d%%", (uint8_t)(model->progress_flash * 100));
|
|
||||||
snprintf(str_eeprom, sizeof(str_eeprom), "%d%%", (uint8_t)(model->progress_eeprom * 100));
|
|
||||||
break;
|
|
||||||
case AvrIspWriterViewStatusWriting:
|
|
||||||
if(float_is_equal(model->progress_flash, 0.f)) {
|
|
||||||
canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "Verifying firmware");
|
|
||||||
snprintf(str_flash, sizeof(str_flash), "***");
|
|
||||||
snprintf(str_eeprom, sizeof(str_eeprom), "***");
|
|
||||||
} else {
|
|
||||||
canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "Writing dump");
|
|
||||||
snprintf(str_flash, sizeof(str_flash), "%d%%", (uint8_t)(model->progress_flash * 100));
|
|
||||||
snprintf(
|
|
||||||
str_eeprom, sizeof(str_eeprom), "%d%%", (uint8_t)(model->progress_eeprom * 100));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case AvrIspWriterViewStatusVerification:
|
|
||||||
canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "Verifying dump");
|
|
||||||
snprintf(str_flash, sizeof(str_flash), "%d%%", (uint8_t)(model->progress_flash * 100));
|
|
||||||
snprintf(str_eeprom, sizeof(str_eeprom), "%d%%", (uint8_t)(model->progress_eeprom * 100));
|
|
||||||
break;
|
|
||||||
case AvrIspWriterViewStatusWritingFuse:
|
|
||||||
canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "Writing fuse");
|
|
||||||
snprintf(str_flash, sizeof(str_flash), "%d%%", (uint8_t)(model->progress_flash * 100));
|
|
||||||
snprintf(str_eeprom, sizeof(str_eeprom), "%d%%", (uint8_t)(model->progress_eeprom * 100));
|
|
||||||
break;
|
|
||||||
case AvrIspWriterViewStatusWritingFuseOk:
|
|
||||||
canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "Done!");
|
|
||||||
snprintf(str_flash, sizeof(str_flash), "%d%%", (uint8_t)(model->progress_flash * 100));
|
|
||||||
snprintf(str_eeprom, sizeof(str_eeprom), "%d%%", (uint8_t)(model->progress_eeprom * 100));
|
|
||||||
canvas_set_font(canvas, FontSecondary);
|
|
||||||
elements_button_center(canvas, "Reflash");
|
|
||||||
elements_button_right(canvas, "Exit");
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
canvas_set_font(canvas, FontSecondary);
|
|
||||||
canvas_draw_str(canvas, 0, 27, "Flash");
|
|
||||||
// snprintf(str_buf, sizeof(str_buf), "%d%%", (uint8_t)(model->progress_flash * 100));
|
|
||||||
elements_progress_bar_with_text(canvas, 44, 17, 84, model->progress_flash, str_flash);
|
|
||||||
canvas_draw_str(canvas, 0, 43, "EEPROM");
|
|
||||||
// snprintf(str_buf, sizeof(str_buf), "%d%%", (uint8_t)(model->progress_eeprom * 100));
|
|
||||||
elements_progress_bar_with_text(canvas, 44, 34, 84, model->progress_eeprom, str_eeprom);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool avr_isp_writer_view_input(InputEvent* event, void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
AvrIspWriterView* instance = context;
|
|
||||||
|
|
||||||
bool ret = true;
|
|
||||||
if(event->key == InputKeyBack && event->type == InputTypeShort) {
|
|
||||||
with_view_model(
|
|
||||||
instance->view,
|
|
||||||
AvrIspWriterViewModel * model,
|
|
||||||
{
|
|
||||||
if((model->status == AvrIspWriterViewStatusIDLE) ||
|
|
||||||
(model->status == AvrIspWriterViewStatusWritingFuseOk)) {
|
|
||||||
if(instance->callback)
|
|
||||||
instance->callback(AvrIspCustomEventSceneExit, instance->context);
|
|
||||||
ret = false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
false);
|
|
||||||
} else if(event->key == InputKeyOk && event->type == InputTypeShort) {
|
|
||||||
with_view_model(
|
|
||||||
instance->view,
|
|
||||||
AvrIspWriterViewModel * model,
|
|
||||||
{
|
|
||||||
if((model->status == AvrIspWriterViewStatusIDLE) ||
|
|
||||||
(model->status == AvrIspWriterViewStatusWritingFuseOk)) {
|
|
||||||
model->status = AvrIspWriterViewStatusWriting;
|
|
||||||
|
|
||||||
avr_isp_worker_rw_write_dump_start(
|
|
||||||
instance->avr_isp_worker_rw, instance->file_path, instance->file_name);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
false);
|
|
||||||
} else if(event->key == InputKeyRight && event->type == InputTypeShort) {
|
|
||||||
with_view_model(
|
|
||||||
instance->view,
|
|
||||||
AvrIspWriterViewModel * model,
|
|
||||||
{
|
|
||||||
if((model->status == AvrIspWriterViewStatusIDLE) ||
|
|
||||||
(model->status == AvrIspWriterViewStatusWritingFuseOk)) {
|
|
||||||
if(instance->callback)
|
|
||||||
instance->callback(AvrIspCustomEventSceneExitStartMenu, instance->context);
|
|
||||||
ret = false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
false);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void avr_isp_writer_callback_status(void* context, AvrIspWorkerRWStatus status) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspWriterView* instance = context;
|
|
||||||
with_view_model(
|
|
||||||
instance->view,
|
|
||||||
AvrIspWriterViewModel * model,
|
|
||||||
{
|
|
||||||
switch(status) {
|
|
||||||
case AvrIspWorkerRWStatusEndWriting:
|
|
||||||
model->status = AvrIspWriterViewStatusVerification;
|
|
||||||
avr_isp_worker_rw_verification_start(
|
|
||||||
instance->avr_isp_worker_rw, instance->file_path, instance->file_name);
|
|
||||||
model->status = AvrIspWriterViewStatusVerification;
|
|
||||||
break;
|
|
||||||
case AvrIspWorkerRWStatusErrorVerification:
|
|
||||||
if(instance->callback)
|
|
||||||
instance->callback(AvrIspCustomEventSceneErrorVerification, instance->context);
|
|
||||||
break;
|
|
||||||
case AvrIspWorkerRWStatusEndVerification:
|
|
||||||
avr_isp_worker_rw_write_fuse_start(
|
|
||||||
instance->avr_isp_worker_rw, instance->file_path, instance->file_name);
|
|
||||||
model->status = AvrIspWriterViewStatusWritingFuse;
|
|
||||||
break;
|
|
||||||
case AvrIspWorkerRWStatusErrorWritingFuse:
|
|
||||||
if(instance->callback)
|
|
||||||
instance->callback(AvrIspCustomEventSceneErrorWritingFuse, instance->context);
|
|
||||||
break;
|
|
||||||
case AvrIspWorkerRWStatusEndWritingFuse:
|
|
||||||
model->status = AvrIspWriterViewStatusWritingFuseOk;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
//AvrIspWorkerRWStatusErrorWriting;
|
|
||||||
if(instance->callback)
|
|
||||||
instance->callback(AvrIspCustomEventSceneErrorWriting, instance->context);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_writer_view_enter(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspWriterView* instance = context;
|
|
||||||
with_view_model(
|
|
||||||
instance->view,
|
|
||||||
AvrIspWriterViewModel * model,
|
|
||||||
{
|
|
||||||
model->status = AvrIspWriterViewStatusIDLE;
|
|
||||||
model->progress_flash = 0.0f;
|
|
||||||
model->progress_eeprom = 0.0f;
|
|
||||||
},
|
|
||||||
true);
|
|
||||||
|
|
||||||
//Start avr_isp_worker_rw
|
|
||||||
instance->avr_isp_worker_rw = avr_isp_worker_rw_alloc(instance->context);
|
|
||||||
|
|
||||||
avr_isp_worker_rw_set_callback_status(
|
|
||||||
instance->avr_isp_worker_rw, avr_isp_writer_callback_status, instance);
|
|
||||||
|
|
||||||
avr_isp_worker_rw_start(instance->avr_isp_worker_rw);
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_writer_view_exit(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
AvrIspWriterView* instance = context;
|
|
||||||
|
|
||||||
//Stop avr_isp_worker_rw
|
|
||||||
if(avr_isp_worker_rw_is_running(instance->avr_isp_worker_rw)) {
|
|
||||||
avr_isp_worker_rw_stop(instance->avr_isp_worker_rw);
|
|
||||||
}
|
|
||||||
|
|
||||||
avr_isp_worker_rw_free(instance->avr_isp_worker_rw);
|
|
||||||
}
|
|
||||||
|
|
||||||
AvrIspWriterView* avr_isp_writer_view_alloc() {
|
|
||||||
AvrIspWriterView* instance = malloc(sizeof(AvrIspWriterView));
|
|
||||||
|
|
||||||
// View allocation and configuration
|
|
||||||
instance->view = view_alloc();
|
|
||||||
|
|
||||||
view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(AvrIspWriterViewModel));
|
|
||||||
view_set_context(instance->view, instance);
|
|
||||||
view_set_draw_callback(instance->view, (ViewDrawCallback)avr_isp_writer_view_draw);
|
|
||||||
view_set_input_callback(instance->view, avr_isp_writer_view_input);
|
|
||||||
view_set_enter_callback(instance->view, avr_isp_writer_view_enter);
|
|
||||||
view_set_exit_callback(instance->view, avr_isp_writer_view_exit);
|
|
||||||
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_writer_view_free(AvrIspWriterView* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
view_free(instance->view);
|
|
||||||
free(instance);
|
|
||||||
}
|
|
||||||
|
|
||||||
View* avr_isp_writer_view_get_view(AvrIspWriterView* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
return instance->view;
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <gui/view.h>
|
|
||||||
#include "../helpers/avr_isp_types.h"
|
|
||||||
#include "../helpers/avr_isp_event.h"
|
|
||||||
|
|
||||||
typedef struct AvrIspWriterView AvrIspWriterView;
|
|
||||||
|
|
||||||
typedef void (*AvrIspWriterViewCallback)(AvrIspCustomEvent event, void* context);
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
AvrIspWriterViewStatusIDLE,
|
|
||||||
AvrIspWriterViewStatusWriting,
|
|
||||||
AvrIspWriterViewStatusVerification,
|
|
||||||
AvrIspWriterViewStatusWritingFuse,
|
|
||||||
AvrIspWriterViewStatusWritingFuseOk,
|
|
||||||
} AvrIspWriterViewStatus;
|
|
||||||
|
|
||||||
void avr_isp_writer_update_progress(AvrIspWriterView* instance);
|
|
||||||
|
|
||||||
void avr_isp_writer_set_file_path(
|
|
||||||
AvrIspWriterView* instance,
|
|
||||||
const char* file_path,
|
|
||||||
const char* file_name);
|
|
||||||
|
|
||||||
void avr_isp_writer_view_set_callback(
|
|
||||||
AvrIspWriterView* instance,
|
|
||||||
AvrIspWriterViewCallback callback,
|
|
||||||
void* context);
|
|
||||||
|
|
||||||
AvrIspWriterView* avr_isp_writer_view_alloc();
|
|
||||||
|
|
||||||
void avr_isp_writer_view_free(AvrIspWriterView* instance);
|
|
||||||
|
|
||||||
View* avr_isp_writer_view_get_view(AvrIspWriterView* instance);
|
|
||||||
|
|
||||||
void avr_isp_writer_view_exit(void* context);
|
|
||||||
16
applications/external/bad_bt/application.fam
vendored
@@ -1,16 +0,0 @@
|
|||||||
App(
|
|
||||||
appid="bad_bt",
|
|
||||||
name="Bad BT",
|
|
||||||
apptype=FlipperAppType.EXTERNAL,
|
|
||||||
entry_point="bad_bt_app",
|
|
||||||
requires=[
|
|
||||||
"gui",
|
|
||||||
"dialogs",
|
|
||||||
],
|
|
||||||
stack_size=2 * 1024,
|
|
||||||
order=70,
|
|
||||||
fap_libs=["assets"],
|
|
||||||
fap_category="Bluetooth",
|
|
||||||
fap_icon="images/badbt_10px.png",
|
|
||||||
fap_icon_assets="images",
|
|
||||||
)
|
|
||||||
333
applications/external/bad_bt/bad_bt_app.c
vendored
@@ -1,333 +0,0 @@
|
|||||||
#include "bad_bt_app.h"
|
|
||||||
#include <furi.h>
|
|
||||||
#include <furi_hal.h>
|
|
||||||
#include <storage/storage.h>
|
|
||||||
#include <lib/toolbox/path.h>
|
|
||||||
#include <lib/flipper_format/flipper_format.h>
|
|
||||||
|
|
||||||
#include <bt/bt_service/bt_i.h>
|
|
||||||
#include <bt/bt_service/bt.h>
|
|
||||||
|
|
||||||
#define BAD_BT_SETTINGS_FILE_NAME ".badbt.settings"
|
|
||||||
#define BAD_BT_APP_PATH_BOUND_KEYS_FOLDER EXT_PATH("badbt")
|
|
||||||
#define BAD_BT_APP_PATH_BOUND_KEYS_FILE BAD_BT_APP_PATH_BOUND_KEYS_FOLDER "/.badbt.keys"
|
|
||||||
|
|
||||||
#define BAD_BT_SETTINGS_PATH BAD_BT_APP_BASE_CONFIG_FOLDER "/" BAD_BT_SETTINGS_FILE_NAME
|
|
||||||
|
|
||||||
static bool bad_bt_app_custom_event_callback(void* context, uint32_t event) {
|
|
||||||
furi_assert(context);
|
|
||||||
BadBtApp* app = context;
|
|
||||||
return scene_manager_handle_custom_event(app->scene_manager, event);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool bad_bt_app_back_event_callback(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
BadBtApp* app = context;
|
|
||||||
return scene_manager_handle_back_event(app->scene_manager);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void bad_bt_app_tick_event_callback(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
BadBtApp* app = context;
|
|
||||||
scene_manager_handle_tick_event(app->scene_manager);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void bad_bt_load_settings(BadBtApp* app) {
|
|
||||||
furi_string_reset(app->keyboard_layout);
|
|
||||||
strcpy(app->config.bt_name, "");
|
|
||||||
memcpy(
|
|
||||||
app->config.bt_mac,
|
|
||||||
furi_hal_bt_get_profile_mac_addr(FuriHalBtProfileHidKeyboard),
|
|
||||||
BAD_BT_MAC_ADDRESS_LEN);
|
|
||||||
|
|
||||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
|
||||||
FlipperFormat* file = flipper_format_file_alloc(storage);
|
|
||||||
if(flipper_format_file_open_existing(file, BAD_BT_SETTINGS_PATH)) {
|
|
||||||
FuriString* tmp_str = furi_string_alloc();
|
|
||||||
if(!flipper_format_read_string(file, "Keyboard_Layout", app->keyboard_layout)) {
|
|
||||||
furi_string_reset(app->keyboard_layout);
|
|
||||||
}
|
|
||||||
if(!flipper_format_read_bool(file, "BT_Remember", &(app->bt_remember), 1)) {
|
|
||||||
app->bt_remember = false;
|
|
||||||
}
|
|
||||||
if(flipper_format_read_string(file, "Bt_Name", tmp_str) && !furi_string_empty(tmp_str)) {
|
|
||||||
strcpy(app->config.bt_name, furi_string_get_cstr(tmp_str));
|
|
||||||
} else {
|
|
||||||
strcpy(app->config.bt_name, "");
|
|
||||||
}
|
|
||||||
if(!flipper_format_read_hex(
|
|
||||||
file, "Bt_Mac", (uint8_t*)&app->config.bt_mac, BAD_BT_MAC_ADDRESS_LEN)) {
|
|
||||||
memcpy(
|
|
||||||
app->config.bt_mac,
|
|
||||||
furi_hal_bt_get_profile_mac_addr(FuriHalBtProfileHidKeyboard),
|
|
||||||
BAD_BT_MAC_ADDRESS_LEN);
|
|
||||||
}
|
|
||||||
furi_string_free(tmp_str);
|
|
||||||
flipper_format_file_close(file);
|
|
||||||
}
|
|
||||||
flipper_format_free(file);
|
|
||||||
|
|
||||||
if(!furi_string_empty(app->keyboard_layout)) {
|
|
||||||
FileInfo layout_file_info;
|
|
||||||
FS_Error file_check_err = storage_common_stat(
|
|
||||||
storage, furi_string_get_cstr(app->keyboard_layout), &layout_file_info);
|
|
||||||
if(file_check_err != FSE_OK) {
|
|
||||||
furi_string_reset(app->keyboard_layout);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(layout_file_info.size != 256) {
|
|
||||||
furi_string_reset(app->keyboard_layout);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
furi_record_close(RECORD_STORAGE);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void bad_bt_save_settings(BadBtApp* app) {
|
|
||||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
|
||||||
FlipperFormat* file = flipper_format_file_alloc(storage);
|
|
||||||
if(flipper_format_file_open_always(file, BAD_BT_SETTINGS_PATH)) {
|
|
||||||
flipper_format_write_string(file, "Keyboard_Layout", app->keyboard_layout);
|
|
||||||
flipper_format_write_bool(file, "BT_Remember", &(app->bt_remember), 1);
|
|
||||||
flipper_format_write_string_cstr(file, "Bt_Name", app->config.bt_name);
|
|
||||||
flipper_format_write_hex(
|
|
||||||
file, "Bt_Mac", (uint8_t*)&app->config.bt_mac, BAD_BT_MAC_ADDRESS_LEN);
|
|
||||||
flipper_format_file_close(file);
|
|
||||||
}
|
|
||||||
flipper_format_free(file);
|
|
||||||
furi_record_close(RECORD_STORAGE);
|
|
||||||
}
|
|
||||||
|
|
||||||
void bad_bt_reload_worker(BadBtApp* app) {
|
|
||||||
bad_bt_script_close(app->bad_bt_script);
|
|
||||||
app->bad_bt_script = bad_bt_script_open(app->file_path, app->bt, app);
|
|
||||||
bad_bt_script_set_keyboard_layout(app->bad_bt_script, app->keyboard_layout);
|
|
||||||
}
|
|
||||||
|
|
||||||
void bad_kb_config_refresh_menu(BadBtApp* app) {
|
|
||||||
scene_manager_next_scene(app->scene_manager, BadBtSceneConfig);
|
|
||||||
scene_manager_previous_scene(app->scene_manager);
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t bad_bt_config_switch_mode(BadBtApp* app) {
|
|
||||||
bad_bt_reload_worker(app);
|
|
||||||
furi_hal_bt_start_advertising();
|
|
||||||
bad_kb_config_refresh_menu(app);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void bad_bt_config_switch_remember_mode(BadBtApp* app) {
|
|
||||||
if(app->bt_remember) {
|
|
||||||
furi_hal_bt_set_profile_pairing_method(
|
|
||||||
FuriHalBtProfileHidKeyboard, GapPairingPinCodeVerifyYesNo);
|
|
||||||
bt_set_profile_mac_address(app->bt, (uint8_t*)&BAD_BT_BOUND_MAC_ADDRESS);
|
|
||||||
bt_enable_peer_key_update(app->bt);
|
|
||||||
} else {
|
|
||||||
furi_hal_bt_set_profile_pairing_method(FuriHalBtProfileHidKeyboard, GapPairingNone);
|
|
||||||
bt_set_profile_mac_address(app->bt, app->config.bt_mac);
|
|
||||||
bt_disable_peer_key_update(app->bt);
|
|
||||||
}
|
|
||||||
bad_bt_reload_worker(app);
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t bad_bt_connection_init(BadBtApp* app) {
|
|
||||||
// Set original name and mac address in prev config
|
|
||||||
strcpy(
|
|
||||||
app->prev_config.bt_name, furi_hal_bt_get_profile_adv_name(FuriHalBtProfileHidKeyboard));
|
|
||||||
|
|
||||||
memcpy(app->prev_config.bt_mac, furi_hal_version_get_ble_mac(), BAD_BT_MAC_ADDRESS_LEN);
|
|
||||||
|
|
||||||
bt_timeout = bt_hid_delays[LevelRssi39_0];
|
|
||||||
bt_disconnect(app->bt);
|
|
||||||
// Wait 2nd core to update nvm storage
|
|
||||||
furi_delay_ms(200);
|
|
||||||
bt_keys_storage_set_storage_path(app->bt, BAD_BT_APP_PATH_BOUND_KEYS_FILE);
|
|
||||||
if(strcmp(app->config.bt_name, "") != 0) {
|
|
||||||
furi_hal_bt_set_profile_adv_name(FuriHalBtProfileHidKeyboard, app->config.bt_name);
|
|
||||||
}
|
|
||||||
if(app->bt_remember) {
|
|
||||||
furi_hal_bt_set_profile_mac_addr(
|
|
||||||
FuriHalBtProfileHidKeyboard, (uint8_t*)&BAD_BT_BOUND_MAC_ADDRESS);
|
|
||||||
furi_hal_bt_set_profile_pairing_method(
|
|
||||||
FuriHalBtProfileHidKeyboard, GapPairingPinCodeVerifyYesNo);
|
|
||||||
} else {
|
|
||||||
if(memcmp(
|
|
||||||
app->config.bt_mac, (uint8_t*)&BAD_BT_EMPTY_MAC_ADDRESS, BAD_BT_MAC_ADDRESS_LEN) !=
|
|
||||||
0) {
|
|
||||||
furi_hal_bt_set_profile_mac_addr(FuriHalBtProfileHidKeyboard, app->config.bt_mac);
|
|
||||||
}
|
|
||||||
furi_hal_bt_set_profile_pairing_method(FuriHalBtProfileHidKeyboard, GapPairingNone);
|
|
||||||
}
|
|
||||||
bt_set_profile(app->bt, BtProfileHidKeyboard);
|
|
||||||
if(strcmp(app->config.bt_name, "") == 0) {
|
|
||||||
strcpy(app->config.bt_name, furi_hal_bt_get_profile_adv_name(FuriHalBtProfileHidKeyboard));
|
|
||||||
}
|
|
||||||
if(memcmp(app->config.bt_mac, (uint8_t*)&BAD_BT_EMPTY_MAC_ADDRESS, BAD_BT_MAC_ADDRESS_LEN) ==
|
|
||||||
0) {
|
|
||||||
memcpy(
|
|
||||||
app->config.bt_mac,
|
|
||||||
furi_hal_bt_get_profile_mac_addr(FuriHalBtProfileHidKeyboard),
|
|
||||||
BAD_BT_MAC_ADDRESS_LEN);
|
|
||||||
}
|
|
||||||
|
|
||||||
furi_hal_bt_start_advertising();
|
|
||||||
if(app->bt_remember) {
|
|
||||||
bt_enable_peer_key_update(app->bt);
|
|
||||||
} else {
|
|
||||||
bt_disable_peer_key_update(app->bt);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void bad_bt_connection_deinit(BadBtApp* app) {
|
|
||||||
bt_disconnect(app->bt);
|
|
||||||
// Wait 2nd core to update nvm storage
|
|
||||||
furi_delay_ms(200);
|
|
||||||
bt_keys_storage_set_default_path(app->bt);
|
|
||||||
furi_hal_bt_set_profile_adv_name(FuriHalBtProfileHidKeyboard, app->prev_config.bt_name);
|
|
||||||
furi_hal_bt_set_profile_mac_addr(FuriHalBtProfileHidKeyboard, app->prev_config.bt_mac);
|
|
||||||
furi_hal_bt_set_profile_pairing_method(
|
|
||||||
FuriHalBtProfileHidKeyboard, GapPairingPinCodeVerifyYesNo);
|
|
||||||
bt_set_profile(app->bt, BtProfileSerial);
|
|
||||||
bt_enable_peer_key_update(app->bt);
|
|
||||||
}
|
|
||||||
|
|
||||||
BadBtApp* bad_bt_app_alloc(char* arg) {
|
|
||||||
BadBtApp* app = malloc(sizeof(BadBtApp));
|
|
||||||
|
|
||||||
app->bad_bt_script = NULL;
|
|
||||||
|
|
||||||
app->file_path = furi_string_alloc();
|
|
||||||
app->keyboard_layout = furi_string_alloc();
|
|
||||||
if(arg && strlen(arg)) {
|
|
||||||
furi_string_set(app->file_path, arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
|
||||||
storage_simply_mkdir(storage, BAD_BT_APP_BASE_CONFIG_FOLDER);
|
|
||||||
furi_record_close(RECORD_STORAGE);
|
|
||||||
|
|
||||||
bad_bt_load_settings(app);
|
|
||||||
|
|
||||||
app->gui = furi_record_open(RECORD_GUI);
|
|
||||||
app->notifications = furi_record_open(RECORD_NOTIFICATION);
|
|
||||||
app->dialogs = furi_record_open(RECORD_DIALOGS);
|
|
||||||
|
|
||||||
app->view_dispatcher = view_dispatcher_alloc();
|
|
||||||
view_dispatcher_enable_queue(app->view_dispatcher);
|
|
||||||
|
|
||||||
app->scene_manager = scene_manager_alloc(&bad_bt_scene_handlers, app);
|
|
||||||
|
|
||||||
view_dispatcher_set_event_callback_context(app->view_dispatcher, app);
|
|
||||||
view_dispatcher_set_tick_event_callback(
|
|
||||||
app->view_dispatcher, bad_bt_app_tick_event_callback, 500);
|
|
||||||
view_dispatcher_set_custom_event_callback(
|
|
||||||
app->view_dispatcher, bad_bt_app_custom_event_callback);
|
|
||||||
view_dispatcher_set_navigation_event_callback(
|
|
||||||
app->view_dispatcher, bad_bt_app_back_event_callback);
|
|
||||||
|
|
||||||
Bt* bt = furi_record_open(RECORD_BT);
|
|
||||||
app->bt = bt;
|
|
||||||
app->bt->suppress_pin_screen = true;
|
|
||||||
|
|
||||||
// Custom Widget
|
|
||||||
app->widget = widget_alloc();
|
|
||||||
view_dispatcher_add_view(
|
|
||||||
app->view_dispatcher, BadBtAppViewError, widget_get_view(app->widget));
|
|
||||||
|
|
||||||
app->var_item_list = variable_item_list_alloc();
|
|
||||||
view_dispatcher_add_view(
|
|
||||||
app->view_dispatcher, BadBtAppViewConfig, variable_item_list_get_view(app->var_item_list));
|
|
||||||
|
|
||||||
app->bad_bt_view = bad_bt_alloc();
|
|
||||||
view_dispatcher_add_view(
|
|
||||||
app->view_dispatcher, BadBtAppViewWork, bad_bt_get_view(app->bad_bt_view));
|
|
||||||
|
|
||||||
app->text_input = text_input_alloc();
|
|
||||||
view_dispatcher_add_view(
|
|
||||||
app->view_dispatcher, BadBtAppViewConfigName, text_input_get_view(app->text_input));
|
|
||||||
|
|
||||||
app->byte_input = byte_input_alloc();
|
|
||||||
view_dispatcher_add_view(
|
|
||||||
app->view_dispatcher, BadBtAppViewConfigMac, byte_input_get_view(app->byte_input));
|
|
||||||
|
|
||||||
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
|
|
||||||
|
|
||||||
app->conn_init_thread = furi_thread_alloc_ex(
|
|
||||||
"BadBtConnInit", 1024, (FuriThreadCallback)bad_bt_connection_init, app);
|
|
||||||
furi_thread_start(app->conn_init_thread);
|
|
||||||
if(!furi_string_empty(app->file_path)) {
|
|
||||||
app->bad_bt_script = bad_bt_script_open(app->file_path, app->bt, app);
|
|
||||||
bad_bt_script_set_keyboard_layout(app->bad_bt_script, app->keyboard_layout);
|
|
||||||
scene_manager_next_scene(app->scene_manager, BadBtSceneWork);
|
|
||||||
} else {
|
|
||||||
furi_string_set(app->file_path, BAD_BT_APP_BASE_FOLDER);
|
|
||||||
scene_manager_next_scene(app->scene_manager, BadBtSceneFileSelect);
|
|
||||||
}
|
|
||||||
|
|
||||||
return app;
|
|
||||||
}
|
|
||||||
|
|
||||||
void bad_bt_app_free(BadBtApp* app) {
|
|
||||||
furi_assert(app);
|
|
||||||
|
|
||||||
if(app->bad_bt_script) {
|
|
||||||
bad_bt_script_close(app->bad_bt_script);
|
|
||||||
app->bad_bt_script = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Views
|
|
||||||
view_dispatcher_remove_view(app->view_dispatcher, BadBtAppViewWork);
|
|
||||||
bad_bt_free(app->bad_bt_view);
|
|
||||||
|
|
||||||
// Custom Widget
|
|
||||||
view_dispatcher_remove_view(app->view_dispatcher, BadBtAppViewError);
|
|
||||||
widget_free(app->widget);
|
|
||||||
|
|
||||||
// Variable item list
|
|
||||||
view_dispatcher_remove_view(app->view_dispatcher, BadBtAppViewConfig);
|
|
||||||
variable_item_list_free(app->var_item_list);
|
|
||||||
|
|
||||||
// Text Input
|
|
||||||
view_dispatcher_remove_view(app->view_dispatcher, BadBtAppViewConfigName);
|
|
||||||
text_input_free(app->text_input);
|
|
||||||
|
|
||||||
// Byte Input
|
|
||||||
view_dispatcher_remove_view(app->view_dispatcher, BadBtAppViewConfigMac);
|
|
||||||
byte_input_free(app->byte_input);
|
|
||||||
|
|
||||||
// View dispatcher
|
|
||||||
view_dispatcher_free(app->view_dispatcher);
|
|
||||||
scene_manager_free(app->scene_manager);
|
|
||||||
|
|
||||||
// Restore bt config
|
|
||||||
app->bt->suppress_pin_screen = false;
|
|
||||||
if(app->conn_init_thread) {
|
|
||||||
furi_thread_join(app->conn_init_thread);
|
|
||||||
furi_thread_free(app->conn_init_thread);
|
|
||||||
bad_bt_connection_deinit(app);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close records
|
|
||||||
furi_record_close(RECORD_GUI);
|
|
||||||
furi_record_close(RECORD_NOTIFICATION);
|
|
||||||
furi_record_close(RECORD_DIALOGS);
|
|
||||||
furi_record_close(RECORD_BT);
|
|
||||||
|
|
||||||
bad_bt_save_settings(app);
|
|
||||||
|
|
||||||
furi_string_free(app->file_path);
|
|
||||||
furi_string_free(app->keyboard_layout);
|
|
||||||
|
|
||||||
free(app);
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t bad_bt_app(void* p) {
|
|
||||||
BadBtApp* bad_bt_app = bad_bt_app_alloc((char*)p);
|
|
||||||
|
|
||||||
view_dispatcher_run(bad_bt_app->view_dispatcher);
|
|
||||||
|
|
||||||
bad_bt_app_free(bad_bt_app);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
39
applications/external/bad_bt/bad_bt_app.h
vendored
@@ -1,39 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "scenes/bad_bt_scene.h"
|
|
||||||
#include "helpers/ducky_script.h"
|
|
||||||
|
|
||||||
#include <gui/gui.h>
|
|
||||||
#include <assets_icons.h>
|
|
||||||
#include <gui/scene_manager.h>
|
|
||||||
#include <dialogs/dialogs.h>
|
|
||||||
#include <notification/notification_messages.h>
|
|
||||||
#include "bad_bt_icons.h"
|
|
||||||
|
|
||||||
#define BAD_BT_APP_BASE_FOLDER EXT_PATH("badusb")
|
|
||||||
#define BAD_BT_APP_BASE_CONFIG_FOLDER EXT_PATH("badbt")
|
|
||||||
#define BAD_BT_APP_PATH_LAYOUT_FOLDER BAD_BT_APP_BASE_FOLDER "/assets/layouts"
|
|
||||||
#define BAD_BT_APP_SCRIPT_EXTENSION ".txt"
|
|
||||||
#define BAD_BT_APP_LAYOUT_EXTENSION ".kl"
|
|
||||||
|
|
||||||
typedef enum BadBtCustomEvent {
|
|
||||||
BadBtAppCustomEventTextEditResult,
|
|
||||||
BadBtAppCustomEventByteInputDone,
|
|
||||||
BadBtCustomEventErrorBack
|
|
||||||
} BadBtCustomEvent;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
BadBtAppViewError,
|
|
||||||
BadBtAppViewWork,
|
|
||||||
BadBtAppViewConfig,
|
|
||||||
BadBtAppViewConfigMac,
|
|
||||||
BadBtAppViewConfigName
|
|
||||||
} BadBtAppView;
|
|
||||||
|
|
||||||
void bad_bt_config_switch_remember_mode(BadBtApp* app);
|
|
||||||
|
|
||||||
int32_t bad_bt_connection_init(BadBtApp* app);
|
|
||||||
|
|
||||||
void bad_bt_connection_deinit(BadBtApp* app);
|
|
||||||
|
|
||||||
void bad_kb_config_refresh_menu(BadBtApp* app);
|
|
||||||
792
applications/external/bad_bt/helpers/ducky_script.c
vendored
@@ -1,792 +0,0 @@
|
|||||||
#include <furi.h>
|
|
||||||
#include <furi_hal.h>
|
|
||||||
#include <gui/gui.h>
|
|
||||||
#include <input/input.h>
|
|
||||||
#include <lib/toolbox/args.h>
|
|
||||||
#include <furi_hal_bt_hid.h>
|
|
||||||
#include <bt/bt_service/bt.h>
|
|
||||||
#include <storage/storage.h>
|
|
||||||
#include "ducky_script.h"
|
|
||||||
#include "ducky_script_i.h"
|
|
||||||
#include <dolphin/dolphin.h>
|
|
||||||
#include <toolbox/hex.h>
|
|
||||||
#include "../bad_bt_app.h"
|
|
||||||
|
|
||||||
const uint8_t BAD_BT_BOUND_MAC_ADDRESS[BAD_BT_MAC_ADDRESS_LEN] =
|
|
||||||
{0x41, 0x4a, 0xef, 0xb6, 0xa9, 0xd4};
|
|
||||||
const uint8_t BAD_BT_EMPTY_MAC_ADDRESS[BAD_BT_MAC_ADDRESS_LEN] =
|
|
||||||
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
|
||||||
|
|
||||||
#define TAG "BadBT"
|
|
||||||
#define WORKER_TAG TAG "Worker"
|
|
||||||
|
|
||||||
#define BADBT_ASCII_TO_KEY(script, x) \
|
|
||||||
(((uint8_t)x < 128) ? (script->layout[(uint8_t)x]) : HID_KEYBOARD_NONE)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Delays for waiting between HID key press and key release
|
|
||||||
*/
|
|
||||||
const uint8_t bt_hid_delays[LevelRssiNum] = {
|
|
||||||
60, // LevelRssi122_100
|
|
||||||
55, // LevelRssi99_80
|
|
||||||
50, // LevelRssi79_60
|
|
||||||
47, // LevelRssi59_40
|
|
||||||
34, // LevelRssi39_0
|
|
||||||
};
|
|
||||||
|
|
||||||
uint8_t bt_timeout = 0;
|
|
||||||
|
|
||||||
static LevelRssiRange bt_remote_rssi_range(Bt* bt) {
|
|
||||||
uint8_t rssi;
|
|
||||||
|
|
||||||
if(!bt_remote_rssi(bt, &rssi)) return LevelRssiError;
|
|
||||||
|
|
||||||
if(rssi <= 39)
|
|
||||||
return LevelRssi39_0;
|
|
||||||
else if(rssi <= 59)
|
|
||||||
return LevelRssi59_40;
|
|
||||||
else if(rssi <= 79)
|
|
||||||
return LevelRssi79_60;
|
|
||||||
else if(rssi <= 99)
|
|
||||||
return LevelRssi99_80;
|
|
||||||
else if(rssi <= 122)
|
|
||||||
return LevelRssi122_100;
|
|
||||||
|
|
||||||
return LevelRssiError;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void update_bt_timeout(Bt* bt) {
|
|
||||||
LevelRssiRange r = bt_remote_rssi_range(bt);
|
|
||||||
if(r < LevelRssiNum) {
|
|
||||||
bt_timeout = bt_hid_delays[r];
|
|
||||||
FURI_LOG_D(WORKER_TAG, "BLE Key timeout : %u", bt_timeout);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
WorkerEvtStartStop = (1 << 0),
|
|
||||||
WorkerEvtPauseResume = (1 << 1),
|
|
||||||
WorkerEvtEnd = (1 << 2),
|
|
||||||
WorkerEvtConnect = (1 << 3),
|
|
||||||
WorkerEvtDisconnect = (1 << 4),
|
|
||||||
} WorkerEvtFlags;
|
|
||||||
|
|
||||||
static const char ducky_cmd_id[] = {"ID"};
|
|
||||||
static const char ducky_cmd_bt_id[] = {"BT_ID"};
|
|
||||||
|
|
||||||
static const uint8_t numpad_keys[10] = {
|
|
||||||
HID_KEYPAD_0,
|
|
||||||
HID_KEYPAD_1,
|
|
||||||
HID_KEYPAD_2,
|
|
||||||
HID_KEYPAD_3,
|
|
||||||
HID_KEYPAD_4,
|
|
||||||
HID_KEYPAD_5,
|
|
||||||
HID_KEYPAD_6,
|
|
||||||
HID_KEYPAD_7,
|
|
||||||
HID_KEYPAD_8,
|
|
||||||
HID_KEYPAD_9,
|
|
||||||
};
|
|
||||||
|
|
||||||
uint32_t ducky_get_command_len(const char* line) {
|
|
||||||
uint32_t len = strlen(line);
|
|
||||||
for(uint32_t i = 0; i < len; i++) {
|
|
||||||
if(line[i] == ' ') return i;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ducky_is_line_end(const char chr) {
|
|
||||||
return ((chr == ' ') || (chr == '\0') || (chr == '\r') || (chr == '\n'));
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t ducky_get_keycode(BadBtScript* bad_bt, const char* param, bool accept_chars) {
|
|
||||||
uint16_t keycode = ducky_get_keycode_by_name(param);
|
|
||||||
if(keycode != HID_KEYBOARD_NONE) {
|
|
||||||
return keycode;
|
|
||||||
}
|
|
||||||
|
|
||||||
if((accept_chars) && (strlen(param) > 0)) {
|
|
||||||
return (BADBT_ASCII_TO_KEY(bad_bt, param[0]) & 0xFF);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ducky_get_number(const char* param, uint32_t* val) {
|
|
||||||
uint32_t value = 0;
|
|
||||||
if(sscanf(param, "%lu", &value) == 1) {
|
|
||||||
*val = value;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ducky_numlock_on(BadBtScript* bad_bt) {
|
|
||||||
UNUSED(bad_bt);
|
|
||||||
if((furi_hal_bt_hid_get_led_state() & HID_KB_LED_NUM) == 0) {
|
|
||||||
furi_hal_bt_hid_kb_press(HID_KEYBOARD_LOCK_NUM_LOCK);
|
|
||||||
furi_delay_ms(bt_timeout);
|
|
||||||
furi_hal_bt_hid_kb_release(HID_KEYBOARD_LOCK_NUM_LOCK);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ducky_numpad_press(BadBtScript* bad_bt, const char num) {
|
|
||||||
UNUSED(bad_bt);
|
|
||||||
if((num < '0') || (num > '9')) return false;
|
|
||||||
|
|
||||||
uint16_t key = numpad_keys[num - '0'];
|
|
||||||
furi_hal_bt_hid_kb_press(key);
|
|
||||||
furi_delay_ms(bt_timeout);
|
|
||||||
furi_hal_bt_hid_kb_release(key);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ducky_altchar(BadBtScript* bad_bt, const char* charcode) {
|
|
||||||
uint8_t i = 0;
|
|
||||||
bool state = false;
|
|
||||||
|
|
||||||
furi_hal_bt_hid_kb_press(KEY_MOD_LEFT_ALT);
|
|
||||||
|
|
||||||
while(!ducky_is_line_end(charcode[i])) {
|
|
||||||
state = ducky_numpad_press(bad_bt, charcode[i]);
|
|
||||||
if(state == false) break;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
furi_hal_bt_hid_kb_release(KEY_MOD_LEFT_ALT);
|
|
||||||
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ducky_altstring(BadBtScript* bad_bt, const char* param) {
|
|
||||||
uint32_t i = 0;
|
|
||||||
bool state = false;
|
|
||||||
|
|
||||||
while(param[i] != '\0') {
|
|
||||||
if((param[i] < ' ') || (param[i] > '~')) {
|
|
||||||
i++;
|
|
||||||
continue; // Skip non-printable chars
|
|
||||||
}
|
|
||||||
|
|
||||||
char temp_str[4];
|
|
||||||
snprintf(temp_str, 4, "%u", param[i]);
|
|
||||||
|
|
||||||
state = ducky_altchar(bad_bt, temp_str);
|
|
||||||
if(state == false) break;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t ducky_error(BadBtScript* bad_bt, const char* text, ...) {
|
|
||||||
va_list args;
|
|
||||||
va_start(args, text);
|
|
||||||
|
|
||||||
vsnprintf(bad_bt->st.error, sizeof(bad_bt->st.error), text, args);
|
|
||||||
|
|
||||||
va_end(args);
|
|
||||||
return SCRIPT_STATE_ERROR;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ducky_string(BadBtScript* bad_bt, const char* param) {
|
|
||||||
uint32_t i = 0;
|
|
||||||
|
|
||||||
while(param[i] != '\0') {
|
|
||||||
if(param[i] != '\n') {
|
|
||||||
uint16_t keycode = BADBT_ASCII_TO_KEY(bad_bt, param[i]);
|
|
||||||
if(keycode != HID_KEYBOARD_NONE) {
|
|
||||||
furi_hal_bt_hid_kb_press(keycode);
|
|
||||||
furi_delay_ms(bt_timeout);
|
|
||||||
furi_hal_bt_hid_kb_release(keycode);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
furi_hal_bt_hid_kb_press(HID_KEYBOARD_RETURN);
|
|
||||||
furi_delay_ms(bt_timeout);
|
|
||||||
furi_hal_bt_hid_kb_release(HID_KEYBOARD_RETURN);
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
bad_bt->stringdelay = 0;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool ducky_string_next(BadBtScript* bad_bt) {
|
|
||||||
if(bad_bt->string_print_pos >= furi_string_size(bad_bt->string_print)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
char print_char = furi_string_get_char(bad_bt->string_print, bad_bt->string_print_pos);
|
|
||||||
|
|
||||||
if(print_char != '\n') {
|
|
||||||
uint16_t keycode = BADBT_ASCII_TO_KEY(bad_bt, print_char);
|
|
||||||
if(keycode != HID_KEYBOARD_NONE) {
|
|
||||||
furi_hal_bt_hid_kb_press(keycode);
|
|
||||||
furi_delay_ms(bt_timeout);
|
|
||||||
furi_hal_bt_hid_kb_release(keycode);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
furi_hal_bt_hid_kb_press(HID_KEYBOARD_RETURN);
|
|
||||||
furi_delay_ms(bt_timeout);
|
|
||||||
furi_hal_bt_hid_kb_release(HID_KEYBOARD_RETURN);
|
|
||||||
}
|
|
||||||
|
|
||||||
bad_bt->string_print_pos++;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int32_t ducky_parse_line(BadBtScript* bad_bt, FuriString* line) {
|
|
||||||
uint32_t line_len = furi_string_size(line);
|
|
||||||
const char* line_tmp = furi_string_get_cstr(line);
|
|
||||||
|
|
||||||
if(line_len == 0) {
|
|
||||||
return SCRIPT_STATE_NEXT_LINE; // Skip empty lines
|
|
||||||
}
|
|
||||||
FURI_LOG_D(WORKER_TAG, "line:%s", line_tmp);
|
|
||||||
|
|
||||||
// Ducky Lang Functions
|
|
||||||
int32_t cmd_result = ducky_execute_cmd(bad_bt, line_tmp);
|
|
||||||
if(cmd_result != SCRIPT_STATE_CMD_UNKNOWN) {
|
|
||||||
return cmd_result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Special keys + modifiers
|
|
||||||
uint16_t key = ducky_get_keycode(bad_bt, line_tmp, false);
|
|
||||||
if(key == HID_KEYBOARD_NONE) {
|
|
||||||
return ducky_error(bad_bt, "No keycode defined for %s", line_tmp);
|
|
||||||
}
|
|
||||||
if((key & 0xFF00) != 0) {
|
|
||||||
// It's a modifier key
|
|
||||||
uint32_t offset = ducky_get_command_len(line_tmp) + 1;
|
|
||||||
// ducky_get_command_len() returns 0 without space, so check for != 1
|
|
||||||
if(offset != 1 && line_len > offset) {
|
|
||||||
// It's also a key combination
|
|
||||||
key |= ducky_get_keycode(bad_bt, line_tmp + offset, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
furi_hal_bt_hid_kb_press(key);
|
|
||||||
furi_delay_ms(bt_timeout);
|
|
||||||
furi_hal_bt_hid_kb_release(key);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool ducky_set_bt_id(BadBtScript* bad_bt, const char* line) {
|
|
||||||
size_t line_len = strlen(line);
|
|
||||||
size_t mac_len = BAD_BT_MAC_ADDRESS_LEN * 3;
|
|
||||||
if(line_len < mac_len + 1) return false; // MAC + at least 1 char for name
|
|
||||||
|
|
||||||
uint8_t mac[BAD_BT_MAC_ADDRESS_LEN];
|
|
||||||
for(size_t i = 0; i < BAD_BT_MAC_ADDRESS_LEN; i++) {
|
|
||||||
char a = line[i * 3];
|
|
||||||
char b = line[i * 3 + 1];
|
|
||||||
if((a < 'A' && a > 'F') || (a < '0' && a > '9') || (b < 'A' && b > 'F') ||
|
|
||||||
(b < '0' && b > '9') || !hex_char_to_uint8(a, b, &mac[i])) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
furi_hal_bt_reverse_mac_addr(mac);
|
|
||||||
|
|
||||||
furi_hal_bt_set_profile_adv_name(FuriHalBtProfileHidKeyboard, line + mac_len);
|
|
||||||
bt_set_profile_mac_address(bad_bt->bt, mac);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool ducky_script_preload(BadBtScript* bad_bt, File* script_file) {
|
|
||||||
uint8_t ret = 0;
|
|
||||||
uint32_t line_len = 0;
|
|
||||||
|
|
||||||
furi_string_reset(bad_bt->line);
|
|
||||||
|
|
||||||
do {
|
|
||||||
ret = storage_file_read(script_file, bad_bt->file_buf, FILE_BUFFER_LEN);
|
|
||||||
for(uint16_t i = 0; i < ret; i++) {
|
|
||||||
if(bad_bt->file_buf[i] == '\n' && line_len > 0) {
|
|
||||||
bad_bt->st.line_nb++;
|
|
||||||
line_len = 0;
|
|
||||||
} else {
|
|
||||||
if(bad_bt->st.line_nb == 0) { // Save first line
|
|
||||||
furi_string_push_back(bad_bt->line, bad_bt->file_buf[i]);
|
|
||||||
}
|
|
||||||
line_len++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(storage_file_eof(script_file)) {
|
|
||||||
if(line_len > 0) {
|
|
||||||
bad_bt->st.line_nb++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while(ret > 0);
|
|
||||||
|
|
||||||
const char* line_tmp = furi_string_get_cstr(bad_bt->line);
|
|
||||||
if(bad_bt->app->switch_mode_thread) {
|
|
||||||
furi_thread_join(bad_bt->app->switch_mode_thread);
|
|
||||||
furi_thread_free(bad_bt->app->switch_mode_thread);
|
|
||||||
bad_bt->app->switch_mode_thread = NULL;
|
|
||||||
}
|
|
||||||
// Looking for ID or BT_ID command at first line
|
|
||||||
bad_bt->set_usb_id = false;
|
|
||||||
bad_bt->set_bt_id = false;
|
|
||||||
bad_bt->has_usb_id = strncmp(line_tmp, ducky_cmd_id, strlen(ducky_cmd_id)) == 0;
|
|
||||||
// TODO: We setting has_usb_id to its value but ignoring it for now and not using anywhere here, may be used in a future to detect script type
|
|
||||||
bad_bt->has_bt_id = strncmp(line_tmp, ducky_cmd_bt_id, strlen(ducky_cmd_bt_id)) == 0;
|
|
||||||
if(bad_bt->has_bt_id) {
|
|
||||||
if(!bad_bt->app->bt_remember) {
|
|
||||||
bad_bt->set_bt_id = ducky_set_bt_id(bad_bt, &line_tmp[strlen(ducky_cmd_bt_id) + 1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bad_kb_config_refresh_menu(bad_bt->app);
|
|
||||||
|
|
||||||
if(!bad_bt->set_bt_id) {
|
|
||||||
const char* bt_name = bad_bt->app->config.bt_name;
|
|
||||||
const uint8_t* bt_mac = bad_bt->app->bt_remember ? (uint8_t*)&BAD_BT_BOUND_MAC_ADDRESS :
|
|
||||||
bad_bt->app->config.bt_mac;
|
|
||||||
bool reset_name = strncmp(
|
|
||||||
bt_name,
|
|
||||||
furi_hal_bt_get_profile_adv_name(FuriHalBtProfileHidKeyboard),
|
|
||||||
BAD_BT_ADV_NAME_MAX_LEN);
|
|
||||||
bool reset_mac = memcmp(
|
|
||||||
bt_mac,
|
|
||||||
furi_hal_bt_get_profile_mac_addr(FuriHalBtProfileHidKeyboard),
|
|
||||||
BAD_BT_MAC_ADDRESS_LEN);
|
|
||||||
if(reset_name && reset_mac) {
|
|
||||||
furi_hal_bt_set_profile_adv_name(FuriHalBtProfileHidKeyboard, bt_name);
|
|
||||||
} else if(reset_name) {
|
|
||||||
bt_set_profile_adv_name(bad_bt->bt, bt_name);
|
|
||||||
}
|
|
||||||
if(reset_mac) {
|
|
||||||
bt_set_profile_mac_address(bad_bt->bt, bt_mac);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
storage_file_seek(script_file, 0, true);
|
|
||||||
furi_string_reset(bad_bt->line);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int32_t ducky_script_execute_next(BadBtScript* bad_bt, File* script_file) {
|
|
||||||
int32_t delay_val = 0;
|
|
||||||
|
|
||||||
if(bad_bt->repeat_cnt > 0) {
|
|
||||||
bad_bt->repeat_cnt--;
|
|
||||||
delay_val = ducky_parse_line(bad_bt, bad_bt->line_prev);
|
|
||||||
if(delay_val == SCRIPT_STATE_NEXT_LINE) { // Empty line
|
|
||||||
return 0;
|
|
||||||
} else if(delay_val == SCRIPT_STATE_STRING_START) { // Print string with delays
|
|
||||||
return delay_val;
|
|
||||||
} else if(delay_val == SCRIPT_STATE_WAIT_FOR_BTN) { // wait for button
|
|
||||||
return delay_val;
|
|
||||||
} else if(delay_val < 0) { // Script error
|
|
||||||
bad_bt->st.error_line = bad_bt->st.line_cur - 1;
|
|
||||||
FURI_LOG_E(WORKER_TAG, "Unknown command at line %u", bad_bt->st.line_cur - 1U);
|
|
||||||
return SCRIPT_STATE_ERROR;
|
|
||||||
} else {
|
|
||||||
return (delay_val + bad_bt->defdelay);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
furi_string_set(bad_bt->line_prev, bad_bt->line);
|
|
||||||
furi_string_reset(bad_bt->line);
|
|
||||||
|
|
||||||
while(1) {
|
|
||||||
if(bad_bt->buf_len == 0) {
|
|
||||||
bad_bt->buf_len = storage_file_read(script_file, bad_bt->file_buf, FILE_BUFFER_LEN);
|
|
||||||
if(storage_file_eof(script_file)) {
|
|
||||||
if((bad_bt->buf_len < FILE_BUFFER_LEN) && (bad_bt->file_end == false)) {
|
|
||||||
bad_bt->file_buf[bad_bt->buf_len] = '\n';
|
|
||||||
bad_bt->buf_len++;
|
|
||||||
bad_bt->file_end = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bad_bt->buf_start = 0;
|
|
||||||
if(bad_bt->buf_len == 0) return SCRIPT_STATE_END;
|
|
||||||
}
|
|
||||||
for(uint8_t i = bad_bt->buf_start; i < (bad_bt->buf_start + bad_bt->buf_len); i++) {
|
|
||||||
if(bad_bt->file_buf[i] == '\n' && furi_string_size(bad_bt->line) > 0) {
|
|
||||||
bad_bt->st.line_cur++;
|
|
||||||
bad_bt->buf_len = bad_bt->buf_len + bad_bt->buf_start - (i + 1);
|
|
||||||
bad_bt->buf_start = i + 1;
|
|
||||||
furi_string_trim(bad_bt->line);
|
|
||||||
delay_val = ducky_parse_line(bad_bt, bad_bt->line);
|
|
||||||
if(delay_val == SCRIPT_STATE_NEXT_LINE) { // Empty line
|
|
||||||
return 0;
|
|
||||||
} else if(delay_val == SCRIPT_STATE_STRING_START) { // Print string with delays
|
|
||||||
return delay_val;
|
|
||||||
} else if(delay_val == SCRIPT_STATE_WAIT_FOR_BTN) { // wait for button
|
|
||||||
return delay_val;
|
|
||||||
} else if(delay_val < 0) {
|
|
||||||
bad_bt->st.error_line = bad_bt->st.line_cur;
|
|
||||||
FURI_LOG_E(WORKER_TAG, "Unknown command at line %u", bad_bt->st.line_cur);
|
|
||||||
return SCRIPT_STATE_ERROR;
|
|
||||||
} else {
|
|
||||||
return (delay_val + bad_bt->defdelay);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
furi_string_push_back(bad_bt->line, bad_bt->file_buf[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bad_bt->buf_len = 0;
|
|
||||||
if(bad_bt->file_end) return SCRIPT_STATE_END;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void bad_bt_bt_hid_state_callback(BtStatus status, void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
BadBtScript* bad_bt = context;
|
|
||||||
bool state = (status == BtStatusConnected);
|
|
||||||
|
|
||||||
if(state == true) {
|
|
||||||
LevelRssiRange r = bt_remote_rssi_range(bad_bt->bt);
|
|
||||||
if(r != LevelRssiError) {
|
|
||||||
bt_timeout = bt_hid_delays[r];
|
|
||||||
}
|
|
||||||
furi_thread_flags_set(furi_thread_get_id(bad_bt->thread), WorkerEvtConnect);
|
|
||||||
} else {
|
|
||||||
furi_thread_flags_set(furi_thread_get_id(bad_bt->thread), WorkerEvtDisconnect);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t bad_bt_flags_get(uint32_t flags_mask, uint32_t timeout) {
|
|
||||||
uint32_t flags = furi_thread_flags_get();
|
|
||||||
furi_check((flags & FuriFlagError) == 0);
|
|
||||||
if(flags == 0) {
|
|
||||||
flags = furi_thread_flags_wait(flags_mask, FuriFlagWaitAny, timeout);
|
|
||||||
furi_check(((flags & FuriFlagError) == 0) || (flags == (unsigned)FuriFlagErrorTimeout));
|
|
||||||
} else {
|
|
||||||
uint32_t state = furi_thread_flags_clear(flags);
|
|
||||||
furi_check((state & FuriFlagError) == 0);
|
|
||||||
}
|
|
||||||
return flags;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int32_t bad_bt_worker(void* context) {
|
|
||||||
BadBtScript* bad_bt = context;
|
|
||||||
|
|
||||||
BadBtWorkerState worker_state = BadBtStateInit;
|
|
||||||
int32_t delay_val = 0;
|
|
||||||
|
|
||||||
FURI_LOG_I(WORKER_TAG, "Init");
|
|
||||||
File* script_file = storage_file_alloc(furi_record_open(RECORD_STORAGE));
|
|
||||||
bad_bt->line = furi_string_alloc();
|
|
||||||
bad_bt->line_prev = furi_string_alloc();
|
|
||||||
bad_bt->string_print = furi_string_alloc();
|
|
||||||
|
|
||||||
bt_set_status_changed_callback(bad_bt->bt, bad_bt_bt_hid_state_callback, bad_bt);
|
|
||||||
|
|
||||||
while(1) {
|
|
||||||
if(worker_state == BadBtStateInit) { // State: initialization
|
|
||||||
if(storage_file_open(
|
|
||||||
script_file,
|
|
||||||
furi_string_get_cstr(bad_bt->file_path),
|
|
||||||
FSAM_READ,
|
|
||||||
FSOM_OPEN_EXISTING)) {
|
|
||||||
if((ducky_script_preload(bad_bt, script_file)) && (bad_bt->st.line_nb > 0)) {
|
|
||||||
if(furi_hal_bt_is_connected()) {
|
|
||||||
worker_state = BadBtStateIdle; // Ready to run
|
|
||||||
} else {
|
|
||||||
worker_state = BadBtStateNotConnected; // Not connected
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
worker_state = BadBtStateScriptError; // Script preload error
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
FURI_LOG_E(WORKER_TAG, "File open error");
|
|
||||||
worker_state = BadBtStateFileError; // File open error
|
|
||||||
}
|
|
||||||
bad_bt->st.state = worker_state;
|
|
||||||
|
|
||||||
} else if(worker_state == BadBtStateNotConnected) { // State: Not connected
|
|
||||||
uint32_t flags = bad_bt_flags_get(
|
|
||||||
WorkerEvtEnd | WorkerEvtConnect | WorkerEvtDisconnect | WorkerEvtStartStop,
|
|
||||||
FuriWaitForever);
|
|
||||||
|
|
||||||
if(flags & WorkerEvtEnd) {
|
|
||||||
break;
|
|
||||||
} else if(flags & WorkerEvtConnect) {
|
|
||||||
worker_state = BadBtStateIdle; // Ready to run
|
|
||||||
} else if(flags & WorkerEvtStartStop) {
|
|
||||||
worker_state = BadBtStateWillRun; // Will run when connected
|
|
||||||
}
|
|
||||||
bad_bt->st.state = worker_state;
|
|
||||||
|
|
||||||
} else if(worker_state == BadBtStateIdle) { // State: ready to start
|
|
||||||
uint32_t flags = bad_bt_flags_get(
|
|
||||||
WorkerEvtEnd | WorkerEvtStartStop | WorkerEvtConnect | WorkerEvtDisconnect,
|
|
||||||
FuriWaitForever);
|
|
||||||
|
|
||||||
if(flags & WorkerEvtEnd) {
|
|
||||||
break;
|
|
||||||
} else if(flags & WorkerEvtStartStop) { // Start executing script
|
|
||||||
delay_val = 0;
|
|
||||||
bad_bt->buf_len = 0;
|
|
||||||
bad_bt->st.line_cur = 0;
|
|
||||||
bad_bt->defdelay = 0;
|
|
||||||
bad_bt->stringdelay = 0;
|
|
||||||
bad_bt->repeat_cnt = 0;
|
|
||||||
bad_bt->key_hold_nb = 0;
|
|
||||||
bad_bt->file_end = false;
|
|
||||||
storage_file_seek(script_file, 0, true);
|
|
||||||
bad_bt_script_set_keyboard_layout(bad_bt, bad_bt->keyboard_layout);
|
|
||||||
worker_state = BadBtStateRunning;
|
|
||||||
} else if(flags & WorkerEvtDisconnect) {
|
|
||||||
worker_state = BadBtStateNotConnected; // Disconnected
|
|
||||||
}
|
|
||||||
bad_bt->st.state = worker_state;
|
|
||||||
|
|
||||||
} else if(worker_state == BadBtStateWillRun) { // State: start on connection
|
|
||||||
uint32_t flags = bad_bt_flags_get(
|
|
||||||
WorkerEvtEnd | WorkerEvtConnect | WorkerEvtDisconnect | WorkerEvtStartStop,
|
|
||||||
FuriWaitForever);
|
|
||||||
|
|
||||||
if(flags & WorkerEvtEnd) {
|
|
||||||
break;
|
|
||||||
} else if(flags & WorkerEvtConnect) { // Start executing script
|
|
||||||
delay_val = 0;
|
|
||||||
bad_bt->buf_len = 0;
|
|
||||||
bad_bt->st.line_cur = 0;
|
|
||||||
bad_bt->defdelay = 0;
|
|
||||||
bad_bt->stringdelay = 0;
|
|
||||||
bad_bt->repeat_cnt = 0;
|
|
||||||
bad_bt->file_end = false;
|
|
||||||
storage_file_seek(script_file, 0, true);
|
|
||||||
// extra time for PC to recognize Flipper as keyboard
|
|
||||||
flags = furi_thread_flags_wait(
|
|
||||||
WorkerEvtEnd | WorkerEvtDisconnect | WorkerEvtStartStop,
|
|
||||||
FuriFlagWaitAny | FuriFlagNoClear,
|
|
||||||
1500);
|
|
||||||
if(flags == (unsigned)FuriFlagErrorTimeout) {
|
|
||||||
// If nothing happened - start script execution
|
|
||||||
worker_state = BadBtStateRunning;
|
|
||||||
} else if(flags & WorkerEvtStartStop) {
|
|
||||||
worker_state = BadBtStateIdle;
|
|
||||||
furi_thread_flags_clear(WorkerEvtStartStop);
|
|
||||||
}
|
|
||||||
|
|
||||||
update_bt_timeout(bad_bt->bt);
|
|
||||||
|
|
||||||
bad_bt_script_set_keyboard_layout(bad_bt, bad_bt->keyboard_layout);
|
|
||||||
} else if(flags & WorkerEvtStartStop) { // Cancel scheduled execution
|
|
||||||
worker_state = BadBtStateNotConnected;
|
|
||||||
}
|
|
||||||
bad_bt->st.state = worker_state;
|
|
||||||
|
|
||||||
} else if(worker_state == BadBtStateRunning) { // State: running
|
|
||||||
uint16_t delay_cur = (delay_val > 1000) ? (1000) : (delay_val);
|
|
||||||
uint32_t flags = furi_thread_flags_wait(
|
|
||||||
WorkerEvtEnd | WorkerEvtStartStop | WorkerEvtConnect | WorkerEvtDisconnect,
|
|
||||||
FuriFlagWaitAny,
|
|
||||||
delay_cur);
|
|
||||||
|
|
||||||
delay_val -= delay_cur;
|
|
||||||
if(!(flags & FuriFlagError)) {
|
|
||||||
if(flags & WorkerEvtEnd) {
|
|
||||||
break;
|
|
||||||
} else if(flags & WorkerEvtStartStop) {
|
|
||||||
worker_state = BadBtStateIdle; // Stop executing script
|
|
||||||
|
|
||||||
furi_hal_bt_hid_kb_release_all();
|
|
||||||
|
|
||||||
} else if(flags & WorkerEvtDisconnect) {
|
|
||||||
worker_state = BadBtStateNotConnected; // Disconnected
|
|
||||||
|
|
||||||
furi_hal_bt_hid_kb_release_all();
|
|
||||||
}
|
|
||||||
bad_bt->st.state = worker_state;
|
|
||||||
continue;
|
|
||||||
} else if(
|
|
||||||
(flags == (unsigned)FuriFlagErrorTimeout) ||
|
|
||||||
(flags == (unsigned)FuriFlagErrorResource)) {
|
|
||||||
if(delay_val > 0) {
|
|
||||||
bad_bt->st.delay_remain--;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
bad_bt->st.state = BadBtStateRunning;
|
|
||||||
delay_val = ducky_script_execute_next(bad_bt, script_file);
|
|
||||||
if(delay_val == SCRIPT_STATE_ERROR) { // Script error
|
|
||||||
delay_val = 0;
|
|
||||||
worker_state = BadBtStateScriptError;
|
|
||||||
bad_bt->st.state = worker_state;
|
|
||||||
|
|
||||||
furi_hal_bt_hid_kb_release_all();
|
|
||||||
|
|
||||||
} else if(delay_val == SCRIPT_STATE_END) { // End of script
|
|
||||||
delay_val = 0;
|
|
||||||
worker_state = BadBtStateIdle;
|
|
||||||
bad_bt->st.state = BadBtStateDone;
|
|
||||||
|
|
||||||
furi_hal_bt_hid_kb_release_all();
|
|
||||||
|
|
||||||
continue;
|
|
||||||
} else if(delay_val == SCRIPT_STATE_STRING_START) { // Start printing string with delays
|
|
||||||
delay_val = bad_bt->defdelay;
|
|
||||||
bad_bt->string_print_pos = 0;
|
|
||||||
worker_state = BadBtStateStringDelay;
|
|
||||||
} else if(delay_val == SCRIPT_STATE_WAIT_FOR_BTN) { // set state to wait for user input
|
|
||||||
worker_state = BadBtStateWaitForBtn;
|
|
||||||
bad_bt->st.state = BadBtStateWaitForBtn; // Show long delays
|
|
||||||
} else if(delay_val > 1000) {
|
|
||||||
bad_bt->st.state = BadBtStateDelay; // Show long delays
|
|
||||||
bad_bt->st.delay_remain = delay_val / 1000;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
furi_check((flags & FuriFlagError) == 0);
|
|
||||||
}
|
|
||||||
} else if(worker_state == BadBtStateWaitForBtn) { // State: Wait for button Press
|
|
||||||
uint16_t delay_cur = (delay_val > 1000) ? (1000) : (delay_val);
|
|
||||||
uint32_t flags = furi_thread_flags_wait(
|
|
||||||
WorkerEvtEnd | WorkerEvtStartStop | WorkerEvtPauseResume | WorkerEvtConnect |
|
|
||||||
WorkerEvtDisconnect,
|
|
||||||
FuriFlagWaitAny,
|
|
||||||
delay_cur);
|
|
||||||
if(!(flags & FuriFlagError)) {
|
|
||||||
if(flags & WorkerEvtEnd) {
|
|
||||||
break;
|
|
||||||
} else if(flags & WorkerEvtStartStop) {
|
|
||||||
delay_val = 0;
|
|
||||||
worker_state = BadBtStateRunning;
|
|
||||||
} else if(flags & WorkerEvtDisconnect) {
|
|
||||||
worker_state = BadBtStateNotConnected; // Disconnected
|
|
||||||
furi_hal_hid_kb_release_all();
|
|
||||||
}
|
|
||||||
bad_bt->st.state = worker_state;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
} else if(worker_state == BadBtStateStringDelay) { // State: print string with delays
|
|
||||||
uint32_t flags = furi_thread_flags_wait(
|
|
||||||
WorkerEvtEnd | WorkerEvtStartStop | WorkerEvtPauseResume | WorkerEvtConnect |
|
|
||||||
WorkerEvtDisconnect,
|
|
||||||
FuriFlagWaitAny,
|
|
||||||
bad_bt->stringdelay);
|
|
||||||
|
|
||||||
if(!(flags & FuriFlagError)) {
|
|
||||||
if(flags & WorkerEvtEnd) {
|
|
||||||
break;
|
|
||||||
} else if(flags & WorkerEvtStartStop) {
|
|
||||||
worker_state = BadBtStateIdle; // Stop executing script
|
|
||||||
|
|
||||||
furi_hal_bt_hid_kb_release_all();
|
|
||||||
|
|
||||||
} else if(flags & WorkerEvtDisconnect) {
|
|
||||||
worker_state = BadBtStateNotConnected; // Disconnected
|
|
||||||
|
|
||||||
furi_hal_bt_hid_kb_release_all();
|
|
||||||
}
|
|
||||||
bad_bt->st.state = worker_state;
|
|
||||||
continue;
|
|
||||||
} else if(
|
|
||||||
(flags == (unsigned)FuriFlagErrorTimeout) ||
|
|
||||||
(flags == (unsigned)FuriFlagErrorResource)) {
|
|
||||||
bool string_end = ducky_string_next(bad_bt);
|
|
||||||
if(string_end) {
|
|
||||||
bad_bt->stringdelay = 0;
|
|
||||||
worker_state = BadBtStateRunning;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
furi_check((flags & FuriFlagError) == 0);
|
|
||||||
}
|
|
||||||
} else if(
|
|
||||||
(worker_state == BadBtStateFileError) ||
|
|
||||||
(worker_state == BadBtStateScriptError)) { // State: error
|
|
||||||
uint32_t flags =
|
|
||||||
bad_bt_flags_get(WorkerEvtEnd, FuriWaitForever); // Waiting for exit command
|
|
||||||
|
|
||||||
if(flags & WorkerEvtEnd) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
update_bt_timeout(bad_bt->bt);
|
|
||||||
}
|
|
||||||
|
|
||||||
bt_set_status_changed_callback(bad_bt->bt, NULL, NULL);
|
|
||||||
|
|
||||||
storage_file_close(script_file);
|
|
||||||
storage_file_free(script_file);
|
|
||||||
furi_string_free(bad_bt->line);
|
|
||||||
furi_string_free(bad_bt->line_prev);
|
|
||||||
furi_string_free(bad_bt->string_print);
|
|
||||||
|
|
||||||
FURI_LOG_I(WORKER_TAG, "End");
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void bad_bt_script_set_default_keyboard_layout(BadBtScript* bad_bt) {
|
|
||||||
furi_assert(bad_bt);
|
|
||||||
furi_string_set_str(bad_bt->keyboard_layout, "");
|
|
||||||
memset(bad_bt->layout, HID_KEYBOARD_NONE, sizeof(bad_bt->layout));
|
|
||||||
memcpy(bad_bt->layout, hid_asciimap, MIN(sizeof(hid_asciimap), sizeof(bad_bt->layout)));
|
|
||||||
}
|
|
||||||
|
|
||||||
BadBtScript* bad_bt_script_open(FuriString* file_path, Bt* bt, BadBtApp* app) {
|
|
||||||
furi_assert(file_path);
|
|
||||||
|
|
||||||
BadBtScript* bad_bt = malloc(sizeof(BadBtScript));
|
|
||||||
bad_bt->app = app;
|
|
||||||
bad_bt->file_path = furi_string_alloc();
|
|
||||||
furi_string_set(bad_bt->file_path, file_path);
|
|
||||||
bad_bt->keyboard_layout = furi_string_alloc();
|
|
||||||
bad_bt_script_set_default_keyboard_layout(bad_bt);
|
|
||||||
|
|
||||||
bad_bt->st.state = BadBtStateInit;
|
|
||||||
bad_bt->st.error[0] = '\0';
|
|
||||||
|
|
||||||
bad_bt->bt = bt;
|
|
||||||
|
|
||||||
bad_bt->thread = furi_thread_alloc_ex("BadBtWorker", 2048, bad_bt_worker, bad_bt);
|
|
||||||
furi_thread_start(bad_bt->thread);
|
|
||||||
return bad_bt;
|
|
||||||
}
|
|
||||||
|
|
||||||
void bad_bt_script_close(BadBtScript* bad_bt) {
|
|
||||||
furi_assert(bad_bt);
|
|
||||||
furi_record_close(RECORD_STORAGE);
|
|
||||||
furi_thread_flags_set(furi_thread_get_id(bad_bt->thread), WorkerEvtEnd);
|
|
||||||
furi_thread_join(bad_bt->thread);
|
|
||||||
furi_thread_free(bad_bt->thread);
|
|
||||||
furi_string_free(bad_bt->file_path);
|
|
||||||
furi_string_free(bad_bt->keyboard_layout);
|
|
||||||
free(bad_bt);
|
|
||||||
}
|
|
||||||
|
|
||||||
void bad_bt_script_set_keyboard_layout(BadBtScript* bad_bt, FuriString* layout_path) {
|
|
||||||
furi_assert(bad_bt);
|
|
||||||
|
|
||||||
if((bad_bt->st.state == BadBtStateRunning) || (bad_bt->st.state == BadBtStateDelay)) {
|
|
||||||
// do not update keyboard layout while a script is running
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
File* layout_file = storage_file_alloc(furi_record_open(RECORD_STORAGE));
|
|
||||||
if(!furi_string_empty(layout_path)) { //-V1051
|
|
||||||
furi_string_set(bad_bt->keyboard_layout, layout_path);
|
|
||||||
if(storage_file_open(
|
|
||||||
layout_file, furi_string_get_cstr(layout_path), FSAM_READ, FSOM_OPEN_EXISTING)) {
|
|
||||||
uint16_t layout[128];
|
|
||||||
if(storage_file_read(layout_file, layout, sizeof(layout)) == sizeof(layout)) {
|
|
||||||
memcpy(bad_bt->layout, layout, sizeof(layout));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
storage_file_close(layout_file);
|
|
||||||
} else {
|
|
||||||
bad_bt_script_set_default_keyboard_layout(bad_bt);
|
|
||||||
}
|
|
||||||
storage_file_free(layout_file);
|
|
||||||
}
|
|
||||||
|
|
||||||
void bad_bt_script_toggle(BadBtScript* bad_bt) {
|
|
||||||
furi_assert(bad_bt);
|
|
||||||
furi_thread_flags_set(furi_thread_get_id(bad_bt->thread), WorkerEvtStartStop);
|
|
||||||
}
|
|
||||||
|
|
||||||
BadBtState* bad_bt_script_get_state(BadBtScript* bad_bt) {
|
|
||||||
furi_assert(bad_bt);
|
|
||||||
return &(bad_bt->st);
|
|
||||||
}
|
|
||||||
154
applications/external/bad_bt/helpers/ducky_script.h
vendored
@@ -1,154 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <furi.h>
|
|
||||||
#include <furi_hal.h>
|
|
||||||
#include <bt/bt_service/bt_i.h>
|
|
||||||
|
|
||||||
#include <gui/view_dispatcher.h>
|
|
||||||
#include <gui/modules/widget.h>
|
|
||||||
#include <gui/modules/variable_item_list.h>
|
|
||||||
#include <gui/modules/text_input.h>
|
|
||||||
#include <gui/modules/byte_input.h>
|
|
||||||
#include "../views/bad_bt_view.h"
|
|
||||||
|
|
||||||
#define FILE_BUFFER_LEN 16
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
LevelRssi122_100,
|
|
||||||
LevelRssi99_80,
|
|
||||||
LevelRssi79_60,
|
|
||||||
LevelRssi59_40,
|
|
||||||
LevelRssi39_0,
|
|
||||||
LevelRssiNum,
|
|
||||||
LevelRssiError = 0xFF,
|
|
||||||
} LevelRssiRange;
|
|
||||||
|
|
||||||
extern const uint8_t bt_hid_delays[LevelRssiNum];
|
|
||||||
|
|
||||||
extern uint8_t bt_timeout;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
BadBtStateInit,
|
|
||||||
BadBtStateNotConnected,
|
|
||||||
BadBtStateIdle,
|
|
||||||
BadBtStateWillRun,
|
|
||||||
BadBtStateRunning,
|
|
||||||
BadBtStateDelay,
|
|
||||||
BadBtStateStringDelay,
|
|
||||||
BadBtStateWaitForBtn,
|
|
||||||
BadBtStateDone,
|
|
||||||
BadBtStateScriptError,
|
|
||||||
BadBtStateFileError,
|
|
||||||
} BadBtWorkerState;
|
|
||||||
|
|
||||||
struct BadBtState {
|
|
||||||
BadBtWorkerState state;
|
|
||||||
uint32_t pin;
|
|
||||||
uint16_t line_cur;
|
|
||||||
uint16_t line_nb;
|
|
||||||
uint32_t delay_remain;
|
|
||||||
uint16_t error_line;
|
|
||||||
char error[64];
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct BadBtApp BadBtApp;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
FuriHalUsbHidConfig hid_cfg;
|
|
||||||
FuriThread* thread;
|
|
||||||
BadBtState st;
|
|
||||||
|
|
||||||
FuriString* file_path;
|
|
||||||
FuriString* keyboard_layout;
|
|
||||||
uint8_t file_buf[FILE_BUFFER_LEN + 1];
|
|
||||||
uint8_t buf_start;
|
|
||||||
uint8_t buf_len;
|
|
||||||
bool file_end;
|
|
||||||
|
|
||||||
uint32_t defdelay;
|
|
||||||
uint32_t stringdelay;
|
|
||||||
uint16_t layout[128];
|
|
||||||
|
|
||||||
FuriString* line;
|
|
||||||
FuriString* line_prev;
|
|
||||||
uint32_t repeat_cnt;
|
|
||||||
uint8_t key_hold_nb;
|
|
||||||
|
|
||||||
bool set_usb_id;
|
|
||||||
bool set_bt_id;
|
|
||||||
bool has_usb_id;
|
|
||||||
bool has_bt_id;
|
|
||||||
|
|
||||||
FuriString* string_print;
|
|
||||||
size_t string_print_pos;
|
|
||||||
|
|
||||||
Bt* bt;
|
|
||||||
BadBtApp* app;
|
|
||||||
} BadBtScript;
|
|
||||||
|
|
||||||
BadBtScript* bad_bt_script_open(FuriString* file_path, Bt* bt, BadBtApp* app);
|
|
||||||
|
|
||||||
void bad_bt_script_close(BadBtScript* bad_bt);
|
|
||||||
|
|
||||||
void bad_bt_script_set_keyboard_layout(BadBtScript* bad_bt, FuriString* layout_path);
|
|
||||||
|
|
||||||
void bad_bt_script_start(BadBtScript* bad_bt);
|
|
||||||
|
|
||||||
void bad_bt_script_stop(BadBtScript* bad_bt);
|
|
||||||
|
|
||||||
void bad_bt_script_toggle(BadBtScript* bad_bt);
|
|
||||||
|
|
||||||
BadBtState* bad_bt_script_get_state(BadBtScript* bad_bt);
|
|
||||||
|
|
||||||
#define BAD_BT_ADV_NAME_MAX_LEN FURI_HAL_BT_ADV_NAME_LENGTH
|
|
||||||
#define BAD_BT_MAC_ADDRESS_LEN GAP_MAC_ADDR_SIZE
|
|
||||||
|
|
||||||
// this is the MAC address used when we do not forget paired device (BOUND STATE)
|
|
||||||
extern const uint8_t BAD_BT_BOUND_MAC_ADDRESS[BAD_BT_MAC_ADDRESS_LEN];
|
|
||||||
extern const uint8_t BAD_BT_EMPTY_MAC_ADDRESS[BAD_BT_MAC_ADDRESS_LEN];
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
BadBtAppErrorNoFiles,
|
|
||||||
BadBtAppErrorCloseRpc,
|
|
||||||
} BadBtAppError;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
char bt_name[BAD_BT_ADV_NAME_MAX_LEN];
|
|
||||||
uint8_t bt_mac[BAD_BT_MAC_ADDRESS_LEN];
|
|
||||||
GapPairing bt_mode;
|
|
||||||
} BadBtConfig;
|
|
||||||
|
|
||||||
struct BadBtApp {
|
|
||||||
Gui* gui;
|
|
||||||
ViewDispatcher* view_dispatcher;
|
|
||||||
SceneManager* scene_manager;
|
|
||||||
NotificationApp* notifications;
|
|
||||||
DialogsApp* dialogs;
|
|
||||||
Widget* widget;
|
|
||||||
VariableItemList* var_item_list;
|
|
||||||
TextInput* text_input;
|
|
||||||
ByteInput* byte_input;
|
|
||||||
|
|
||||||
BadBtAppError error;
|
|
||||||
FuriString* file_path;
|
|
||||||
FuriString* keyboard_layout;
|
|
||||||
BadBt* bad_bt_view;
|
|
||||||
BadBtScript* bad_bt_script;
|
|
||||||
|
|
||||||
Bt* bt;
|
|
||||||
bool bt_remember;
|
|
||||||
BadBtConfig config;
|
|
||||||
BadBtConfig prev_config;
|
|
||||||
FuriThread* conn_init_thread;
|
|
||||||
FuriThread* switch_mode_thread;
|
|
||||||
};
|
|
||||||
|
|
||||||
int32_t bad_bt_config_switch_mode(BadBtApp* app);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
@@ -1,201 +0,0 @@
|
|||||||
#include <furi_hal.h>
|
|
||||||
#include <furi_hal_bt_hid.h>
|
|
||||||
#include "ducky_script.h"
|
|
||||||
#include "ducky_script_i.h"
|
|
||||||
|
|
||||||
typedef int32_t (*DuckyCmdCallback)(BadBtScript* bad_bt, const char* line, int32_t param);
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
char* name;
|
|
||||||
DuckyCmdCallback callback;
|
|
||||||
int32_t param;
|
|
||||||
} DuckyCmd;
|
|
||||||
|
|
||||||
static int32_t ducky_fnc_delay(BadBtScript* bad_bt, const char* line, int32_t param) {
|
|
||||||
UNUSED(param);
|
|
||||||
|
|
||||||
line = &line[ducky_get_command_len(line) + 1];
|
|
||||||
uint32_t delay_val = 0;
|
|
||||||
bool state = ducky_get_number(line, &delay_val);
|
|
||||||
if((state) && (delay_val > 0)) {
|
|
||||||
return (int32_t)delay_val;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ducky_error(bad_bt, "Invalid number %s", line);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int32_t ducky_fnc_defdelay(BadBtScript* bad_bt, const char* line, int32_t param) {
|
|
||||||
UNUSED(param);
|
|
||||||
|
|
||||||
line = &line[ducky_get_command_len(line) + 1];
|
|
||||||
bool state = ducky_get_number(line, &bad_bt->defdelay);
|
|
||||||
if(!state) {
|
|
||||||
return ducky_error(bad_bt, "Invalid number %s", line);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int32_t ducky_fnc_strdelay(BadBtScript* bad_bt, const char* line, int32_t param) {
|
|
||||||
UNUSED(param);
|
|
||||||
|
|
||||||
line = &line[ducky_get_command_len(line) + 1];
|
|
||||||
bool state = ducky_get_number(line, &bad_bt->stringdelay);
|
|
||||||
if(!state) {
|
|
||||||
return ducky_error(bad_bt, "Invalid number %s", line);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int32_t ducky_fnc_string(BadBtScript* bad_bt, const char* line, int32_t param) {
|
|
||||||
line = &line[ducky_get_command_len(line) + 1];
|
|
||||||
furi_string_set_str(bad_bt->string_print, line);
|
|
||||||
if(param == 1) {
|
|
||||||
furi_string_cat(bad_bt->string_print, "\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
if(bad_bt->stringdelay == 0) { // stringdelay not set - run command immidiately
|
|
||||||
bool state = ducky_string(bad_bt, furi_string_get_cstr(bad_bt->string_print));
|
|
||||||
if(!state) {
|
|
||||||
return ducky_error(bad_bt, "Invalid string %s", line);
|
|
||||||
}
|
|
||||||
} else { // stringdelay is set - run command in thread to keep handling external events
|
|
||||||
return SCRIPT_STATE_STRING_START;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int32_t ducky_fnc_repeat(BadBtScript* bad_bt, const char* line, int32_t param) {
|
|
||||||
UNUSED(param);
|
|
||||||
|
|
||||||
line = &line[ducky_get_command_len(line) + 1];
|
|
||||||
bool state = ducky_get_number(line, &bad_bt->repeat_cnt);
|
|
||||||
if((!state) || (bad_bt->repeat_cnt == 0)) {
|
|
||||||
return ducky_error(bad_bt, "Invalid number %s", line);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int32_t ducky_fnc_sysrq(BadBtScript* bad_bt, const char* line, int32_t param) {
|
|
||||||
UNUSED(param);
|
|
||||||
|
|
||||||
line = &line[ducky_get_command_len(line) + 1];
|
|
||||||
uint16_t key = ducky_get_keycode(bad_bt, line, true);
|
|
||||||
|
|
||||||
furi_hal_bt_hid_kb_press(KEY_MOD_LEFT_ALT | HID_KEYBOARD_PRINT_SCREEN);
|
|
||||||
furi_hal_bt_hid_kb_press(key);
|
|
||||||
furi_delay_ms(bt_timeout);
|
|
||||||
furi_hal_bt_hid_kb_release(key);
|
|
||||||
furi_hal_bt_hid_kb_release(KEY_MOD_LEFT_ALT | HID_KEYBOARD_PRINT_SCREEN);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int32_t ducky_fnc_altchar(BadBtScript* bad_bt, const char* line, int32_t param) {
|
|
||||||
UNUSED(param);
|
|
||||||
|
|
||||||
line = &line[ducky_get_command_len(line) + 1];
|
|
||||||
ducky_numlock_on(bad_bt);
|
|
||||||
bool state = ducky_altchar(bad_bt, line);
|
|
||||||
if(!state) {
|
|
||||||
return ducky_error(bad_bt, "Invalid altchar %s", line);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int32_t ducky_fnc_altstring(BadBtScript* bad_bt, const char* line, int32_t param) {
|
|
||||||
UNUSED(param);
|
|
||||||
|
|
||||||
line = &line[ducky_get_command_len(line) + 1];
|
|
||||||
ducky_numlock_on(bad_bt);
|
|
||||||
bool state = ducky_altstring(bad_bt, line);
|
|
||||||
if(!state) {
|
|
||||||
return ducky_error(bad_bt, "Invalid altstring %s", line);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int32_t ducky_fnc_hold(BadBtScript* bad_bt, const char* line, int32_t param) {
|
|
||||||
UNUSED(param);
|
|
||||||
|
|
||||||
line = &line[ducky_get_command_len(line) + 1];
|
|
||||||
uint16_t key = ducky_get_keycode(bad_bt, line, true);
|
|
||||||
if(key == HID_KEYBOARD_NONE) {
|
|
||||||
return ducky_error(bad_bt, "No keycode defined for %s", line);
|
|
||||||
}
|
|
||||||
bad_bt->key_hold_nb++;
|
|
||||||
if(bad_bt->key_hold_nb > (HID_KB_MAX_KEYS - 1)) {
|
|
||||||
return ducky_error(bad_bt, "Too many keys are hold");
|
|
||||||
}
|
|
||||||
furi_hal_bt_hid_kb_press(key);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int32_t ducky_fnc_release(BadBtScript* bad_bt, const char* line, int32_t param) {
|
|
||||||
UNUSED(param);
|
|
||||||
|
|
||||||
line = &line[ducky_get_command_len(line) + 1];
|
|
||||||
uint16_t key = ducky_get_keycode(bad_bt, line, true);
|
|
||||||
if(key == HID_KEYBOARD_NONE) {
|
|
||||||
return ducky_error(bad_bt, "No keycode defined for %s", line);
|
|
||||||
}
|
|
||||||
if(bad_bt->key_hold_nb == 0) {
|
|
||||||
return ducky_error(bad_bt, "No keys are hold");
|
|
||||||
}
|
|
||||||
bad_bt->key_hold_nb--;
|
|
||||||
furi_hal_bt_hid_kb_release(key);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int32_t ducky_fnc_waitforbutton(BadBtScript* bad_bt, const char* line, int32_t param) {
|
|
||||||
UNUSED(param);
|
|
||||||
UNUSED(bad_bt);
|
|
||||||
UNUSED(line);
|
|
||||||
|
|
||||||
return SCRIPT_STATE_WAIT_FOR_BTN;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const DuckyCmd ducky_commands[] = {
|
|
||||||
{"REM", NULL, -1},
|
|
||||||
{"ID", NULL, -1},
|
|
||||||
{"BT_ID", NULL, -1},
|
|
||||||
{"DELAY", ducky_fnc_delay, -1},
|
|
||||||
{"STRING", ducky_fnc_string, 0},
|
|
||||||
{"STRINGLN", ducky_fnc_string, 1},
|
|
||||||
{"DEFAULT_DELAY", ducky_fnc_defdelay, -1},
|
|
||||||
{"DEFAULTDELAY", ducky_fnc_defdelay, -1},
|
|
||||||
{"STRINGDELAY", ducky_fnc_strdelay, -1},
|
|
||||||
{"STRING_DELAY", ducky_fnc_strdelay, -1},
|
|
||||||
{"REPEAT", ducky_fnc_repeat, -1},
|
|
||||||
{"SYSRQ", ducky_fnc_sysrq, -1},
|
|
||||||
{"ALTCHAR", ducky_fnc_altchar, -1},
|
|
||||||
{"ALTSTRING", ducky_fnc_altstring, -1},
|
|
||||||
{"ALTCODE", ducky_fnc_altstring, -1},
|
|
||||||
{"HOLD", ducky_fnc_hold, -1},
|
|
||||||
{"RELEASE", ducky_fnc_release, -1},
|
|
||||||
{"WAIT_FOR_BUTTON_PRESS", ducky_fnc_waitforbutton, -1},
|
|
||||||
};
|
|
||||||
|
|
||||||
#define TAG "BadBT"
|
|
||||||
#define WORKER_TAG TAG "Worker"
|
|
||||||
|
|
||||||
int32_t ducky_execute_cmd(BadBtScript* bad_bt, const char* line) {
|
|
||||||
size_t cmd_word_len = strcspn(line, " ");
|
|
||||||
for(size_t i = 0; i < COUNT_OF(ducky_commands); i++) {
|
|
||||||
size_t cmd_compare_len = strlen(ducky_commands[i].name);
|
|
||||||
|
|
||||||
if(cmd_compare_len != cmd_word_len) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(strncmp(line, ducky_commands[i].name, cmd_compare_len) == 0) {
|
|
||||||
if(ducky_commands[i].callback == NULL) {
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
return ((ducky_commands[i].callback)(bad_bt, line, ducky_commands[i].param));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return SCRIPT_STATE_CMD_UNKNOWN;
|
|
||||||
}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <furi.h>
|
|
||||||
#include <furi_hal.h>
|
|
||||||
#include "ducky_script.h"
|
|
||||||
|
|
||||||
#define SCRIPT_STATE_ERROR (-1)
|
|
||||||
#define SCRIPT_STATE_END (-2)
|
|
||||||
#define SCRIPT_STATE_NEXT_LINE (-3)
|
|
||||||
#define SCRIPT_STATE_CMD_UNKNOWN (-4)
|
|
||||||
#define SCRIPT_STATE_STRING_START (-5)
|
|
||||||
#define SCRIPT_STATE_WAIT_FOR_BTN (-6)
|
|
||||||
|
|
||||||
uint16_t ducky_get_keycode(BadBtScript* bad_bt, const char* param, bool accept_chars);
|
|
||||||
|
|
||||||
uint32_t ducky_get_command_len(const char* line);
|
|
||||||
|
|
||||||
bool ducky_is_line_end(const char chr);
|
|
||||||
|
|
||||||
uint16_t ducky_get_keycode_by_name(const char* param);
|
|
||||||
|
|
||||||
bool ducky_get_number(const char* param, uint32_t* val);
|
|
||||||
|
|
||||||
void ducky_numlock_on(BadBtScript* bad_bt);
|
|
||||||
|
|
||||||
bool ducky_numpad_press(BadBtScript* bad_bt, const char num);
|
|
||||||
|
|
||||||
bool ducky_altchar(BadBtScript* bad_bt, const char* charcode);
|
|
||||||
|
|
||||||
bool ducky_altstring(BadBtScript* bad_bt, const char* param);
|
|
||||||
|
|
||||||
bool ducky_string(BadBtScript* bad_bt, const char* param);
|
|
||||||
|
|
||||||
int32_t ducky_execute_cmd(BadBtScript* bad_bt, const char* line);
|
|
||||||
|
|
||||||
int32_t ducky_error(BadBtScript* bad_bt, const char* text, ...);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
#include <furi_hal.h>
|
|
||||||
#include "ducky_script_i.h"
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
char* name;
|
|
||||||
uint16_t keycode;
|
|
||||||
} DuckyKey;
|
|
||||||
|
|
||||||
static const DuckyKey ducky_keys[] = {
|
|
||||||
{"CTRL-ALT", KEY_MOD_LEFT_CTRL | KEY_MOD_LEFT_ALT},
|
|
||||||
{"CTRL-SHIFT", KEY_MOD_LEFT_CTRL | KEY_MOD_LEFT_SHIFT},
|
|
||||||
{"ALT-SHIFT", KEY_MOD_LEFT_ALT | KEY_MOD_LEFT_SHIFT},
|
|
||||||
{"ALT-GUI", KEY_MOD_LEFT_ALT | KEY_MOD_LEFT_GUI},
|
|
||||||
{"GUI-SHIFT", KEY_MOD_LEFT_GUI | KEY_MOD_LEFT_SHIFT},
|
|
||||||
{"GUI-CTRL", KEY_MOD_LEFT_GUI | KEY_MOD_LEFT_CTRL},
|
|
||||||
|
|
||||||
{"CTRL", KEY_MOD_LEFT_CTRL},
|
|
||||||
{"CONTROL", KEY_MOD_LEFT_CTRL},
|
|
||||||
{"SHIFT", KEY_MOD_LEFT_SHIFT},
|
|
||||||
{"ALT", KEY_MOD_LEFT_ALT},
|
|
||||||
{"GUI", KEY_MOD_LEFT_GUI},
|
|
||||||
{"WINDOWS", KEY_MOD_LEFT_GUI},
|
|
||||||
|
|
||||||
{"DOWNARROW", HID_KEYBOARD_DOWN_ARROW},
|
|
||||||
{"DOWN", HID_KEYBOARD_DOWN_ARROW},
|
|
||||||
{"LEFTARROW", HID_KEYBOARD_LEFT_ARROW},
|
|
||||||
{"LEFT", HID_KEYBOARD_LEFT_ARROW},
|
|
||||||
{"RIGHTARROW", HID_KEYBOARD_RIGHT_ARROW},
|
|
||||||
{"RIGHT", HID_KEYBOARD_RIGHT_ARROW},
|
|
||||||
{"UPARROW", HID_KEYBOARD_UP_ARROW},
|
|
||||||
{"UP", HID_KEYBOARD_UP_ARROW},
|
|
||||||
|
|
||||||
{"ENTER", HID_KEYBOARD_RETURN},
|
|
||||||
{"BREAK", HID_KEYBOARD_PAUSE},
|
|
||||||
{"PAUSE", HID_KEYBOARD_PAUSE},
|
|
||||||
{"CAPSLOCK", HID_KEYBOARD_CAPS_LOCK},
|
|
||||||
{"DELETE", HID_KEYBOARD_DELETE_FORWARD},
|
|
||||||
{"BACKSPACE", HID_KEYBOARD_DELETE},
|
|
||||||
{"END", HID_KEYBOARD_END},
|
|
||||||
{"ESC", HID_KEYBOARD_ESCAPE},
|
|
||||||
{"ESCAPE", HID_KEYBOARD_ESCAPE},
|
|
||||||
{"HOME", HID_KEYBOARD_HOME},
|
|
||||||
{"INSERT", HID_KEYBOARD_INSERT},
|
|
||||||
{"NUMLOCK", HID_KEYPAD_NUMLOCK},
|
|
||||||
{"PAGEUP", HID_KEYBOARD_PAGE_UP},
|
|
||||||
{"PAGEDOWN", HID_KEYBOARD_PAGE_DOWN},
|
|
||||||
{"PRINTSCREEN", HID_KEYBOARD_PRINT_SCREEN},
|
|
||||||
{"SCROLLLOCK", HID_KEYBOARD_SCROLL_LOCK},
|
|
||||||
{"SPACE", HID_KEYBOARD_SPACEBAR},
|
|
||||||
{"TAB", HID_KEYBOARD_TAB},
|
|
||||||
{"MENU", HID_KEYBOARD_APPLICATION},
|
|
||||||
{"APP", HID_KEYBOARD_APPLICATION},
|
|
||||||
|
|
||||||
{"F1", HID_KEYBOARD_F1},
|
|
||||||
{"F2", HID_KEYBOARD_F2},
|
|
||||||
{"F3", HID_KEYBOARD_F3},
|
|
||||||
{"F4", HID_KEYBOARD_F4},
|
|
||||||
{"F5", HID_KEYBOARD_F5},
|
|
||||||
{"F6", HID_KEYBOARD_F6},
|
|
||||||
{"F7", HID_KEYBOARD_F7},
|
|
||||||
{"F8", HID_KEYBOARD_F8},
|
|
||||||
{"F9", HID_KEYBOARD_F9},
|
|
||||||
{"F10", HID_KEYBOARD_F10},
|
|
||||||
{"F11", HID_KEYBOARD_F11},
|
|
||||||
{"F12", HID_KEYBOARD_F12},
|
|
||||||
};
|
|
||||||
|
|
||||||
uint16_t ducky_get_keycode_by_name(const char* param) {
|
|
||||||
for(size_t i = 0; i < COUNT_OF(ducky_keys); i++) {
|
|
||||||
size_t key_cmd_len = strlen(ducky_keys[i].name);
|
|
||||||
if((strncmp(param, ducky_keys[i].name, key_cmd_len) == 0) &&
|
|
||||||
(ducky_is_line_end(param[key_cmd_len]))) {
|
|
||||||
return ducky_keys[i].keycode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return HID_KEYBOARD_NONE;
|
|
||||||
}
|
|
||||||
BIN
applications/external/bad_bt/images/badbt_10px.png
vendored
|
Before Width: | Height: | Size: 576 B |
@@ -1,30 +0,0 @@
|
|||||||
#include "bad_bt_scene.h"
|
|
||||||
|
|
||||||
// Generate scene on_enter handlers array
|
|
||||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
|
|
||||||
void (*const bad_bt_scene_on_enter_handlers[])(void*) = {
|
|
||||||
#include "bad_bt_scene_config.h"
|
|
||||||
};
|
|
||||||
#undef ADD_SCENE
|
|
||||||
|
|
||||||
// Generate scene on_event handlers array
|
|
||||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event,
|
|
||||||
bool (*const bad_bt_scene_on_event_handlers[])(void* context, SceneManagerEvent event) = {
|
|
||||||
#include "bad_bt_scene_config.h"
|
|
||||||
};
|
|
||||||
#undef ADD_SCENE
|
|
||||||
|
|
||||||
// Generate scene on_exit handlers array
|
|
||||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit,
|
|
||||||
void (*const bad_bt_scene_on_exit_handlers[])(void* context) = {
|
|
||||||
#include "bad_bt_scene_config.h"
|
|
||||||
};
|
|
||||||
#undef ADD_SCENE
|
|
||||||
|
|
||||||
// Initialize scene handlers configuration structure
|
|
||||||
const SceneManagerHandlers bad_bt_scene_handlers = {
|
|
||||||
.on_enter_handlers = bad_bt_scene_on_enter_handlers,
|
|
||||||
.on_event_handlers = bad_bt_scene_on_event_handlers,
|
|
||||||
.on_exit_handlers = bad_bt_scene_on_exit_handlers,
|
|
||||||
.scene_num = BadBtSceneNum,
|
|
||||||
};
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <gui/scene_manager.h>
|
|
||||||
|
|
||||||
// Generate scene id and total number
|
|
||||||
#define ADD_SCENE(prefix, name, id) BadBtScene##id,
|
|
||||||
typedef enum {
|
|
||||||
#include "bad_bt_scene_config.h"
|
|
||||||
BadBtSceneNum,
|
|
||||||
} BadBtScene;
|
|
||||||
#undef ADD_SCENE
|
|
||||||
|
|
||||||
extern const SceneManagerHandlers bad_bt_scene_handlers;
|
|
||||||
|
|
||||||
// Generate scene on_enter handlers declaration
|
|
||||||
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*);
|
|
||||||
#include "bad_bt_scene_config.h"
|
|
||||||
#undef ADD_SCENE
|
|
||||||
|
|
||||||
// Generate scene on_event handlers declaration
|
|
||||||
#define ADD_SCENE(prefix, name, id) \
|
|
||||||
bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event);
|
|
||||||
#include "bad_bt_scene_config.h"
|
|
||||||
#undef ADD_SCENE
|
|
||||||
|
|
||||||
// Generate scene on_exit handlers declaration
|
|
||||||
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context);
|
|
||||||
#include "bad_bt_scene_config.h"
|
|
||||||
#undef ADD_SCENE
|
|
||||||
@@ -1,104 +0,0 @@
|
|||||||
#include "../bad_bt_app.h"
|
|
||||||
#include "../helpers/ducky_script.h"
|
|
||||||
#include "furi_hal_power.h"
|
|
||||||
|
|
||||||
enum VarItemListIndex {
|
|
||||||
VarItemListIndexKeyboardLayout,
|
|
||||||
VarItemListIndexBtRemember,
|
|
||||||
VarItemListIndexBtDeviceName,
|
|
||||||
VarItemListIndexBtMacAddress,
|
|
||||||
VarItemListIndexRandomizeBtMac,
|
|
||||||
};
|
|
||||||
|
|
||||||
void bad_bt_scene_config_bt_remember_callback(VariableItem* item) {
|
|
||||||
BadBtApp* bad_bt = variable_item_get_context(item);
|
|
||||||
bad_bt->bt_remember = variable_item_get_current_value_index(item);
|
|
||||||
variable_item_set_current_value_text(item, bad_bt->bt_remember ? "ON" : "OFF");
|
|
||||||
view_dispatcher_send_custom_event(bad_bt->view_dispatcher, VarItemListIndexBtRemember);
|
|
||||||
}
|
|
||||||
|
|
||||||
void bad_bt_scene_config_var_item_list_callback(void* context, uint32_t index) {
|
|
||||||
BadBtApp* bad_bt = context;
|
|
||||||
view_dispatcher_send_custom_event(bad_bt->view_dispatcher, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
void bad_bt_scene_config_on_enter(void* context) {
|
|
||||||
BadBtApp* bad_bt = context;
|
|
||||||
VariableItemList* var_item_list = bad_bt->var_item_list;
|
|
||||||
VariableItem* item;
|
|
||||||
|
|
||||||
item = variable_item_list_add(var_item_list, "Keyboard layout", 0, NULL, bad_bt);
|
|
||||||
|
|
||||||
item = variable_item_list_add(
|
|
||||||
var_item_list, "BT Remember", 2, bad_bt_scene_config_bt_remember_callback, bad_bt);
|
|
||||||
variable_item_set_current_value_index(item, bad_bt->bt_remember);
|
|
||||||
variable_item_set_current_value_text(item, bad_bt->bt_remember ? "ON" : "OFF");
|
|
||||||
|
|
||||||
item = variable_item_list_add(var_item_list, "BT Device Name", 0, NULL, bad_bt);
|
|
||||||
if(bad_bt->bad_bt_script->set_bt_id) {
|
|
||||||
variable_item_set_locked(item, true, "Script has\nBT_ID cmd!\nLocked to\nset Name!");
|
|
||||||
}
|
|
||||||
|
|
||||||
item = variable_item_list_add(var_item_list, "BT MAC Address", 0, NULL, bad_bt);
|
|
||||||
if(bad_bt->bt_remember) {
|
|
||||||
variable_item_set_locked(item, true, "Remember\nmust be Off!");
|
|
||||||
} else if(bad_bt->bad_bt_script->set_bt_id) {
|
|
||||||
variable_item_set_locked(item, true, "Script has\nBT_ID cmd!\nLocked to\nset MAC!");
|
|
||||||
}
|
|
||||||
|
|
||||||
item = variable_item_list_add(var_item_list, "Randomize BT MAC", 0, NULL, bad_bt);
|
|
||||||
if(bad_bt->bt_remember) {
|
|
||||||
variable_item_set_locked(item, true, "Remember\nmust be Off!");
|
|
||||||
} else if(bad_bt->bad_bt_script->set_bt_id) {
|
|
||||||
variable_item_set_locked(item, true, "Script has\nBT_ID cmd!\nLocked to\nset MAC!");
|
|
||||||
}
|
|
||||||
|
|
||||||
variable_item_list_set_enter_callback(
|
|
||||||
var_item_list, bad_bt_scene_config_var_item_list_callback, bad_bt);
|
|
||||||
|
|
||||||
variable_item_list_set_selected_item(
|
|
||||||
var_item_list, scene_manager_get_scene_state(bad_bt->scene_manager, BadBtSceneConfig));
|
|
||||||
|
|
||||||
view_dispatcher_switch_to_view(bad_bt->view_dispatcher, BadBtAppViewConfig);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bad_bt_scene_config_on_event(void* context, SceneManagerEvent event) {
|
|
||||||
BadBtApp* bad_bt = context;
|
|
||||||
bool consumed = false;
|
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
|
||||||
scene_manager_set_scene_state(bad_bt->scene_manager, BadBtSceneConfig, event.event);
|
|
||||||
consumed = true;
|
|
||||||
switch(event.event) {
|
|
||||||
case VarItemListIndexKeyboardLayout:
|
|
||||||
scene_manager_next_scene(bad_bt->scene_manager, BadBtSceneConfigLayout);
|
|
||||||
break;
|
|
||||||
case VarItemListIndexBtRemember:
|
|
||||||
bad_bt_config_switch_remember_mode(bad_bt);
|
|
||||||
scene_manager_previous_scene(bad_bt->scene_manager);
|
|
||||||
scene_manager_next_scene(bad_bt->scene_manager, BadBtSceneConfig);
|
|
||||||
break;
|
|
||||||
case VarItemListIndexBtDeviceName:
|
|
||||||
scene_manager_next_scene(bad_bt->scene_manager, BadBtSceneConfigName);
|
|
||||||
break;
|
|
||||||
case VarItemListIndexBtMacAddress:
|
|
||||||
scene_manager_next_scene(bad_bt->scene_manager, BadBtSceneConfigMac);
|
|
||||||
break;
|
|
||||||
case VarItemListIndexRandomizeBtMac:
|
|
||||||
furi_hal_random_fill_buf(bad_bt->config.bt_mac, BAD_BT_MAC_ADDRESS_LEN);
|
|
||||||
bt_set_profile_mac_address(bad_bt->bt, bad_bt->config.bt_mac);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return consumed;
|
|
||||||
}
|
|
||||||
|
|
||||||
void bad_bt_scene_config_on_exit(void* context) {
|
|
||||||
BadBtApp* bad_bt = context;
|
|
||||||
VariableItemList* var_item_list = bad_bt->var_item_list;
|
|
||||||
|
|
||||||
variable_item_list_reset(var_item_list);
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
ADD_SCENE(bad_bt, file_select, FileSelect)
|
|
||||||
ADD_SCENE(bad_bt, work, Work)
|
|
||||||
ADD_SCENE(bad_bt, error, Error)
|
|
||||||
ADD_SCENE(bad_bt, config, Config)
|
|
||||||
ADD_SCENE(bad_bt, config_layout, ConfigLayout)
|
|
||||||
ADD_SCENE(bad_bt, config_name, ConfigName)
|
|
||||||
ADD_SCENE(bad_bt, config_mac, ConfigMac)
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
#include "../bad_bt_app.h"
|
|
||||||
#include "furi_hal_power.h"
|
|
||||||
#include <storage/storage.h>
|
|
||||||
|
|
||||||
static bool bad_bt_layout_select(BadBtApp* bad_bt) {
|
|
||||||
furi_assert(bad_bt);
|
|
||||||
|
|
||||||
FuriString* predefined_path;
|
|
||||||
predefined_path = furi_string_alloc();
|
|
||||||
if(!furi_string_empty(bad_bt->keyboard_layout)) {
|
|
||||||
furi_string_set(predefined_path, bad_bt->keyboard_layout);
|
|
||||||
} else {
|
|
||||||
furi_string_set(predefined_path, BAD_BT_APP_PATH_LAYOUT_FOLDER);
|
|
||||||
}
|
|
||||||
|
|
||||||
DialogsFileBrowserOptions browser_options;
|
|
||||||
dialog_file_browser_set_basic_options(
|
|
||||||
&browser_options, BAD_BT_APP_LAYOUT_EXTENSION, &I_keyboard_10px);
|
|
||||||
browser_options.base_path = BAD_BT_APP_PATH_LAYOUT_FOLDER;
|
|
||||||
browser_options.skip_assets = false;
|
|
||||||
|
|
||||||
// Input events and views are managed by file_browser
|
|
||||||
bool res = dialog_file_browser_show(
|
|
||||||
bad_bt->dialogs, bad_bt->keyboard_layout, predefined_path, &browser_options);
|
|
||||||
|
|
||||||
furi_string_free(predefined_path);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
void bad_bt_scene_config_layout_on_enter(void* context) {
|
|
||||||
BadBtApp* bad_bt = context;
|
|
||||||
|
|
||||||
if(bad_bt_layout_select(bad_bt)) {
|
|
||||||
bad_bt_script_set_keyboard_layout(bad_bt->bad_bt_script, bad_bt->keyboard_layout);
|
|
||||||
}
|
|
||||||
scene_manager_previous_scene(bad_bt->scene_manager);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bad_bt_scene_config_layout_on_event(void* context, SceneManagerEvent event) {
|
|
||||||
UNUSED(context);
|
|
||||||
UNUSED(event);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void bad_bt_scene_config_layout_on_exit(void* context) {
|
|
||||||
UNUSED(context);
|
|
||||||
}
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
#include "../bad_bt_app.h"
|
|
||||||
|
|
||||||
#define TAG "BadBtConfigMac"
|
|
||||||
|
|
||||||
void bad_bt_scene_config_mac_byte_input_callback(void* context) {
|
|
||||||
BadBtApp* bad_bt = context;
|
|
||||||
|
|
||||||
view_dispatcher_send_custom_event(bad_bt->view_dispatcher, BadBtAppCustomEventByteInputDone);
|
|
||||||
}
|
|
||||||
|
|
||||||
void bad_bt_scene_config_mac_on_enter(void* context) {
|
|
||||||
BadBtApp* bad_bt = context;
|
|
||||||
|
|
||||||
furi_hal_bt_reverse_mac_addr(bad_bt->config.bt_mac);
|
|
||||||
|
|
||||||
// Setup view
|
|
||||||
ByteInput* byte_input = bad_bt->byte_input;
|
|
||||||
byte_input_set_header_text(byte_input, "Set BT MAC address");
|
|
||||||
byte_input_set_result_callback(
|
|
||||||
byte_input,
|
|
||||||
bad_bt_scene_config_mac_byte_input_callback,
|
|
||||||
NULL,
|
|
||||||
bad_bt,
|
|
||||||
bad_bt->config.bt_mac,
|
|
||||||
GAP_MAC_ADDR_SIZE);
|
|
||||||
view_dispatcher_switch_to_view(bad_bt->view_dispatcher, BadBtAppViewConfigMac);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bad_bt_scene_config_mac_on_event(void* context, SceneManagerEvent event) {
|
|
||||||
BadBtApp* bad_bt = context;
|
|
||||||
bool consumed = false;
|
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
|
||||||
if(event.event == BadBtAppCustomEventByteInputDone) {
|
|
||||||
scene_manager_previous_scene(bad_bt->scene_manager);
|
|
||||||
consumed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return consumed;
|
|
||||||
}
|
|
||||||
|
|
||||||
void bad_bt_scene_config_mac_on_exit(void* context) {
|
|
||||||
BadBtApp* bad_bt = context;
|
|
||||||
|
|
||||||
furi_hal_bt_reverse_mac_addr(bad_bt->config.bt_mac);
|
|
||||||
|
|
||||||
bt_set_profile_mac_address(bad_bt->bt, bad_bt->config.bt_mac);
|
|
||||||
|
|
||||||
// Clear view
|
|
||||||
byte_input_set_result_callback(bad_bt->byte_input, NULL, NULL, NULL, NULL, 0);
|
|
||||||
byte_input_set_header_text(bad_bt->byte_input, "");
|
|
||||||
}
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
#include "../bad_bt_app.h"
|
|
||||||
|
|
||||||
static void bad_bt_scene_config_name_text_input_callback(void* context) {
|
|
||||||
BadBtApp* bad_bt = context;
|
|
||||||
|
|
||||||
view_dispatcher_send_custom_event(bad_bt->view_dispatcher, BadBtAppCustomEventTextEditResult);
|
|
||||||
}
|
|
||||||
|
|
||||||
void bad_bt_scene_config_name_on_enter(void* context) {
|
|
||||||
BadBtApp* bad_bt = context;
|
|
||||||
TextInput* text_input = bad_bt->text_input;
|
|
||||||
|
|
||||||
text_input_set_header_text(text_input, "Set BT device name");
|
|
||||||
|
|
||||||
text_input_set_result_callback(
|
|
||||||
text_input,
|
|
||||||
bad_bt_scene_config_name_text_input_callback,
|
|
||||||
bad_bt,
|
|
||||||
bad_bt->config.bt_name,
|
|
||||||
BAD_BT_ADV_NAME_MAX_LEN,
|
|
||||||
true);
|
|
||||||
|
|
||||||
view_dispatcher_switch_to_view(bad_bt->view_dispatcher, BadBtAppViewConfigName);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bad_bt_scene_config_name_on_event(void* context, SceneManagerEvent event) {
|
|
||||||
BadBtApp* bad_bt = context;
|
|
||||||
bool consumed = false;
|
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
|
||||||
consumed = true;
|
|
||||||
if(event.event == BadBtAppCustomEventTextEditResult) {
|
|
||||||
bt_set_profile_adv_name(bad_bt->bt, bad_bt->config.bt_name);
|
|
||||||
}
|
|
||||||
scene_manager_previous_scene(bad_bt->scene_manager);
|
|
||||||
}
|
|
||||||
return consumed;
|
|
||||||
}
|
|
||||||
|
|
||||||
void bad_bt_scene_config_name_on_exit(void* context) {
|
|
||||||
BadBtApp* bad_bt = context;
|
|
||||||
TextInput* text_input = bad_bt->text_input;
|
|
||||||
|
|
||||||
text_input_reset(text_input);
|
|
||||||
}
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
#include "../bad_bt_app.h"
|
|
||||||
|
|
||||||
static void
|
|
||||||
bad_bt_scene_error_event_callback(GuiButtonType result, InputType type, void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
BadBtApp* app = context;
|
|
||||||
|
|
||||||
if((result == GuiButtonTypeLeft) && (type == InputTypeShort)) {
|
|
||||||
view_dispatcher_send_custom_event(app->view_dispatcher, BadBtCustomEventErrorBack);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void bad_bt_scene_error_on_enter(void* context) {
|
|
||||||
BadBtApp* app = context;
|
|
||||||
|
|
||||||
if(app->error == BadBtAppErrorNoFiles) {
|
|
||||||
widget_add_icon_element(app->widget, 0, 0, &I_SDQuestion_35x43);
|
|
||||||
widget_add_string_multiline_element(
|
|
||||||
app->widget,
|
|
||||||
81,
|
|
||||||
4,
|
|
||||||
AlignCenter,
|
|
||||||
AlignTop,
|
|
||||||
FontSecondary,
|
|
||||||
"No SD card or\napp data found.\nThis app will not\nwork without\nrequired files.");
|
|
||||||
widget_add_button_element(
|
|
||||||
app->widget, GuiButtonTypeLeft, "Back", bad_bt_scene_error_event_callback, app);
|
|
||||||
} else if(app->error == BadBtAppErrorCloseRpc) {
|
|
||||||
widget_add_icon_element(app->widget, 78, 0, &I_ActiveConnection_50x64);
|
|
||||||
widget_add_string_multiline_element(
|
|
||||||
app->widget, 3, 2, AlignLeft, AlignTop, FontPrimary, "Connection\nis active!");
|
|
||||||
widget_add_string_multiline_element(
|
|
||||||
app->widget,
|
|
||||||
3,
|
|
||||||
30,
|
|
||||||
AlignLeft,
|
|
||||||
AlignTop,
|
|
||||||
FontSecondary,
|
|
||||||
"Disconnect from\nPC or phone to\nuse this function.");
|
|
||||||
}
|
|
||||||
|
|
||||||
view_dispatcher_switch_to_view(app->view_dispatcher, BadBtAppViewError);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bad_bt_scene_error_on_event(void* context, SceneManagerEvent event) {
|
|
||||||
BadBtApp* app = context;
|
|
||||||
bool consumed = false;
|
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
|
||||||
if(event.event == BadBtCustomEventErrorBack) {
|
|
||||||
view_dispatcher_stop(app->view_dispatcher);
|
|
||||||
consumed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return consumed;
|
|
||||||
}
|
|
||||||
|
|
||||||
void bad_bt_scene_error_on_exit(void* context) {
|
|
||||||
BadBtApp* app = context;
|
|
||||||
widget_reset(app->widget);
|
|
||||||
}
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
#include "../bad_bt_app.h"
|
|
||||||
#include <furi_hal_power.h>
|
|
||||||
#include <storage/storage.h>
|
|
||||||
|
|
||||||
static bool bad_bt_file_select(BadBtApp* bad_bt) {
|
|
||||||
furi_assert(bad_bt);
|
|
||||||
|
|
||||||
DialogsFileBrowserOptions browser_options;
|
|
||||||
dialog_file_browser_set_basic_options(
|
|
||||||
&browser_options, BAD_BT_APP_SCRIPT_EXTENSION, &I_badbt_10px);
|
|
||||||
browser_options.base_path = BAD_BT_APP_BASE_FOLDER;
|
|
||||||
browser_options.skip_assets = true;
|
|
||||||
|
|
||||||
// Input events and views are managed by file_browser
|
|
||||||
bool res = dialog_file_browser_show(
|
|
||||||
bad_bt->dialogs, bad_bt->file_path, bad_bt->file_path, &browser_options);
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
void bad_bt_scene_file_select_on_enter(void* context) {
|
|
||||||
BadBtApp* bad_bt = context;
|
|
||||||
|
|
||||||
if(bad_bt->bad_bt_script) {
|
|
||||||
bad_bt_script_close(bad_bt->bad_bt_script);
|
|
||||||
bad_bt->bad_bt_script = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(bad_bt_file_select(bad_bt)) {
|
|
||||||
bad_bt->bad_bt_script = bad_bt_script_open(bad_bt->file_path, bad_bt->bt, bad_bt);
|
|
||||||
bad_bt_script_set_keyboard_layout(bad_bt->bad_bt_script, bad_bt->keyboard_layout);
|
|
||||||
|
|
||||||
scene_manager_next_scene(bad_bt->scene_manager, BadBtSceneWork);
|
|
||||||
} else {
|
|
||||||
view_dispatcher_stop(bad_bt->view_dispatcher);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bad_bt_scene_file_select_on_event(void* context, SceneManagerEvent event) {
|
|
||||||
UNUSED(context);
|
|
||||||
UNUSED(event);
|
|
||||||
// BadBtApp* bad_bt = context;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void bad_bt_scene_file_select_on_exit(void* context) {
|
|
||||||
UNUSED(context);
|
|
||||||
// BadBtApp* bad_bt = context;
|
|
||||||
}
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
#include "../helpers/ducky_script.h"
|
|
||||||
#include "../bad_bt_app.h"
|
|
||||||
#include "../views/bad_bt_view.h"
|
|
||||||
#include <furi_hal.h>
|
|
||||||
#include "toolbox/path.h"
|
|
||||||
|
|
||||||
void bad_bt_scene_work_button_callback(InputKey key, void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
BadBtApp* app = context;
|
|
||||||
view_dispatcher_send_custom_event(app->view_dispatcher, key);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bad_bt_scene_work_on_event(void* context, SceneManagerEvent event) {
|
|
||||||
BadBtApp* app = context;
|
|
||||||
bool consumed = false;
|
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
|
||||||
if(event.event == InputKeyLeft) {
|
|
||||||
if(bad_bt_is_idle_state(app->bad_bt_view)) {
|
|
||||||
scene_manager_next_scene(app->scene_manager, BadBtSceneConfig);
|
|
||||||
}
|
|
||||||
consumed = true;
|
|
||||||
} else if(event.event == InputKeyOk) {
|
|
||||||
bad_bt_script_toggle(app->bad_bt_script);
|
|
||||||
consumed = true;
|
|
||||||
}
|
|
||||||
} else if(event.type == SceneManagerEventTypeTick) {
|
|
||||||
bad_bt_set_state(app->bad_bt_view, bad_bt_script_get_state(app->bad_bt_script));
|
|
||||||
}
|
|
||||||
return consumed;
|
|
||||||
}
|
|
||||||
|
|
||||||
void bad_bt_scene_work_on_enter(void* context) {
|
|
||||||
BadBtApp* app = context;
|
|
||||||
|
|
||||||
FuriString* file_name;
|
|
||||||
file_name = furi_string_alloc();
|
|
||||||
path_extract_filename(app->file_path, file_name, true);
|
|
||||||
bad_bt_set_file_name(app->bad_bt_view, furi_string_get_cstr(file_name));
|
|
||||||
furi_string_free(file_name);
|
|
||||||
|
|
||||||
FuriString* layout;
|
|
||||||
layout = furi_string_alloc();
|
|
||||||
path_extract_filename(app->keyboard_layout, layout, true);
|
|
||||||
bad_bt_set_layout(app->bad_bt_view, furi_string_get_cstr(layout));
|
|
||||||
furi_string_free(layout);
|
|
||||||
|
|
||||||
bad_bt_set_state(app->bad_bt_view, bad_bt_script_get_state(app->bad_bt_script));
|
|
||||||
|
|
||||||
bad_bt_set_button_callback(app->bad_bt_view, bad_bt_scene_work_button_callback, app);
|
|
||||||
view_dispatcher_switch_to_view(app->view_dispatcher, BadBtAppViewWork);
|
|
||||||
}
|
|
||||||
|
|
||||||
void bad_bt_scene_work_on_exit(void* context) {
|
|
||||||
UNUSED(context);
|
|
||||||
}
|
|
||||||
233
applications/external/bad_bt/views/bad_bt_view.c
vendored
@@ -1,233 +0,0 @@
|
|||||||
#include "bad_bt_view.h"
|
|
||||||
#include "../helpers/ducky_script.h"
|
|
||||||
#include "../bad_bt_app.h"
|
|
||||||
#include <toolbox/path.h>
|
|
||||||
#include <gui/elements.h>
|
|
||||||
#include <assets_icons.h>
|
|
||||||
|
|
||||||
#define MAX_NAME_LEN 64
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
char file_name[MAX_NAME_LEN];
|
|
||||||
char layout[MAX_NAME_LEN];
|
|
||||||
BadBtState state;
|
|
||||||
uint8_t anim_frame;
|
|
||||||
} BadBtModel;
|
|
||||||
|
|
||||||
static void bad_bt_draw_callback(Canvas* canvas, void* _model) {
|
|
||||||
BadBtModel* model = _model;
|
|
||||||
|
|
||||||
FuriString* disp_str;
|
|
||||||
disp_str = furi_string_alloc_set("(BT) ");
|
|
||||||
furi_string_cat_str(disp_str, model->file_name);
|
|
||||||
elements_string_fit_width(canvas, disp_str, 128 - 2);
|
|
||||||
canvas_set_font(canvas, FontSecondary);
|
|
||||||
canvas_draw_str(canvas, 2, 8, furi_string_get_cstr(disp_str));
|
|
||||||
|
|
||||||
if(strlen(model->layout) == 0) {
|
|
||||||
furi_string_set(disp_str, "(default)");
|
|
||||||
} else {
|
|
||||||
furi_string_reset(disp_str);
|
|
||||||
furi_string_push_back(disp_str, '(');
|
|
||||||
for(size_t i = 0; i < strlen(model->layout); i++)
|
|
||||||
furi_string_push_back(disp_str, model->layout[i]);
|
|
||||||
furi_string_push_back(disp_str, ')');
|
|
||||||
}
|
|
||||||
if(model->state.pin) {
|
|
||||||
furi_string_cat_printf(disp_str, " PIN: %ld", model->state.pin);
|
|
||||||
}
|
|
||||||
elements_string_fit_width(canvas, disp_str, 128 - 2);
|
|
||||||
canvas_draw_str(
|
|
||||||
canvas, 2, 8 + canvas_current_font_height(canvas), furi_string_get_cstr(disp_str));
|
|
||||||
|
|
||||||
furi_string_reset(disp_str);
|
|
||||||
|
|
||||||
if((model->state.state == BadBtStateIdle) || (model->state.state == BadBtStateDone) ||
|
|
||||||
(model->state.state == BadBtStateNotConnected)) {
|
|
||||||
elements_button_center(canvas, "Run");
|
|
||||||
elements_button_left(canvas, "Config");
|
|
||||||
} else if((model->state.state == BadBtStateRunning) || (model->state.state == BadBtStateDelay)) {
|
|
||||||
elements_button_center(canvas, "Stop");
|
|
||||||
} else if(model->state.state == BadBtStateWaitForBtn) {
|
|
||||||
elements_button_center(canvas, "Press to continue");
|
|
||||||
} else if(model->state.state == BadBtStateWillRun) {
|
|
||||||
elements_button_center(canvas, "Cancel");
|
|
||||||
}
|
|
||||||
|
|
||||||
if(model->state.state == BadBtStateNotConnected) {
|
|
||||||
canvas_draw_icon(canvas, 4, 26, &I_Clock_18x18);
|
|
||||||
canvas_set_font(canvas, FontPrimary);
|
|
||||||
canvas_draw_str_aligned(canvas, 127, 31, AlignRight, AlignBottom, "Connect to");
|
|
||||||
canvas_draw_str_aligned(canvas, 127, 43, AlignRight, AlignBottom, "a device");
|
|
||||||
} else if(model->state.state == BadBtStateWillRun) {
|
|
||||||
canvas_draw_icon(canvas, 4, 26, &I_Clock_18x18);
|
|
||||||
canvas_set_font(canvas, FontPrimary);
|
|
||||||
canvas_draw_str_aligned(canvas, 127, 31, AlignRight, AlignBottom, "Will run");
|
|
||||||
canvas_draw_str_aligned(canvas, 127, 43, AlignRight, AlignBottom, "on connect");
|
|
||||||
} else if(model->state.state == BadBtStateFileError) {
|
|
||||||
canvas_draw_icon(canvas, 4, 26, &I_Error_18x18);
|
|
||||||
canvas_set_font(canvas, FontPrimary);
|
|
||||||
canvas_draw_str_aligned(canvas, 127, 31, AlignRight, AlignBottom, "File");
|
|
||||||
canvas_draw_str_aligned(canvas, 127, 43, AlignRight, AlignBottom, "ERROR");
|
|
||||||
} else if(model->state.state == BadBtStateScriptError) {
|
|
||||||
canvas_draw_icon(canvas, 4, 26, &I_Error_18x18);
|
|
||||||
canvas_set_font(canvas, FontPrimary);
|
|
||||||
canvas_draw_str_aligned(canvas, 127, 33, AlignRight, AlignBottom, "ERROR:");
|
|
||||||
canvas_set_font(canvas, FontSecondary);
|
|
||||||
furi_string_printf(disp_str, "line %u", model->state.error_line);
|
|
||||||
canvas_draw_str_aligned(
|
|
||||||
canvas, 127, 46, AlignRight, AlignBottom, furi_string_get_cstr(disp_str));
|
|
||||||
furi_string_reset(disp_str);
|
|
||||||
furi_string_set_str(disp_str, model->state.error);
|
|
||||||
elements_string_fit_width(canvas, disp_str, canvas_width(canvas));
|
|
||||||
canvas_draw_str_aligned(
|
|
||||||
canvas, 127, 56, AlignRight, AlignBottom, furi_string_get_cstr(disp_str));
|
|
||||||
furi_string_reset(disp_str);
|
|
||||||
} else if(model->state.state == BadBtStateIdle) {
|
|
||||||
canvas_draw_icon(canvas, 4, 26, &I_Smile_18x18);
|
|
||||||
canvas_set_font(canvas, FontBigNumbers);
|
|
||||||
canvas_draw_str_aligned(canvas, 114, 40, AlignRight, AlignBottom, "0");
|
|
||||||
canvas_draw_icon(canvas, 117, 26, &I_Percent_10x14);
|
|
||||||
} else if(model->state.state == BadBtStateRunning) {
|
|
||||||
if(model->anim_frame == 0) {
|
|
||||||
canvas_draw_icon(canvas, 4, 23, &I_EviSmile1_18x21);
|
|
||||||
} else {
|
|
||||||
canvas_draw_icon(canvas, 4, 23, &I_EviSmile2_18x21);
|
|
||||||
}
|
|
||||||
canvas_set_font(canvas, FontBigNumbers);
|
|
||||||
furi_string_printf(
|
|
||||||
disp_str, "%u", ((model->state.line_cur - 1) * 100) / model->state.line_nb);
|
|
||||||
canvas_draw_str_aligned(
|
|
||||||
canvas, 114, 40, AlignRight, AlignBottom, furi_string_get_cstr(disp_str));
|
|
||||||
furi_string_reset(disp_str);
|
|
||||||
canvas_draw_icon(canvas, 117, 26, &I_Percent_10x14);
|
|
||||||
} else if(model->state.state == BadBtStateDone) {
|
|
||||||
canvas_draw_icon(canvas, 4, 23, &I_EviSmile1_18x21);
|
|
||||||
canvas_set_font(canvas, FontBigNumbers);
|
|
||||||
canvas_draw_str_aligned(canvas, 114, 40, AlignRight, AlignBottom, "100");
|
|
||||||
furi_string_reset(disp_str);
|
|
||||||
canvas_draw_icon(canvas, 117, 26, &I_Percent_10x14);
|
|
||||||
} else if(model->state.state == BadBtStateDelay) {
|
|
||||||
if(model->anim_frame == 0) {
|
|
||||||
canvas_draw_icon(canvas, 4, 23, &I_EviWaiting1_18x21);
|
|
||||||
} else {
|
|
||||||
canvas_draw_icon(canvas, 4, 23, &I_EviWaiting2_18x21);
|
|
||||||
}
|
|
||||||
canvas_set_font(canvas, FontBigNumbers);
|
|
||||||
furi_string_printf(
|
|
||||||
disp_str, "%u", ((model->state.line_cur - 1) * 100) / model->state.line_nb);
|
|
||||||
canvas_draw_str_aligned(
|
|
||||||
canvas, 114, 40, AlignRight, AlignBottom, furi_string_get_cstr(disp_str));
|
|
||||||
furi_string_reset(disp_str);
|
|
||||||
canvas_draw_icon(canvas, 117, 26, &I_Percent_10x14);
|
|
||||||
canvas_set_font(canvas, FontSecondary);
|
|
||||||
furi_string_printf(disp_str, "delay %lus", model->state.delay_remain);
|
|
||||||
canvas_draw_str_aligned(
|
|
||||||
canvas, 127, 50, AlignRight, AlignBottom, furi_string_get_cstr(disp_str));
|
|
||||||
furi_string_reset(disp_str);
|
|
||||||
} else {
|
|
||||||
canvas_draw_icon(canvas, 4, 26, &I_Clock_18x18);
|
|
||||||
}
|
|
||||||
|
|
||||||
furi_string_free(disp_str);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool bad_bt_input_callback(InputEvent* event, void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
BadBt* bad_bt = context;
|
|
||||||
bool consumed = false;
|
|
||||||
|
|
||||||
if(event->type == InputTypeShort) {
|
|
||||||
if((event->key == InputKeyLeft) || (event->key == InputKeyOk)) {
|
|
||||||
consumed = true;
|
|
||||||
furi_assert(bad_bt->callback);
|
|
||||||
bad_bt->callback(event->key, bad_bt->context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return consumed;
|
|
||||||
}
|
|
||||||
|
|
||||||
BadBt* bad_bt_alloc() {
|
|
||||||
BadBt* bad_bt = malloc(sizeof(BadBt));
|
|
||||||
|
|
||||||
bad_bt->view = view_alloc();
|
|
||||||
view_allocate_model(bad_bt->view, ViewModelTypeLocking, sizeof(BadBtModel));
|
|
||||||
view_set_context(bad_bt->view, bad_bt);
|
|
||||||
view_set_draw_callback(bad_bt->view, bad_bt_draw_callback);
|
|
||||||
view_set_input_callback(bad_bt->view, bad_bt_input_callback);
|
|
||||||
|
|
||||||
return bad_bt;
|
|
||||||
}
|
|
||||||
|
|
||||||
void bad_bt_free(BadBt* bad_bt) {
|
|
||||||
furi_assert(bad_bt);
|
|
||||||
view_free(bad_bt->view);
|
|
||||||
free(bad_bt);
|
|
||||||
}
|
|
||||||
|
|
||||||
View* bad_bt_get_view(BadBt* bad_bt) {
|
|
||||||
furi_assert(bad_bt);
|
|
||||||
return bad_bt->view;
|
|
||||||
}
|
|
||||||
|
|
||||||
void bad_bt_set_button_callback(BadBt* bad_bt, BadBtButtonCallback callback, void* context) {
|
|
||||||
furi_assert(bad_bt);
|
|
||||||
furi_assert(callback);
|
|
||||||
with_view_model(
|
|
||||||
bad_bt->view,
|
|
||||||
BadBtModel * model,
|
|
||||||
{
|
|
||||||
UNUSED(model);
|
|
||||||
bad_bt->callback = callback;
|
|
||||||
bad_bt->context = context;
|
|
||||||
},
|
|
||||||
true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void bad_bt_set_file_name(BadBt* bad_bt, const char* name) {
|
|
||||||
furi_assert(name);
|
|
||||||
with_view_model(
|
|
||||||
bad_bt->view, BadBtModel * model, { strlcpy(model->file_name, name, MAX_NAME_LEN); }, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void bad_bt_set_layout(BadBt* bad_bt, const char* layout) {
|
|
||||||
furi_assert(layout);
|
|
||||||
with_view_model(
|
|
||||||
bad_bt->view, BadBtModel * model, { strlcpy(model->layout, layout, MAX_NAME_LEN); }, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void bad_bt_set_state(BadBt* bad_bt, BadBtState* st) {
|
|
||||||
furi_assert(st);
|
|
||||||
uint32_t pin = 0;
|
|
||||||
if(bad_bt->context != NULL) {
|
|
||||||
BadBtApp* app = bad_bt->context;
|
|
||||||
if(app->bt != NULL) {
|
|
||||||
pin = app->bt->pin;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
st->pin = pin;
|
|
||||||
with_view_model(
|
|
||||||
bad_bt->view,
|
|
||||||
BadBtModel * model,
|
|
||||||
{
|
|
||||||
memcpy(&(model->state), st, sizeof(BadBtState));
|
|
||||||
model->anim_frame ^= 1;
|
|
||||||
},
|
|
||||||
true);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bad_bt_is_idle_state(BadBt* bad_bt) {
|
|
||||||
bool is_idle = false;
|
|
||||||
with_view_model(
|
|
||||||
bad_bt->view,
|
|
||||||
BadBtModel * model,
|
|
||||||
{
|
|
||||||
if((model->state.state == BadBtStateIdle) || (model->state.state == BadBtStateDone) ||
|
|
||||||
(model->state.state == BadBtStateNotConnected)) {
|
|
||||||
is_idle = true;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
false);
|
|
||||||
return is_idle;
|
|
||||||
}
|
|
||||||
29
applications/external/bad_bt/views/bad_bt_view.h
vendored
@@ -1,29 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <gui/view.h>
|
|
||||||
|
|
||||||
typedef void (*BadBtButtonCallback)(InputKey key, void* context);
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
View* view;
|
|
||||||
BadBtButtonCallback callback;
|
|
||||||
void* context;
|
|
||||||
} BadBt;
|
|
||||||
|
|
||||||
typedef struct BadBtState BadBtState;
|
|
||||||
|
|
||||||
BadBt* bad_bt_alloc();
|
|
||||||
|
|
||||||
void bad_bt_free(BadBt* bad_bt);
|
|
||||||
|
|
||||||
View* bad_bt_get_view(BadBt* bad_bt);
|
|
||||||
|
|
||||||
void bad_bt_set_button_callback(BadBt* bad_bt, BadBtButtonCallback callback, void* context);
|
|
||||||
|
|
||||||
void bad_bt_set_file_name(BadBt* bad_bt, const char* name);
|
|
||||||
|
|
||||||
void bad_bt_set_layout(BadBt* bad_bt, const char* layout);
|
|
||||||
|
|
||||||
void bad_bt_set_state(BadBt* bad_bt, BadBtState* st);
|
|
||||||
|
|
||||||
bool bad_bt_is_idle_state(BadBt* bad_bt);
|
|
||||||
22
applications/external/barcode_gen/LICENSE
vendored
@@ -1,22 +0,0 @@
|
|||||||
|
|
||||||
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.
|
|
||||||
88
applications/external/barcode_gen/README.md
vendored
@@ -1,88 +0,0 @@
|
|||||||
<p align="center">
|
|
||||||
<h1 align="center">Barcode Generator</h1>
|
|
||||||
<p align="center">
|
|
||||||
|
|
||||||
A barcode generator for the Flipper Zero that supports **UPC-A**, **EAN-8**, **EAN-13**, **Code-39**, **Codabar**, and **Code-128**[1]
|
|
||||||
</p>
|
|
||||||
|
|
||||||
Note: Barcode save locations have been moved from `/barcodes` to `/apps_data/barcodes`
|
|
||||||
|
|
||||||
## Table of Contents
|
|
||||||
- [Table of Contents](#table-of-contents)
|
|
||||||
- [Installing](#installing)
|
|
||||||
- [Building](#building)
|
|
||||||
- [Usage](#usage)
|
|
||||||
- [Creating a barcode](#creating-a-barcode)
|
|
||||||
- [Editing a barcode](#editing-a-barcode)
|
|
||||||
- [Deleting a barcode](#deleting-a-barcode)
|
|
||||||
- [Viewing a barcode](#viewing-a-barcode)
|
|
||||||
- [Screenshots](#screenshots)
|
|
||||||
- [Credits](#credits)
|
|
||||||
|
|
||||||
|
|
||||||
## Installing
|
|
||||||
1) Download the `.zip` file from the release section
|
|
||||||
2) Extract/unzip the `.zip` file onto your computer
|
|
||||||
3) Open qFlipper and go to the file manager
|
|
||||||
4) Navigate to the `apps` folder
|
|
||||||
5) Drag & drop the `.fap` file into the `apps` folder
|
|
||||||
6) Navigate back to the root folder of the SD card and create the folder `apps_data`, if not already there
|
|
||||||
7) Navigate into `apps_data` and create another folder called `barcode_data`
|
|
||||||
8) Navigate into `barcode_data`
|
|
||||||
9) Drag & drop the encoding txts (`code39_encodings.txt`, `code128_encodings.txt` & `codabar_encodings.txt`) into the `barcode_data` folder
|
|
||||||
|
|
||||||
## Building
|
|
||||||
1) Clone the [flipperzero-firmware](https://github.com/flipperdevices/flipperzero-firmware) repository or a firmware of your choice
|
|
||||||
2) Clone this repository and put it in the `applications_user` folder
|
|
||||||
3) Build this app by using the command `./fbt fap_Barcode_App`
|
|
||||||
4) Copy the `.fap` from `build\f7-firmware-D\.extapps\Barcode_App.fap` to `apps\Misc` using the qFlipper app
|
|
||||||
5) While still in the qFlipper app, navigate to the root folder of the SD card and create the folder `apps_data`, if not already there
|
|
||||||
6) Navigate into `apps_data` and create another folder called `barcode_data`
|
|
||||||
7) Navigate into `barcode_data`
|
|
||||||
8) Drag & drop the encoding txts (`code39_encodings.txt`, `code128_encodings.txt` & `codabar_encodings.txt`) from the `encoding_tables` folder in this repository into the `barcode_data` folder
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
### Creating a barcode
|
|
||||||
1) To create a barcode click on `Create Barcode`
|
|
||||||
2) Next select your type using the left and right arrows
|
|
||||||
3) Enter your filename and then your barcode data
|
|
||||||
4) Click save
|
|
||||||
|
|
||||||
**Note**: For Codabar barcodes, you must manually add the start and stop codes to the barcode data
|
|
||||||
Start/Stop codes can be A, B, C, or D
|
|
||||||
For example, if you wanted to represent `1234` as a barcode you will need to enter something like `A1234A`. (You can replace the letters A with either A, B, C, or D)
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
### 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
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
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_file_assets="barcode_encoding_files",
|
|
||||||
fap_author="@Kingal1337",
|
|
||||||
fap_weburl="https://github.com/Kingal1337/flipper-barcode-generator",
|
|
||||||
fap_version="1.1",
|
|
||||||
fap_description="App allows you to display various barcodes on flipper screen",
|
|
||||||
)
|
|
||||||
348
applications/external/barcode_gen/barcode_app.c
vendored
@@ -1,348 +0,0 @@
|
|||||||
#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;
|
|
||||||
}
|
|
||||||
88
applications/external/barcode_gen/barcode_app.h
vendored
@@ -1,88 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <furi.h>
|
|
||||||
#include <furi_hal.h>
|
|
||||||
|
|
||||||
#include <gui/gui.h>
|
|
||||||
#include <input/input.h>
|
|
||||||
#include <dialogs/dialogs.h>
|
|
||||||
#include <gui/view_dispatcher.h>
|
|
||||||
#include <gui/modules/submenu.h>
|
|
||||||
#include <gui/modules/text_input.h>
|
|
||||||
#include <gui/modules/text_input.h>
|
|
||||||
|
|
||||||
#include <flipper_format/flipper_format.h>
|
|
||||||
|
|
||||||
#include "barcode_utils.h"
|
|
||||||
|
|
||||||
#define TAG "BARCODE"
|
|
||||||
#define VERSION "1.1"
|
|
||||||
#define FILE_VERSION "1"
|
|
||||||
|
|
||||||
#define TEXT_BUFFER_SIZE 128
|
|
||||||
|
|
||||||
#define BARCODE_HEIGHT 50
|
|
||||||
#define BARCODE_Y_START 3
|
|
||||||
|
|
||||||
//the folder where the codabar encoding table is located
|
|
||||||
#define CODABAR_DICT_FILE_PATH APP_ASSETS_PATH("codabar_encodings.txt")
|
|
||||||
|
|
||||||
//the folder where the code 39 encoding table is located
|
|
||||||
#define CODE39_DICT_FILE_PATH APP_ASSETS_PATH("code39_encodings.txt")
|
|
||||||
|
|
||||||
//the folder where the code 128 encoding table is located
|
|
||||||
#define CODE128_DICT_FILE_PATH APP_ASSETS_PATH("code128_encodings.txt")
|
|
||||||
|
|
||||||
//the folder where the code 128 C encoding table is located
|
|
||||||
#define CODE128C_DICT_FILE_PATH APP_ASSETS_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);
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
# 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
|
|
||||||
@@ -1,202 +0,0 @@
|
|||||||
: 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
|
|
||||||
@@ -1,106 +0,0 @@
|
|||||||
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
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
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
|
|
||||||
147
applications/external/barcode_gen/barcode_utils.c
vendored
@@ -1,147 +0,0 @@
|
|||||||
#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";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
|
|
||||||
#pragma once
|
|
||||||
#include <furi.h>
|
|
||||||
#include <furi_hal.h>
|
|
||||||
|
|
||||||
#define NUMBER_OF_BARCODE_TYPES 8
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
WrongNumberOfDigits, //There is too many or too few digits in the barcode
|
|
||||||
InvalidCharacters, //The barcode contains invalid characters
|
|
||||||
UnsupportedType, //the barcode type is not supported
|
|
||||||
FileOpening, //A problem occurred when opening the barcode data file
|
|
||||||
InvalidFileData, //One of the key in the file doesn't exist or there is a typo
|
|
||||||
MissingEncodingTable, //The encoding table txt for the barcode type is missing
|
|
||||||
EncodingTableError, //Something is wrong with the encoding table, probably missing data or typo
|
|
||||||
OKCode
|
|
||||||
} ErrorCode;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
UPCA,
|
|
||||||
EAN8,
|
|
||||||
EAN13,
|
|
||||||
CODE39,
|
|
||||||
CODE128,
|
|
||||||
CODE128C,
|
|
||||||
CODABAR,
|
|
||||||
|
|
||||||
UNKNOWN
|
|
||||||
} BarcodeType;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
char* name; //The name of the barcode type
|
|
||||||
BarcodeType type; //The barcode type enum
|
|
||||||
int min_digits; //the minimum number of digits
|
|
||||||
int max_digits; //the maximum number of digits
|
|
||||||
int start_pos; //where to start drawing the barcode, set to -1 to dynamically draw barcode
|
|
||||||
} BarcodeTypeObj;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
BarcodeTypeObj* type_obj;
|
|
||||||
int check_digit; //A place to store the check digit
|
|
||||||
FuriString* raw_data; //the data directly from the file
|
|
||||||
FuriString* correct_data; //the corrected/processed data
|
|
||||||
bool valid; //true if the raw data is correctly formatted, such as correct num of digits, valid characters, etc.
|
|
||||||
ErrorCode reason; //the reason why this barcode is invalid
|
|
||||||
} BarcodeData;
|
|
||||||
|
|
||||||
//All available barcode types
|
|
||||||
extern BarcodeTypeObj* barcode_type_objs[NUMBER_OF_BARCODE_TYPES];
|
|
||||||
|
|
||||||
void init_types();
|
|
||||||
void free_types();
|
|
||||||
BarcodeTypeObj* get_type(FuriString* type_string);
|
|
||||||
const char* get_error_code_name(ErrorCode error_code);
|
|
||||||
const char* get_error_code_message(ErrorCode error_code);
|
|
||||||
@@ -1,532 +0,0 @@
|
|||||||
#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);
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
#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);
|
|
||||||
52
applications/external/barcode_gen/encodings.c
vendored
@@ -1,52 +0,0 @@
|
|||||||
#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
|
|
||||||
};
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
#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];
|
|
||||||
|
Before Width: | Height: | Size: 161 B |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.3 KiB |
@@ -1,510 +0,0 @@
|
|||||||
#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;
|
|
||||||
}
|
|
||||||