// Module for interfacing with adc hardware #include "module.h" #include "lauxlib.h" #include "platform.h" #include "CAN.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "freertos/queue.h" #include "esp_task.h" #include "esp_log.h" #include #include "task/task.h" CAN_device_t CAN_cfg = { .speed = CAN_SPEED_1000KBPS, // CAN Node baudrade .tx_pin_id = -1, // CAN TX pin .rx_pin_id = -1, // CAN RX pin .rx_queue = NULL, // FreeRTOS queue for RX frames .code = 0, .mask = 0xffffffff, .dual_filter = false }; static task_handle_t can_data_task_id; static int can_on_received = LUA_NOREF; static xTaskHandle xCanTaskHandle = NULL; // LUA static void can_data_task( task_param_t param, task_prio_t prio ) { CAN_frame_t *frame = (CAN_frame_t *)param; if(can_on_received == LUA_NOREF) { free( frame ); return; } lua_State *L = lua_getstate(); lua_rawgeti(L, LUA_REGISTRYINDEX, can_on_received); lua_pushinteger(L, frame->Extended? 1 : 0); lua_pushinteger(L, frame->MsgID); lua_pushlstring(L, (char *)frame->data.u8, frame->DLC); free( frame ); lua_call(L, 3, 0); } // RTOS static void task_CAN( void *pvParameters ){ (void)pvParameters; //frame buffer CAN_frame_t frame; //create CAN RX Queue CAN_cfg.rx_queue = xQueueCreate(10, sizeof(CAN_frame_t)); //start CAN Module CAN_init(); for (;;){ //receive next CAN frame from queue if( xQueueReceive( CAN_cfg.rx_queue, &frame, 3 * portTICK_PERIOD_MS ) == pdTRUE ){ CAN_frame_t *postFrame = (CAN_frame_t *)malloc( sizeof( CAN_frame_t ) ); memcpy(postFrame, &frame, sizeof( CAN_frame_t )); task_post_medium( can_data_task_id, (task_param_t)postFrame ); } } } // Lua: setup( {}, callback ) static int can_setup( lua_State *L ) { if(xCanTaskHandle != NULL) luaL_error( L, "Stop CAN before setup" ); luaL_checkanytable (L, 1); luaL_checkanyfunction (L, 2); lua_settop (L, 2); if(can_on_received != LUA_NOREF) luaL_unref(L, LUA_REGISTRYINDEX, can_on_received); can_on_received = luaL_ref(L, LUA_REGISTRYINDEX); lua_getfield (L, 1, "speed"); CAN_cfg.speed = luaL_checkint(L, -1); lua_getfield (L, 1, "tx"); CAN_cfg.tx_pin_id = luaL_checkint(L, -1); lua_getfield (L, 1, "rx"); CAN_cfg.rx_pin_id = luaL_checkint(L, -1); lua_getfield (L, 1, "dual_filter"); CAN_cfg.dual_filter = lua_toboolean(L, 0); lua_getfield (L, 1, "code"); CAN_cfg.code = (uint32_t)luaL_optnumber(L, -1, 0); lua_getfield (L, 1, "mask"); CAN_cfg.mask = (uint32_t)luaL_optnumber(L, -1, 0x0ffffffff); return 0; } static int can_start( lua_State *L ) { if(xCanTaskHandle != NULL) luaL_error( L, "CAN started" ); xTaskCreate(task_CAN, "CAN", 2048, NULL, ESP_TASK_MAIN_PRIO + 1, &xCanTaskHandle); return 0; } static int can_stop( lua_State *L ) { if(xCanTaskHandle) { vTaskDelete(xCanTaskHandle); xCanTaskHandle = NULL; } CAN_stop(); if(CAN_cfg.rx_queue) { vQueueDelete( CAN_cfg.rx_queue ); CAN_cfg.rx_queue = NULL; } return 0; } static int can_send( lua_State *L ) { uint32_t format = (uint8_t)luaL_checkinteger( L, 1 ); uint32_t msg_id = luaL_checkinteger( L, 2 ); size_t len; const char *data = luaL_checklstring( L, 3, &len ); uint8_t i; CAN_frame_t frame; if(xCanTaskHandle == NULL) luaL_error( L, "CAN not started" ); if(len > 8) luaL_error( L, "CAN can not send more than 8 bytes" ); frame.Extended = format? 1 : 0; frame.MsgID = msg_id; frame.DLC = len; for(i = 0; i < len; i++) frame.data.u8[i] = data[i]; CAN_write_frame(&frame); return 0; } // Module function map LROT_BEGIN(can) LROT_FUNCENTRY( setup, can_setup ) LROT_FUNCENTRY( start, can_start ) LROT_FUNCENTRY( stop, can_stop ) LROT_FUNCENTRY( send, can_send ) LROT_NUMENTRY ( STANDARD_FRAME, 0 ) LROT_NUMENTRY ( EXTENDED_FRAME, 1 ) LROT_END(can, NULL, 0) int luaopen_can( lua_State *L ) { can_data_task_id = task_get_id( can_data_task ); // reset CAN after sw reset CAN_stop(); return 0; } NODEMCU_MODULE(CAN, "can", can, luaopen_can);