Increase cvend reliability

This commit is contained in:
Edith Boles
2026-03-18 16:18:31 -07:00
parent 77aec099d8
commit 703e019d73
17 changed files with 4801 additions and 61 deletions

1
.gitignore vendored
View File

@@ -3,5 +3,6 @@ obj/
.cache
.build
.config.old
.gdb_history
build.log
include

View File

@@ -12,7 +12,7 @@ else
CFLAGS := $(CFLAGS) -lX11
endif
TARGETS := pm3-lvgl cvend_test audio_test
TARGETS := pm3-lvgl cvend_test cvend_decode audio_test
EXES := $(patsubst %,bin/%,$(TARGETS))
SRCS := $(shell find src inc -type f -iname '*.c')
OBJS := $(patsubst src/%.c,obj/%.o,$(patsubst inc/%.c,obj/lib/%.o,$(SRCS)))

Binary file not shown.

Binary file not shown.

Binary file not shown.

3
extra/README.md Normal file
View File

@@ -0,0 +1,3 @@
These are pulled from the pm3 wiki.
<https://wiki.pm3.dev/cvend#cvend_protocol_notes>

BIN
extra/startup-host.bin Normal file

Binary file not shown.

142
extra/startup-host.hex Normal file
View File

@@ -0,0 +1,142 @@
0x00
0x00
0xBC
0x01
0x00
0xEA
0x00
0x02
0xA6
0x01
0x00
0x41
0xDC
0x3D
0xA7
0xBC
0x02
0x00
0x02
0x00
0x00
0xB6
0xBC
0x03
0x00
0xE4
0x00
0x04
0x0C
0x00
0x05
0x01
0x01
0xDF
0xE3
0x6C
0xB6
0xBC
0x04
0x00
0xE4
0x00
0x04
0x5D
0x00
0x07
0x01
0x01
0xB1
0x37
0xE8
0xB5
0xBC
0x05
0x00
0xE4
0x00
0x04
0x90
0x00
0x0A
0x01
0x01
0xE2
0xA4
0x30
0xBD
0xBC
0x06
0x00
0xAA
0x00
0x04
0x1B
0x69
0xA2
0x95
0x6C
0x48
0x42
0x5B
0x0A
0xBC
0x07
0x00
0xE8
0x00
0x05
0xF6
0x04
0xFE
0x0A
0x00
0x00
0x60
0x4A
0x73
0xA7
0xBC
0x08
0x00
0x02
0x00
0x00
0x0B
0xBC
0x09
0x00
0x98
0x00
0x1A
0x67
0x00
0x12
0x2F
0x68
0x6F
0x6D
0x65
0x2F
0x61
0x70
0x70
0x30
0x2F
0x76
0x65
0x72
0x73
0x69
0x6F
0x6E
0x00
0x00
0x00
0x00
0x00
0x64
0xF8
0x78
0x80
0x2B

BIN
extra/startup-reader.bin Normal file

Binary file not shown.

4483
extra/startup-reader.hex Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -77,11 +77,14 @@ typedef struct cvend_packet {
const char *stringify_msg_type(uint8_t msg_type);
void cvend_init(const char *path);
cvend_packet *cvend_read();
cvend_packet *cvend_read_type(uint8_t msg_type);
void cvend_write(uint8_t msg_type, uint8_t *msg_data, uint16_t msg_len);
void cvend_init();
void cvend_lock();
void cvend_unlock();
cvend_packet *cvend_read(FILE *file);
cvend_packet *cvend_read_type(FILE *file, uint8_t msg_type);
void cvend_write(FILE *file, uint8_t msg_type, uint8_t *msg_data, uint16_t msg_len);
void cvend_free(cvend_packet *packet);
void print_packet(cvend_packet *packet);
void print_packet_short(char *brief, cvend_packet *packet);
#endif /* end of include guard: CVEND_H_WNGPTXM7 */

View File

@@ -6,7 +6,7 @@
typedef void (*nfc_cb)(uint8_t status, uint8_t *version, uint16_t version_size,
uint8_t *data, uint16_t data_size);
void nfc_init(const char *path);
void nfc_reset(const char *path);
void *nfc_handle(void *data);
#endif /* end of include guard: NFC_H_3196CYAP */

View File

@@ -7,8 +7,6 @@
#include "crc32.h"
#include "cvend.h"
const char *cvend_path;
FILE *file;
pthread_mutex_t cvend_mutex = PTHREAD_MUTEX_INITIALIZER;
int last_seq = 0;
@@ -112,6 +110,14 @@ const char *stringify_msg_type(uint8_t msg_type)
}
}
void cvend_lock() {
pthread_mutex_lock(&cvend_mutex);
}
void cvend_unlock() {
pthread_mutex_unlock(&cvend_mutex);
}
void calc_hdr_crc(cvend_packet *packet)
{
packet->magic = 0xbc;
@@ -128,25 +134,23 @@ void calc_msg_crc(cvend_packet *packet)
packet->msg_crc = 0;
}
void cvend_init(const char *path)
void cvend_init()
{
cvend_path = path;
file = fopen(path, "wb+");
}
cvend_packet *cvend_read()
cvend_packet *cvend_read(FILE *file)
{
pthread_mutex_lock(&cvend_mutex);
cvend_lock();
uint8_t buf = 0x00;
uint8_t res = 0;
while (buf != 0xbc) {
res = fread(&buf, 1, 1, file);
if (res == 0) {
fclose(file);
file = fopen(cvend_path, "wb+");
cvend_unlock();
return NULL;
}
if (buf != 0xbc) {
printf("bad magic char: %x\n", buf);
printf("[WARN] bad magic char: %x\n", buf);
}
}
@@ -159,35 +163,41 @@ cvend_packet *cvend_read()
fread(&packet->hdr_crc, 1, 1, file);
packet->msg_data = malloc(packet->msg_len);
fread(packet->msg_data, 1, packet->msg_len, file);
uint16_t read = fread(packet->msg_data, 1, packet->msg_len, file);
if (read < packet->msg_len) {
printf("[ERROR] bad packet length\n");
cvend_free(packet);
return NULL;
}
if (packet->msg_type & 0x80)
fread(&packet->msg_crc, 1, 4, file);
else
packet->msg_crc = 0;
pthread_mutex_unlock(&cvend_mutex);
cvend_unlock();
if (packet->msg_type != MTYPE_HEARTBEAT) {
printf("RECEIVED:\n");
print_packet(packet);
print_packet_short("received", packet);
}
return packet;
}
cvend_packet *cvend_read_type(uint8_t msg_type)
cvend_packet *cvend_read_type(FILE *file, uint8_t msg_type)
{
cvend_packet *packet = NULL;
do {
if (packet)
cvend_free(packet);
packet = cvend_read();
packet = cvend_read(file);
if (!packet)
return NULL;
} while (packet->msg_type != msg_type);
return packet;
}
void cvend_write(uint8_t msg_type, uint8_t *msg_data,
void cvend_write(FILE *file, uint8_t msg_type, uint8_t *msg_data,
uint16_t msg_len)
{
pthread_mutex_lock(&cvend_mutex);
cvend_lock();
cvend_packet packet;
packet.seq = ++last_seq;
packet.flags = 0;
@@ -197,8 +207,7 @@ void cvend_write(uint8_t msg_type, uint8_t *msg_data,
calc_hdr_crc(&packet);
calc_msg_crc(&packet);
int res = fwrite(&packet.magic, 1, 1, file);
printf("wrote %i\n", res);
fwrite(&packet.magic, 1, 1, file);
fwrite(&packet.seq, 1, 1, file);
fwrite(&packet.flags, 1, 1, file);
fwrite(&packet.msg_type, 1, 1, file);
@@ -209,13 +218,14 @@ void cvend_write(uint8_t msg_type, uint8_t *msg_data,
if (packet.msg_type & 0x80)
fwrite(&packet.msg_crc, 1, 4, file);
pthread_mutex_unlock(&cvend_mutex);
printf("SENT:\n");
print_packet(&packet);
cvend_unlock();
print_packet_short("sent", &packet);
}
void cvend_free(cvend_packet *packet)
{
if (!packet)
return;
free(packet->msg_data);
free(packet);
}
@@ -238,3 +248,18 @@ void print_packet(cvend_packet *packet)
printf("\n");
printf("msg_crc = %u\n\n", packet->msg_crc);
}
void print_packet_short(char *brief, cvend_packet *packet)
{
printf("[INFO] (cvend) %s: ", brief);
printf("%s ", stringify_msg_type(packet->msg_type));
printf("(%02X)", packet->msg_type);
printf(", ");
if (packet->msg_type == MTYPE_LOG) {
printf("%s", packet->msg_data);
} else {
for (uint16_t i = 0; i < packet->msg_len; i++)
printf("%02x ", packet->msg_data[i]);
}
printf("\n");
}

22
src/cvend_decode.c Normal file
View File

@@ -0,0 +1,22 @@
#include "cvend.h"
int main(int argc, char *argv[])
{
const char *path = argc > 1 ? argv[1] : "extra/startup-reader.bin";
FILE *file = fopen(path, "rb");
if (!file) {
printf("Failed to open %s\n", path);
return 1;
}
cvend_init();
cvend_packet *packet = cvend_read(file);
while (packet) {
// print_packet(packet);
cvend_free(packet);
packet = cvend_read(file);
}
return 0;
}

View File

@@ -2,7 +2,7 @@
int main(int argc, char *argv[])
{
char *file = argc > 1 ? argv[1] : "/dev/ttymxc3";
FILE *file = fopen(argc > 1 ? argv[1] : "/dev/ttymxc3", "wb+");
uint8_t desfire_enable[] = { 0x00, CTYPE_DESFIRE, 0x01, FUNC_ENABLE };
// uint8_t desfire_get_version[] = { 0x60 };
uint8_t desfire_select_application[] = { 0x5a, 0xF2, 0x10, 0xE0 };
@@ -10,28 +10,28 @@ int main(int argc, char *argv[])
uint8_t desfire_read[] = { 0xbd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
uint8_t desfire_free[] = { 0x6e };
cvend_init(file);
cvend_write(MTYPE_PROX_CARD_FUNCTION, desfire_enable, 4);
cvend_init();
cvend_write(file, MTYPE_PROX_CARD_FUNCTION, desfire_enable, 4);
while (1) {
cvend_packet *packet;
packet = cvend_read();
packet = cvend_read(file);
// if (packet->msg_type != MTYPE_HEARTBEAT)
print_packet(packet);
if (packet->msg_type == MTYPE_DESFIRE_READ) {
//cvend_write(MTYPE_DESFIRE_INTERACT, desfire_get_version, 1);
cvend_write(MTYPE_DESFIRE_COMMAND, desfire_select_application, 4);
cvend_write(file, MTYPE_DESFIRE_COMMAND, desfire_select_application, 4);
cvend_packet *response;
do {
response = cvend_read();
response = cvend_read(file);
} while (!response);
print_packet(response);
cvend_write(MTYPE_DESFIRE_COMMAND, desfire_fid_list, 1);
cvend_write(file, MTYPE_DESFIRE_COMMAND, desfire_fid_list, 1);
cvend_free(response);
cvend_write(MTYPE_DESFIRE_COMMAND, desfire_read, 8);
cvend_write(MTYPE_DESFIRE_COMMAND, desfire_free, 1);
cvend_write(file, MTYPE_DESFIRE_COMMAND, desfire_read, 8);
cvend_write(file, MTYPE_DESFIRE_COMMAND, desfire_free, 1);
}
cvend_free(packet);

105
src/nfc.c
View File

@@ -1,23 +1,68 @@
#include "cvend.h"
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <poll.h>
#include "nfc.h"
void nfc_init(const char *path)
FILE *nfc_stream = NULL;
const char *nfc_path = NULL;
void nfc_reset(const char *path)
{
uint8_t desfire_enable[] = { 0x00, CTYPE_DESFIRE, 0x01, FUNC_ENABLE };
cvend_packet *packet;
struct pollfd stream_poll;
cvend_init(path);
cvend_write(MTYPE_PROX_CARD_FUNCTION, desfire_enable, 4);
if (nfc_stream)
fclose(nfc_stream);
nfc_stream = fopen(path, "wb+");
stream_poll.fd = fileno(nfc_stream);
stream_poll.events = POLLIN;
cvend_init();
printf("[INFO] checking for signs of life\n");
cvend_write(nfc_stream, MTYPE_STATUS, NULL, 0);
int status = poll(&stream_poll, 1, 1);
if (status) {
printf("[INFO] buffer active, checking status\n");
packet = cvend_read_type(nfc_stream, MTYPE_STATUS_REPLY);
if (!packet) {
printf("[ERROR] failed reading status\n");
exit(1);
}
printf("[INFO] cvend seems to be working\n");
cvend_free(packet);
} else {
printf("[INFO] waiting for startup\n");
packet = cvend_read_type(nfc_stream, MTYPE_STARTUP);
if (!packet) {
printf("[ERROR] stream closed before startup\n");
exit(1);
}
printf("[INFO] startup complete\n");
cvend_free(packet);
}
printf("[INFO] enabling desfire\n");
cvend_write(nfc_stream, MTYPE_PROX_CARD_FUNCTION, desfire_enable, 4);
packet = cvend_read_type(nfc_stream, MTYPE_PROX_CARD_FUNCTION_REPLY);
if (!packet) {
printf("[ERROR] failed to start desfire\n");
exit(1);
}
printf("[INFO] desfire enabled\n");
cvend_free(packet);
}
void *nfc_heartbeat(void *data)
{
uint8_t heartbeat[2] = { 0x00, 0x00 };
while (1) {
cvend_write(MTYPE_STATUS, heartbeat, 2);
sleep(10);
cvend_write(nfc_stream, MTYPE_STATUS, heartbeat, 2);
sleep(1);
}
return NULL;
}
@@ -33,34 +78,50 @@ void *nfc_handle(void *data)
uint8_t desfire_read[] = { 0xbd, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00 };
while (1) {
cvend_packet *packet = cvend_read();
usleep(100);
cvend_packet *packet = cvend_read(nfc_stream);
cvend_packet *resp_version = NULL;
cvend_packet *resp_data = NULL;
if (!packet)
goto reset;
if (packet->msg_type != MTYPE_DESFIRE_READ) {
cvend_free(packet);
continue;
goto cleanup;
}
cvend_free(packet);
cvend_write(MTYPE_DESFIRE_COMMAND,
cvend_write(nfc_stream, MTYPE_DESFIRE_COMMAND,
desfire_select_application, 4);
cvend_free(cvend_read_type(MTYPE_DESFIRE_COMMAND_REPLY));
cvend_free(cvend_read_type(nfc_stream,
MTYPE_DESFIRE_COMMAND_REPLY));
cvend_write(MTYPE_DESFIRE_COMMAND, desfire_get_version,
1);
cvend_packet *resp_version =
cvend_read_type(MTYPE_DESFIRE_COMMAND_REPLY);
cvend_write(nfc_stream, MTYPE_DESFIRE_COMMAND,
desfire_get_version, 1);
resp_version = cvend_read_type(nfc_stream,
MTYPE_DESFIRE_COMMAND_REPLY);
if (!resp_version)
goto reset;
if (resp_version->msg_len == 2 && resp_version->msg_data[1] == 0x6e) {
cvend_free(resp_version);
continue;
}
if (resp_version->msg_len == 2 &&
resp_version->msg_data[1] == 0x6e)
goto cleanup;
cvend_write(nfc_stream, MTYPE_DESFIRE_COMMAND, desfire_read, 8);
resp_data = cvend_read_type(nfc_stream,
MTYPE_DESFIRE_COMMAND_REPLY);
if (!resp_data)
goto reset;
cvend_write(MTYPE_DESFIRE_COMMAND, desfire_read, 8);
cvend_packet *resp_data =
cvend_read_type(MTYPE_DESFIRE_COMMAND_REPLY);
callback(resp_data->msg_data[0], resp_version->msg_data,
resp_version->msg_len, resp_data->msg_data,
resp_version->msg_len);
goto cleanup;
reset:
nfc_reset("/dev/ttymxc3");
cleanup:
cvend_free(packet);
cvend_free(resp_version);
cvend_free(resp_data);
}

View File

@@ -57,7 +57,7 @@ int main(int argc, char *argv[])
lv_linux_fbdev_set_file(display, "/dev/fb0");
pthread_t nfc_thread;
nfc_init("/dev/ttymxc3");
nfc_reset("/dev/ttymxc3");
pthread_create(&nfc_thread, NULL, nfc_handle, read_card);
#else
display = lv_x11_window_create("LVGL X11 Simulation", 800, 480);