Can read and decode TIC data (badly tested)
This commit is contained in:
parent
e9ffb4a032
commit
6c84324fc4
17 changed files with 758 additions and 2 deletions
195
TIC.raw.sample
Normal file
195
TIC.raw.sample
Normal file
|
@ -0,0 +1,195 @@
|
|||
SE 000051519
|
||||
|
||||
PTEC TH.. $
|
||||
|
||||
IINS
|
||||
ADCO 042375023610 8
|
||||
|
||||
OPTARIF BASE 0
|
||||
|
||||
ISOUSC 30 9
|
||||
|
||||
BASE 000051521 Y
|
||||
|
||||
PTEC TH.. $
|
||||
|
||||
IINST 001 X
|
||||
|
||||
IMAX 090 H
|
||||
|
||||
PAPP 00250 (
|
||||
|
||||
HHPHC A ,
|
||||
|
||||
MOTDETAT 000000 B
|
||||
|
||||
ADCO 042375023610 8
|
||||
|
||||
OPTARIF BASE 0
|
||||
|
||||
ISOUSC 30 9
|
||||
|
||||
BASE 000051521 Y
|
||||
|
||||
PTEC TH.. $
|
||||
|
||||
IINST 001 X
|
||||
|
||||
IMAX 090 H
|
||||
|
||||
PAPP 00250 (
|
||||
|
||||
HHPHC A ,
|
||||
|
||||
MOTDETAT 000000 B
|
||||
|
||||
ADCO 042375023610 8
|
||||
|
||||
OPTARIF BASE 0
|
||||
|
||||
ISOUSC 30 9
|
||||
|
||||
BASE 000051521 Y
|
||||
|
||||
PTEC TH.. $
|
||||
|
||||
IINST 001 X
|
||||
|
||||
IMAX 090 H
|
||||
|
||||
PAPP 00250 (
|
||||
|
||||
HHPHC A ,
|
||||
|
||||
MOTDETAT 000000 B
|
||||
|
||||
ADCO 042375023610 8
|
||||
|
||||
OPTARIF BASE 0
|
||||
|
||||
ISOUSC 30 9
|
||||
|
||||
BASE 000051521 Y
|
||||
|
||||
PTEC TH.. $
|
||||
|
||||
IINST 005 \
|
||||
|
||||
IMAX 090 H
|
||||
|
||||
PAPP 01250 )
|
||||
|
||||
HHPHC A ,
|
||||
|
||||
MOTDETAT 000000 B
|
||||
|
||||
ADCO 042375023610 8
|
||||
|
||||
OPTARIF BASE 0
|
||||
|
||||
ISOUSC 30 9
|
||||
|
||||
BASE 000051521 Y
|
||||
|
||||
PTEC TH.. $
|
||||
|
||||
IINST 005 \
|
||||
|
||||
IMAX 090 H
|
||||
|
||||
PAPP 01160 )
|
||||
|
||||
HHPHC A ,
|
||||
|
||||
MOTDETAT 000000 B
|
||||
|
||||
ADCO 042375023610 8
|
||||
|
||||
OPTARIF BASE 0
|
||||
|
||||
ISOUSC 30 9
|
||||
|
||||
BASE 000051521 Y
|
||||
|
||||
PTEC TH.. $
|
||||
|
||||
IINST 004 [
|
||||
|
||||
IMAX 090 H
|
||||
|
||||
PAPP 00980 2
|
||||
|
||||
HHPHC A ,
|
||||
|
||||
MOTDETAT 000000 B
|
||||
|
||||
ADCO 042375023610 8
|
||||
|
||||
OPTARIF BASE 0
|
||||
|
||||
ISOUSC 30 9
|
||||
|
||||
BASE 000051522 Z
|
||||
|
||||
PTEC TH.. $
|
||||
|
||||
IINST 004 [
|
||||
|
||||
IMAX 090 H
|
||||
|
||||
PAPP 01020 $
|
||||
|
||||
HHPHC A ,
|
||||
|
||||
MOTDETAT 000000 B
|
||||
|
||||
ADCO 042375023610 8
|
||||
|
||||
OPTARIF BASE 0
|
||||
|
||||
ISOUSC 30 9
|
||||
|
||||
BASE 000051522 Z
|
||||
|
||||
PTEC TH.. $
|
||||
|
||||
IINST 004 [
|
||||
|
||||
IMAX 090 H
|
||||
|
||||
PAPP 01020 $
|
||||
|
||||
HHPHC A ,
|
||||
|
||||
MOTDETAT 000000 B
|
||||
|
||||
ADCO 042375023610 8
|
||||
|
||||
OPTARIF BASE 0
|
||||
|
||||
ISOUSC 30 9
|
||||
|
||||
BASE 000051522 Z
|
||||
|
||||
PTEC TH.. $
|
||||
|
||||
IINST 004 [
|
||||
|
||||
IMAX 090 H
|
||||
|
||||
PAPP 01010 #
|
||||
|
||||
HHPHC A ,
|
||||
|
||||
MOTDETAT 000000 B
|
||||
|
||||
ADCO 042375023610 8
|
||||
|
||||
OPTARIF BASE 0
|
||||
|
||||
ISOUSC 30 9
|
||||
|
||||
BASE 000051522 Z
|
||||
|
||||
PTEC TH.. $
|
||||
|
|
@ -1,2 +1,2 @@
|
|||
idf_component_register(SRCS "main.c"
|
||||
idf_component_register(SRCS "tic.c" "uart.c" "main.c"
|
||||
INCLUDE_DIRS ".")
|
||||
|
|
44
main/Kconfig.projbuild
Normal file
44
main/Kconfig.projbuild
Normal file
|
@ -0,0 +1,44 @@
|
|||
menu "Enedis TIC configuration"
|
||||
|
||||
orsource "$IDF_PATH/examples/common_components/env_caps/$IDF_TARGET/Kconfig.env_caps"
|
||||
|
||||
config TIC_UART_PORT_NUM
|
||||
int "UART port number"
|
||||
range 0 2 if IDF_TARGET_ESP32 || IDF_TARGET_ESP32S3
|
||||
default 1 if IDF_TARGET_ESP32 || IDF_TARGET_ESP32S3
|
||||
range 0 1
|
||||
default 1
|
||||
help
|
||||
UART communication port number towards Enedis' TIC
|
||||
|
||||
config TIC_UART_BAUD_RATE
|
||||
int "UART communication speed"
|
||||
range 1200 115200
|
||||
default 1200
|
||||
help
|
||||
UART communication speed for TIC. 1200 for historique, 9600 for
|
||||
standard
|
||||
|
||||
config TIC_UART_RXD
|
||||
int "UART RXD pin number"
|
||||
range ENV_GPIO_RANGE_MIN ENV_GPIO_IN_RANGE_MAX
|
||||
default 5
|
||||
help
|
||||
GPIO number for UART RX pin. See UART documentation for more information
|
||||
about available pin numbers for UART.
|
||||
|
||||
# config TIC_UART_TXD
|
||||
# int "UART TXD pin number"
|
||||
# range ENV_GPIO_RANGE_MIN ENV_GPIO_OUT_RANGE_MAX
|
||||
# default 4
|
||||
# help
|
||||
# GPIO number for UART TX pin. See UART documentation for more information
|
||||
# about available pin numbers for UART.
|
||||
|
||||
config TIC_UART_TASK_STACK_SIZE
|
||||
int "UART task stack size"
|
||||
range 1024 16384
|
||||
default 2048
|
||||
help
|
||||
Defines stack size for UART echo example. Insufficient stack size can cause crash.
|
||||
endmenu
|
10
main/main.c
10
main/main.c
|
@ -1,6 +1,14 @@
|
|||
#include <stdio.h>
|
||||
#include "driver/uart.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "uart.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
static const char *TAG = "MAIN";
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
|
||||
ESP_LOGI(TAG, "Arriving in main\n");
|
||||
xTaskCreate(uart_listen_task, "uart_listen_task", TIC_TASK_STACK_SIZE, NULL, 10, NULL);
|
||||
}
|
||||
|
|
174
main/tic.c
Normal file
174
main/tic.c
Normal file
|
@ -0,0 +1,174 @@
|
|||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "tic.h"
|
||||
|
||||
static const char FRAME_START = 0x02;
|
||||
static const char GROUP_START = 0x0a;
|
||||
static const char FIELD_SEP = 0x20;
|
||||
|
||||
DecodeState* create_decode_state(size_t queue_size) {
|
||||
DecodeState* out = malloc(sizeof(DecodeState));
|
||||
out->cur_frame = NULL;
|
||||
out->frame_queue = xQueueCreate(queue_size, sizeof(InfoFrame*));
|
||||
out->checksum = 0;
|
||||
out->fill_step = GFS_NotStarted;
|
||||
out->postpone_buffer[0] = '\0';
|
||||
out->postpone_buffer_size = 0;
|
||||
return out;
|
||||
}
|
||||
|
||||
void free_decode_state(DecodeState* st) {
|
||||
vQueueDelete(st->frame_queue);
|
||||
if(st->cur_frame != NULL) {
|
||||
tic_delete_frame(st->cur_frame);
|
||||
free(st->cur_frame);
|
||||
}
|
||||
free(st);
|
||||
}
|
||||
|
||||
void tic_delete_group(InfoGroup* group) {
|
||||
free(group->time_str);
|
||||
if(group->data_type == GROUP_DATA_STR)
|
||||
free(group->data.str);
|
||||
}
|
||||
void tic_delete_frame(InfoFrame* frame) {
|
||||
for(size_t g_id=0; g_id < frame->group_count; ++g_id)
|
||||
tic_delete_group(frame->groups + g_id);
|
||||
}
|
||||
|
||||
char* tic_discard_until_frame(char* buffer, size_t buf_size) {
|
||||
size_t pos=0;
|
||||
for(pos=0; pos < buf_size; ++pos) {
|
||||
if(buffer[pos] == FRAME_START) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(pos == buf_size)
|
||||
return NULL;
|
||||
return buffer + pos;
|
||||
}
|
||||
|
||||
const uint32_t BAD_STR_TO_INT = ~0U;
|
||||
uint32_t str_to_int(char* buffer, const char* buffer_end) {
|
||||
uint64_t res = 0;
|
||||
for(char* chr=buffer; chr != buffer_end; ++chr) {
|
||||
if('0' <= *chr && *chr <= '9') {
|
||||
res *= 10;
|
||||
res += (*chr - '0');
|
||||
} else {
|
||||
return BAD_STR_TO_INT;
|
||||
}
|
||||
}
|
||||
if(res > BAD_STR_TO_INT)
|
||||
return BAD_STR_TO_INT;
|
||||
return res;
|
||||
}
|
||||
|
||||
static void get_data_pointers(char** start, char** end, const char* buffer, char* pos, DecodeState* state) {
|
||||
if(*start == NULL) { // Postponed data
|
||||
*start = state->postpone_buffer;
|
||||
size_t copy_size = pos - buffer;
|
||||
if(copy_size + state->postpone_buffer_size > POSTPONE_BUFFER_MAXSIZE)
|
||||
copy_size = POSTPONE_BUFFER_MAXSIZE - state->postpone_buffer_size;
|
||||
char* postpone_end = state->postpone_buffer
|
||||
+ state->postpone_buffer_size;
|
||||
memcpy(
|
||||
postpone_end,
|
||||
buffer,
|
||||
copy_size);
|
||||
*end = postpone_end + copy_size;
|
||||
} else { // No postponed data
|
||||
*end = pos;
|
||||
}
|
||||
}
|
||||
|
||||
int tic_decode(char* buffer, size_t buf_size, DecodeState* state) {
|
||||
int frames_decoded = 0;
|
||||
char* start = NULL;
|
||||
char* data_end = NULL;
|
||||
|
||||
for(char* pos = buffer; pos != buffer + buf_size; ++pos) {
|
||||
if(state->fill_step == GFS_Checksum) { // End of frame -- verify checksum
|
||||
if(((state->checksum & 0x3F) + 0x20) != *pos) {
|
||||
state->fill_step = GFS_Invalid;
|
||||
continue;
|
||||
}
|
||||
state->fill_step = GFS_Done;
|
||||
continue;
|
||||
}
|
||||
state->checksum += *pos; // Update checksum
|
||||
|
||||
if(*pos == FRAME_START) {
|
||||
if(state->cur_frame != NULL) {
|
||||
frames_decoded += 1;
|
||||
if(uxQueueSpacesAvailable(state->frame_queue) == 0) {
|
||||
tic_delete_frame(state->cur_frame);
|
||||
free(state->cur_frame);
|
||||
}
|
||||
else
|
||||
xQueueSend(state->frame_queue, state->cur_frame, 0);
|
||||
}
|
||||
state->cur_frame = malloc(sizeof(InfoFrame));
|
||||
memset(state->cur_frame, 0, sizeof(InfoFrame));
|
||||
state->cur_frame->group_count = 0;
|
||||
}
|
||||
else if(*pos == GROUP_START) {
|
||||
// Reset checksum
|
||||
state->checksum = 0;
|
||||
|
||||
if(state->fill_step == GFS_Done) {
|
||||
state->cur_frame->group_count++;
|
||||
state->fill_step = GFS_NotStarted;
|
||||
} else if(state->fill_step == GFS_Invalid) {
|
||||
memset(state->cur_frame->groups + state->cur_frame->group_count,
|
||||
'0', sizeof(InfoGroup));
|
||||
state->fill_step = GFS_NotStarted;
|
||||
} else if(state->fill_step == GFS_NotStarted) {
|
||||
state->fill_step = GFS_Tag;
|
||||
start = pos + 1;
|
||||
} else {
|
||||
state->fill_step = GFS_Invalid;
|
||||
}
|
||||
}
|
||||
else if(*pos == FIELD_SEP) {
|
||||
InfoGroup* cur_group =
|
||||
state->cur_frame->groups + state->cur_frame->group_count;
|
||||
if(state->fill_step == GFS_Tag) {
|
||||
get_data_pointers(&start, &data_end, buffer, pos, state);
|
||||
size_t label_size = data_end - start + 1;
|
||||
if(label_size > INFO_GROUP_LABEL_MAX_SIZE)
|
||||
label_size = INFO_GROUP_LABEL_MAX_SIZE;
|
||||
memcpy(cur_group->label, start, label_size-1);
|
||||
cur_group->label[label_size-1] = '\0';
|
||||
state->fill_step = GFS_Data;
|
||||
start = pos + 1;
|
||||
}
|
||||
else if(state->fill_step == GFS_Data) {
|
||||
get_data_pointers(&start, &data_end, buffer, pos, state);
|
||||
uint32_t int_val = str_to_int(start, data_end);
|
||||
if(int_val == BAD_STR_TO_INT) {
|
||||
size_t len = data_end - start + 1;
|
||||
cur_group->data_type = GROUP_DATA_STR;
|
||||
cur_group->data.str = malloc(sizeof(char) * len);
|
||||
memcpy(cur_group->data.str, start, len-1);
|
||||
cur_group->data.str[len-1] = '\0';
|
||||
} else {
|
||||
cur_group->data_type = GROUP_DATA_NUM;
|
||||
cur_group->data.num = int_val;
|
||||
}
|
||||
state->fill_step = GFS_Checksum;
|
||||
state->checksum -= *pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if((state->fill_step == GFS_Tag || state->fill_step == GFS_Data) && start != NULL) {
|
||||
size_t postpone_size = (buffer + buf_size) - start;
|
||||
if(postpone_size > POSTPONE_BUFFER_MAXSIZE)
|
||||
postpone_size = POSTPONE_BUFFER_MAXSIZE;
|
||||
memcpy(state->postpone_buffer, start, postpone_size);
|
||||
state->postpone_buffer_size = postpone_size;
|
||||
}
|
||||
|
||||
return frames_decoded;
|
||||
}
|
75
main/tic.h
Normal file
75
main/tic.h
Normal file
|
@ -0,0 +1,75 @@
|
|||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef CPU_TEST
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/queue.h"
|
||||
#else
|
||||
#include "cpu_test_harness.h"
|
||||
#endif
|
||||
|
||||
#define INFO_GROUP_LABEL_MAX_SIZE 12lu
|
||||
typedef struct {
|
||||
char label[INFO_GROUP_LABEL_MAX_SIZE];
|
||||
char* time_str;
|
||||
union {
|
||||
uint32_t num;
|
||||
char* str;
|
||||
} data;
|
||||
enum {
|
||||
GROUP_DATA_NUM,
|
||||
GROUP_DATA_STR
|
||||
} data_type;
|
||||
} InfoGroup;
|
||||
|
||||
#define INFO_FRAME_MAX_GROUPS 12lu
|
||||
typedef struct {
|
||||
InfoGroup groups[INFO_FRAME_MAX_GROUPS];
|
||||
uint8_t group_count;
|
||||
} InfoFrame;
|
||||
|
||||
typedef QueueHandle_t InfoFrameQueue;
|
||||
|
||||
typedef enum {
|
||||
GFS_NotStarted,
|
||||
GFS_Tag,
|
||||
GFS_Data,
|
||||
GFS_Checksum,
|
||||
GFS_Done,
|
||||
GFS_Invalid
|
||||
} GroupFillStep;
|
||||
|
||||
#define POSTPONE_BUFFER_MAXSIZE 32lu
|
||||
typedef struct {
|
||||
InfoFrameQueue frame_queue;
|
||||
InfoFrame* cur_frame;
|
||||
char checksum;
|
||||
GroupFillStep fill_step;
|
||||
char postpone_buffer[POSTPONE_BUFFER_MAXSIZE];
|
||||
size_t postpone_buffer_size;
|
||||
} DecodeState;
|
||||
|
||||
/// Initialize a decode state
|
||||
DecodeState* create_decode_state(size_t queue_size);
|
||||
/// Frees a DecodeState
|
||||
void free_decode_state(DecodeState*);
|
||||
|
||||
/// Deletes the contents of an InfoGroup
|
||||
void tic_delete_group(InfoGroup* group);
|
||||
/** Deletes the contents of an InfoFrame. The call to free() itself must be
|
||||
* done by the user */
|
||||
void tic_delete_frame(InfoFrame* frame);
|
||||
|
||||
/**
|
||||
* Discard characters until just before a frame is started, and return a
|
||||
* pointer to the beginning of the next frame (including the start of frame
|
||||
* marker), or NULL if no frame was started.
|
||||
*/
|
||||
char* tic_discard_until_frame(char* buffer, size_t buf_size);
|
||||
|
||||
/**
|
||||
* Decode the buffer, updating the decode state and emitting frames as they are
|
||||
* finished.
|
||||
* Returns how many groups were decoded.
|
||||
*/
|
||||
int tic_decode(char* buffer, size_t buf_size, DecodeState* state);
|
102
main/uart.c
Normal file
102
main/uart.c
Normal file
|
@ -0,0 +1,102 @@
|
|||
/* UART reception file -- reads data from Linky's TIC */
|
||||
#include <stdio.h>
|
||||
#include "driver/uart.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "esp_sleep.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
#include "tic.h"
|
||||
|
||||
/**
|
||||
* This is an example which echos any data it receives on configured UART back to the sender,
|
||||
* with hardware flow control turned off. It does not use UART driver event queue.
|
||||
*
|
||||
* - Port: configured UART
|
||||
* - Receive (Rx) buffer: on
|
||||
* - Transmit (Tx) buffer: off
|
||||
* - Flow control: off
|
||||
* - Event queue: off
|
||||
* - Pin assignment: see defines below (See Kconfig)
|
||||
*/
|
||||
|
||||
#define TIC_RXD (CONFIG_TIC_UART_RXD)
|
||||
#define TIC_RTS (UART_PIN_NO_CHANGE)
|
||||
#define TIC_CTS (UART_PIN_NO_CHANGE)
|
||||
|
||||
#define TIC_UART_PORT_NUM (CONFIG_TIC_UART_PORT_NUM)
|
||||
#define TIC_UART_BAUD_RATE (CONFIG_TIC_UART_BAUD_RATE)
|
||||
static const char *TAG = "TIC UART";
|
||||
|
||||
#define BUF_SIZE (1024)
|
||||
#define TIC_QUEUE_SIZE 64
|
||||
|
||||
static void uart_light_sleep() {
|
||||
// TODO
|
||||
/*
|
||||
ESP_LOGI(TAG, "Entering sleep.\n");
|
||||
vTaskDelay(10/portTICK_PERIOD_MS);
|
||||
ESP_ERROR_CHECK(esp_light_sleep_start());
|
||||
esp_sleep_wakeup_cause_t wakeup_cause = esp_sleep_get_wakeup_cause();
|
||||
ESP_LOGI(TAG, "Woken up: %d\n", wakeup_cause);
|
||||
*/
|
||||
}
|
||||
|
||||
void uart_listen_task(void *arg)
|
||||
{
|
||||
/* Configure parameters of an UART driver,
|
||||
* communication pins and install the driver */
|
||||
uart_config_t uart_config = {
|
||||
.baud_rate = TIC_UART_BAUD_RATE,
|
||||
.data_bits = UART_DATA_8_BITS,
|
||||
.parity = UART_PARITY_DISABLE,
|
||||
.stop_bits = UART_STOP_BITS_1,
|
||||
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
|
||||
.source_clk = UART_SCLK_DEFAULT,
|
||||
};
|
||||
int intr_alloc_flags = 0;
|
||||
|
||||
#if CONFIG_UART_ISR_IN_IRAM
|
||||
intr_alloc_flags = ESP_INTR_FLAG_IRAM;
|
||||
#endif
|
||||
|
||||
ESP_ERROR_CHECK(uart_param_config(TIC_UART_PORT_NUM, &uart_config));
|
||||
ESP_ERROR_CHECK(uart_set_pin(TIC_UART_PORT_NUM, UART_PIN_NO_CHANGE, TIC_RXD, TIC_RTS, TIC_CTS));
|
||||
ESP_ERROR_CHECK(uart_driver_install(TIC_UART_PORT_NUM, BUF_SIZE * 2, 0, 0, NULL, intr_alloc_flags));
|
||||
//ESP_ERROR_CHECK(uart_set_wakeup_threshold(TIC_UART_PORT_NUM, 3));
|
||||
//ESP_ERROR_CHECK(esp_sleep_enable_uart_wakeup(TIC_UART_PORT_NUM));
|
||||
|
||||
// Configure a temporary buffer for the incoming data
|
||||
char *data = (char *) malloc(BUF_SIZE);
|
||||
|
||||
// Setup the TIC decoding
|
||||
DecodeState* tic_state = create_decode_state(TIC_QUEUE_SIZE);
|
||||
int initialized = 0;
|
||||
|
||||
// Discard any data already buffered
|
||||
ESP_ERROR_CHECK(uart_flush(TIC_UART_PORT_NUM));
|
||||
|
||||
ESP_LOGI(TAG, "Start receiving.\n");
|
||||
while (1) {
|
||||
int len = uart_read_bytes(TIC_UART_PORT_NUM, data, (BUF_SIZE - 1), 30 / portTICK_PERIOD_MS);
|
||||
if (len) {
|
||||
if(!initialized) {
|
||||
char* init_begin = tic_discard_until_frame(data, len);
|
||||
if(init_begin != NULL) {
|
||||
size_t discarded = init_begin - data;
|
||||
initialized = 1;
|
||||
tic_decode(init_begin, len - discarded, tic_state);
|
||||
}
|
||||
} else {
|
||||
tic_decode(data, len, tic_state);
|
||||
}
|
||||
|
||||
data[len] = '\0';
|
||||
ESP_LOGI(TAG, "Recv str: %s", (char *) data);
|
||||
}
|
||||
else {
|
||||
uart_light_sleep();
|
||||
}
|
||||
}
|
||||
|
||||
free_decode_state(tic_state);
|
||||
}
|
6
main/uart.h
Normal file
6
main/uart.h
Normal file
|
@ -0,0 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "sdkconfig.h"
|
||||
#define TIC_TASK_STACK_SIZE (CONFIG_TIC_UART_TASK_STACK_SIZE)
|
||||
|
||||
void uart_listen_task(void* arg);
|
18
test_cpu/Makefile
Normal file
18
test_cpu/Makefile
Normal file
|
@ -0,0 +1,18 @@
|
|||
ESP_DIR=../main/
|
||||
COMMON_OBJS=cpu_test_harness.o
|
||||
ESP_OBJS=tic.o
|
||||
CFLAGS=-Wextra -O2 -g -I$(ESP_DIR) -I. -DCPU_TEST
|
||||
CC=gcc
|
||||
|
||||
TARGETS=test_tic.bin
|
||||
|
||||
all: $(TARGETS)
|
||||
|
||||
test_%.bin: test_%.o $(COMMON_OBJS) $(ESP_OBJS)
|
||||
$(CC) $(CFLAGS) $^ -o $@
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
%.o: $(ESP_DIR)/%.c
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
2
test_cpu/README.md
Normal file
2
test_cpu/README.md
Normal file
|
@ -0,0 +1,2 @@
|
|||
Harness to test relevant parts of the code on a standard CPU instead of the
|
||||
ESP32.
|
31
test_cpu/cpu_test_harness.c
Normal file
31
test_cpu/cpu_test_harness.c
Normal file
|
@ -0,0 +1,31 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "cpu_test_harness.h"
|
||||
#include "tic.h"
|
||||
|
||||
QueueHandle_t xQueueCreate(int a, int b) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void vQueueDelete(QueueHandle_t _) {}
|
||||
|
||||
int uxQueueSpacesAvailable(QueueHandle_t _) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
void xQueueSend(QueueHandle_t _, void* elt, int _b) {
|
||||
InfoFrame* frame = elt;
|
||||
printf(">> SENT: Frame with %u groups.\n", frame->group_count);
|
||||
for(size_t grp_id=0; grp_id < frame->group_count; ++grp_id) {
|
||||
InfoGroup* grp = frame->groups + grp_id;
|
||||
printf("Group %02lu: %s %s ", grp_id, grp->label,
|
||||
(grp->data_type == GROUP_DATA_NUM) ? "num" : "str");
|
||||
if(grp->data_type == GROUP_DATA_NUM)
|
||||
printf("%u\n", grp->data.num);
|
||||
else
|
||||
printf("%s\n", grp->data.str);
|
||||
}
|
||||
|
||||
tic_delete_frame(frame);
|
||||
free(frame);
|
||||
}
|
11
test_cpu/cpu_test_harness.h
Normal file
11
test_cpu/cpu_test_harness.h
Normal file
|
@ -0,0 +1,11 @@
|
|||
#pragma once
|
||||
#ifndef CPU_TEST
|
||||
#define CPU_TEST
|
||||
#endif
|
||||
|
||||
// ========== FreeRtos queues ==========
|
||||
typedef void* QueueHandle_t;
|
||||
QueueHandle_t xQueueCreate(int, int);
|
||||
int uxQueueSpacesAvailable(QueueHandle_t);
|
||||
void xQueueSend(QueueHandle_t, void* elt, int);
|
||||
void vQueueDelete(QueueHandle_t);
|
BIN
test_cpu/cpu_test_harness.o
Normal file
BIN
test_cpu/cpu_test_harness.o
Normal file
Binary file not shown.
BIN
test_cpu/test_tic.bin
Executable file
BIN
test_cpu/test_tic.bin
Executable file
Binary file not shown.
36
test_cpu/test_tic.c
Normal file
36
test_cpu/test_tic.c
Normal file
|
@ -0,0 +1,36 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "tic.h"
|
||||
|
||||
#define BUF_SIZE 32
|
||||
|
||||
int main(void) {
|
||||
DecodeState* state = create_decode_state(42);
|
||||
FILE* tic_handle = fopen("../TIC.raw.sample", "rb");
|
||||
|
||||
//int initialized = 0;
|
||||
char buffer[BUF_SIZE];
|
||||
int buf_size = 0;
|
||||
while(1) {
|
||||
buf_size = fread(buffer, sizeof(char), BUF_SIZE, tic_handle);
|
||||
fprintf(stderr, "Read %d bytes\n", buf_size);
|
||||
if(buf_size == 0)
|
||||
break;
|
||||
/*
|
||||
if(!initialized) {
|
||||
char* init_begin = tic_discard_until_frame(buffer, buf_size);
|
||||
if(init_begin != NULL) {
|
||||
size_t discarded = (init_begin - buffer);
|
||||
initialized = 1;
|
||||
tic_decode(init_begin, buf_size - discarded, state);
|
||||
}
|
||||
} else {
|
||||
*/
|
||||
tic_decode(buffer, buf_size, state);
|
||||
//}
|
||||
}
|
||||
|
||||
free_decode_state(state);
|
||||
|
||||
return 0;
|
||||
}
|
BIN
test_cpu/tic.o
Normal file
BIN
test_cpu/tic.o
Normal file
Binary file not shown.
54
tester/feed_tic.py
Executable file
54
tester/feed_tic.py
Executable file
|
@ -0,0 +1,54 @@
|
|||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import typing as t
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
import serial
|
||||
|
||||
|
||||
def iter_frames(raw_data: bytes) -> t.Iterator[bytes]:
|
||||
FRAME_START = 0x02
|
||||
next_frame = b""
|
||||
# Discard first bytes
|
||||
raw_data = raw_data[raw_data.find(FRAME_START) :]
|
||||
|
||||
for ch in raw_data:
|
||||
# Discard first bytes
|
||||
if ch == FRAME_START and next_frame:
|
||||
yield next_frame
|
||||
next_frame = b""
|
||||
next_frame += bytes([ch])
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("-p", "--port", default="/dev/ttyUSB1")
|
||||
parser.add_argument("-b", "--baud", type=int, default=1200)
|
||||
parser.add_argument(
|
||||
"--frame-gap", type=int, default=1500, help="Time between two frames (in ms)"
|
||||
)
|
||||
parser.add_argument(
|
||||
"recorded_data",
|
||||
help="File containing real recorded data to replay",
|
||||
type=Path,
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
data: bytes = b""
|
||||
with args.recorded_data.open("rb") as h:
|
||||
data = h.read()
|
||||
|
||||
with serial.Serial(port=args.port, baudrate=args.baud) as ser:
|
||||
for frame in iter_frames(data):
|
||||
print(f"Feeding {len(frame)}b frame")
|
||||
start_time = time.monotonic()
|
||||
ser.write(frame)
|
||||
elapsed_time = time.monotonic() - start_time
|
||||
sleep_time = args.frame_gap / 1000 - elapsed_time
|
||||
if sleep_time > 0:
|
||||
time.sleep(sleep_time)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
Loading…
Reference in a new issue