1 //-----------------------------------------------------------------------------
2 // Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // See LICENSE.txt for the text of the license.
15 //-----------------------------------------------------------------------------
17 //-----------------------------------------------------------------------------
18 // from ST25R3911B-NFC-Demo source code by Waveshare team
20 #include "cmdhfwaveshare.h"
25 #include "cmdparser.h"
28 #include "fileutils.h"
29 #include "util_posix.h" // msleep
30 #include "cliparser.h"
36 #define EPD_1IN54BCV2 3
48 #define EPD_7IN5BCV2 15
52 typedef struct model_s
{
54 uint8_t len
; // The data sent in one time shall not be greater than 128-3
71 static model_t models
[] = {
72 {"2.13 inch e-paper", 16, 122, 250}, // tested
73 {"2.9 inch e-paper", 16, 296, 128},
74 {"4.2 inch e-paper", 100, 400, 300}, // tested
75 {"7.5 inch e-paper", 120, 800, 480},
76 {"2.7 inch e-paper", 121, 176, 276}, // tested
77 {"2.13 inch e-paper B (with red)", 106, 104, 212}, // tested
78 {"1.54 inch e-paper B (with red)", 100, 200, 200}, // tested
79 {"7.5 inch e-paper HD", 120, 880, 528},
82 static int CmdHelp(const char *Cmd
);
84 static uint8_t *map8to1(gdImagePtr img
, int color
) {
85 // Calculate width rounding up
86 uint16_t width8
= (gdImageSX(img
) + 7) / 8;
88 uint8_t *colormap8
= calloc(width8
* gdImageSY(img
), sizeof(uint8_t));
95 for (uint16_t Y
= 0; Y
< gdImageSY(img
); Y
++) {
96 for (uint16_t X
= 0; X
< gdImageSX(img
); X
++) {
97 if (gdImageGetPixel(img
, X
, Y
) == color
) {
101 if ((count
>= 8) || (X
== gdImageSX(img
) - 1)) {
102 colormap8
[X
/ 8 + Y
* width8
] = (~data
) & 0xFF;
106 data
= (data
<< 1) & 0xFF;
113 static void read_black(uint32_t i
, uint8_t *l
, uint8_t model_nr
, const uint8_t *black
) {
114 for (uint8_t j
= 0; j
< models
[model_nr
].len
; j
++) {
115 l
[3 + j
] = black
[i
* models
[model_nr
].len
+ j
];
118 static void read_red(uint32_t i
, uint8_t *l
, uint8_t model_nr
, const uint8_t *red
) {
119 // spurious warning with GCC10 (-Wstringop-overflow) when j is uint8_t, even if all len are < 128
120 for (uint16_t j
= 0; j
< models
[model_nr
].len
; j
++) {
121 if (model_nr
== M1in54B
) {
122 //1.54B needs to flip the red picture data, other screens do not need to flip data
123 l
[3 + j
] = ~red
[i
* models
[model_nr
].len
+ j
];
125 l
[3 + j
] = red
[i
* models
[model_nr
].len
+ j
];
130 static int transceive_blocking(uint8_t *txBuf
, uint16_t txBufLen
, uint8_t *rxBuf
, uint16_t rxBufLen
, uint16_t *actLen
, bool retransmit
) {
131 uint8_t fail_num
= 0;
137 PacketResponseNG resp
;
138 SendCommandMIX(CMD_HF_ISO14443A_READER
, ISO14A_RAW
| ISO14A_APPEND_CRC
| ISO14A_NO_DISCONNECT
, txBufLen
, 0, txBuf
, txBufLen
);
140 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 2000)) {
141 if (resp
.oldarg
[0] > rxBufLen
) {
142 PrintAndLogEx(WARNING
, "Received %"PRIu64
" bytes, rxBuf too small (%u)", resp
.oldarg
[0], rxBufLen
);
143 memcpy(rxBuf
, resp
.data
.asBytes
, rxBufLen
);
147 memcpy(rxBuf
, resp
.data
.asBytes
, resp
.oldarg
[0]);
148 *actLen
= resp
.oldarg
[0];
151 if ((retransmit
) && (rxBuf
[0] != 0 || rxBuf
[1] != 0)) {
155 PrintAndLogEx(WARNING
, "Transmission failed, please try again.");
167 // 1.54B does not share the common base and requires specific handling
168 static int start_drawing_1in54B(uint8_t model_nr
, uint8_t *black
, uint8_t *red
) {
170 uint8_t step_5
[128] = {0xcd, 0x05, 100};
171 uint8_t step_4
[2] = {0xcd, 0x04};
172 uint8_t step_6
[2] = {0xcd, 0x06};
173 uint8_t rx
[20] = {0};
174 uint16_t actrxlen
[20], i
, progress
;
176 if (model_nr
== M1in54B
) {
179 PrintAndLogEx(DEBUG
, "1.54_Step9: e-paper config2 (black)");
180 if (model_nr
== M1in54B
) { //1.54inch B Keychain
181 for (i
= 0; i
< 50; i
++) {
182 read_black(i
, step_5
, model_nr
, black
);
183 ret
= transceive_blocking(step_5
, 103, rx
, 20, actrxlen
, true); // cd 05
184 if (ret
!= PM3_SUCCESS
) {
187 progress
= i
* 100 / 100;
188 PrintAndLogEx(INPLACE
, "Progress: %d %%", progress
);
192 PrintAndLogEx(DEBUG
, "1.54_Step6: e-paper power on");
193 ret
= transceive_blocking(step_4
, 2, rx
, 20, actrxlen
, true); //cd 04
194 if (ret
!= PM3_SUCCESS
) {
198 PrintAndLogEx(DEBUG
, "1.54_Step7: e-paper config2 (red)");
199 if (model_nr
== M1in54B
) { //1.54inch B Keychain
200 for (i
= 0; i
< 50; i
++) {
201 read_red(i
, step_5
, model_nr
, red
);
202 ret
= transceive_blocking(step_5
, 103, rx
, 20, actrxlen
, true); // cd 05
203 if (ret
!= PM3_SUCCESS
) {
206 progress
= i
* 100 / 100 + 50;
207 PrintAndLogEx(INPLACE
, "Progress: %d %%", progress
);
211 // Send update instructions
212 PrintAndLogEx(DEBUG
, "1.54_Step8: EDP load to main");
213 ret
= transceive_blocking(step_6
, 2, rx
, 20, actrxlen
, true); //cd 06
214 if (ret
!= PM3_SUCCESS
) {
218 PrintAndLogEx(DEBUG
, "1.54_Step9");
222 static int start_drawing(uint8_t model_nr
, uint8_t *black
, uint8_t *red
) {
223 uint8_t step0
[2] = {0xcd, 0x0d};
224 uint8_t step1
[3] = {0xcd, 0x00, 10}; // select e-paper type and reset e-paper
225 // 4 :2.13inch e-Paper
226 // 7 :2.9inch e-Paper
227 // 10 :4.2inch e-Paper
228 // 14 :7.5inch e-Paper
229 uint8_t step2
[2] = {0xcd, 0x01}; // e-paper normal mode type:
230 uint8_t step3
[2] = {0xcd, 0x02}; // e-paper config1
231 uint8_t step4
[2] = {0xcd, 0x03}; // e-paper power on
232 uint8_t step5
[2] = {0xcd, 0x05}; // e-paper config2
233 uint8_t step6
[2] = {0xcd, 0x06}; // EDP load to main
234 uint8_t step7
[3] = {0xcd, 0x07, 0}; // Data preparation
236 uint8_t step8
[123] = {0xcd, 0x08, 0x64}; // Data start command
237 // 2.13inch(0x10:Send 16 data at a time)
238 // 2.9inch(0x10:Send 16 data at a time)
239 // 4.2inch(0x64:Send 100 data at a time)
240 // 7.5inch(0x78:Send 120 data at a time)
241 uint8_t step9
[2] = {0xcd, 0x18}; // e-paper power on
242 uint8_t step10
[2] = {0xcd, 0x09}; // Refresh e-paper
243 uint8_t step11
[2] = {0xcd, 0x0a}; // wait for ready
244 uint8_t step12
[2] = {0xcd, 0x04}; // e-paper power off command
245 uint8_t step13
[124] = {0xcd, 0x19, 121};
246 // uint8_t step13[2]={0xcd,0x0b}; // Judge whether the power supply is turned off successfully
247 // uint8_t step14[2]={0xcd,0x0c}; // The end of the transmission
249 uint16_t actrxlen
[20];
251 clearCommandBuffer();
252 SendCommandMIX(CMD_HF_ISO14443A_READER
, ISO14A_CONNECT
| ISO14A_NO_DISCONNECT
, 0, 0, NULL
, 0);
253 PacketResponseNG resp
;
254 if (WaitForResponseTimeout(CMD_ACK
, &resp
, 2500) == false) {
255 PrintAndLogEx(ERR
, "No tag found");
260 iso14a_card_select_t card
;
261 memcpy(&card
, (iso14a_card_select_t
*)resp
.data
.asBytes
, sizeof(iso14a_card_select_t
));
263 uint64_t select_status
= resp
.oldarg
[0];
265 if (select_status
== 0) {
266 PrintAndLogEx(ERR
, "Tag select error");
269 } else if (select_status
== 3) {
270 PrintAndLogEx(WARNING
, "Card doesn't support standard iso14443-3 anticollision, doesn't look like Waveshare tag");
275 if ((card
.uidlen
!= 7) || ((memcmp(card
.uid
, "FSTN10m", 7) != 0) && (memcmp(card
.uid
, "FSTN11m", 7) != 0) && (memcmp(card
.uid
, "WSDZ10m", 7) != 0))) {
276 PrintAndLogEx(WARNING
, "Card doesn't look like Waveshare tag");
280 if (((model_nr
!= M1in54B
) && ((memcmp(card
.uid
, "FSTN10m", 7) == 0) || (memcmp(card
.uid
, "FSTN11m", 7) == 0)))) {
281 PrintAndLogEx(WARNING
, "Card is a Waveshare tag 1.54\", not %s", models
[model_nr
].desc
);
285 if (((model_nr
== M1in54B
) && (memcmp(card
.uid
, "FSTN10m", 7) != 0) && (memcmp(card
.uid
, "FSTN11m", 7) != 0))) {
286 PrintAndLogEx(WARNING
, "Card is not a Waveshare tag 1.54\", check your model number");
290 PrintAndLogEx(DEBUG
, "model_nr = %d", model_nr
);
292 PrintAndLogEx(DEBUG
, "Step0");
293 int ret
= transceive_blocking(step0
, 2, rx
, 20, actrxlen
, true); //cd 0d
294 if (ret
!= PM3_SUCCESS
) {
298 PrintAndLogEx(DEBUG
, "Step1: e-paper config");
299 // step1[2] screen model
300 // step8[2] nr of bytes sent at once
301 // step13[2] nr of bytes sent for the second time
302 // generally, step8 sends a black image, step13 sends a red image
303 if (model_nr
== M2in13
) { // 2.13inch
304 step1
[2] = EPD_2IN13V2
;
307 } else if (model_nr
== M2in9
) { // 2.9inch
311 } else if (model_nr
== M4in2
) { // 4.2inch
315 } else if (model_nr
== M7in5
) { // 7.5inch
316 step1
[2] = EPD_7IN5V2
;
319 } else if (model_nr
== M2in7
) { // 2.7inch
322 // Send blank data for the first time, and send other data to 0xff without processing the bottom layer
324 // Sending the second data is the real image data. If the previous 0xff is not sent, the last output image is abnormally black
325 } else if (model_nr
== M2in13B
) { // 2.13inch B
326 step1
[2] = EPD_2IN13BC
;
329 } else if (model_nr
== M7in5HD
) {
330 step1
[2] = EPD_7IN5HD
;
335 if (model_nr
== M1in54B
) {
336 ret
= transceive_blocking(step1
, 2, rx
, 20, actrxlen
, true); // cd 00
338 ret
= transceive_blocking(step1
, 3, rx
, 20, actrxlen
, true);
340 if (ret
!= PM3_SUCCESS
) {
345 PrintAndLogEx(DEBUG
, "Step2: e-paper normal mode type");
346 ret
= transceive_blocking(step2
, 2, rx
, 20, actrxlen
, true); // cd 01
347 if (ret
!= PM3_SUCCESS
) {
352 PrintAndLogEx(DEBUG
, "Step3: e-paper config1");
353 ret
= transceive_blocking(step3
, 2, rx
, 20, actrxlen
, true); // cd 02
354 if (ret
!= PM3_SUCCESS
) {
359 PrintAndLogEx(DEBUG
, "Step4: e-paper power on");
360 ret
= transceive_blocking(step4
, 2, rx
, 20, actrxlen
, true); // cd 03
361 if (ret
!= PM3_SUCCESS
) {
365 if (model_nr
== M1in54B
) {
366 // 1.54B Keychain handler
367 PrintAndLogEx(DEBUG
, "Start_Drawing_1in54B");
368 ret
= start_drawing_1in54B(model_nr
, black
, red
);
369 if (ret
!= PM3_SUCCESS
) {
372 // 1.54B Data transfer is complete and wait for refresh
375 PrintAndLogEx(DEBUG
, "Step5: e-paper config2");
376 ret
= transceive_blocking(step5
, 2, rx
, 20, actrxlen
, true); // cd 05
377 if (ret
!= PM3_SUCCESS
) {
381 PrintAndLogEx(DEBUG
, "Step6: EDP load to main") ;
382 ret
= transceive_blocking(step6
, 2, rx
, 20, actrxlen
, true); // cd 06
383 if (ret
!= PM3_SUCCESS
) {
387 PrintAndLogEx(DEBUG
, "Step7: Data preparation");
388 ret
= transceive_blocking(step7
, 3, rx
, 20, actrxlen
, true); // cd 07
389 if (ret
!= PM3_SUCCESS
) {
392 PrintAndLogEx(DEBUG
, "Step8: Start data transfer");
393 if (model_nr
== M2in13
) { // 2.13inch
394 for (uint16_t i
= 0; i
< 250; i
++) {
395 read_black(i
, step8
, model_nr
, black
);
396 ret
= transceive_blocking(step8
, 19, rx
, 20, actrxlen
, true); // cd 08
397 if (ret
!= PM3_SUCCESS
) {
400 progress
= i
* 100 / 250;
401 PrintAndLogEx(INPLACE
, "Progress: %d %%", progress
);
403 } else if (model_nr
== M2in9
) {
404 for (uint16_t i
= 0; i
< 296; i
++) {
405 read_black(i
, step8
, model_nr
, black
);
406 ret
= transceive_blocking(step8
, 19, rx
, 20, actrxlen
, true); // cd 08
407 if (ret
!= PM3_SUCCESS
) {
410 progress
= i
* 100 / 296;
411 PrintAndLogEx(INPLACE
, "Progress: %d %%", progress
);
413 } else if (model_nr
== M4in2
) { //4.2inch
414 for (uint16_t i
= 0; i
< 150; i
++) {
415 read_black(i
, step8
, model_nr
, black
);
416 ret
= transceive_blocking(step8
, 103, rx
, 20, actrxlen
, true); // cd 08
417 if (ret
!= PM3_SUCCESS
) {
420 progress
= i
* 100 / 150;
421 PrintAndLogEx(INPLACE
, "Progress: %d %%", progress
);
423 } else if (model_nr
== M7in5
) { //7.5inch
424 for (uint16_t i
= 0; i
< 400; i
++) {
425 read_black(i
, step8
, model_nr
, black
);
426 ret
= transceive_blocking(step8
, 123, rx
, 20, actrxlen
, true); // cd 08
427 if (ret
!= PM3_SUCCESS
) {
430 progress
= i
* 100 / 400;
431 PrintAndLogEx(INPLACE
, "Progress: %d %%", progress
);
434 } else if (model_nr
== M2in13B
) { //2.13inch B
435 for (uint16_t i
= 0; i
< 26; i
++) {
436 read_black(i
, step8
, model_nr
, black
);
437 ret
= transceive_blocking(step8
, 109, rx
, 20, actrxlen
, false); // cd 08
438 if (ret
!= PM3_SUCCESS
) {
441 progress
= i
* 50 / 26;
442 PrintAndLogEx(INPLACE
, "Progress: %d %%", progress
);
444 } else if (model_nr
== M7in5HD
) { //7.5HD
446 for (uint16_t i
= 0; i
< 484; i
++) {
447 read_black(i
, step8
, model_nr
, black
);
448 //memset(&step8[3], 0xf0, 120);
449 ret
= transceive_blocking(step8
, 123, rx
, 20, actrxlen
, true); // cd 08
450 if (ret
!= PM3_SUCCESS
) {
453 progress
= i
* 100 / 484;
454 PrintAndLogEx(INPLACE
, "Progress: %d %%", progress
);
456 memset(&step8
[3], 0xff, 120);
457 ret
= transceive_blocking(step8
, 110 + 3, rx
, 20, actrxlen
, true); // cd 08
458 if (ret
!= PM3_SUCCESS
) {
461 } else if (model_nr
== M2in7
) { //2.7inch
462 for (uint16_t i
= 0; i
< 48; i
++) {
463 //read_black(i,step8, model_nr, black);
464 memset(&step8
[3], 0xFF, sizeof(step8
) - 3);
465 ret
= transceive_blocking(step8
, 124, rx
, 20, actrxlen
, true); // cd 08
466 if (ret
!= PM3_SUCCESS
) {
469 progress
= i
* 50 / 48;
470 PrintAndLogEx(INPLACE
, "Progress: %d %%", progress
);
474 PrintAndLogEx(DEBUG
, "Step9: e-paper power on");
475 if (model_nr
== M2in13
|| model_nr
== M2in9
|| model_nr
== M4in2
|| model_nr
== M7in5
|| model_nr
== M7in5HD
) {
476 ret
= transceive_blocking(step9
, 2, rx
, 20, actrxlen
, true); //cd 18
477 // The black-and-white screen sending backplane is also shielded, with no effect. Except 2.7
478 if (ret
!= PM3_SUCCESS
) {
481 } else if (model_nr
== M2in13B
|| model_nr
== M2in7
) {
482 ret
= transceive_blocking(step9
, 2, rx
, 20, actrxlen
, true); //cd 18
483 if (ret
!= PM3_SUCCESS
) {
486 PrintAndLogEx(DEBUG
, "Step9b");
487 if (model_nr
== M2in7
) {
488 for (uint16_t i
= 0; i
< 48; i
++) {
489 read_black(i
, step13
, model_nr
, black
);
490 ret
= transceive_blocking(step13
, 124, rx
, 20, actrxlen
, true); //CD 19
491 if (ret
!= PM3_SUCCESS
) {
494 progress
= i
* 50 / 48 + 50;
495 PrintAndLogEx(INPLACE
, "Progress: %d %%", progress
);
497 } else if (model_nr
== M2in13B
) {
498 for (uint16_t i
= 0; i
< 26; i
++) {
499 read_red(i
, step13
, model_nr
, red
);
500 //memset(&step13[3], 0xfE, 106);
501 ret
= transceive_blocking(step13
, 109, rx
, 20, actrxlen
, false);
502 if (ret
!= PM3_SUCCESS
) {
505 progress
= i
* 50 / 26 + 50;
506 PrintAndLogEx(INPLACE
, "Progress: %d %%", progress
);
511 PrintAndLogEx(DEBUG
, "Step10: Refresh e-paper");
512 ret
= transceive_blocking(step10
, 2, rx
, 20, actrxlen
, true); //cd 09 refresh command
513 if (ret
!= PM3_SUCCESS
) {
518 PrintAndLogEx(DEBUG
, "Step11: Wait tag to be ready");
519 PrintAndLogEx(INPLACE
, "E-paper Reflashing, Waiting");
520 if (model_nr
== M2in13B
|| model_nr
== M1in54B
) { // Black, white and red screen refresh time is longer, wait first
522 } else if (model_nr
== M7in5HD
) {
526 uint8_t fail_num
= 0;
528 if (model_nr
== M1in54B
) {
529 // send 0xcd 0x08 with 1.54B
530 ret
= transceive_blocking(step8
, 2, rx
, 20, actrxlen
, false); //cd 08
532 ret
= transceive_blocking(step11
, 2, rx
, 20, actrxlen
, false); //cd 0a
534 if (ret
!= PM3_SUCCESS
) {
537 if (rx
[0] == 0xff && rx
[1] == 0) {
538 PrintAndLogEx(NORMAL
, "");
539 PrintAndLogEx(SUCCESS
, "E-paper Reflash OK");
544 PrintAndLogEx(WARNING
, "Update failed, please try again.");
549 PrintAndLogEx(INPLACE
, "E-paper Reflashing, Waiting");
554 PrintAndLogEx(DEBUG
, "Step12: e-paper power off command");
555 ret
= transceive_blocking(step12
, 2, rx
, 20, actrxlen
, true); //cd 04
556 if (ret
!= PM3_SUCCESS
) {
560 PrintAndLogEx(SUCCESS
, "E-paper Update OK");
566 static int CmdHF14AWSLoad(const char *Cmd
) {
568 char desc
[800] = {0};
569 for (uint8_t i
= 0; i
< MEND
; i
++) {
570 snprintf(desc
+ strlen(desc
),
571 sizeof(desc
) - strlen(desc
),
572 "hf waveshare load -f myfile -m %2u -> %s ( %u, %u )\n",
580 CLIParserContext
*ctx
;
581 CLIParserInit(&ctx
, "hf waveshare load",
582 "Load image file to Waveshare NFC ePaper",
587 snprintf(modeldesc
, sizeof(modeldesc
), "model number [0 - %d] of your tag", MEND
- 1);
591 arg_int1("m", NULL
, "<nr>", modeldesc
),
592 arg_str1("f", "file", "<fn>", "specify image to upload to tag"),
593 arg_str0("s", "save", "<fn>", "save paletized version in file"),
597 CLIExecWithReturn(ctx
, Cmd
, argtable
, false);
599 int model_nr
= arg_get_int_def(ctx
, 1, -1);
601 int infilelen
, outfilelen
;
602 char infile
[FILE_PATH_SIZE
];
603 char outfile
[FILE_PATH_SIZE
];
604 CLIParamStrToBuf(arg_get_str(ctx
, 2), (uint8_t *)infile
, FILE_PATH_SIZE
, &infilelen
);
605 CLIParamStrToBuf(arg_get_str(ctx
, 3), (uint8_t *)outfile
, FILE_PATH_SIZE
, &outfilelen
);
610 PrintAndLogEx(WARNING
, "Missing input file");
613 if (model_nr
== -1) {
614 PrintAndLogEx(WARNING
, "Missing model");
617 if (model_nr
>= MEND
) {
618 PrintAndLogEx(WARNING
, "Unknown model");
621 if (!g_session
.pm3_present
&& !outfilelen
) {
622 PrintAndLogEx(WARNING
, "Offline - can only perform image conversion");
626 bool model_has_red
= model_nr
== M1in54B
|| model_nr
== M2in13B
;
628 gdImagePtr rgb_img
= gdImageCreateFromFile(infile
);
630 PrintAndLogEx(WARNING
, "Could not load image from " _YELLOW_("%s"), infile
);
634 gdImagePtr scaled_img
= img_crop_to_fit(rgb_img
, models
[model_nr
].width
, models
[model_nr
].height
);
635 if (scaled_img
== NULL
) {
636 PrintAndLogEx(WARNING
, "Failed to scale input image");
637 gdImageDestroy(rgb_img
);
640 gdImageDestroy(rgb_img
);
644 pal
[0] = gdTrueColorAlpha(0xFF, 0xFF, 0xFF, 0); // White
645 pal
[1] = gdTrueColorAlpha(0x00, 0x00, 0x00, 0); // Black
648 pal
[2] = gdTrueColorAlpha(0xFF, 0x00, 0x00, 0); // Red
651 gdImagePtr pal_img
= img_palettize(scaled_img
, pal
, pal_len
);
652 gdImageDestroy(scaled_img
);
655 PrintAndLogEx(WARNING
, "Could not convert image");
660 if (gdImageFile(pal_img
, outfile
)) {
661 PrintAndLogEx(INFO
, "Save converted image to " _YELLOW_("%s"), outfile
);
662 gdImageDestroy(pal_img
);
665 PrintAndLogEx(WARNING
, "Could not save converted image", outfile
);
666 gdImageDestroy(pal_img
);
671 uint8_t *black_plane
= map8to1(pal_img
, 1);
673 PrintAndLogEx(WARNING
, "Could not convert image to bit plane");
674 gdImageDestroy(pal_img
);
678 uint8_t *red_plane
= NULL
;
680 red_plane
= map8to1(pal_img
, 2);
682 PrintAndLogEx(WARNING
, "Could not convert image to bit plane");
684 gdImageDestroy(pal_img
);
688 gdImageDestroy(pal_img
);
690 int res
= start_drawing(model_nr
, black_plane
, red_plane
);
696 static command_t CommandTable
[] = {
697 {"help", CmdHelp
, AlwaysAvailable
, "This help"},
698 {"load", CmdHF14AWSLoad
, AlwaysAvailable
, "Load image file to Waveshare NFC ePaper"},
699 {NULL
, NULL
, NULL
, NULL
}
702 static int CmdHelp(const char *Cmd
) {
703 (void)Cmd
; // Cmd is not used so far
704 CmdsHelp(CommandTable
);
708 int CmdHFWaveshare(const char *Cmd
) {
709 clearCommandBuffer();
710 return CmdsParse(CommandTable
, Cmd
);