Files
Sillyfilly-CAN/main/main.c
T
2023-07-16 15:12:43 +09:00

423 lines
13 KiB
C

/*
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "freertos/event_groups.h"
#include "freertos/semphr.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_vfs.h"
#include "nvs_flash.h"
#include "esp_err.h"
#include "esp_log.h"
#include "esp_spiffs.h"
#include "mdns.h"
#include "lwip/dns.h"
#include "driver/twai.h" // Update from V4.2
#include "twai.h"
#define TAG "MAIN"
static const twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL();
#if CONFIG_CAN_BITRATE_25
static const twai_timing_config_t t_config = TWAI_TIMING_CONFIG_25KBITS();
#define BITRATE "Bitrate is 25 Kbit/s"
#elif CONFIG_CAN_BITRATE_50
static const twai_timing_config_t t_config = TWAI_TIMING_CONFIG_50KBITS();
#define BITRATE "Bitrate is 50 Kbit/s"
#elif CONFIG_CAN_BITRATE_100
static const twai_timing_config_t t_config = TWAI_TIMING_CONFIG_100KBITS();
#define BITRATE "Bitrate is 100 Kbit/s"
#elif CONFIG_CAN_BITRATE_125
static const twai_timing_config_t t_config = TWAI_TIMING_CONFIG_125KBITS();
#define BITRATE "Bitrate is 125 Kbit/s"
#elif CONFIG_CAN_BITRATE_250
static const twai_timing_config_t t_config = TWAI_TIMING_CONFIG_250KBITS();
#define BITRATE "Bitrate is 250 Kbit/s"
#elif CONFIG_CAN_BITRATE_500
static const twai_timing_config_t t_config = TWAI_TIMING_CONFIG_500KBITS();
#define BITRATE "Bitrate is 500 Kbit/s"
#elif CONFIG_CAN_BITRATE_800
static const twai_timing_config_t t_config = TWAI_TIMING_CONFIG_800KBITS();
#define BITRATE "Bitrate is 800 Kbit/s"
#elif CONFIG_CAN_BITRATE_1000
static const twai_timing_config_t t_config = TWAI_TIMING_CONFIG_1MBITS();
#define BITRATE "Bitrate is 1 Mbit/s"
#endif
/* FreeRTOS event group to signal when we are connected*/
static EventGroupHandle_t s_wifi_event_group;
/* The event group allows multiple bits for each event, but we only care about two events:
* - we are connected to the AP with an IP
* - we failed to connect after the maximum amount of retries */
#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT BIT1
static int s_retry_num = 0;
QueueHandle_t xQueue_http_client;
QueueHandle_t xQueue_twai_tx;
TOPIC_t *publish;
int16_t npublish;
static void event_handler(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data)
{
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
esp_wifi_connect();
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
if (s_retry_num < CONFIG_ESP_MAXIMUM_RETRY) {
esp_wifi_connect();
s_retry_num++;
ESP_LOGI(TAG, "retry to connect to the AP");
} else {
xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
}
ESP_LOGI(TAG,"connect to the AP fail");
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
s_retry_num = 0;
xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
}
}
void wifi_init_sta()
{
s_wifi_event_group = xEventGroupCreate();
ESP_LOGI(TAG,"ESP-IDF Ver%d.%d", ESP_IDF_VERSION_MAJOR, ESP_IDF_VERSION_MINOR);
ESP_LOGI(TAG,"ESP_IDF_VERSION %d", ESP_IDF_VERSION);
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
esp_netif_t *netif = esp_netif_create_default_wifi_sta();
assert(netif);
#if CONFIG_STATIC_IP
ESP_LOGI(TAG, "CONFIG_STATIC_IP_ADDRESS=[%s]",CONFIG_STATIC_IP_ADDRESS);
ESP_LOGI(TAG, "CONFIG_STATIC_GW_ADDRESS=[%s]",CONFIG_STATIC_GW_ADDRESS);
ESP_LOGI(TAG, "CONFIG_STATIC_NM_ADDRESS=[%s]",CONFIG_STATIC_NM_ADDRESS);
/* Stop DHCP client */
ESP_ERROR_CHECK(esp_netif_dhcpc_stop(netif));
ESP_LOGI(TAG, "Stop DHCP Services");
/* Set STATIC IP Address */
esp_netif_ip_info_t ip_info;
memset(&ip_info, 0 , sizeof(esp_netif_ip_info_t));
ip_info.ip.addr = ipaddr_addr(CONFIG_STATIC_IP_ADDRESS);
ip_info.netmask.addr = ipaddr_addr(CONFIG_STATIC_NM_ADDRESS);
ip_info.gw.addr = ipaddr_addr(CONFIG_STATIC_GW_ADDRESS);;
esp_netif_set_ip_info(netif, &ip_info);
/*
I referred from here.
https://www.esp32.com/viewtopic.php?t=5380
if we should not be using DHCP (for example we are using static IP addresses),
then we need to instruct the ESP32 of the locations of the DNS servers manually.
Google publicly makes available two name servers with the addresses of 8.8.8.8 and 8.8.4.4.
*/
ip_addr_t d;
d.type = IPADDR_TYPE_V4;
d.u_addr.ip4.addr = 0x08080808; //8.8.8.8 dns
dns_setserver(0, &d);
d.u_addr.ip4.addr = 0x08080404; //8.8.4.4 dns
dns_setserver(1, &d);
#endif // CONFIG_STATIC_IP
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL));
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL));
wifi_config_t wifi_config = {
.sta = {
.ssid = CONFIG_ESP_WIFI_SSID,
.password = CONFIG_ESP_WIFI_PASSWORD
},
};
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) );
ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config) );
ESP_ERROR_CHECK(esp_wifi_start() );
ESP_LOGI(TAG, "wifi_init_sta finished.");
/* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum
* number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */
EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
pdFALSE,
pdFALSE,
portMAX_DELAY);
/* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually
* happened. */
if (bits & WIFI_CONNECTED_BIT) {
ESP_LOGI(TAG, "connected to ap SSID:%s password:%s", CONFIG_ESP_WIFI_SSID, CONFIG_ESP_WIFI_PASSWORD);
} else if (bits & WIFI_FAIL_BIT) {
ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s", CONFIG_ESP_WIFI_SSID, CONFIG_ESP_WIFI_PASSWORD);
} else {
ESP_LOGE(TAG, "UNEXPECTED EVENT");
}
vEventGroupDelete(s_wifi_event_group);
}
void initialise_mdns(void)
{
//initialize mDNS
ESP_ERROR_CHECK( mdns_init() );
//set mDNS hostname (required if you want to advertise services)
ESP_ERROR_CHECK( mdns_hostname_set(CONFIG_MDNS_HOSTNAME) );
ESP_LOGI(TAG, "mdns hostname set to: [%s]", CONFIG_MDNS_HOSTNAME);
#if 0
//set default mDNS instance name
ESP_ERROR_CHECK( mdns_instance_name_set("ESP32 with mDNS") );
#endif
}
esp_err_t mountSPIFFS(char * partition_label, char * base_path) {
ESP_LOGI(TAG, "Initializing SPIFFS file system");
esp_vfs_spiffs_conf_t conf = {
.base_path = base_path,
.partition_label = partition_label,
.max_files = 5,
.format_if_mount_failed = true
};
// Use settings defined above to initialize and mount SPIFFS filesystem.
// Note: esp_vfs_spiffs_register is an all-in-one convenience function.
esp_err_t ret = esp_vfs_spiffs_register(&conf);
if (ret != ESP_OK) {
if (ret == ESP_FAIL) {
ESP_LOGE(TAG, "Failed to mount or format filesystem");
} else if (ret == ESP_ERR_NOT_FOUND) {
ESP_LOGE(TAG, "Failed to find SPIFFS partition");
} else {
ESP_LOGE(TAG, "Failed to initialize SPIFFS (%s)", esp_err_to_name(ret));
}
return ret;
}
size_t total = 0, used = 0;
ret = esp_spiffs_info(partition_label, &total, &used);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to get SPIFFS partition information (%s)", esp_err_to_name(ret));
} else {
ESP_LOGI(TAG, "Partition size: total: %d, used: %d", total, used);
DIR* dir = opendir(base_path);
assert(dir != NULL);
while (true) {
struct dirent*pe = readdir(dir);
if (!pe) break;
ESP_LOGI(TAG, "d_name=%s d_ino=%d d_type=%x", pe->d_name,pe->d_ino, pe->d_type);
}
closedir(dir);
}
ESP_LOGI(TAG, "Mount SPIFFS filesystem");
return ret;
}
esp_err_t build_table(TOPIC_t **topics, char *file, int16_t *ntopic)
{
ESP_LOGI(TAG, "build_table file=%s", file);
char line[128];
int _ntopic = 0;
FILE* f = fopen(file, "r");
if (f == NULL) {
ESP_LOGE(TAG, "Failed to open file for reading");
return ESP_FAIL;
}
while (1){
if ( fgets(line, sizeof(line) ,f) == 0 ) break;
// strip newline
char* pos = strchr(line, '\n');
if (pos) {
*pos = '\0';
}
ESP_LOGD(TAG, "line=[%s]", line);
if (strlen(line) == 0) continue;
if (line[0] == '#') continue;
_ntopic++;
}
fclose(f);
ESP_LOGI(TAG, "build_table _ntopic=%d", _ntopic);
*topics = calloc(_ntopic, sizeof(TOPIC_t));
if (*topics == NULL) {
ESP_LOGE(TAG, "Error allocating memory for topic");
return ESP_ERR_NO_MEM;
}
f = fopen(file, "r");
if (f == NULL) {
ESP_LOGE(TAG, "Failed to open file for reading");
return ESP_FAIL;
}
char *ptr;
int index = 0;
while (1){
if ( fgets(line, sizeof(line) ,f) == 0 ) break;
// strip newline
char* pos = strchr(line, '\n');
if (pos) {
*pos = '\0';
}
ESP_LOGD(TAG, "line=[%s]", line);
if (strlen(line) == 0) continue;
if (line[0] == '#') continue;
// Frame type
ptr = strtok(line, ",");
ESP_LOGD(TAG, "ptr=%s", ptr);
if (strcmp(ptr, "S") == 0) {
(*topics+index)->frame = 0;
} else if (strcmp(ptr, "E") == 0) {
(*topics+index)->frame = 1;
} else {
ESP_LOGE(TAG, "This line is invalid [%s]", line);
continue;
}
// CAN ID
uint32_t canid;
ptr = strtok(NULL, ",");
if(ptr == NULL) continue;
ESP_LOGD(TAG, "ptr=%s", ptr);
canid = strtol(ptr, NULL, 16);
if (canid == 0) {
ESP_LOGE(TAG, "This line is invalid [%s]", line);
continue;
}
(*topics+index)->canid = canid;
// mqtt topic
char *sp;
ptr = strtok(NULL, ",");
if(ptr == NULL) {
ESP_LOGE(TAG, "This line is invalid [%s]", line);
continue;
}
ESP_LOGD(TAG, "ptr=[%s] strlen=%d", ptr, strlen(ptr));
sp = strstr(ptr,"#");
if (sp != NULL) {
ESP_LOGE(TAG, "This line is invalid [%s]", line);
continue;
}
sp = strstr(ptr,"+");
if (sp != NULL) {
ESP_LOGE(TAG, "This line is invalid [%s]", line);
continue;
}
(*topics+index)->topic = (char *)malloc(strlen(ptr)+1);
strcpy((*topics+index)->topic, ptr);
(*topics+index)->topic_len = strlen(ptr);
index++;
}
fclose(f);
*ntopic = index;
return ESP_OK;
}
void dump_table(TOPIC_t *topics, int16_t ntopic)
{
for(int i=0;i<ntopic;i++) {
ESP_LOGI(pcTaskGetName(0), "topics=[%d] frame=%d canid=0x%"PRIx32" topic=[%s] topic_len=%d",
i, (topics+i)->frame, (topics+i)->canid, (topics+i)->topic, (topics+i)->topic_len);
}
}
void http_client_task(void *pvParameters);
void http_server_task(void *pvParameters);
void twai_task(void *pvParameters);
void app_main()
{
// Initialize NVS
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
ESP_LOGI(TAG, "ESP_WIFI_MODE_STA");
wifi_init_sta();
initialise_mdns();
// Install and start TWAI driver
ESP_LOGI(TAG, "%s",BITRATE);
ESP_LOGI(TAG, "CTX_GPIO=%d",CONFIG_CTX_GPIO);
ESP_LOGI(TAG, "CRX_GPIO=%d",CONFIG_CRX_GPIO);
static const twai_general_config_t g_config = TWAI_GENERAL_CONFIG_DEFAULT(CONFIG_CTX_GPIO, CONFIG_CRX_GPIO, TWAI_MODE_NORMAL);
ESP_ERROR_CHECK(twai_driver_install(&g_config, &t_config, &f_config));
ESP_LOGI(TAG, "Driver installed");
ESP_ERROR_CHECK(twai_start());
ESP_LOGI(TAG, "Driver started");
// Mount SPIFFS
char *partition_label = "storage";
char *base_path = "/spiffs";
ret = mountSPIFFS(partition_label, base_path);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "mountSPIFFS fail");
while(1) { vTaskDelay(1); }
}
// Create Queue
xQueue_http_client = xQueueCreate( 10, sizeof(FRAME_t) );
configASSERT( xQueue_http_client );
xQueue_twai_tx = xQueueCreate( 10, sizeof(twai_message_t) );
configASSERT( xQueue_twai_tx );
// build publish table
ret = build_table(&publish, "/spiffs/can2http.csv", &npublish);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "build publish table fail");
while(1) { vTaskDelay(1); }
}
dump_table(publish, npublish);
/* Get the local IP address */
//tcpip_adapter_ip_info_t ip_info;
//ESP_ERROR_CHECK(tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &ip_info));
esp_netif_ip_info_t ip_info;
ESP_ERROR_CHECK(esp_netif_get_ip_info(esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"), &ip_info));
char cparam0[64];
//sprintf(cparam0, "%s", ip4addr_ntoa(&ip_info.ip));
sprintf(cparam0, IPSTR, IP2STR(&ip_info.ip));
xTaskCreate(http_server_task, "server", 1024*6, (void *)cparam0, 2, NULL);
xTaskCreate(http_client_task, "client", 1024*6, NULL, 2, NULL);
xTaskCreate(twai_task, "twai_rx", 1024*6, NULL, 2, NULL);
}