can_controllers
main.cpp
Go to the documentation of this file.
1 
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <inttypes.h>
19 #include "freertos/FreeRTOS.h"
20 #include "freertos/task.h"
21 #include "NMEA_msg.h"
22 #include "esp_log.h"
23 #include <N2kMsg.h>
24 #include <NMEA2000_esp32-c6.h>
25 #include <NMEA2000.h>
26 #include <N2kMessages.h>
27 #include "esp_err.h"
28 #include "esp_pthread.h"
29 #include <NMEA2000_mcp.h>
30 
31 #include "driver/gpio.h"
32 #include "bi-inc/attr_container.h"
33 
34 #include "wasm_export.h"
35 #include "bh_read_file.h"
36 #include "bh_getopt.h"
37 #include "bh_platform.h"
38 
39 #include <queue>
40 #include <string>
41 #include <iomanip>
42 #include <chrono>
43 #include "driver/spi_master.h"
44 
45 //WebAssembley App
46 #include "nmea_attack.h"
47 
48 #define NATIVE_STACK_SIZE (32*1024)
49 #define NATIVE_HEAP_SIZE (32*1024)
50 #define PTHREAD_STACK_SIZE 4096
51 #define MAX_DATA_LENGTH_BTYES 223
52 #define MSG_BUFFER_SIZE (10 + 223*2) //10 bytes for id, 223*2 bytes for data
53 #define MODE_BUFFER_SIZE 1 // 1 byte to store modes 0 -> 3
54 #define MY_ESP_LOG_LEVEL ESP_LOG_INFO // the log level for this file
55 
56 #define STATS_TASK_PRIO tskIDLE_PRIORITY //3
57 #define STATS_TICKS pdMS_TO_TICKS(1000)
58 #define ARRAY_SIZE_OFFSET 5 //Increase this if print_real_time_stats returns ESP_ERR_INVALID_SIZE
59 #define TX_QUEUE_SIZE 100
60 #define RX_QUEUE_SIZE 100
61 
62 #define MCP0_TX GPIO_NUM_22
63 #define MCP0_RX GPIO_NUM_23
64 #define MCP1_CS 16
65 #define MCP1_INT 10
66 #define MCP2_CS 17
67 #define MCP2_INT 11
68 
69 #define ESP_INTR_FLAG_DEFAULT 0
70 /*
71  * GPIO_OUTPUT_IO_0=18, GPIO_OUTPUT_IO_1=19
72  * In binary representation,
73  * 1ULL<<GPIO_OUTPUT_IO_0 is equal to 0000000000000000000001000000000000000000 and
74  * 1ULL<<GPIO_OUTPUT_IO_1 is equal to 0000000000000000000010000000000000000000
75  * GPIO_OUTPUT_PIN_SEL 0000000000000000000011000000000000000000
76  * */
77 #define MODE_SETTING_PIN_LSB GPIO_NUM_18
78 #define MODE_SETTING_PIN_MSB GPIO_NUM_19
79 #define MODE_SETTING_MASK ((1ULL<<MODE_SETTING_PIN_LSB) | (1ULL<<MODE_SETTING_PIN_MSB))
80 
81 #define PRINT_STATS // Uncomment to print task stats periodically
82 
83 // Tag for ESP logging
84 static const char* TAG_TWAI = "TWAI";
85 static const char* TAG_WASM = "WASM";
86 static const char* TAG_MCP1 = "MCP1";
87 static const char* TAG_MCP2 = "MCP2";
88 static const char* TAG_STATUS = "STATUS";
89 
90 spi_device_handle_t spi1;
91 spi_device_handle_t spi2;
92 
93 tNMEA2000_esp32c6 C0(MCP0_TX, MCP0_RX);
94 tNMEA2000_mcp C1(&spi1,MCP1_CS,MCP_8MHZ,MCP1_INT,50);
95 tNMEA2000_mcp C2(&spi2,MCP2_CS,MCP_8MHZ,MCP2_INT,50);
96 
97 
98 
99 // Task Handles
100 static TaskHandle_t C0_send_task_handle = NULL;
101 static TaskHandle_t C0_receive_task_handle = NULL;
102 static TaskHandle_t C1_send_task_handle = NULL;
103 static TaskHandle_t C1_receive_task_handle = NULL;
104 static TaskHandle_t C2_send_task_handle = NULL;
105 static TaskHandle_t C2_receive_task_handle = NULL;
106 static TaskHandle_t stats_task_handle = NULL;
107 static TaskHandle_t modes_task_handle = NULL;
108 
109 QueueHandle_t C0_tx_queue;
110 QueueHandle_t C1_tx_queue;
111 QueueHandle_t C2_tx_queue;
112 QueueHandle_t rx_queue;
113 static QueueHandle_t gpio_evt_queue = NULL;
114 
115 SemaphoreHandle_t x_sem_mcp1;
116 SemaphoreHandle_t x_sem_mcp2;
117 
118 static unsigned long C0_MsgSentCount=0;
119 static unsigned long C0_MsgFailCount=0;
120 static unsigned long C1_MsgSentCount=0;
121 static unsigned long C1_MsgFailCount=0;
122 static unsigned long C2_MsgSentCount=0;
123 static unsigned long C2_MsgFailCount=0;
124 
127  C0_NUM = 0,
128  C1_NUM = 1,
129  C2_NUM = 2
130 };
131 
132 //----------------------------------------------------------------------------------------------------------------------------
133 // Forward Declarations
134 //----------------------------------------------------------------------------------------------------------------------------
135 void HandleNMEA2000Msg(const tN2kMsg &N2kMsg);
136 std::string nmea_to_string(NMEA_msg& msg);
137 void uintArrToCharrArray(uint8_t (&data_uint8_arr)[MAX_DATA_LENGTH_BTYES], unsigned char (&data_char_arr)[MAX_DATA_LENGTH_BTYES]);
138 //----------------------------------------------------------------------------------------------------------------------------
139 // Variables
140 //-----------------------------------------------------------------------------------------------------------------------------
141 char * wasm_buffer = NULL;
142 char * wasm_mode_buffer = NULL;
143 int read_msg_count = 0;
144 int send_msg_count = 0;
145 std::string tc_mode = "1";
146 uint32_t alerts_to_enable = TWAI_ALERT_RX_DATA | TWAI_ALERT_TX_FAILED | TWAI_ALERT_RX_QUEUE_FULL;
147 
148 // Task Counters - temporary, for debugging
149 int C0_rx_task_count = 0;
150 int C0_tx_task_count = 0;
151 int C1_rx_task_count = 0;
152 int C1_tx_task_count = 0;
153 int C2_rx_task_count = 0;
154 int C2_tx_task_count = 0;
155 int wasm_pthread_count = 0;
156 int stats_task_count = 0;
157 double wasm_main_duration;
158 //-------------------------------------------------------------------------------------------------------------------------------
159 // Native Functions to Export to WASM App
160 //-----------------------------------------------------------------------------------------------------------------------------
161 
171 void PrintStr(wasm_exec_env_t exec_env,uint8_t* input, int32_t length){
172  printf("PrintStr: ");
173  for (int32_t i = 0; i < length;i++ ) {
174  printf("%u ", *(input+i));
175  }
176  printf("\n");
177  return;
178 }
179 
189 void PrintInt32(wasm_exec_env_t exec_env,int32_t number,int32_t hex){
190  if (hex == 1){
191  printf("PrintInt32: %lx \n", number);
192  }
193  else {
194  printf("PrintInt32: %li \n", number);
195  }
196  return;
197 }
198 
199 /****************************************************************************
200  * \brief Puts a message in a controller send queue
201  *
202  * This function is exported to the WASM app to be called from app to send a message.
203  * Creates a NMEA_msg object and puts it into the appropriate send queue.
204  *
205  * @param exec_env
206  * @param[in] controller_number
207  * @param[in] priority
208  * @param[in] PGN
209  * @param[in] source
210  * @param[in] data
211  * @param[in] data_length_bytes
212  *
213  * \return 1 if message converted successfully, 0 if not.
214 */
215 int32_t SendMsg(wasm_exec_env_t exec_env, int32_t controller_number, int32_t priority, int32_t PGN, int32_t source, uint8_t* data, int32_t data_length_bytes ){
216  ESP_LOGD(TAG_WASM, "SendMsg called \n");
217  NMEA_msg msg;
218  msg.controller_number = controller_number;
219  msg.priority = priority;
220  msg.PGN = PGN;
221  msg.source = source;
222  msg.data_length_bytes = data_length_bytes;
223 
224  // Copy the data bytes
225  for (size_t i = 0; i < data_length_bytes; ++i) {
226  uint8_t value = static_cast<uint8_t>(data[i]);
227  msg.data[i] = value;
228  }
229 
230 
231  if (controller_number == C0_NUM){
232  // Add to controller 0 queue
233  ESP_LOGD(TAG_WASM,"Added a msg to ctrl0_q with PGN %u \n", msg.PGN);
234  if (xQueueSendToBack(C0_tx_queue, &msg, pdMS_TO_TICKS(10))){
235  return 1;
236  }
237  }
238  else if(controller_number == C1_NUM)
239  {
240  // Add to controller 1 queue
241  ESP_LOGD(TAG_WASM,"Added a msg to ctrl1_q with PGN %u \n", msg.PGN);
242  if (xQueueSendToBack(C1_tx_queue, &msg, pdMS_TO_TICKS(10))){
243  return 1;
244  }
245  }
246  else if(controller_number == C2_NUM)
247  {
248  // Add to controller 2 queue
249  ESP_LOGD(TAG_WASM,"Added a msg to ctrl2_q with PGN %u \n", msg.PGN);
250  if (xQueueSendToBack(C2_tx_queue, &msg, pdMS_TO_TICKS(10))){
251  return 1;
252  }
253  }
254  else{
255  ESP_LOGE(TAG_WASM, "Invalid controller number: %" PRIu32 "", controller_number);
256  return 0;
257  }
258 
259  return 0;
260 }
261 
262 //----------------------------------------------------------------------------------------------------------------------------------------------------------------
263 // Helper Functions for Conversions
264 //-----------------------------------------------------------------------------------------------------------------------------------------------------------------
265 
272 std::string nmea_to_string(NMEA_msg& msg){
273  std::stringstream ss;
274  ss << std::hex << std::setw(1) << std::setfill('0') << static_cast<int>(msg.controller_number);
275  ss << std::hex << std::setw(1) << std::setfill('0') << static_cast<int>(msg.priority);
276  ss << std::hex << std::setw(5) << std::setfill('0') << msg.PGN;
277  ss << std::hex << std::setw(1) << std::setfill('0') << static_cast<int>(msg.source);
278  ss << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(msg.data_length_bytes);
279  for (uint8_t d : msg.data){
280  char hex_num[3];
281  sprintf(hex_num, "%X", d);
282  ss << std::setw(2) << hex_num;
283  }
284  const std::string s = ss.str();
285  return s;
286 
287 }
288 
296 void uint8ArrayToCharrArray(uint8_t (&data_uint8_arr)[MAX_DATA_LENGTH_BTYES], unsigned char (&data_char_arr)[MAX_DATA_LENGTH_BTYES]){
297  for (size_t i = 0; i < MAX_DATA_LENGTH_BTYES; ++i) {
298  data_char_arr[i] = static_cast<unsigned char>(data_uint8_arr[i]);
299  }
300 }
301 
302 //---------------------------------------------------------------------------------------------------------------------------------------------
306 static void IRAM_ATTR gpio_isr_handler(void* arg)
307 {
308  uint32_t gpio_num = (uint32_t) arg;
309  xQueueSendFromISR(gpio_evt_queue, &gpio_num, NULL);
310 }
316 {
317  //zero-initialize the config structure.
318  gpio_config_t io_conf = {};
319  //disable interrupt
320  io_conf.intr_type = GPIO_INTR_ANYEDGE; // Trigger on both rising and falling edge
321  //set as output mode
322  io_conf.mode = GPIO_MODE_INPUT;
323  //bit mask of the pins that you want to set,e.g.GPIO18/19
324  io_conf.pin_bit_mask = MODE_SETTING_MASK;
325  //disable pull-down mode
326  io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
327  //disable pull-up mode
328  io_conf.pull_up_en = GPIO_PULLUP_DISABLE ;
329  //configure GPIO with the given settings
330  gpio_config(&io_conf);
331 
332  //create a queue to handle gpio event from isr
333  gpio_evt_queue = xQueueCreate(10, sizeof(uint32_t));
334 
335  //install gpio isr service
336  gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT);
337  //hook isr handler for specific gpio pin
338  gpio_isr_handler_add(MODE_SETTING_PIN_LSB, gpio_isr_handler, (void*) MODE_SETTING_PIN_LSB);
339  //hook isr handler for specific gpio pin
340  gpio_isr_handler_add(MODE_SETTING_PIN_MSB, gpio_isr_handler, (void*) MODE_SETTING_PIN_MSB);
341 }
351 void get_mode_task(void *pvParameters)
352 {
354  uint32_t io_num;
355  for(;;) {
356  if(xQueueReceive(gpio_evt_queue, &io_num, portMAX_DELAY)) {
357  ESP_LOGD("MODE: ","GPIO[%" PRIu32 "] intr, val: %i\n", io_num, gpio_get_level(GPIO_NUM_18));
358  ESP_LOGD("MODE: ","GPIO[%" PRIu32 "] intr, val: %i\n", io_num, gpio_get_level(GPIO_NUM_19));
359  int msb = gpio_get_level(GPIO_NUM_19);
360  int lsb = gpio_get_level(GPIO_NUM_18);
361  int mode = (msb << 1) | lsb;
362  tc_mode = std::to_string(mode);
363  ESP_LOGD("MODE: ", "%i",mode);
364  }
365  }
366 }
376 bool SendN2kMsg(NMEA_msg msg, int controller_num) {
377  tN2kMsg N2kMsg;
378  N2kMsg.Priority = msg.priority;
379  N2kMsg.PGN = msg.PGN;
380  N2kMsg.Source = msg.source;
381  N2kMsg.Destination = 0xff; //not used
382 
383  N2kMsg.DataLen = msg.data_length_bytes;
384 
385  uint8ArrayToCharrArray(msg.data, N2kMsg.Data);
386 
387  N2kMsg.MsgTime = N2kMillis64();//TODO
388 
389  if(controller_num == C0_NUM){
390  if ( C0.SendMsg(N2kMsg) ) {
391  ESP_LOGD(TAG_TWAI, "sent a message \n");
392  C0_MsgSentCount++;
393  send_msg_count++;
394  } else {
395  ESP_LOGW(TAG_TWAI, "failed to send a message \n");
396  C0_MsgFailCount++;
397  }
398  }
399  else if(controller_num == C1_NUM){
400  if ( C1.SendMsg(N2kMsg) ) {
401  ESP_LOGD(TAG_MCP1, "sent a message \n");
402  C1_MsgSentCount++;
403  send_msg_count++;
404  } else {
405  ESP_LOGW(TAG_MCP1, "failed to send a message \n");
406  C1_MsgFailCount++;
407  }
408  }
409  else if(controller_num == C2_NUM){
410  if ( C2.SendMsg(N2kMsg) ) {
411  ESP_LOGD(TAG_MCP2, "sent a message \n");
412  C2_MsgSentCount++;
413  send_msg_count++;
414  } else {
415  //ESP_LOGW(TAG_MCP2, "failed to send a message \n");
416  C2_MsgFailCount++;
417  }
418  }
419 
420  return true;
421 }
422 
442 static esp_err_t print_real_time_stats(TickType_t xTicksToWait)
443 {
444  TaskStatus_t *start_array = NULL, *end_array = NULL;
445  UBaseType_t start_array_size, end_array_size;
446  uint32_t start_run_time, end_run_time;
447  esp_err_t ret;
448 
449  //Allocate array to store current task states
450  start_array_size = uxTaskGetNumberOfTasks() + ARRAY_SIZE_OFFSET;
451  start_array = reinterpret_cast<TaskStatus_t*>(std::malloc(sizeof(TaskStatus_t) * start_array_size));
452  if (start_array == NULL) {
453  ret = ESP_ERR_NO_MEM;
454  free(start_array);
455  free(end_array);
456  return ret;
457  }
458  //Get current task states
459  start_array_size = uxTaskGetSystemState(start_array, start_array_size, &start_run_time);
460  if (start_array_size == 0) {
461  ret = ESP_ERR_INVALID_SIZE;
462  free(start_array);
463  free(end_array);
464  return ret;
465  }
466 
467  vTaskDelay(xTicksToWait);
468 
469  //Allocate array to store tasks states post delay
470  end_array_size = uxTaskGetNumberOfTasks() + ARRAY_SIZE_OFFSET;
471  end_array = reinterpret_cast<TaskStatus_t*>(std::malloc(sizeof(TaskStatus_t) * end_array_size));
472  if (end_array == NULL) {
473  ret = ESP_ERR_NO_MEM;
474  free(start_array);
475  free(end_array);
476  return ret;
477  }
478  //Get post delay task states
479  end_array_size = uxTaskGetSystemState(end_array, end_array_size, &end_run_time);
480  if (end_array_size == 0) {
481  ret = ESP_ERR_INVALID_SIZE;
482  free(start_array);
483  free(end_array);
484  return ret;
485  }
486 
487  //Calculate total_elapsed_time in units of run time stats clock period.
488  uint32_t total_elapsed_time = (end_run_time - start_run_time);
489  if (total_elapsed_time == 0) {
490  ret = ESP_ERR_INVALID_STATE;
491  free(start_array);
492  free(end_array);
493  return ret;
494  }
495 
496  printf("| Task | Run Time | Percentage\n");
497  //Match each task in start_array to those in the end_array
498  for (int i = 0; i < start_array_size; i++) {
499  int k = -1;
500  for (int j = 0; j < end_array_size; j++) {
501  if (start_array[i].xHandle == end_array[j].xHandle) {
502  k = j;
503  //Mark that task have been matched by overwriting their handles
504  start_array[i].xHandle = NULL;
505  end_array[j].xHandle = NULL;
506  break;
507  }
508  }
509  //Check if matching task found
510  if (k >= 0) {
511  uint32_t task_elapsed_time = end_array[k].ulRunTimeCounter - start_array[i].ulRunTimeCounter;
512  uint32_t percentage_time = (task_elapsed_time * 100UL) / (total_elapsed_time * portNUM_PROCESSORS);
513  printf("| %s | %" PRIu32 " | %" PRIu32 "%%\n", start_array[i].pcTaskName, task_elapsed_time, percentage_time);
514  }
515  }
516 
517  //Print unmatched tasks
518  for (int i = 0; i < start_array_size; i++) {
519  if (start_array[i].xHandle != NULL) {
520  printf("| %s | Deleted\n", start_array[i].pcTaskName);
521  }
522  }
523  for (int i = 0; i < end_array_size; i++) {
524  if (end_array[i].xHandle != NULL) {
525  printf("| %s | Created\n", end_array[i].pcTaskName);
526  }
527  }
528  ret = ESP_OK;
529  free(start_array);
530  free(end_array);
531  return ret;
532 
533 }
534 
535 
543 void GetStatus(const char* TAG){
544  uint32_t alerts = 0;
545  C0.ReadAlerts(alerts, pdMS_TO_TICKS(1));
546  if (alerts & TWAI_ALERT_RX_QUEUE_FULL){
547  ESP_LOGW(TAG, "TWAI rx queue full");
548  }
549  twai_status_info_t status;
550  C0.GetTwaiStatus(status);
551  ESP_LOGI(TAG, "TWAI Msgs queued for transmission: %" PRIu32 " Unread messages in rx queue: %" PRIu32, status.msgs_to_tx, status.msgs_to_rx);
552  ESP_LOGI(TAG, "Msgs lost due to TWAI RX FIFO overrun: %" PRIu32 "", status.rx_overrun_count);
553  ESP_LOGI(TAG, "Msgs lost due to full TWAI RX queue: %" PRIu32 "", status.rx_missed_count);
554  ESP_LOGI(TAG, "Messages Read: %d, Messages Sent %d", read_msg_count, send_msg_count);
555  UBaseType_t msgs_in_rx_q = uxQueueMessagesWaiting(rx_queue);
556  ESP_LOGI(TAG, "Received Messages queue size: %d \n", msgs_in_rx_q);
557  UBaseType_t msgs_in_q0 = uxQueueMessagesWaiting(C0_tx_queue);
558  UBaseType_t msgs_in_q1 = uxQueueMessagesWaiting(C1_tx_queue);
559  UBaseType_t msgs_in_q2 = uxQueueMessagesWaiting(C2_tx_queue);
560  ESP_LOGI(TAG, "Controller 0 send queue size: %d \n", msgs_in_q0);
561  ESP_LOGI(TAG, "Controller 1 send queue size: %d \n", msgs_in_q1);
562  ESP_LOGI(TAG, "Controller 2 send queue size: %d \n", msgs_in_q2);
563 
564  // Task Counters
565  ESP_LOGI(TAG, "RX task count: %d", C0_rx_task_count);
566  ESP_LOGI(TAG, "TX task count: %d", C0_tx_task_count);
567  ESP_LOGI(TAG, "MCP1 RX task count: %d", C1_rx_task_count);
568  ESP_LOGI(TAG, "MCP1 TX task count: %d", C1_tx_task_count);
569  ESP_LOGI(TAG, "MCP2 RX task count: %d", C2_rx_task_count);
570  ESP_LOGI(TAG, "MCP2 TX task count: %d", C2_tx_task_count);
571  ESP_LOGI(TAG, "Wasm pthread count: %d", wasm_pthread_count);
572  ESP_LOGI(TAG, "Stats task count: %d", stats_task_count);
573 
574  //Duration of the app_instance_main for the wasm pthread
575  ESP_LOGI(TAG, "Duration of wasm task (ms): %f",wasm_main_duration/1000000);
576 }
577 
584 static void stats_task(void *arg)
585 {
586  //Print real time stats periodically
587  while (1) {
588  printf("\n\nGetting real time stats over %" PRIu32 " ticks\n", STATS_TICKS);
589  if (print_real_time_stats(STATS_TICKS) == ESP_OK) {
590  printf("Real time stats obtained\n");
591  } else {
592  printf("Error getting real time stats\n");
593  }
594  GetStatus(TAG_STATUS);
595  stats_task_count++;
596  vTaskDelay(pdMS_TO_TICKS(1000));
597  }
598 }
599 
600 //--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
601 // Controller 0 (TWAI)
602 //--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
613 void C0_receive_task(void *pvParameters){
614  esp_log_level_set(TAG_TWAI, MY_ESP_LOG_LEVEL);
615  C0.SetN2kCANMsgBufSize(8);
616  C0.SetN2kCANReceiveFrameBufSize(250);
617  C0.EnableForward(false);
618  C0.SetMsgHandler(HandleNMEA2000Msg);
619  C0.SetMode(tNMEA2000::N2km_ListenAndSend);
620  C0.Open();
621  C0.ConfigureAlerts(alerts_to_enable);
622 
623  // Task Loop
624  while(1)
625  {
626  C0.CAN_read_frame(); // retrieves available messages - for TWAI controller only
627  C0.ParseMessages(); // Calls message handle whenever a message is available
628  C0_rx_task_count++;
629  }
630  vTaskDelete(NULL); // should never get here...
631 }
632 
641 void C0_send_task(void *pvParameters)
642 {
643  esp_log_level_set(TAG_TWAI, MY_ESP_LOG_LEVEL);
644  ESP_LOGI(TAG_TWAI, "Starting C0_send_task");
645  NMEA_msg msg;
646 
647  // Task Loop
648  for (;;)
649  {
650  if( xQueueReceive( C0_tx_queue, &msg, (100 / portTICK_PERIOD_MS) ))
651  {
652 
653  SendN2kMsg(msg, C0_NUM);
654 
655  }
656  ESP_LOGV(TAG_TWAI, "Send task called");
657 
658  C0_tx_task_count++;
659  }
660  vTaskDelete(NULL); // should never get here...
661 }
662 
663 //--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
664 // Controller 1 (MCP)
665 //--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
675 void C1_receive_task(void *pvParameters){
676  esp_log_level_set(TAG_MCP1, MY_ESP_LOG_LEVEL);
677  C1.SetN2kCANMsgBufSize(8);
678  C1.SetN2kCANReceiveFrameBufSize(250);
679  C1.EnableForward(false);
680  C1.SetMsgHandler(HandleNMEA2000Msg);
681  C1.SetMode(tNMEA2000::N2km_ListenAndSend);
682  C1.CANinit(); // Initialize SPI bus, call before C1.Open() and only call once for all the MCP tasks
683  C1.Open();
684 
685  // Task Loop
686  while(1)
687  {
688  if( xSemaphoreTake( x_sem_mcp1, (100 / portTICK_PERIOD_MS) ) == pdTRUE )
689  {
690  // We were able to obtain the semaphore and can now access the shared resource.
691  C1.ParseMessages(); // Calls message handle whenever a message is available
692  // We have finished accessing the shared resource. Release the semaphore.
693  xSemaphoreGive( x_sem_mcp1 );
694  vTaskDelay(10 / portTICK_PERIOD_MS);
695  }
696  C1_rx_task_count++;
697  vTaskDelay(10 / portTICK_PERIOD_MS);
698 
699  }
700  vTaskDelete(NULL); // should never get here...
701 }
702 
711 void C1_send_task(void *pvParameters)
712 {
713  esp_log_level_set(TAG_MCP1, MY_ESP_LOG_LEVEL);
714  ESP_LOGI(TAG_TWAI, "Starting C1_send_task");
715  NMEA_msg msg;
716 
717  // Task Loop
718  for (;;)
719  {
720  if( xQueueReceive( C1_tx_queue, &msg, (100 / portTICK_PERIOD_MS) ))
721  {
722  if( xSemaphoreTake( x_sem_mcp1, portMAX_DELAY ) == pdTRUE )
723  {
724  // We were able to obtain the semaphore and can now access the shared resource.
725  ESP_LOGD(TAG_MCP1, "About to send message with PGN: %i", msg.PGN);
726 
727  SendN2kMsg(msg, C1_NUM);
728 
729  // We have finished accessing the shared resource. Release the semaphore.
730  xSemaphoreGive( x_sem_mcp1 );
731  }
732 
733  }
734  ESP_LOGD(TAG_TWAI, "Send task called");
735 
736  C1_tx_task_count++;
737  }
738  vTaskDelete(NULL); // should never get here...
739 }
740 
741 //--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
742 // Controller 2 (MCP)
743 //--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
753 void C2_receive_task(void *pvParameters){
754  esp_log_level_set(TAG_MCP2, MY_ESP_LOG_LEVEL);
755 
756  C2.SetN2kCANMsgBufSize(8);
757  C2.SetN2kCANReceiveFrameBufSize(250);
758  C2.EnableForward(false);
759  C2.SetMsgHandler(HandleNMEA2000Msg);
760  C2.SetMode(tNMEA2000::N2km_ListenAndSend);
761 
762  C2.Open();
763  // Task Loop
764  while(1)
765  {
766  if( xSemaphoreTake( x_sem_mcp2, (100 / portTICK_PERIOD_MS) ) == pdTRUE )
767  {
768  // We were able to obtain the semaphore and can now access the shared resource.
769  C2.ParseMessages(); // Calls message handle whenever a message is available
770 
771  xSemaphoreGive( x_sem_mcp2 ); // We have finished accessing the shared resource. Release the semaphore.
772  vTaskDelay(100 / portTICK_PERIOD_MS);
773  }
774  C2_rx_task_count++;
775  vTaskDelay(10 / portTICK_PERIOD_MS);
776 
777  }
778  vTaskDelete(NULL); // should never get here...
779 }
780 
789 void C2_send_task(void *pvParameters)
790 {
791  esp_log_level_set(TAG_MCP2, MY_ESP_LOG_LEVEL);
792  ESP_LOGI(TAG_TWAI, "Starting C2_send_task");
793  NMEA_msg msg;
794 
795  // Task Loop
796  for (;;)
797  {
798  if( xQueueReceive( C2_tx_queue, &msg, (100 / portTICK_PERIOD_MS) ))
799  {
800  if( xSemaphoreTake( x_sem_mcp2, portMAX_DELAY ) == pdTRUE )
801  {
802  // We were able to obtain the semaphore and can now access the shared resource.
803  ESP_LOGD(TAG_MCP2, "About to send message with PGN: %i", msg.PGN);
804 
805  SendN2kMsg(msg, C2_NUM);
806  xSemaphoreGive( x_sem_mcp2 ); // We have finished accessing the shared resource. Release the semaphore.
807  }
808 
809  }
810  ESP_LOGD(TAG_TWAI, "Send task called");
811 
812  C2_tx_task_count++;
813  }
814  vTaskDelete(NULL); // should never get here...
815 }
816 
824 void HandleNMEA2000Msg(const tN2kMsg &N2kMsg) {
825  if (N2kMsg.Source == 14){
826  ESP_LOGD(TAG_TWAI, "source is 14");
827  return;
828  }
829  ESP_LOGV(TAG_TWAI, "Message Handler called");
830  NMEA_msg msg;
831  msg.controller_number = 0;
832  msg.priority = N2kMsg.Priority;
833 
834  msg.PGN = N2kMsg.PGN;
835  ESP_LOGD(TAG_TWAI, "PGN %u", msg.PGN);
836  msg.source = N2kMsg.Source;
837  msg.data_length_bytes = N2kMsg.DataLen;
838  size_t size = sizeof(N2kMsg.Data) / sizeof(N2kMsg.Data[0]);
839  // Perform the conversion with range checking
840  for (size_t i = 0; i < size; i++) {
841  if (N2kMsg.Data[i] <= static_cast<unsigned char>(CHAR_MAX)) {
842  msg.data[i] = static_cast<signed char>(N2kMsg.Data[i]);
843  } else {
844  // Handle out-of-range value
845  //msg.data[i] = /* Your desired behavior for out-of-range values */;
846  ESP_LOGE("Message Handle", "data out of range for signed array");
847  }
848  }
849 
850  if(xQueueSendToBack(rx_queue, &msg, pdMS_TO_TICKS(10)) == 0){
851  ESP_LOGW(TAG_TWAI, "Could not add received message to RX queue");
852  }
853  else{
854  ESP_LOGV(TAG_TWAI, " added msg to received queue");
855  }
856  read_msg_count++;
857 
858 }
859 
860 
861 
867 static void * app_instance_main(wasm_module_inst_t module_inst)
868 {
869  const char *exception;
870 
871  wasm_application_execute_main(module_inst, 0, NULL);
872  if ((exception = wasm_runtime_get_exception(module_inst)))
873  ESP_LOGW(TAG_WASM,"%s\n", exception);
874  return NULL;
875 }
876 
887 void * iwasm_main(void *arg)
888 {
889  esp_log_level_set(TAG_WASM, MY_ESP_LOG_LEVEL);
890  (void)arg; /* unused */
891  /* setup variables for instantiating and running the wasm module */
892  uint8_t *wasm_file_buf = NULL;
893  unsigned wasm_file_buf_size = 0;
894  wasm_exec_env_t exec_env = NULL;
895  wasm_module_t wasm_module = NULL;
896  wasm_module_inst_t wasm_module_inst = NULL;
897  char error_buf[128];
898  void *ret;
899  wasm_function_inst_t func = NULL;
900  RuntimeInitArgs init_args;
901 
902  uint32_t buffer_for_wasm = 0;
903  uint32_t buffer_for_wasm_mode = 0;
904 
905  /* configure memory allocation */
906  memset(&init_args, 0, sizeof(RuntimeInitArgs));
907 
908  /* the native functions that will be exported to WASM app */
909  static NativeSymbol native_symbols[] = {
910  {
911  "PrintStr", // the name of WASM function name
912  reinterpret_cast<void*>(PrintStr), // the native function pointer
913  "($i)", // the function prototype signature, avoid to use i32
914  NULL // attachment is NULL
915  },
916  {
917  "PrintInt32",
918  reinterpret_cast<void*>(PrintInt32),
919  "(ii)",
920  NULL
921  },
922  {
923  "SendMsg",
924  reinterpret_cast<void*>(SendMsg),
925  "(iiii*~)i",
926  NULL
927  }
928  };
929 #if WASM_ENABLE_GLOBAL_HEAP_POOL == 0
930  init_args.mem_alloc_type = Alloc_With_Allocator;
931  init_args.mem_alloc_option.allocator.malloc_func = (void *)os_malloc;
932  init_args.mem_alloc_option.allocator.realloc_func = (void *)os_realloc;
933  init_args.mem_alloc_option.allocator.free_func = (void *)os_free;
934 #else
935 #error The usage of a global heap pool is not implemented yet for esp-idf.
936 #endif
937 
938  /* configure the native functions being exported to WASM app */
939  init_args.n_native_symbols = sizeof(native_symbols) / sizeof(NativeSymbol);
940  init_args.native_module_name = "env";
941  init_args.native_symbols = native_symbols;
942 
943 
944  ESP_LOGI(TAG_WASM, "Initialize WASM runtime");
945  /* initialize runtime environment */
946  if (!wasm_runtime_full_init(&init_args)) {
947  ESP_LOGE(TAG_WASM, "Init runtime failed.");
948  return NULL;
949  }
950  ESP_LOGI(TAG_WASM, "Run wamr with interpreter");
951 
952  wasm_file_buf = (uint8_t *)nmea_attack_wasm;
953  wasm_file_buf_size = sizeof(nmea_attack_wasm);
954 
955  /* load WASM module */
956  if (!(wasm_module = wasm_runtime_load(wasm_file_buf, wasm_file_buf_size,
957  error_buf, sizeof(error_buf)))) {
958  ESP_LOGE(TAG_WASM, "Error in wasm_runtime_load: %s", error_buf);
959  goto fail;
960  }
961 
962  ESP_LOGI(TAG_WASM, "Instantiate WASM runtime");
963  if (!(wasm_module_inst =
964  wasm_runtime_instantiate(wasm_module, NATIVE_STACK_SIZE, // stack size
965  NATIVE_HEAP_SIZE, // heap size
966  error_buf, sizeof(error_buf)))) {
967  ESP_LOGE(TAG_WASM, "Error while instantiating: %s", error_buf);
968  goto fail;
969  }
970 
971 
972  exec_env = wasm_runtime_create_exec_env(wasm_module_inst, NATIVE_STACK_SIZE);//stack size
973  if (!exec_env) {
974  ESP_LOGW(TAG_WASM,"Create wasm execution environment failed.\n");
975  goto fail;
976  }
977 
978  // Link buffer for Messages
979  ESP_LOGI(TAG_WASM, "Malloc buffer in wasm function");
980  buffer_for_wasm = wasm_runtime_module_malloc(wasm_module_inst, 100, (void **)&wasm_buffer);
981  if (buffer_for_wasm == 0) {
982  ESP_LOGI(TAG_WASM, "Malloc failed");
983  goto fail;
984  }
985  uint32 argv[2];
986  argv[0] = buffer_for_wasm; /* pass the buffer address for WASM space */
987  argv[1] = MSG_BUFFER_SIZE; /* the size of buffer */
988  ESP_LOGI(TAG_WASM, "Call wasm function");
989  /* it is runtime embedder's responsibility to release the memory,
990  unless the WASM app will free the passed pointer in its code */
991 
992  if (!(func = wasm_runtime_lookup_function(wasm_module_inst, "link_msg_buffer",
993  NULL))) {
994  ESP_LOGW(TAG_WASM,
995  "The wasm function link_msg_buffer wasm function is not found.\n");
996  goto fail;
997  }
998 
999  if (wasm_runtime_call_wasm(exec_env, func, 2, argv)) {
1000  ESP_LOGI(TAG_WASM,"Native finished calling wasm function: link_msg_buffer, "
1001  "returned a formatted string: %s\n",
1002  wasm_buffer);
1003  }
1004  else {
1005  ESP_LOGW(TAG_WASM,"call wasm function link_msg_buffer failed. error: %s\n",
1006  wasm_runtime_get_exception(wasm_module_inst));
1007  goto fail;
1008  }
1009 
1010  // Link buffer for mode
1011  ESP_LOGI(TAG_WASM, "Malloc buffer in wasm function");
1012  buffer_for_wasm_mode = wasm_runtime_module_malloc(wasm_module_inst, 100, (void **)&wasm_mode_buffer);
1013  if (buffer_for_wasm_mode == 0) {
1014  ESP_LOGI(TAG_WASM, "Malloc failed");
1015  goto fail;
1016  }
1017  uint32 argv_mode[2];
1018  argv_mode[0] = buffer_for_wasm_mode; /* pass the buffer address for WASM space */
1019  argv_mode[1] = MODE_BUFFER_SIZE; /* the size of buffer */
1020  ESP_LOGI(TAG_WASM, "Call wasm function");
1021  /* it is runtime embedder's responsibility to release the memory,
1022  unless the WASM app will free the passed pointer in its code */
1023 
1024  if (!(func = wasm_runtime_lookup_function(wasm_module_inst, "link_mode_buffer",
1025  NULL))) {
1026  ESP_LOGW(TAG_WASM,
1027  "The wasm function link_mode_buffer wasm function is not found.\n");
1028  goto fail;
1029  }
1030 
1031  if (wasm_runtime_call_wasm(exec_env, func, 2, argv_mode)) {
1032  ESP_LOGI(TAG_WASM,"Native finished calling wasm function: link_mode_buffer, "
1033  "returned a formatted string: %s\n",
1035  }
1036  else {
1037  ESP_LOGW(TAG_WASM,"call wasm function link_mode_buffer failed. error: %s\n",
1038  wasm_runtime_get_exception(wasm_module_inst));
1039  goto fail;
1040  }
1041 
1042 
1043  // Task Loop
1044  while (true){
1045  ESP_LOGV(TAG_WASM, "run main() of the application");
1046  auto start = std::chrono::high_resolution_clock::now();
1047  NMEA_msg msg;
1048  if (xQueueReceive(rx_queue, &msg, (100 / portTICK_PERIOD_MS) == 1)){
1049  std::string str_msg = nmea_to_string(msg);
1050  strncpy(wasm_buffer, str_msg.c_str(), str_msg.size()); // fill message buffer
1051  strncpy(wasm_mode_buffer, tc_mode.c_str(), tc_mode.size()); // fill mode buffer
1052  ret = app_instance_main(wasm_module_inst); //Call the main function
1053  assert(!ret);
1054  } else{
1055  vTaskDelay(10 / portTICK_PERIOD_MS); // I don't understand why this is nessesary
1056  }
1057 
1058  auto end = std::chrono::high_resolution_clock::now();
1059  auto ns_duration = duration_cast<std::chrono::nanoseconds>(end-start);
1060  wasm_main_duration = static_cast<double>(ns_duration.count());
1061 
1062  wasm_pthread_count++;
1063  }
1064 
1065 
1066  //wasm_runtime_module_free(wasm_module_inst, buffer_for_wasm);
1067  //wasm_runtime_module_free(wasm_module_inst, buffer_for_wasm_mode);
1068 
1069  /* destroy the module instance */
1070  ESP_LOGI(TAG_WASM, "Deinstantiate WASM runtime");
1071  wasm_runtime_deinstantiate(wasm_module_inst);
1072 
1073 fail:
1074  if (exec_env)
1075  wasm_runtime_destroy_exec_env(exec_env);
1076  if (wasm_module_inst) {
1077  if (buffer_for_wasm){
1078  wasm_runtime_module_free(wasm_module_inst, buffer_for_wasm);}
1079  if (buffer_for_wasm_mode)
1080  {
1081  wasm_runtime_module_free(wasm_module_inst, buffer_for_wasm_mode);
1082  }
1083  wasm_runtime_deinstantiate(wasm_module_inst);
1084  }
1085  if (wasm_module){
1086  /* unload the module */
1087  ESP_LOGI(TAG_WASM, "Unload WASM module");
1088  wasm_runtime_unload(wasm_module);
1089  }
1090  if (wasm_buffer)
1091  BH_FREE(wasm_buffer);
1092  if (wasm_mode_buffer)
1093  BH_FREE(wasm_mode_buffer);
1094 
1095 
1096  /* destroy runtime environment */
1097  ESP_LOGI(TAG_WASM, "Destroy WASM runtime");
1098  wasm_runtime_destroy();
1099  return NULL;
1100 }
1101 
1107 extern "C" int app_main(void)
1108 {
1109  C0_tx_queue = xQueueCreate(TX_QUEUE_SIZE, sizeof(NMEA_msg));
1110  C1_tx_queue = xQueueCreate(TX_QUEUE_SIZE, sizeof(NMEA_msg));
1111  C2_tx_queue = xQueueCreate(TX_QUEUE_SIZE, sizeof(NMEA_msg));
1112  rx_queue = xQueueCreate(RX_QUEUE_SIZE, sizeof(NMEA_msg));
1113 
1114  x_sem_mcp1 = xSemaphoreCreateMutex();
1115  x_sem_mcp2 = xSemaphoreCreateMutex();
1116 
1117  esp_err_t result = ESP_OK;
1118 
1119 #ifdef PRINT_STATS
1120  /* Status Task*/
1121  printf( "create task");
1122  xTaskCreatePinnedToCore(
1123  &stats_task, // Pointer to the task entry function.
1124  "stats_task", // A descriptive name for the task for debugging.
1125  4096, // size of the task stack in bytes.
1126  NULL, // Optional pointer to pvParameters
1127  STATS_TASK_PRIO, // priority at which the task should run
1128  &stats_task_handle, // Optional pass back task handle
1129  1
1130  );
1131  if (stats_task_handle == NULL)
1132  {
1133  printf("Unable to create task.");
1134  result = ESP_ERR_NO_MEM;
1135  goto err_out;
1136  }
1137 #endif
1138  /* T Connector Modes Task*/
1139  printf( "create task");
1140  xTaskCreatePinnedToCore(
1141  &get_mode_task, // Pointer to the task entry function.
1142  "get_mode_task", // A descriptive name for the task for debugging.
1143  4096, // size of the task stack in bytes.
1144  NULL, // Optional pointer to pvParameters
1145  STATS_TASK_PRIO, // priority at which the task should run
1146  &modes_task_handle, // Optional pass back task handle
1147  1
1148  );
1149  if (modes_task_handle == NULL)
1150  {
1151  printf("Unable to create task.");
1152  result = ESP_ERR_NO_MEM;
1153  goto err_out;
1154  }
1155  /* Controller 0 Sending task */
1156  ESP_LOGV(TAG_WASM, "create task");
1157  xTaskCreatePinnedToCore(
1158  &C0_send_task, // Pointer to the task entry function.
1159  "Send_task", // A descriptive name for the task for debugging.
1160  3072, // size of the task stack in bytes.
1161  NULL, // Optional pointer to pvParameters
1162  tskIDLE_PRIORITY+1, // priority at which the task should run
1163  &C0_send_task_handle, // Optional pass back task handle
1164  1
1165  );
1166  if (C0_send_task_handle == NULL)
1167  {
1168  ESP_LOGE(TAG_TWAI, "Unable to create task.");
1169  result = ESP_ERR_NO_MEM;
1170  goto err_out;
1171  }
1172  /* Controller 0 Receiving task */
1173  ESP_LOGV(TAG_TWAI, "create task");
1174  xTaskCreatePinnedToCore(
1175  &C0_receive_task, // Pointer to the task entry function.
1176  "Receive_task", // A descriptive name for the task for debugging.
1177  3072, // size of the task stack in bytes.
1178  NULL, // Optional pointer to pvParameters
1179  tskIDLE_PRIORITY+3, // priority at which the task should run
1180  &C0_receive_task_handle, // Optional pass back task handle
1181  0
1182  );
1183  if (C0_receive_task_handle == NULL)
1184  {
1185  ESP_LOGE(TAG_TWAI, "Unable to create task.");
1186  result = ESP_ERR_NO_MEM;
1187  goto err_out;
1188 
1189  }
1190 
1191  /* Controller 1 Sending task */
1192  ESP_LOGV(TAG_MCP1, "create task");
1193  xTaskCreatePinnedToCore(
1194  &C1_send_task, // Pointer to the task entry function.
1195  "Send_task", // A descriptive name for the task for debugging.
1196  3072, // size of the task stack in bytes.
1197  NULL, // Optional pointer to pvParameters
1198  tskIDLE_PRIORITY+1, // priority at which the task should run
1199  &C1_send_task_handle, // Optional pass back task handle
1200  1
1201  );
1202  if (C1_send_task_handle == NULL)
1203  {
1204  ESP_LOGE(TAG_MCP1, "Unable to create task.");
1205  result = ESP_ERR_NO_MEM;
1206  goto err_out;
1207  }
1209  ESP_LOGV(TAG_MCP1, "create task");
1210  xTaskCreatePinnedToCore(
1211  &C1_receive_task, // Pointer to the task entry function.
1212  "Receive_task", // A descriptive name for the task for debugging.
1213  3072, // size of the task stack in bytes.
1214  NULL, // Optional pointer to pvParameters
1215  tskIDLE_PRIORITY+3, // priority at which the task should run
1216  &C1_receive_task_handle, // Optional pass back task handle
1217  0
1218  );
1219  if (C1_receive_task_handle == NULL)
1220  {
1221  ESP_LOGE(TAG_MCP1, "Unable to create task.");
1222  result = ESP_ERR_NO_MEM;
1223  goto err_out;
1224  }
1225  /* Controller 2 Sending task */
1226  ESP_LOGV(TAG_MCP2, "create task");
1227  xTaskCreatePinnedToCore(
1228  &C2_send_task, // Pointer to the task entry function.
1229  "Send_task", // A descriptive name for the task for debugging.
1230  3072, // size of the task stack in bytes.
1231  NULL, // Optional pointer to pvParameters
1232  tskIDLE_PRIORITY+1, // priority at which the task should run
1233  &C2_send_task_handle, // Optional pass back task handle
1234  1
1235  );
1236  if (C2_send_task_handle == NULL)
1237  {
1238  ESP_LOGE(TAG_MCP2, "Unable to create task.");
1239  result = ESP_ERR_NO_MEM;
1240  goto err_out;
1241  }
1243  ESP_LOGV(TAG_MCP2, "create task");
1244  xTaskCreatePinnedToCore(
1245  &C2_receive_task, // Pointer to the task entry function.
1246  "Receive_task", // A descriptive name for the task for debugging.
1247  3072, // size of the task stack in bytes.
1248  NULL, // Optional pointer to pvParameters
1249  tskIDLE_PRIORITY+3, // priority at which the task should run
1250  &C2_receive_task_handle, // Optional pass back task handle
1251  0
1252  );
1253  if (C2_receive_task_handle == NULL)
1254  {
1255  ESP_LOGE(TAG_MCP2, "Unable to create task.");
1256  result = ESP_ERR_NO_MEM;
1257  goto err_out;
1258  }
1259 
1260  /* Wasm pthread */
1261  pthread_t t;
1262  int res;
1263  esp_pthread_cfg_t esp_pthread_cfg;
1264 
1265 
1266 
1267  pthread_attr_t tattr;
1268  pthread_attr_init(&tattr);
1269  pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_JOINABLE);
1270  pthread_attr_setstacksize(&tattr, PTHREAD_STACK_SIZE);
1271 
1272  // Use the ESP-IDF API to change the default thread attributes
1273  esp_pthread_cfg = esp_pthread_get_default_config();
1274  ESP_LOGI(TAG_WASM, "Pthread priority: %d", esp_pthread_cfg.prio);
1275  ESP_LOGI(TAG_WASM, "Pthread core: %d", esp_pthread_cfg.pin_to_core);
1276  esp_pthread_cfg.prio = tskIDLE_PRIORITY+1; //change priority
1277  esp_pthread_cfg.pin_to_core = 1; // pin to core 1
1278  ESP_ERROR_CHECK( esp_pthread_set_cfg(&esp_pthread_cfg) );
1279 
1280  res = pthread_create(&t, &tattr, iwasm_main, (void *)NULL);
1281  assert(res == 0);
1282 
1283  esp_pthread_get_cfg(&esp_pthread_cfg);
1284  ESP_LOGI(TAG_WASM, "Pthread priority: %d", esp_pthread_cfg.prio);
1285  res = pthread_join(t, NULL);
1286  assert(res == 0);
1287 
1288 err_out:
1289  if (result != ESP_OK)
1290  {
1291  if (C0_send_task_handle != NULL || C0_receive_task_handle != NULL || C1_send_task_handle != NULL || C1_receive_task_handle != NULL || C2_send_task_handle != NULL || C2_receive_task_handle != NULL|| stats_task_handle != NULL)
1292  {
1293  vTaskDelete(C0_send_task_handle);
1294  vTaskDelete(C0_receive_task_handle);
1295  vTaskDelete(C1_send_task_handle);
1296  vTaskDelete(C1_receive_task_handle);
1297  vTaskDelete(C2_send_task_handle);
1298  vTaskDelete(C2_receive_task_handle);
1299  vTaskDelete(stats_task_handle);
1300  C0_send_task_handle = NULL;
1301  C0_receive_task_handle = NULL;
1302  C1_send_task_handle = NULL;
1303  C1_receive_task_handle = NULL;
1304  C2_send_task_handle = NULL;
1305  C2_receive_task_handle = NULL;
1306  stats_task_handle = NULL;
1307  }
1308  }
1309 
1310  return 0;
1311 };
Represents a NMEA 2000 messages.
QueueHandle_t C0_tx_queue
Queue that stores messages to be sent out on controller 0.
Definition: main.cpp:109
void uint8ArrayToCharrArray(uint8_t(&data_uint8_arr)[MAX_DATA_LENGTH_BTYES], unsigned char(&data_char_arr)[MAX_DATA_LENGTH_BTYES])
Fills a char array with values from a uint8_t array.
Definition: main.cpp:296
QueueHandle_t rx_queue
Queue that stores all messages received on all controllers.
Definition: main.cpp:112
int app_main(void)
Creates a FreeRTOS task for sending and receiving to and from CAN Controller and creates a pthread to...
Definition: main.cpp:1107
SemaphoreHandle_t x_sem_mcp2
Semaphore handle for MCP2.
Definition: main.cpp:116
std::string tc_mode
Contains the T Connector mode-> 0 - OFF, 1 - PASSIVE, 2 - GPS_ATTACK, 3 - TBD.
Definition: main.cpp:145
void C1_receive_task(void *pvParameters)
FreeRTOS task for receiving messages from MCP CAN controller 1.
Definition: main.cpp:675
void get_mode_task(void *pvParameters)
Task to get the Controller Mode set by the Raspberry Pi.
Definition: main.cpp:351
void configTConnectorModes()
Configures GPIO used to read mode settings from the Raspberry Pi.
Definition: main.cpp:315
void * iwasm_main(void *arg)
WASM pthread to host wasm app.
Definition: main.cpp:887
void C1_send_task(void *pvParameters)
FreeRTOS task for processing and sending messages from MCP CAN controller 1 with NMEA2000 library.
Definition: main.cpp:711
char * wasm_buffer
buffer allocated for wasm app, used to hold received messages so app can access them
Definition: main.cpp:141
CONTROLLER
enum to store identifiers for each controller
Definition: main.cpp:126
bool SendN2kMsg(NMEA_msg msg, int controller_num)
Sends a message.
Definition: main.cpp:376
void PrintStr(wasm_exec_env_t exec_env, uint8_t *input, int32_t length)
prints a uint8_t array to terminal
Definition: main.cpp:171
tNMEA2000_esp32c6 C0(MCP0_TX, MCP0_RX)
Controller 0 -> TWAI, (TX_PIN, RX_PIN)
void C0_send_task(void *pvParameters)
FreeRTOS task for processing and sending messages from CAN controller with NMEA2000 library.
Definition: main.cpp:641
int send_msg_count
Used to track messages sent.
Definition: main.cpp:144
void HandleNMEA2000Msg(const tN2kMsg &N2kMsg)
Creates a NMEA_msg object and adds it to.data the received messages queue.
Definition: main.cpp:824
void C0_receive_task(void *pvParameters)
FreeRTOS task for receiving messages from CAN controller.
Definition: main.cpp:613
SemaphoreHandle_t x_sem_mcp1
Semaphore handle for MCP1.
Definition: main.cpp:115
QueueHandle_t C2_tx_queue
Queue that stores messages to be sent out on controller 2.
Definition: main.cpp:111
std::string nmea_to_string(NMEA_msg &msg)
converts a NMEA_msg to a string
Definition: main.cpp:272
void C2_receive_task(void *pvParameters)
FreeRTOS task for receiving messages from MCP CAN controller 2.
Definition: main.cpp:753
void C2_send_task(void *pvParameters)
FreeRTOS task for processing and sending messages from MCP CAN controller 2 with NMEA2000 library.
Definition: main.cpp:789
int read_msg_count
Used to track messages read.
Definition: main.cpp:143
spi_device_handle_t spi2
MCP controller 2 spi handle.
Definition: main.cpp:91
uint32_t alerts_to_enable
Sets which alerts to enable for TWAI controller.
Definition: main.cpp:146
spi_device_handle_t spi1
MCP controller 1 spi handle.
Definition: main.cpp:90
void PrintInt32(wasm_exec_env_t exec_env, int32_t number, int32_t hex)
prints a integer to terminal
Definition: main.cpp:189
QueueHandle_t C1_tx_queue
Queue that stores messages to be sent out on controller 1.
Definition: main.cpp:110
char * wasm_mode_buffer
buffer allocated for wasm app, used to hold current t connector mode set by Raspberry Pi
Definition: main.cpp:142
void GetStatus(const char *TAG)
Retrieves twai status and alerts.
Definition: main.cpp:543