Przeglądaj źródła

added "stats", increased stack size, github workflow

Bob Matcuk 3 lat temu
rodzic
commit
56ae06e7b5
4 zmienionych plików z 192 dodań i 34 usunięć
  1. 30 0
      .github/workflows/release.yml
  2. 80 24
      README.md
  3. 1 1
      application.fam
  4. 81 9
      qrcode_app.c

+ 30 - 0
.github/workflows/release.yml

@@ -0,0 +1,30 @@
+name: Release
+
+on:
+  push:
+    tags:
+      - 'v[0-9]+.[0-9]+.[0-9]+'
+
+jobs:
+  build:
+    name: Build
+    runs-on: ubuntu-latest
+    steps:
+      - name: Checkout Flipper Zero Firmware
+        uses: actions/checkout@v3
+        with:
+          repository: 'flipperdevices/flipperzero-firmware'
+          ref: '0.74.2'
+          submodules: true
+      - name: Checkout
+        uses: actions/checkout@v3
+        with:
+          path: 'applications_user/qrcode_app'
+      - name: Build
+        run: ./fbt fap_qrcode
+      - name: Publish
+        uses: softprops/action-gh-release@v1
+        with:
+          files: build/f7-firmware-D/.extapps/qrcode.fap
+          generate_release_notes: true
+          fail_on_unmatched_files: true

+ 80 - 24
README.md

@@ -1,35 +1,19 @@
 # flipperzero-qrcode
 Display qrcodes on the [Flipper Zero]
 
-## Building
-First, clone the [flipperzero-firmware] repo and then clone this repo in the
-`applications_user` directory:
-
-```bash
-git clone git@github.com:flipperdevices/flipperzero-firmware.git
-cd flipperzero-firmware/applications_user
-git clone git@github.com:bmatcuk/flipperzero-qrcode.git
-```
-
-Next, in the base of the [flipperzero-firmware] directory, run fbt:
-
-```bash
-cd ..
-./fbt fap_qrcode
-```
-
-This will automatically install dependencies and build the application. When it
-has finished building, the .fap will be in
-`build/f7-firmware-D/.extapps/qrcode.fap` (fbt output will tell you where to
-find the .fap, should it change in the future).
+## Download
+Grab the latest `qrcode.fap` from [Releases].
 
 ## Installation
 Copy the `qrcode.fap` file onto your [Flipper Zero] sd card in the `apps/Tools`
 directory. Then create a top level directory called `qrcodes` to store your
-qrcode files.
+qrcode files. This can be done using [qFlipper], for example, by
+draging-and-dropping `qrcode.fap` into `apps/Tools` and then navigating back to
+the top level (where the directories like `infrared` and `nfc` live), right
+click, and create a new folder called `qrcodes`.
 
 ## Creating QR Codes
-qrcode files are simple text files with the extension .qrcode. This app will
+qrcode files are simple text files with the extension `.qrcode`. This app will
 expect them to live in a top-level directory on your sd card called `qrcodes`.
 They should have the following content:
 
@@ -76,7 +60,77 @@ A qrcode in binary mode can encode ~60% less data than numeric mode, and ~30%
 less than alpha-numeric.
 
 #### Kanji Mode
-This mode is unsupported, so I won't go into detail.
+This mode is unsupported, so I won't go into detail. A limitation of the
+underlying qrcode library that I'm using, unfortunately. If there's interest,
+perhaps I'll hack in support sometime.
+
+## Using the App
+The app is fairly straightforward. When it first starts, the file browser will
+automatically open to the `qrcodes` directory and display any `.qrcode` files.
+Select one using the arrow keys and the center button. The qrcode will display.
+If you push the right arrow, some stats will display: the qrcode "Version" -
+which corresponds to how big it is; the ECC level - which determines the
+qrcode's resilience to damage, such as a dirty screen (Low, Medium, Quartile,
+and High); and the qrcode Mode (Numeric, Alpha-Numeric, Binary, or Kanji). You
+can hide the stats by pressing the left arrow.
+
+When you're done viewing the qrcode, press the back button to return to the
+file browser. If you push the back button in the file browser, the app will
+exit.
+
+I will ask that you temper your expectations: the Flipper Zero screen is small
+and many readers may have difficulty reading the qrcodes, especially if they
+are encoding a lot of data. I have successfully got my iPhone to read qrcodes
+encoding phone numbers and wifi info, both of which are relatively short.
+
+## Wifi QRCodes
+Most phones can automatically connect to wifi networks from a qrcode. If you
+should like to encode your wifi's connection info into a qrcode, here's how
+you'd do it:
+
+```
+Filetype: QRCode
+Version: 0
+Message: WIFI:S:<ssid>;P:<password>;T:<encryption>;
+```
+
+Replace `<ssid>` with the name of your wifi, `<password>` with the password.
+`<encryption>` would be "WPA" or "WEP". If your wifi is open (no password),
+this can be "None" and you can remove `P:<password>;` from the message. If your
+wifi is hidden (ie, does not broadcast the ssid), you can add `H:true;` to the
+end.
+
+Note that if your ssid or password contain any of these characters: `\";,:`,
+you'll need to "escape" it by placing a backslash (`\`) before it.
+
+For example, if my ssid was "wifiball" and not broadcast, and the password was
+"pa$$:word" with WPA encryption, the message would be:
+
+```
+Message: WIFI:S:wifiball;P:pa$$\:word;T:WPA;H:true;
+```
+
+## Building
+First, clone the [flipperzero-firmware] repo and then clone this repo in the
+`applications_user` directory:
+
+```bash
+git clone git@github.com:flipperdevices/flipperzero-firmware.git
+cd flipperzero-firmware/applications_user
+git clone git@github.com:bmatcuk/flipperzero-qrcode.git
+```
+
+Next, in the base of the [flipperzero-firmware] directory, run fbt:
+
+```bash
+cd ..
+./fbt fap_qrcode
+```
+
+This will automatically install dependencies and build the application. When it
+has finished building, the .fap will be in
+`build/f7-firmware-D/.extapps/qrcode.fap` (fbt output will tell you where to
+find the .fap, should it change in the future).
 
 ## qrcode library
 This application uses the [QRCode] library by ricmoo. This is the same library
@@ -88,3 +142,5 @@ compiler errors.
 [flipperzero-firmware]: https://github.com/flipperdevices/flipperzero-firmware
 [Flipper Zero]: https://flipperzero.one/
 [QRCode]: https://github.com/ricmoo/QRCode
+[qFlipper]: https://docs.flipperzero.one/qflipper
+[Releases]: https://github.com/bmatcuk/flipperzero-qrcode/releases/latest

+ 1 - 1
application.fam

@@ -6,7 +6,7 @@ App(
     fap_weburl="https://github.com/bmatcuk/flipperzero-qrcode",
     apptype=FlipperAppType.EXTERNAL,
     entry_point="qrcode_app",
-    stack_size=1024,
+    stack_size=2 * 1024,
     cdefines=["APP_QRCODE"],
     requires=[
         "gui",

+ 81 - 9
qrcode_app.c

@@ -55,28 +55,63 @@ typedef struct {
 
     FuriMutex** mutex;
     QRCode* qrcode;
+    bool loading;
     bool too_long;
+    bool show_stats;
 } 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
  * @param canvas The canvas to render to
  * @param ctx Context provided to the callback by view_port_draw_callback_set
  */
 static void render_callback(Canvas* canvas, void* ctx) {
+    furi_assert(canvas);
+    furi_assert(ctx);
+
     QRCodeApp* instance = ctx;
     furi_check(furi_mutex_acquire(instance->mutex, FuriWaitForever) == FuriStatusOk);
 
     canvas_clear(canvas);
     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 height = canvas_height(canvas);
     if (instance->qrcode) {
         uint8_t size = instance->qrcode->size;
         uint8_t pixel_size = height / size;
         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 x = 0; x < size; x++) {
                 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;
         canvas_draw_str_aligned(canvas, width / 2, margin, AlignCenter, AlignTop, "Could not load qrcode.");
         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
  */
 static void input_callback(InputEvent* input_event, void* ctx) {
+    furi_assert(input_event);
+    furi_assert(ctx);
     if (input_event->type == InputTypeShort) {
         QRCodeApp* instance = ctx;
         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
  */
 static bool is_numeric(const char* str, uint16_t len) {
+    furi_assert(str);
     while (len > 0) {
         char c = str[--len];
         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
  */
 static bool is_alphanumeric(const char* str, uint16_t len) {
+    furi_assert(str);
     while (len > 0) {
         char c = str[--len];
         if (c >= '0' && c <= '9') continue;
@@ -169,6 +225,7 @@ static QRCode* qrcode_alloc(uint8_t version) {
  * @param qrcode The QRCode to free
  */
 static void qrcode_free(QRCode* qrcode) {
+    furi_assert(qrcode);
     free(qrcode->modules);
     free(qrcode);
 }
@@ -180,12 +237,16 @@ static void qrcode_free(QRCode* qrcode) {
  * @returns true if the string was successfully loaded
  */
 static bool qrcode_load_string(QRCodeApp* instance, FuriString* str) {
+    furi_assert(instance);
+    furi_assert(str);
+
     furi_check(furi_mutex_acquire(instance->mutex, FuriWaitForever) == FuriStatusOk);
     if (instance->qrcode) {
         qrcode_free(instance->qrcode);
         instance->qrcode = NULL;
     }
     instance->too_long = false;
+    instance->show_stats = false;
 
     bool result = false;
     do {
@@ -238,6 +299,8 @@ static bool qrcode_load_string(QRCodeApp* instance, FuriString* str) {
         result = true;
     } while (false);
 
+    instance->loading = false;
+
     furi_mutex_release(instance->mutex);
 
     return result;
@@ -307,6 +370,11 @@ static QRCodeApp* qrcode_app_alloc() {
 
     instance->mutex = furi_mutex_alloc(FuriMutexTypeNormal);
 
+    instance->qrcode = NULL;
+    instance->loading = true;
+    instance->too_long = false;
+    instance->show_stats = false;
+
     return instance;
 }
 
@@ -332,9 +400,7 @@ static void qrcode_app_free(QRCodeApp* instance) {
 /** App entrypoint */
 int32_t qrcode_app(void* p) {
     QRCodeApp* instance = qrcode_app_alloc();
-
-    FuriString* file_path;
-    file_path = furi_string_alloc();
+    FuriString* file_path = furi_string_alloc();
 
     do {
         if (p && strlen(p)) {
@@ -371,8 +437,13 @@ int32_t qrcode_app(void* p) {
                     qrcode_free(instance->qrcode);
                     instance->qrcode = NULL;
                 }
+                instance->loading = true;
                 furi_mutex_release(instance->mutex);
                 break;
+            } else if (input.key == InputKeyRight) {
+                instance->show_stats = true;
+            } else if (input.key == InputKeyLeft) {
+                instance->show_stats = false;
             }
 
             furi_mutex_release(instance->mutex);
@@ -380,10 +451,11 @@ int32_t qrcode_app(void* 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;
         }
-    } while (1);
+    } while (true);
 
     furi_string_free(file_path);
     qrcode_app_free(instance);