|
@@ -55,28 +55,63 @@ typedef struct {
|
|
|
|
|
|
|
|
FuriMutex** mutex;
|
|
FuriMutex** mutex;
|
|
|
QRCode* qrcode;
|
|
QRCode* qrcode;
|
|
|
|
|
+ bool loading;
|
|
|
bool too_long;
|
|
bool too_long;
|
|
|
|
|
+ bool show_stats;
|
|
|
} QRCodeApp;
|
|
} QRCodeApp;
|
|
|
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * @param ecc ECC number
|
|
|
|
|
+ * @returns a character corresponding to the ecc level
|
|
|
|
|
+ */
|
|
|
|
|
+static char get_ecc_char(uint8_t ecc) {
|
|
|
|
|
+ switch (ecc) {
|
|
|
|
|
+ case 0: return 'L';
|
|
|
|
|
+ case 1: return 'M';
|
|
|
|
|
+ case 2: return 'Q';
|
|
|
|
|
+ case 3: return 'H';
|
|
|
|
|
+ default: return '?';
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * @param mode qrcode mode
|
|
|
|
|
+ * @returns a character corresponding to the mode
|
|
|
|
|
+ */
|
|
|
|
|
+static char get_mode_char(uint8_t mode) {
|
|
|
|
|
+ switch (mode) {
|
|
|
|
|
+ case 0: return 'N';
|
|
|
|
|
+ case 1: return 'A';
|
|
|
|
|
+ case 2: return 'B';
|
|
|
|
|
+ case 3: return 'K';
|
|
|
|
|
+ default: return '?';
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
/**
|
|
/**
|
|
|
* Render
|
|
* Render
|
|
|
* @param canvas The canvas to render to
|
|
* @param canvas The canvas to render to
|
|
|
* @param ctx Context provided to the callback by view_port_draw_callback_set
|
|
* @param ctx Context provided to the callback by view_port_draw_callback_set
|
|
|
*/
|
|
*/
|
|
|
static void render_callback(Canvas* canvas, void* ctx) {
|
|
static void render_callback(Canvas* canvas, void* ctx) {
|
|
|
|
|
+ furi_assert(canvas);
|
|
|
|
|
+ furi_assert(ctx);
|
|
|
|
|
+
|
|
|
QRCodeApp* instance = ctx;
|
|
QRCodeApp* instance = ctx;
|
|
|
furi_check(furi_mutex_acquire(instance->mutex, FuriWaitForever) == FuriStatusOk);
|
|
furi_check(furi_mutex_acquire(instance->mutex, FuriWaitForever) == FuriStatusOk);
|
|
|
|
|
|
|
|
canvas_clear(canvas);
|
|
canvas_clear(canvas);
|
|
|
canvas_set_color(canvas, ColorBlack);
|
|
canvas_set_color(canvas, ColorBlack);
|
|
|
|
|
+ canvas_set_font(canvas, FontPrimary);
|
|
|
|
|
|
|
|
|
|
+ uint8_t font_height = canvas_current_font_height(canvas);
|
|
|
uint8_t width = canvas_width(canvas);
|
|
uint8_t width = canvas_width(canvas);
|
|
|
uint8_t height = canvas_height(canvas);
|
|
uint8_t height = canvas_height(canvas);
|
|
|
if (instance->qrcode) {
|
|
if (instance->qrcode) {
|
|
|
uint8_t size = instance->qrcode->size;
|
|
uint8_t size = instance->qrcode->size;
|
|
|
uint8_t pixel_size = height / size;
|
|
uint8_t pixel_size = height / size;
|
|
|
uint8_t top = (height - pixel_size * size) / 2;
|
|
uint8_t top = (height - pixel_size * size) / 2;
|
|
|
- uint8_t left = (width - pixel_size * size) / 2;
|
|
|
|
|
|
|
+ uint8_t left = instance->show_stats ? top : (width - pixel_size * size) / 2;
|
|
|
for (uint8_t y = 0; y < size; y++) {
|
|
for (uint8_t y = 0; y < size; y++) {
|
|
|
for (uint8_t x = 0; x < size; x++) {
|
|
for (uint8_t x = 0; x < size; x++) {
|
|
|
if (qrcode_getModule(instance->qrcode, x, y)) {
|
|
if (qrcode_getModule(instance->qrcode, x, y)) {
|
|
@@ -88,10 +123,27 @@ static void render_callback(Canvas* canvas, void* ctx) {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
- } else {
|
|
|
|
|
- canvas_set_font(canvas, FontPrimary);
|
|
|
|
|
|
|
|
|
|
- uint8_t font_height = canvas_current_font_height(canvas);
|
|
|
|
|
|
|
+ if (instance->show_stats) {
|
|
|
|
|
+ if (top < 2) top = 2;
|
|
|
|
|
+ left += size * pixel_size + top;
|
|
|
|
|
+
|
|
|
|
|
+ FuriString* str = furi_string_alloc();
|
|
|
|
|
+
|
|
|
|
|
+ furi_string_printf(str, "Ver: %i", instance->qrcode->version);
|
|
|
|
|
+ canvas_draw_str(canvas, left, top + font_height, furi_string_get_cstr(str));
|
|
|
|
|
+
|
|
|
|
|
+ furi_string_printf(str, "ECC: %c", get_ecc_char(instance->qrcode->ecc));
|
|
|
|
|
+ canvas_draw_str(canvas, left, 2 * (top + font_height), furi_string_get_cstr(str));
|
|
|
|
|
+
|
|
|
|
|
+ furi_string_printf(str, "Mod: %c", get_mode_char(instance->qrcode->mode));
|
|
|
|
|
+ canvas_draw_str(canvas, left, 3 * (top + font_height), furi_string_get_cstr(str));
|
|
|
|
|
+
|
|
|
|
|
+ furi_string_free(str);
|
|
|
|
|
+ }
|
|
|
|
|
+ } else if (instance->loading) {
|
|
|
|
|
+ canvas_draw_str_aligned(canvas, width / 2, height / 2, AlignCenter, AlignCenter, "Loading...");
|
|
|
|
|
+ } else {
|
|
|
uint8_t margin = (height - font_height * 2) / 3;
|
|
uint8_t margin = (height - font_height * 2) / 3;
|
|
|
canvas_draw_str_aligned(canvas, width / 2, margin, AlignCenter, AlignTop, "Could not load qrcode.");
|
|
canvas_draw_str_aligned(canvas, width / 2, margin, AlignCenter, AlignTop, "Could not load qrcode.");
|
|
|
if (instance->too_long) {
|
|
if (instance->too_long) {
|
|
@@ -109,6 +161,8 @@ static void render_callback(Canvas* canvas, void* ctx) {
|
|
|
* @param ctx Context provided to the callback by view_port_input_callback_set
|
|
* @param ctx Context provided to the callback by view_port_input_callback_set
|
|
|
*/
|
|
*/
|
|
|
static void input_callback(InputEvent* input_event, void* ctx) {
|
|
static void input_callback(InputEvent* input_event, void* ctx) {
|
|
|
|
|
+ furi_assert(input_event);
|
|
|
|
|
+ furi_assert(ctx);
|
|
|
if (input_event->type == InputTypeShort) {
|
|
if (input_event->type == InputTypeShort) {
|
|
|
QRCodeApp* instance = ctx;
|
|
QRCodeApp* instance = ctx;
|
|
|
furi_message_queue_put(instance->input_queue, input_event, 0);
|
|
furi_message_queue_put(instance->input_queue, input_event, 0);
|
|
@@ -121,6 +175,7 @@ static void input_callback(InputEvent* input_event, void* ctx) {
|
|
|
* @returns true if the string is all numeric
|
|
* @returns true if the string is all numeric
|
|
|
*/
|
|
*/
|
|
|
static bool is_numeric(const char* str, uint16_t len) {
|
|
static bool is_numeric(const char* str, uint16_t len) {
|
|
|
|
|
+ furi_assert(str);
|
|
|
while (len > 0) {
|
|
while (len > 0) {
|
|
|
char c = str[--len];
|
|
char c = str[--len];
|
|
|
if (c < '0' || c > '9') return false;
|
|
if (c < '0' || c > '9') return false;
|
|
@@ -134,6 +189,7 @@ static bool is_numeric(const char* str, uint16_t len) {
|
|
|
* @returns true if the string is alphanumeric
|
|
* @returns true if the string is alphanumeric
|
|
|
*/
|
|
*/
|
|
|
static bool is_alphanumeric(const char* str, uint16_t len) {
|
|
static bool is_alphanumeric(const char* str, uint16_t len) {
|
|
|
|
|
+ furi_assert(str);
|
|
|
while (len > 0) {
|
|
while (len > 0) {
|
|
|
char c = str[--len];
|
|
char c = str[--len];
|
|
|
if (c >= '0' && c <= '9') continue;
|
|
if (c >= '0' && c <= '9') continue;
|
|
@@ -169,6 +225,7 @@ static QRCode* qrcode_alloc(uint8_t version) {
|
|
|
* @param qrcode The QRCode to free
|
|
* @param qrcode The QRCode to free
|
|
|
*/
|
|
*/
|
|
|
static void qrcode_free(QRCode* qrcode) {
|
|
static void qrcode_free(QRCode* qrcode) {
|
|
|
|
|
+ furi_assert(qrcode);
|
|
|
free(qrcode->modules);
|
|
free(qrcode->modules);
|
|
|
free(qrcode);
|
|
free(qrcode);
|
|
|
}
|
|
}
|
|
@@ -180,12 +237,16 @@ static void qrcode_free(QRCode* qrcode) {
|
|
|
* @returns true if the string was successfully loaded
|
|
* @returns true if the string was successfully loaded
|
|
|
*/
|
|
*/
|
|
|
static bool qrcode_load_string(QRCodeApp* instance, FuriString* str) {
|
|
static bool qrcode_load_string(QRCodeApp* instance, FuriString* str) {
|
|
|
|
|
+ furi_assert(instance);
|
|
|
|
|
+ furi_assert(str);
|
|
|
|
|
+
|
|
|
furi_check(furi_mutex_acquire(instance->mutex, FuriWaitForever) == FuriStatusOk);
|
|
furi_check(furi_mutex_acquire(instance->mutex, FuriWaitForever) == FuriStatusOk);
|
|
|
if (instance->qrcode) {
|
|
if (instance->qrcode) {
|
|
|
qrcode_free(instance->qrcode);
|
|
qrcode_free(instance->qrcode);
|
|
|
instance->qrcode = NULL;
|
|
instance->qrcode = NULL;
|
|
|
}
|
|
}
|
|
|
instance->too_long = false;
|
|
instance->too_long = false;
|
|
|
|
|
+ instance->show_stats = false;
|
|
|
|
|
|
|
|
bool result = false;
|
|
bool result = false;
|
|
|
do {
|
|
do {
|
|
@@ -238,6 +299,8 @@ static bool qrcode_load_string(QRCodeApp* instance, FuriString* str) {
|
|
|
result = true;
|
|
result = true;
|
|
|
} while (false);
|
|
} while (false);
|
|
|
|
|
|
|
|
|
|
+ instance->loading = false;
|
|
|
|
|
+
|
|
|
furi_mutex_release(instance->mutex);
|
|
furi_mutex_release(instance->mutex);
|
|
|
|
|
|
|
|
return result;
|
|
return result;
|
|
@@ -307,6 +370,11 @@ static QRCodeApp* qrcode_app_alloc() {
|
|
|
|
|
|
|
|
instance->mutex = furi_mutex_alloc(FuriMutexTypeNormal);
|
|
instance->mutex = furi_mutex_alloc(FuriMutexTypeNormal);
|
|
|
|
|
|
|
|
|
|
+ instance->qrcode = NULL;
|
|
|
|
|
+ instance->loading = true;
|
|
|
|
|
+ instance->too_long = false;
|
|
|
|
|
+ instance->show_stats = false;
|
|
|
|
|
+
|
|
|
return instance;
|
|
return instance;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -332,9 +400,7 @@ static void qrcode_app_free(QRCodeApp* instance) {
|
|
|
/** App entrypoint */
|
|
/** App entrypoint */
|
|
|
int32_t qrcode_app(void* p) {
|
|
int32_t qrcode_app(void* p) {
|
|
|
QRCodeApp* instance = qrcode_app_alloc();
|
|
QRCodeApp* instance = qrcode_app_alloc();
|
|
|
-
|
|
|
|
|
- FuriString* file_path;
|
|
|
|
|
- file_path = furi_string_alloc();
|
|
|
|
|
|
|
+ FuriString* file_path = furi_string_alloc();
|
|
|
|
|
|
|
|
do {
|
|
do {
|
|
|
if (p && strlen(p)) {
|
|
if (p && strlen(p)) {
|
|
@@ -371,8 +437,13 @@ int32_t qrcode_app(void* p) {
|
|
|
qrcode_free(instance->qrcode);
|
|
qrcode_free(instance->qrcode);
|
|
|
instance->qrcode = NULL;
|
|
instance->qrcode = NULL;
|
|
|
}
|
|
}
|
|
|
|
|
+ instance->loading = true;
|
|
|
furi_mutex_release(instance->mutex);
|
|
furi_mutex_release(instance->mutex);
|
|
|
break;
|
|
break;
|
|
|
|
|
+ } else if (input.key == InputKeyRight) {
|
|
|
|
|
+ instance->show_stats = true;
|
|
|
|
|
+ } else if (input.key == InputKeyLeft) {
|
|
|
|
|
+ instance->show_stats = false;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
furi_mutex_release(instance->mutex);
|
|
furi_mutex_release(instance->mutex);
|
|
@@ -380,10 +451,11 @@ int32_t qrcode_app(void* p) {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (p && strlen(p)) {
|
|
if (p && strlen(p)) {
|
|
|
- // if started with an arg, exit instead of going to the browser
|
|
|
|
|
|
|
+ // if started with an arg, exit instead
|
|
|
|
|
+ // of looping back to the browser
|
|
|
break;
|
|
break;
|
|
|
}
|
|
}
|
|
|
- } while (1);
|
|
|
|
|
|
|
+ } while (true);
|
|
|
|
|
|
|
|
furi_string_free(file_path);
|
|
furi_string_free(file_path);
|
|
|
qrcode_app_free(instance);
|
|
qrcode_app_free(instance);
|