Added built-in HTTP Server

This commit is contained in:
nopnop2002
2021-07-09 14:43:01 +09:00
parent 52a1ab54a2
commit 298730dbe3
11 changed files with 606 additions and 74 deletions
+42 -19
View File
@@ -2,13 +2,11 @@
CANbus to http bridge using esp32.
It's purpose is to be a bridge between a CAN-Bus and a HTTP-Server.
![slide0001](https://user-images.githubusercontent.com/6020549/124377885-62528d00-dce9-11eb-8995-265a249d968d.jpg)
![slide0001](https://user-images.githubusercontent.com/6020549/125028569-3ce7c980-e0c3-11eb-8450-6aabb9a564d6.jpg)
![slide0002](https://user-images.githubusercontent.com/6020549/125028561-3b1e0600-e0c3-11eb-81bc-670b8b510847.jpg)
You can visualize CAN-Frame using a visualization library such as Matplotlib.
![slide0002](https://user-images.githubusercontent.com/6020549/124377889-65e61400-dce9-11eb-8ff0-4aad3f55eefc.jpg)
I inspired from [here](https://github.com/c3re/can2mqtt).
![slide0003](https://user-images.githubusercontent.com/6020549/125028566-3c4f3300-e0c3-11eb-8f16-bf86126a75c2.jpg)
# Software requirement
esp-idf v4.2-dev-2243 or later.
@@ -100,7 +98,13 @@ idf.py flash
![config-can](https://user-images.githubusercontent.com/6020549/123870665-a05c5380-d96d-11eb-89b1-78a274bfd957.jpg)
## WiFi Setting
![config-wifi](https://user-images.githubusercontent.com/6020549/123870681-a81bf800-d96d-11eb-8637-66295408b055.jpg)
![config-wifi-1](https://user-images.githubusercontent.com/6020549/125028704-73254900-e0c3-11eb-9a44-25482d7a08be.jpg)
You can use static IP.
![config-wifi-2](https://user-images.githubusercontent.com/6020549/125028738-80423800-e0c3-11eb-984f-9dc4f892bdb6.jpg)
Connect using mDNS.
![config-wifi-3](https://user-images.githubusercontent.com/6020549/125028763-89cba000-e0c3-11eb-921d-9baca5ec58d4.jpg)
## HTTP Server Setting
![config-http](https://user-images.githubusercontent.com/6020549/123873614-b5d37c80-d971-11eb-8ead-827f52aed982.jpg)
@@ -111,8 +115,8 @@ The file can2http.csv has three columns.
In the first column you need to specify the CAN Frame type.
The CAN frame type is either S(Standard frame) or E(Extended frame).
In the second column you have to specify the CAN-ID as a __hexdecimal number__.
In the last column you have to specify the HTTP-POST-Path.
Each CAN-ID and each HTTP-POST-Path is allowed to appear only once in the whole file.
In the last column you have to specify the HTTP-POST-Path of external HTTP server.
Each CAN-ID is allowed to appear only once in the whole file.
```
S,101,/post
@@ -121,20 +125,39 @@ S,103,/post
E,103,/post
```
When a Standard CAN frame with ID 0x101 is received, POST with the "/post" PATH.
When a Extended CAN frame with ID 0x101 is received, POST with the "/post" PATH.
# POST Parameter Example
```
{'canid':257, 'frame': 'standard', 'data': [1,2,3,4,5,6,7,8]}
{'canid':257, 'frame': 'extended', 'data': [1,2,3,4,5,6,7,8]}
{'canid':259, 'frame': 'standard', 'data': [1,2,3,4,5,6,7,8]}
{'canid':259, 'frame': 'extended', 'data': [1,2,3,4,5,6,7,8]}
```
When a CAN frame with ID 0x101 is received, POST with the 'canid':257.
When a CAN frame with ID 0x103 is received, POST with the 'canid':259.
POST Parameter Example:
```
{"canid":257, "frame": "standard", "data": [16, 17, 18]}
{"canid":257, "frame": "extended", "data": [16, 17, 18]}
{"canid":259, "frame": "standard", "data": [16, 17, 18]}
{"canid":259, "frame": "extended", "data": [16, 17, 18]}
```
# Definition from HTTP to CANbus
When HTTP POST is received, it is sent by CANBus according to csv/http2can.csv.
Other than this, it is the same as csv/can2http.csv.
In the last column you have to specify the HTTP-POST-Path of built-in HTTP server.
```
S,201,/receive
E,201,/receive
S,203,/receive
E,203,/receive
```
When receiving the {"canid": 513, "frame": "standard", "data": [16, 17, 18]}, send the Standard CAN frame with ID 0x201.
When receiving the {"canid": 515, "frame": "extended", "data": [16, 17, 18]}, send the Extended CAN frame with ID 0x201.
# Send message using curl
```
$ curl -X POST -H "Content-Type: application/json" -d '{"canid": 513, "frame": "standard", "data": [16, 17, 18]}' http://esp32-server.local:8000/api/twai/send
$ curl -X POST -H "Content-Type: application/json" -d '{"canid": 513, "frame": "extended", "data": [16, 17, 18]}' http://esp32-server.local:8000/api/twai/send
```
# HTTP Server Using Tornado
```
+2 -2
View File
@@ -2,8 +2,8 @@
#In the first column you need to specify the CAN Frame type.
#The CAN frame type is either S(Standard frame) or E(Extended frame).
#In the second column you have to specify the CAN-ID as a __hexdecimal number__.
#In the last column you have to specify the HTTP-Path.
#Each CAN-ID and each HTTP-Path is allowed to appear only once in the whole file.
#In the last column you have to specify the PATH of external web server.
#Each CAN-ID is allowed to appear only once in the whole file.
S,101,/post
E,101,/post
1 #The file can2http.csv has three columns.
2 #In the first column you need to specify the CAN Frame type.
3 #The CAN frame type is either S(Standard frame) or E(Extended frame).
4 #In the second column you have to specify the CAN-ID as a __hexdecimal number__.
5 #In the last column you have to specify the HTTP-Path. #In the last column you have to specify the PATH of external web server.
6 #Each CAN-ID and each HTTP-Path is allowed to appear only once in the whole file. #Each CAN-ID is allowed to appear only once in the whole file.
7 S,101,/post
8 E,101,/post
9 S,103,/post
+11
View File
@@ -0,0 +1,11 @@
#The file mqtt2can.csv has three columns.
#In the first column you need to specify the CAN Frame type.
#The CAN frame type is either S(Standard frame) or E(Extended frame).
#In the second column you have to specify the CAN-ID as a __hexdecimal number__.
#In the last column you have to specify the PATH of built-in web server.
#Each CAN-ID is allowed to appear only once in the whole file.
S,201,/receive
E,201,/receive
S,203,/receive
E,203,/receive
1 #The file mqtt2can.csv has three columns.
2 #In the first column you need to specify the CAN Frame type.
3 #The CAN frame type is either S(Standard frame) or E(Extended frame).
4 #In the second column you have to specify the CAN-ID as a __hexdecimal number__.
5 #In the last column you have to specify the PATH of built-in web server.
6 #Each CAN-ID is allowed to appear only once in the whole file.
7 S,201,/receive
8 E,201,/receive
9 S,203,/receive
10 E,203,/receive
+1 -1
View File
@@ -1,4 +1,4 @@
set(COMPONENT_SRCS "main.c" "http_post.c" "twai.c")
set(COMPONENT_SRCS "main.c" "http_post.c" "http_server.c" "twai.c")
set(COMPONENT_ADD_INCLUDEDIRS ".")
register_component()
+33
View File
@@ -90,6 +90,39 @@ menu "Application Configuration"
help
Set the Maximum retry to avoid station reconnecting to the AP unlimited when the AP is really inexistent.
config MDNS_HOSTNAME
string "mDNS Hostname"
default "esp32-server"
help
The mDNS host name used by the ESP32.
config STATIC_IP
bool "Enable Static IP Address"
default false
help
Enable Static IP Address.
config STATIC_IP_ADDRESS
depends on STATIC_IP
string "Static IP Address"
default "192.168.10.100"
help
Static IP Address for Station.
config STATIC_GW_ADDRESS
depends on STATIC_IP
string "Static GW Address"
default "192.168.10.1"
help
Static GW Address for Station.
config STATIC_NM_ADDRESS
depends on STATIC_IP
string "Static Netmask"
default "255.255.255.0"
help
Static Netmask for Station.
endmenu
menu "HTTP Server Setting"
+2 -2
View File
@@ -22,7 +22,7 @@
static const char *TAG = "HTTP";
extern QueueHandle_t xQueue_http;
extern QueueHandle_t xQueue_http_client;
esp_err_t _http_event_handler(esp_http_client_event_t *evt)
{
@@ -151,7 +151,7 @@ void http_client_task(void *pvParameters)
ESP_LOGI(TAG, "Start HTTP Client: http://%s:%d", CONFIG_WEB_SERVER, CONFIG_WEB_PORT);
FRAME_t frameBuf;
while (1) {
xQueueReceive(xQueue_http, &frameBuf, portMAX_DELAY);
xQueueReceive(xQueue_http_client, &frameBuf, portMAX_DELAY);
ESP_LOGI(TAG, "canid=%x ext=%d topic=[%s]", frameBuf.canid, frameBuf.ext, frameBuf.topic);
for(int i=0;i<frameBuf.data_len;i++) {
ESP_LOGI(TAG, "DATA=%x", frameBuf.data[i]);
+356
View File
@@ -0,0 +1,356 @@
/* HTTP Server Example
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 <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "freertos/semphr.h"
#include "esp_log.h"
#include "esp_err.h"
#include "esp_vfs.h"
#include "esp_spiffs.h"
#include "esp_http_server.h"
#include "cJSON.h"
#include "driver/twai.h"
#include "twai.h"
static const char *TAG = "SERVER";
//static SemaphoreHandle_t ctrl_task_sem;
extern QueueHandle_t xQueue_twai_tx;
extern TOPIC_t *subscribe;
extern int16_t nsubscribe;
#define SCRATCH_BUFSIZE (1024)
typedef struct rest_server_context {
char base_path[ESP_VFS_PATH_MAX + 1]; // Not used in this project
char scratch[SCRATCH_BUFSIZE];
} rest_server_context_t;
/* Handler for roor get handler */
static esp_err_t root_get_handler(httpd_req_t *req)
{
ESP_LOGI(TAG, "root_get_handler req->uri=[%s]", req->uri);
for(int index=0;index<nsubscribe;index++) {
ESP_LOGI(TAG, "subscribe[%d] frame=%d canid=0x%x topic=[%s] topic_len=%d",
index, subscribe[index].frame, subscribe[index].canid, subscribe[index].topic, subscribe[index].topic_len);
}
/* Send HTML header */
httpd_resp_sendstr_chunk(req, "<!DOCTYPE html><html><body>");
httpd_resp_sendstr_chunk(req, "<table border=\"1\">");
httpd_resp_sendstr_chunk(req, "<thead><tr><th>Frame Type</th><th>Frame ID</th><th>HTTP Path</th></tr></thead>");
char chunk[64];
for(int index=0;index<nsubscribe;index++) {
char frameType[16];
strcpy(frameType, "Standard");
if (subscribe[index].frame == 1) strcpy(frameType, "Entended");
httpd_resp_sendstr_chunk(req, "<tr>");
sprintf(chunk, "<td align=\"center\">%16s</td>", frameType);
httpd_resp_sendstr_chunk(req, chunk);
sprintf(chunk, "<td align=\"center\">%x</td>", subscribe[index].canid);
httpd_resp_sendstr_chunk(req, chunk);
sprintf(chunk, "<td align=\"center\">%s</td>", subscribe[index].topic);
httpd_resp_sendstr_chunk(req, chunk);
httpd_resp_sendstr_chunk(req, "</tr>");
}
/* Finish the table */
httpd_resp_sendstr_chunk(req, "</tbody></table>");
/* Send remaining chunk of HTML file to complete it */
httpd_resp_sendstr_chunk(req, "</body></html>");
/* Send empty chunk to signal HTTP response completion */
httpd_resp_sendstr_chunk(req, NULL);
return ESP_OK;
}
/* Handler for getting system information handler */
// curl 'http://esp32-server.local:8000/api/system/info' | python -m json.tool
static esp_err_t system_info_get_handler(httpd_req_t *req)
{
ESP_LOGI(TAG, "system_info_get_handler req->uri=[%s]", req->uri);
httpd_resp_set_type(req, "application/json");
cJSON *root = cJSON_CreateObject();
esp_chip_info_t chip_info;
esp_chip_info(&chip_info);
cJSON_AddStringToObject(root, "version", IDF_VER);
cJSON_AddNumberToObject(root, "cores", chip_info.cores);
//const char *sys_info = cJSON_Print(root);
char *sys_info = cJSON_Print(root);
httpd_resp_sendstr(req, sys_info);
// Buffers returned by cJSON_Print must be freed by the caller.
// Please use the proper API (cJSON_free) rather than directly calling stdlib free.
cJSON_free(sys_info);
cJSON_Delete(root);
return ESP_OK;
}
// Create array
cJSON *Create_array_of_anything(cJSON **objects,int array_num)
{
cJSON *prev = 0;
cJSON *root;
root = cJSON_CreateArray();
for (int i=0;i<array_num;i++) {
if (!i) {
root->child=objects[i];
} else {
prev->next=objects[i];
objects[i]->prev=prev;
}
prev=objects[i];
}
return root;
}
char *JSON_Types(int type) {
if (type == cJSON_Invalid) return ("cJSON_Invalid");
if (type == cJSON_False) return ("cJSON_False");
if (type == cJSON_True) return ("cJSON_True");
if (type == cJSON_NULL) return ("cJSON_NULL");
if (type == cJSON_Number) return ("cJSON_Number");
if (type == cJSON_String) return ("cJSON_String");
if (type == cJSON_Array) return ("cJSON_Array");
if (type == cJSON_Object) return ("cJSON_Object");
if (type == cJSON_Raw) return ("cJSON_Raw");
return NULL;
}
/* Handler for twai send handler */
// curl -X POST -H "Content-Type: application/json" -d '{"canid": 513, "frame": "standard", "data": [11, 12, 13, 14]}' http://esp32-server.local:8000/api/twai/send
static esp_err_t twai_send_handler(httpd_req_t *req)
{
ESP_LOGI(TAG, "twai_send_handler req->uri=[%s]", req->uri);
int total_len = req->content_len;
int cur_len = 0;
char *buf = ((rest_server_context_t *)(req->user_ctx))->scratch;
int received = 0;
if (total_len >= SCRATCH_BUFSIZE) {
/* Respond with 500 Internal Server Error */
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "content too long");
return ESP_FAIL;
}
while (cur_len < total_len) {
received = httpd_req_recv(req, buf + cur_len, total_len);
if (received <= 0) {
/* Respond with 500 Internal Server Error */
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to post control value");
return ESP_FAIL;
}
cur_len += received;
}
buf[total_len] = '\0';
ESP_LOGI(TAG, "buf=[%s]", buf);
bool parse = true;
cJSON *root = cJSON_Parse(buf);
// Search canid item
int32_t canid = 0;
cJSON* state = cJSON_GetObjectItem(root, "canid");
if (state) {
canid = cJSON_GetObjectItem(root, "canid")->valueint;
ESP_LOGI(TAG, "canid=%x", canid);
} else {
ESP_LOGE(TAG, "canid item not found");
parse = false;
}
// Search frame item
char frameStr[12];
uint16_t frame = 0;
state = cJSON_GetObjectItem(root, "frame");
if (state) {
strcpy(frameStr, cJSON_GetObjectItem(root,"frame")->valuestring);
ESP_LOGI(TAG, "frameStr=[%s]", frameStr);
if (strcmp(frameStr, "standard") != 0 && strcmp(frameStr, "extended") != 0 ) {
ESP_LOGE(TAG, "frame item not correct");
parse = false;
} else {
if (strcmp(frameStr, "standard") == 0) frame = STANDARD_FRAME;
if (strcmp(frameStr, "extended") == 0) frame = EXTENDED_FRAME;
}
} else {
ESP_LOGE(TAG, "frame item not found");
parse = false;
}
// Search data item
int16_t data_len;
char data_value[8];
state = cJSON_GetObjectItem(root, "data");
if (state) {
cJSON *data_array = cJSON_GetObjectItem(root,"data");
ESP_LOGI(TAG, "data_array->type=%s", JSON_Types(data_array->type));
if (data_array->type == cJSON_Array) {
int data_array_size = cJSON_GetArraySize(data_array);
ESP_LOGI(TAG, "data_array_size=%d", data_array_size);
bool data_valid = true;
data_len = data_array_size;
for (int i=0;i<data_array_size;i++) {
cJSON *array = cJSON_GetArrayItem(data_array,i);
//ESP_LOGI(TAG, "array->type=%s", JSON_Types(array->type));
uint16_t data_int = array->valueint;
ESP_LOGI(TAG, "data_int[%d]=%x", i, data_int);
if (data_int <= 0xff) {
data_value[i] = data_int;
} else {
ESP_LOGE(TAG, "data too large");
data_valid = false;
}
} // end for
if (data_valid == false) {
parse = false;
}
} else {
ESP_LOGE(TAG, "data item not array");
parse = false;
} // end if
} else {
ESP_LOGE(TAG, "data item not found");
parse = false;
}
cJSON_Delete(root);
// JSON parse success. Send twai data.
if (parse) {
ESP_LOGI(TAG, "twai_send_handler frame=%d canid=%x data_len=%d", frame, canid, data_len);
ESP_LOG_BUFFER_HEX(TAG, data_value, data_len);
bool isMatch = false;
for(int index=0;index<nsubscribe;index++) {
ESP_LOGI(TAG, "subscribe[%d] frame=%d canid=%x topic=[%s] topic_len=%d",
index, subscribe[index].frame, subscribe[index].canid, subscribe[index].topic, subscribe[index].topic_len);
if (subscribe[index].frame == frame && subscribe[index].canid == canid) {
isMatch = true;
twai_message_t tx_msg;
tx_msg.extd = frame;
tx_msg.ss = 1;
tx_msg.self = 0;
tx_msg.dlc_non_comp = 0;
tx_msg.identifier = canid;
tx_msg.data_length_code = data_len;
for (int i=0;i<data_len;i++) {
tx_msg.data[i] = data_value[i];
}
if (xQueueSend(xQueue_twai_tx, &tx_msg, portMAX_DELAY) != pdPASS) {
ESP_LOGE(TAG, "xQueueSend Fail");
}
httpd_resp_sendstr(req, "twai send successfully");
break;
} // end if
} // end for
if (isMatch == false) {
ESP_LOGE(TAG, "Not found canid in csv");
httpd_resp_sendstr(req, "Not found canid in csv");
}
} else {
ESP_LOGE(TAG, "Request parameter not correct");
httpd_resp_sendstr(req, "Request parameter not correct");
}
return ESP_OK;
}
/* Function to start the file server */
esp_err_t start_server(const char *base_path, int port)
{
rest_server_context_t *rest_context = calloc(1, sizeof(rest_server_context_t));
if (rest_context == NULL) {
ESP_LOGE(TAG, "No memory for rest context");
while(1) { vTaskDelay(1); }
}
httpd_handle_t server = NULL;
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
config.server_port = port;
/* Use the URI wildcard matching function in order to
* allow the same handler to respond to multiple different
* target URIs which match the wildcard scheme */
config.uri_match_fn = httpd_uri_match_wildcard;
ESP_LOGD(TAG, "Starting HTTP Server on port: '%d'", config.server_port);
if (httpd_start(&server, &config) != ESP_OK) {
ESP_LOGE(TAG, "Failed to start file server!");
return ESP_FAIL;
}
/* URI handler for root */
httpd_uri_t root = {
.uri = "/", // Match all URIs of type /path/to/file
.method = HTTP_GET,
.handler = root_get_handler,
//.user_ctx = server_data // Pass server data as context
};
httpd_register_uri_handler(server, &root);
/* URI handler for getting system info */
httpd_uri_t system_info_get_uri = {
.uri = "/api/system/info",
.method = HTTP_GET,
.handler = system_info_get_handler,
.user_ctx = rest_context
};
httpd_register_uri_handler(server, &system_info_get_uri);
/* URI handler for send twai */
httpd_uri_t twai_send_post_uri = {
.uri = "/api/twai/send",
.method = HTTP_POST,
.handler = twai_send_handler,
.user_ctx = rest_context
};
httpd_register_uri_handler(server, &twai_send_post_uri);
return ESP_OK;
}
void http_server_task(void *pvParameters)
{
char *task_parameter = (char *)pvParameters;
ESP_LOGI(TAG, "Start task_parameter=%s", task_parameter);
char url[64];
sprintf(url, "http://%s:%d", task_parameter, CONFIG_WEB_PORT);
ESP_LOGI(TAG, "Starting server on %s", url);
#if 0
// Create Semaphore
// This Semaphore is used for locking
ctrl_task_sem = xSemaphoreCreateBinary();
configASSERT( ctrl_task_sem );
xSemaphoreGive(ctrl_task_sem);
#endif
ESP_ERROR_CHECK(start_server("/spiffs", CONFIG_WEB_PORT));
while(1) {
// Nothing to do
vTaskDelay(1);
}
// Never reach here
ESP_LOGI(TAG, "finish");
vTaskDelete(NULL);
}
+109 -40
View File
@@ -22,6 +22,8 @@
#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"
@@ -67,10 +69,13 @@ static EventGroupHandle_t s_wifi_event_group;
static int s_retry_num = 0;
QueueHandle_t xQueue_http;
QueueHandle_t xQueue_http_client;
QueueHandle_t xQueue_twai_tx;
TOPIC_t *publish;
int16_t npublish;
TOPIC_t *subscribe;
int16_t nsubscribe;
static void event_handler(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data)
@@ -94,45 +99,83 @@ static void event_handler(void* arg, esp_event_base_t event_base,
}
}
bool wifi_init_sta(void)
void wifi_init_sta()
{
bool ret = false;
s_wifi_event_group = xEventGroupCreate();
ESP_ERROR_CHECK(esp_netif_init());
ESP_LOGI(TAG,"ESP-IDF Ver%d.%d", ESP_IDF_VERSION_MAJOR, ESP_IDF_VERSION_MINOR);
#if ESP_IDF_VERSION_MAJOR >= 4 && ESP_IDF_VERSION_MINOR >= 1
ESP_LOGI(TAG,"ESP-IDF esp_netif");
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
esp_netif_create_default_wifi_sta();
esp_netif_t *netif = esp_netif_create_default_wifi_sta();
#else
ESP_LOGI(TAG,"ESP-IDF tcpip_adapter");
tcpip_adapter_init();
ESP_ERROR_CHECK(esp_event_loop_create_default());
#endif
#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);
#if ESP_IDF_VERSION_MAJOR >= 4 && ESP_IDF_VERSION_MINOR >= 1
/* 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);
#else
/* Stop DHCP client */
tcpip_adapter_dhcpc_stop(TCPIP_ADAPTER_IF_STA);
ESP_LOGI(TAG, "Stop DHCP Services");
/* Set STATIC IP Address */
tcpip_adapter_ip_info_t ip_info;
memset(&ip_info, 0 , sizeof(tcpip_adapter_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);;
tcpip_adapter_set_ip_info(TCPIP_ADAPTER_IF_STA, &ip_info);
#endif
/*
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
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
esp_event_handler_instance_t instance_any_id;
esp_event_handler_instance_t instance_got_ip;
ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
ESP_EVENT_ANY_ID,
&event_handler,
NULL,
&instance_any_id));
ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
IP_EVENT_STA_GOT_IP,
&event_handler,
NULL,
&instance_got_ip));
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,
/* Setting a password implies station will connect to all security modes including WEP/WPA.
* However these modes are deprecated and not advisable to be used. Incase your Access point
* doesn't support WPA2, these mode can be enabled by commenting below line */
.threshold.authmode = WIFI_AUTH_WPA2_PSK,
.pmf_cfg = {
.capable = true,
.required = false
},
.password = CONFIG_ESP_WIFI_PASSWORD
},
};
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) );
@@ -154,19 +197,27 @@ bool wifi_init_sta(void)
if (bits & WIFI_CONNECTED_BIT) {
ESP_LOGI(TAG, "connected to ap SSID:%s password:%s",
CONFIG_ESP_WIFI_SSID, CONFIG_ESP_WIFI_PASSWORD);
ret = true;
} 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");
}
/* The event will not be processed after unregister */
ESP_ERROR_CHECK(esp_event_handler_instance_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, instance_got_ip));
ESP_ERROR_CHECK(esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, instance_any_id));
vEventGroupDelete(s_wifi_event_group);
return ret;
}
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) {
@@ -326,6 +377,7 @@ void dump_table(TOPIC_t *topics, int16_t ntopic)
}
void http_client_task(void *pvParameters);
void http_server_task(void *pvParameters);
void twai_task(void *pvParameters);
void app_main()
@@ -338,10 +390,9 @@ void app_main()
}
ESP_ERROR_CHECK(ret);
// WiFi initialize
if (wifi_init_sta() == false) {
while(1) vTaskDelay(10);
}
ESP_LOGI(TAG, "ESP_WIFI_MODE_STA");
wifi_init_sta();
initialise_mdns();
// Install and start TWAI driver
ESP_LOGI(TAG, "%s",BITRATE);
@@ -364,8 +415,10 @@ void app_main()
}
// Create Queue
xQueue_http = xQueueCreate( 10, sizeof(FRAME_t) );
configASSERT( xQueue_http );
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);
@@ -375,6 +428,22 @@ void app_main()
}
dump_table(publish, npublish);
xTaskCreate(http_client_task, "http", 1024*6, NULL, 2, NULL);
// build subscribe table
ret = build_table(&subscribe, "/spiffs/http2can.csv", &nsubscribe);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "build subscribe table fail");
while(1) { vTaskDelay(1); }
}
dump_table(subscribe, nsubscribe);
/* 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));
char cparam0[64];
sprintf(cparam0, "%s", ip4addr_ntoa(&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);
}
+26 -6
View File
@@ -22,8 +22,8 @@
static const char *TAG = "TWAI";
extern QueueHandle_t xQueue_http;
//extern QueueHandle_t xQueue_twai_tx;
extern QueueHandle_t xQueue_http_client;
extern QueueHandle_t xQueue_twai_tx;
extern TOPIC_t *publish;
extern int16_t npublish;
@@ -36,9 +36,9 @@ void twai_task(void *pvParameters)
dump_table(publish, npublish);
twai_message_t rx_msg;
twai_message_t tx_msg;
FRAME_t frameBuf;
while (1) {
//esp_err_t ret = twai_receive(&rx_msg, pdMS_TO_TICKS(1));
esp_err_t ret = twai_receive(&rx_msg, pdMS_TO_TICKS(10));
if (ret == ESP_OK) {
ESP_LOGD(TAG,"twai_receive identifier=0x%x flags=0x%x data_length_code=%d",
@@ -49,7 +49,7 @@ void twai_task(void *pvParameters)
ESP_LOGD(TAG, "ext=%x rtr=%x", ext, rtr);
#if CONFIG_ENABLE_PRINT
if (ext == 0) {
if (ext == STANDARD_FRAME) {
printf("Standard ID: 0x%03x ", rx_msg.identifier);
} else {
printf("Extended ID: 0x%08x", rx_msg.identifier);
@@ -73,6 +73,7 @@ void twai_task(void *pvParameters)
ESP_LOGI(TAG, "publish[%d] frame=%d canid=0x%x topic=[%s] topic_len=%d",
index, publish[index].frame, publish[index].canid, publish[index].topic, publish[index].topic_len);
strcpy(frameBuf.topic, publish[index].topic);
frameBuf.command = CMD_RECEIVE;
frameBuf.topic_len = publish[index].topic_len;
frameBuf.canid = rx_msg.identifier;
frameBuf.ext = ext;
@@ -85,20 +86,39 @@ void twai_task(void *pvParameters)
for(int i=0;i<frameBuf.data_len;i++) {
frameBuf.data[i] = rx_msg.data[i];
}
if (xQueueSend(xQueue_http, &frameBuf, portMAX_DELAY) != pdPASS) {
if (xQueueSend(xQueue_http_client, &frameBuf, portMAX_DELAY) != pdPASS) {
ESP_LOGE(TAG, "xQueueSend Fail");
}
}
}
} else if (ret == ESP_ERR_TIMEOUT) {
if (xQueueReceive(xQueue_twai_tx, &tx_msg, 0) == pdTRUE) {
ESP_LOGI(TAG, "tx_msg.identifier=[0x%x] tx_msg.extd=%d", tx_msg.identifier, tx_msg.extd);
twai_status_info_t status_info;
twai_get_status_info(&status_info);
ESP_LOGD(TAG, "status_info.state=%d",status_info.state);
if (status_info.state != TWAI_STATE_RUNNING) {
ESP_LOGE(TAG, "TWAI driver not running %d", status_info.state);
continue;
}
ESP_LOGD(TAG, "status_info.msgs_to_tx=%d",status_info.msgs_to_tx);
ESP_LOGD(TAG, "status_info.msgs_to_rx=%d",status_info.msgs_to_rx);
//esp_err_t ret = twai_transmit(&tx_msg, pdMS_TO_TICKS(10));
esp_err_t ret = twai_transmit(&tx_msg, 0);
if (ret == ESP_OK) {
ESP_LOGI(TAG, "twai_transmit success");
} else {
ESP_LOGE(TAG, "twai_transmit Fail %s", esp_err_to_name(ret));
}
}
} else {
ESP_LOGE(TAG, "twai_receive Fail %s", esp_err_to_name(ret));
}
}
// never reach
// Never reach here
vTaskDelete(NULL);
}
+10
View File
@@ -1,4 +1,14 @@
#define STANDARD_FRAME 0
#define EXTENDED_FRAME 1
#define DATA_FRAME 0
#define REMOTE_FRAME 1
#define CMD_RECEIVE 100
#define CMD_SEND 200
typedef struct {
int16_t command;
char topic[64];
int16_t topic_len;
int32_t canid;
+10
View File
@@ -15,3 +15,13 @@ CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
#
CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y
CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ=240
#
# mDNS
#
CONFIG_MDNS_STRICT_MODE=y
#
# HTTP Server
#
CONFIG_HTTPD_MAX_REQ_HDR_LEN=1024