Skip to content

Commit 084893a

Browse files
committed
update qrcode app
1 parent 8e800a3 commit 084893a

File tree

5 files changed

+492
-168
lines changed

5 files changed

+492
-168
lines changed

README.md

Lines changed: 91 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -23,22 +23,49 @@ Version: 0
2323
Message: your content here
2424
```
2525

26+
qrcode v2 supports a newer format as well (the old format still works for
27+
backward compatibility, or, if you don't need the newer features, the app will
28+
read version "0" files faster):
29+
30+
```
31+
Filetype: QRCode
32+
Version: 1
33+
QRMode: B
34+
QRVersion: 6
35+
QRECC: L
36+
Message: your content here
37+
Message: multi-line content is possible
38+
```
39+
40+
In a version "1" file, the `QRMode`, `QRVersion`, and `QRECC` are optional
41+
(though, must be in that order if more than one are specified). The app will
42+
attempt to use the specified mode, version, and/or ECC, if the content will
43+
fit. Otherwise, it may select a different mode, version, and/or ECC. Keep
44+
reading to learn about the meaning of `QRMode`, `QRVersion`, and `QRECC`.
45+
46+
Version "1" files also support multi-line content. Each line starting with
47+
`Message:` will be concatenated together with newline characters.
48+
49+
My recommendation is to allow the app to select a mode, version, and ECC level
50+
for you and, then, if you find that your qrcode reader prefers specific
51+
settings, update the file appropriately.
52+
2653
### Message Format
2754
qrcodes support 4 formats called "modes": numeric, alpha-numeric, binary, and
2855
kanji. Because of the limited screen real-estate on the [Flipper Zero], you'll
2956
want to pick the best mode for the data you are trying to display.
3057

31-
The app will automatically detect the best mode to use, so the only thing you
32-
need to do is make sure the message in your file is formatted to use the best
33-
mode. For example, if your message is entirely numeric, make sure you don't
34-
include any extraneous punctuation in your file. If you're only encoding a
35-
domain name, make sure it's uppercase to take advantage of alpha-numeric mode,
36-
etc.
58+
If unspecified in the `.qrcode` file, the app will automatically detect the
59+
best mode to use based on the message content.
3760

38-
#### Numeric Mode
39-
Consists of only numbers, nothing else. This mode can encode the most data.
61+
#### Numeric Mode (QRMode: N)
62+
Consists of only numbers, nothing else. This mode can encode the most data and
63+
is useful for things like phone numbers. To use this mode, your message must
64+
_not_ contain non-numeric characters. For example, a message content of "(xxx)
65+
xxx-xxxx" can _not_ use numeric mode (it would require "binary" mode, in fact).
66+
Instead, your message should just be "xxxxxxxxxx".
4067

41-
#### Alpha-Numeric Mode
68+
#### Alpha-Numeric Mode (QRMode: A)
4269
This mode can encode numbers, uppercase letters *only*, spaces, and the
4370
following symbols: `$%*+-./:`. This format _may_ be appropriate for urls, as
4471
long as you're only encoding the domain name and you remember to use uppercase
@@ -48,30 +75,56 @@ case-sensitive.
4875

4976
A qrcode in alpha-numeric mode can encode ~40% less data than numeric mode.
5077

51-
#### Binary Mode
78+
#### Binary Mode (QRMode: B)
5279
This mode is a little bit of a misnomer: binary mode simply means that the
5380
message will be encoded as 8-bit bytes. The qrcode standard stipulates that
5481
text will use ISO-8859-1 (also known as Latin-1) encoding, _not_ utf8 as would
5582
be the standard these days. However, _some_ readers _may_ automatically detect
5683
utf8. To be standard-compliant, that basically means you can only use Latin
5784
letters, numbers, and symbols.
5885

86+
Multi-line messages will always be in binary mode, since the other modes cannot
87+
encode a newline character.
88+
5989
A qrcode in binary mode can encode ~60% less data than numeric mode, and ~30%
6090
less than alpha-numeric.
6191

62-
#### Kanji Mode
92+
#### Kanji Mode (QRMode: K)
6393
This mode is unsupported, so I won't go into detail. A limitation of the
6494
underlying qrcode library that I'm using, unfortunately. If there's interest,
6595
perhaps I'll hack in support sometime.
6696

97+
### QRVersion
98+
A qrcode's version specifies how "big" it is. Higher versions contain more
99+
"modules" (ie, the "pixels" that make up qrcodes) and, thus, can encode more
100+
data. A version 1 qrcode contains 21x21 modules, whereas a version 11 code (the
101+
largest the Flipper Zero can display) contains 61x61 modules. The modules of a
102+
version 1 code will be 3x3 pixels on the Flipper Zero screen; version 2 and 3
103+
qrcodes will each have 2x2 pixel modules; and version 4 through 11 qrcodes will
104+
have single pixel modules.
105+
106+
If unspecified in the `.qrcode` file, the app will automatically select the
107+
lowest version that can contain all of the message content, given the mode
108+
selected in the previous step.
109+
110+
### QRECC
111+
A qrcode's ECC level determines the qrcode's resilience to "damage". In the
112+
case of the Flipper Zero, "damage" might be a dirty screen, dead pixels, or
113+
even screen glare. Higher ECC modes are more resilient, but can contain less
114+
data. The ECC modes are Low, Medium, Quartile, and High and can be specified in
115+
the `.qrcode` file using the first letter (L, M, Q, and H).
116+
117+
qrcode readers may have an easier time reading qrcodes with higher ECC levels,
118+
so, if unspecified in the `.qrcode` file, the app will select the highest ECC
119+
level that can contain all of the message content, given the qrcode mode and
120+
version selected in the previous steps.
121+
67122
## Using the App
68123
The app is fairly straightforward. When it first starts, the file browser will
69124
automatically open to the `qrcodes` directory and display any `.qrcode` files.
70125
Select one using the arrow keys and the center button. The qrcode will display.
71-
If you push the right arrow, some stats will display: the qrcode "Version" -
72-
which corresponds to how big it is; the ECC level - which determines the
73-
qrcode's resilience to damage, such as a dirty screen (Low, Medium, Quartile,
74-
and High); and the qrcode Mode (Numeric, Alpha-Numeric, Binary, or Kanji).
126+
If you push the right arrow, some stats will display: the qrcode "Version"; the
127+
ECC level; and the qrcode Mode (Numeric, Alpha-Numeric, Binary, or Kanji).
75128

76129
While viewing the stats, you can select Version or ECC using the up and down
77130
arrows and the center button. You can then increase or decrease the Version or
@@ -120,6 +173,27 @@ For example, if my ssid was "wifiball" and not broadcast, and the password was
120173
Message: WIFI:S:wifiball;P:pa$$\:word;T:WPA;H:true;
121174
```
122175

176+
## Example: vCard
177+
Phones can scan [vCard] qrcodes to automatically add a contact to their address
178+
book. Starting with qrcode v2, multi-line qrcodes can be created, allowing you
179+
to create vCards!
180+
181+
```
182+
Filetype: QRCode
183+
Version: 1
184+
Message: BEGIN:VCARD
185+
Message: VERSION:3.0
186+
Message: N:Smith;John
187+
Message: FN:John Smith
188+
Message: ADR;TYPE=dom,home,postal,parcel:;;123 Example St;Exampleton;CA;90210;
189+
Message: BDAY:1970-01-01
190+
Message: TEL;TYPE=pref,voice,msg,cell:+18005551212
191+
Message: END:VCARD
192+
```
193+
194+
Check the [vCard] specification to learn about all of the fields and their
195+
values.
196+
123197
## Building
124198
First, clone the [flipperzero-firmware] repo and then clone this repo in the
125199
`applications_user` directory:
@@ -133,7 +207,6 @@ git clone [email protected]:bmatcuk/flipperzero-qrcode.git
133207
Next, in the base of the [flipperzero-firmware] directory, run fbt:
134208

135209
```bash
136-
cd ..
137210
./fbt fap_qrcode
138211
```
139212

@@ -146,11 +219,12 @@ find the .fap, should it change in the future).
146219
This application uses the [QRCode] library by ricmoo. This is the same library
147220
that is in the lib directory of the flipper-firmware repo (which was originally
148221
included for a [now-removed demo app]), but modified slightly to fix some
149-
compiler errors.
222+
compiler errors and allow the explicit selection of the qrcode mode.
150223

151224
[now-removed demo app]: https://github.com/flipperdevices/flipperzero-firmware/pull/160/files
152225
[flipperzero-firmware]: https://github.com/flipperdevices/flipperzero-firmware
153226
[Flipper Zero]: https://flipperzero.one/
154227
[QRCode]: https://github.com/ricmoo/QRCode
155228
[qFlipper]: https://docs.flipperzero.one/qflipper
156229
[Releases]: https://github.com/bmatcuk/flipperzero-qrcode/releases/latest
230+
[vCard]: https://www.evenx.com/vcard-3-0-format-specification

application.fam

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
App(
22
appid="qrcode",
33
name="QR Code",
4-
fap_version=(1, 1),
4+
fap_version=(2,0),
55
fap_description="Display qrcodes",
66
fap_author="Bob Matcuk",
77
fap_weburl="https://github.com/bmatcuk/flipperzero-qrcode",

qrcode.c

Lines changed: 22 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -175,24 +175,20 @@ static int8_t getAlphanumeric(char c) {
175175
return -1;
176176
}
177177

178-
static bool isAlphanumeric(const char* text, uint16_t length) {
179-
while(length != 0) {
180-
if(getAlphanumeric(text[--length]) == -1) {
181-
return false;
182-
}
183-
}
184-
return true;
185-
}
186-
187-
static bool isNumeric(const char* text, uint16_t length) {
188-
while(length != 0) {
189-
char c = text[--length];
190-
if(c < '0' || c > '9') {
191-
return false;
192-
}
193-
}
194-
return true;
195-
}
178+
/* static bool isAlphanumeric(const char *text, uint16_t length) { */
179+
/* while (length != 0) { */
180+
/* if (getAlphanumeric(text[--length]) == -1) { return false; } */
181+
/* } */
182+
/* return true; */
183+
/* } */
184+
185+
/* static bool isNumeric(const char *text, uint16_t length) { */
186+
/* while (length != 0) { */
187+
/* char c = text[--length]; */
188+
/* if (c < '0' || c > '9') { return false; } */
189+
/* } */
190+
/* return true; */
191+
/* } */
196192

197193
// We store the following tightly packed (less 8) in modeInfo
198194
// <=9 <=26 <= 40
@@ -703,11 +699,9 @@ static int8_t encodeDataCodewords(
703699
BitBucket* dataCodewords,
704700
const uint8_t* text,
705701
uint16_t length,
702+
int8_t mode,
706703
uint8_t version) {
707-
int8_t mode = MODE_BYTE;
708-
709-
if(isNumeric((char*)text, length)) {
710-
mode = MODE_NUMERIC;
704+
if(mode == MODE_NUMERIC) {
711705
bb_appendBits(dataCodewords, 1 << MODE_NUMERIC, 4);
712706
bb_appendBits(dataCodewords, length, getModeBits(version, MODE_NUMERIC));
713707

@@ -728,8 +722,7 @@ static int8_t encodeDataCodewords(
728722
bb_appendBits(dataCodewords, accumData, accumCount * 3 + 1);
729723
}
730724

731-
} else if(isAlphanumeric((char*)text, length)) {
732-
mode = MODE_ALPHANUMERIC;
725+
} else if(mode == MODE_ALPHANUMERIC) {
733726
bb_appendBits(dataCodewords, 1 << MODE_ALPHANUMERIC, 4);
734727
bb_appendBits(dataCodewords, length, getModeBits(version, MODE_ALPHANUMERIC));
735728

@@ -853,6 +846,7 @@ uint16_t qrcode_getBufferSize(uint8_t version) {
853846
int8_t qrcode_initBytes(
854847
QRCode* qrcode,
855848
uint8_t* modules,
849+
int8_t mode,
856850
uint8_t version,
857851
uint8_t ecc,
858852
uint8_t* data,
@@ -880,7 +874,7 @@ int8_t qrcode_initBytes(
880874
bb_initBuffer(&codewords, codewordBytes, (int32_t)sizeof(codewordBytes));
881875

882876
// Place the data code words into the buffer
883-
int8_t mode = encodeDataCodewords(&codewords, data, length, version);
877+
mode = encodeDataCodewords(&codewords, data, length, mode, version);
884878

885879
if(mode < 0) {
886880
return -1;
@@ -938,14 +932,9 @@ int8_t qrcode_initBytes(
938932
return 0;
939933
}
940934

941-
int8_t qrcode_initText(
942-
QRCode* qrcode,
943-
uint8_t* modules,
944-
uint8_t version,
945-
uint8_t ecc,
946-
const char* data) {
947-
return qrcode_initBytes(qrcode, modules, version, ecc, (uint8_t*)data, strlen(data));
948-
}
935+
/* int8_t qrcode_initText(QRCode *qrcode, uint8_t *modules, uint8_t version, uint8_t ecc, const char *data) { */
936+
/* return qrcode_initBytes(qrcode, modules, version, ecc, (uint8_t*)data, strlen(data)); */
937+
/* } */
949938

950939
bool qrcode_getModule(QRCode* qrcode, uint8_t x, uint8_t y) {
951940
if(x >= qrcode->size || y >= qrcode->size) {

qrcode.h

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -77,15 +77,11 @@ extern "C" {
7777

7878
uint16_t qrcode_getBufferSize(uint8_t version);
7979

80-
int8_t qrcode_initText(
81-
QRCode* qrcode,
82-
uint8_t* modules,
83-
uint8_t version,
84-
uint8_t ecc,
85-
const char* data);
80+
/* int8_t qrcode_initText(QRCode *qrcode, uint8_t *modules, uint8_t version, uint8_t ecc, const char *data); */
8681
int8_t qrcode_initBytes(
8782
QRCode* qrcode,
8883
uint8_t* modules,
84+
int8_t mode,
8985
uint8_t version,
9086
uint8_t ecc,
9187
uint8_t* data,

0 commit comments

Comments
 (0)