commit
a054b4c546
9 changed files with 219 additions and 0 deletions
@ -0,0 +1,2 @@ |
|||
build |
|||
sdkconfig.old |
|||
@ -0,0 +1,6 @@ |
|||
# The following lines of boilerplate have to be in your project's CMakeLists |
|||
# in this exact order for cmake to work correctly |
|||
cmake_minimum_required(VERSION 3.5) |
|||
|
|||
include($ENV{IDF_PATH}/tools/cmake/project.cmake) |
|||
project(tic_to_mqtt) |
|||
@ -0,0 +1,8 @@ |
|||
#
|
|||
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
|||
# project subdirectory.
|
|||
#
|
|||
|
|||
PROJECT_NAME := tic_to_mqtt |
|||
|
|||
include $(IDF_PATH)/make/project.mk |
|||
@ -0,0 +1,2 @@ |
|||
idf_component_register(SRCS "main.c" "tic.c" |
|||
INCLUDE_DIRS ".") |
|||
@ -0,0 +1,26 @@ |
|||
menu "TIC-to-MQTT Configuration" |
|||
|
|||
config TIC_MODE |
|||
int "Mode historique (0) ou standard (1)" |
|||
range 0 1 |
|||
default 0 |
|||
help |
|||
Configure la liaison TIC en mode historique ou en mode standard. |
|||
|
|||
config TIC_UART_RXD |
|||
int "Pin utilisée pour recevoir la TIC" |
|||
range 0 34 if IDF_TARGET_ESP32 |
|||
range 0 46 if IDF_TARGET_ESP32S2 |
|||
range 0 19 if IDF_TARGET_ESP32C3 |
|||
default 16 |
|||
help |
|||
GPIO number for UART RX pin. |
|||
|
|||
config TIC_UART_STACK_SIZE |
|||
int "Taille de la pile pour le décodage de la TIC" |
|||
range 1024 16384 |
|||
default 2048 |
|||
help |
|||
Defines stack size. Insufficient stack size can cause crash. |
|||
|
|||
endmenu |
|||
@ -0,0 +1,3 @@ |
|||
#
|
|||
# Main Makefile. This is basically the same as a component makefile.
|
|||
#
|
|||
@ -0,0 +1,12 @@ |
|||
#include <stdio.h> |
|||
#include <string.h> |
|||
#include "freertos/FreeRTOS.h" |
|||
#include "freertos/task.h" |
|||
#include "freertos/queue.h" |
|||
#include "driver/uart.h" |
|||
#include "esp_log.h" |
|||
#include "tic.h" |
|||
|
|||
void app_main(void) { |
|||
tic_uart_init(); |
|||
} |
|||
@ -0,0 +1,149 @@ |
|||
#include <stdio.h> |
|||
#include <string.h> |
|||
#include "freertos/FreeRTOS.h" |
|||
#include "freertos/task.h" |
|||
#include "freertos/queue.h" |
|||
#include "driver/uart.h" |
|||
#include "esp_log.h" |
|||
#include "tic.h" |
|||
|
|||
static const char *TIC_LOGGER = "tic"; |
|||
static QueueHandle_t uart_queue; |
|||
|
|||
uint8_t tic_checksum(uint8_t* buffer, size_t start, size_t end) { |
|||
uint16_t checksum = 0; |
|||
for (size_t i = start; i <= end; i++) { |
|||
checksum += buffer[i]; |
|||
} |
|||
checksum = (checksum & 0x3F) + 0x20; |
|||
return (uint8_t)checksum; |
|||
} |
|||
|
|||
static void tic_uart_events(void *pvParameters) { |
|||
uart_event_t event; |
|||
size_t buffered_size; |
|||
uint8_t* buffer = (uint8_t*) malloc(TIC_READ_BUFFER_SIZE); |
|||
uint8_t methods[2] = {0, 0}; |
|||
for(;;) { |
|||
// Waiting for UART event.
|
|||
if(xQueueReceive(uart_queue, (void * )&event, (portTickType)portMAX_DELAY)) { |
|||
switch(event.type) { |
|||
case UART_FIFO_OVF: |
|||
case UART_BUFFER_FULL: |
|||
case UART_PARITY_ERR: |
|||
case UART_FRAME_ERR: |
|||
ESP_LOGI(TIC_LOGGER, "error: event type %d. Discarding existing data...", event.type); |
|||
uart_flush_input(TIC_UART_NUM); |
|||
xQueueReset(uart_queue); |
|||
break; |
|||
case UART_PATTERN_DET: |
|||
bzero(buffer, TIC_READ_BUFFER_SIZE); |
|||
uart_get_buffered_data_len(TIC_UART_NUM, &buffered_size); |
|||
int pos = uart_pattern_pop_pos(TIC_UART_NUM); |
|||
if (pos == -1) { |
|||
// There used to be a UART_PATTERN_DET event, but the pattern position queue is full so that it can not
|
|||
// record the position. We should set a larger queue size.
|
|||
// As an example, we directly flush the rx buffer here.
|
|||
uart_flush_input(TIC_UART_NUM); |
|||
} else { |
|||
uint8_t* scratch = buffer; |
|||
uart_read_bytes(TIC_UART_NUM, scratch, pos + 1, 100 / portTICK_PERIOD_MS); |
|||
scratch[pos] = '\0'; |
|||
ESP_LOGD(TIC_LOGGER, "read data: '%s', separator at %d", scratch, pos); |
|||
|
|||
// '\n' + tag + sep + value + sep + checksum = at least 6 characters
|
|||
if (pos < 6) { |
|||
ESP_LOGI(TIC_LOGGER, "read string is too short: %d", pos); |
|||
break; |
|||
} |
|||
|
|||
// during manual tests, there is no '\n' at the start of the string
|
|||
// but according to Enedis, there is one in the actual data sent.
|
|||
if (scratch[0] == '\n') { |
|||
scratch++; |
|||
pos--; |
|||
} |
|||
|
|||
if (methods[0] >= TIC_CHECKSUM_THRESHOLD || methods[1] >= TIC_CHECKSUM_THRESHOLD) { |
|||
if (methods[0] >= TIC_CHECKSUM_THRESHOLD && tic_checksum(scratch, 0, pos - 3) == scratch[pos - 1]) { |
|||
ESP_LOGD(TIC_LOGGER, "validated with method1: %s", scratch); |
|||
} else if (methods[1] >= TIC_CHECKSUM_THRESHOLD && tic_checksum(scratch, 0, pos - 2) == scratch[pos - 1]) { |
|||
ESP_LOGD(TIC_LOGGER, "validated with method2: %s", scratch); |
|||
} else { |
|||
ESP_LOGI(TIC_LOGGER, "wrong checksum: %s", scratch); |
|||
break; |
|||
} |
|||
} else { |
|||
if (tic_checksum(scratch, 0, pos - 3) == scratch[pos - 1]) { |
|||
methods[0]++; |
|||
ESP_LOGD(TIC_LOGGER, "validated with method 1 while learning: %s", scratch); |
|||
} else if (tic_checksum(scratch, 0, pos - 2) == scratch[pos - 1]) { |
|||
methods[1]++; |
|||
ESP_LOGD(TIC_LOGGER, "validated with method 2 while learning: %s", scratch); |
|||
} else { |
|||
ESP_LOGI(TIC_LOGGER, "wrong checksum: %s", scratch); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
// trim the checksum
|
|||
scratch[pos - 2] = '\0'; |
|||
ESP_LOGD(TIC_LOGGER, "validated: '%s'", scratch); |
|||
} |
|||
break; |
|||
//Others
|
|||
default: |
|||
break; |
|||
} |
|||
} |
|||
} |
|||
free(buffer); |
|||
buffer = NULL; |
|||
vTaskDelete(NULL); |
|||
} |
|||
|
|||
void tic_uart_init() { |
|||
// Eventually, the log level can be reduced here
|
|||
//ESP_ERROR_CHECK(esp_log_level_set(TIC_LOGGER, ESP_LOG_INFO));
|
|||
|
|||
#if CONFIG_TIC_MODE == 0 |
|||
uart_config_t uart_config = { |
|||
.baud_rate = 1200, |
|||
.data_bits = UART_DATA_7_BITS, |
|||
.parity = UART_PARITY_EVEN, |
|||
.stop_bits = UART_STOP_BITS_1, |
|||
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE, |
|||
.source_clk = UART_SCLK_APB, |
|||
}; |
|||
#endif |
|||
#if CONFIG_TIC_MODE == 1 |
|||
uart_config_t uart_config = { |
|||
.baud_rate = 9600, |
|||
// TODO: validate other parameters
|
|||
.data_bits = UART_DATA_7_BITS, |
|||
.parity = UART_PARITY_EVEN, |
|||
.stop_bits = UART_STOP_BITS_1, |
|||
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE, |
|||
.source_clk = UART_SCLK_APB, |
|||
}; |
|||
#endif |
|||
// Setup the UART
|
|||
ESP_ERROR_CHECK(uart_driver_install(TIC_UART_NUM, TIC_BUFFER_SIZE, TIC_BUFFER_SIZE, 20, &uart_queue, 0)); |
|||
ESP_ERROR_CHECK(uart_param_config(TIC_UART_NUM, &uart_config)); |
|||
ESP_ERROR_CHECK(uart_set_pin(TIC_UART_NUM, UART_PIN_NO_CHANGE, CONFIG_TIC_UART_RXD, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE)); |
|||
ESP_ERROR_CHECK(uart_enable_pattern_det_baud_intr(TIC_UART_NUM, '\r', 1, 9, 0, 0)); |
|||
ESP_ERROR_CHECK(uart_pattern_queue_reset(TIC_UART_NUM, 20)); |
|||
|
|||
// Create a task to handler UART event from ISR
|
|||
BaseType_t xReturned; |
|||
xReturned = xTaskCreate(tic_uart_events, |
|||
"tic_uart_events", |
|||
CONFIG_TIC_UART_STACK_SIZE, /* Stack size in words, not bytes. */ |
|||
NULL, /* Parameter passed into the task. */ |
|||
tskIDLE_PRIORITY + 12, |
|||
NULL); |
|||
if (xReturned != pdPASS) { |
|||
ESP_LOGE(TIC_LOGGER, "xTaskCreate('tic_uart_events'): %d", xReturned); |
|||
abort(); |
|||
} |
|||
} |
|||
@ -0,0 +1,11 @@ |
|||
#ifndef __TIC_H__ |
|||
#define __TIC_H__ |
|||
|
|||
#define TIC_BUFFER_SIZE (2048) |
|||
#define TIC_READ_BUFFER_SIZE (TIC_BUFFER_SIZE / 2) |
|||
#define TIC_CHECKSUM_THRESHOLD (10) |
|||
#define TIC_UART_NUM UART_NUM_2 |
|||
|
|||
void tic_uart_init(); |
|||
|
|||
#endif |
|||
Loading…
Reference in new issue