Lua CAN RX (#3403)
* wiring * static * implementation * comment * unit tests happy * guard * guard smarter, not harder * guard smarter not harder * guard even smarter, not even harder * don't need that
This commit is contained in:
parent
fdc3a83838
commit
383d8caad9
|
@ -10,6 +10,8 @@
|
||||||
|
|
||||||
#include "pch.h"
|
#include "pch.h"
|
||||||
|
|
||||||
|
#include "rusefi_lua.h"
|
||||||
|
|
||||||
typedef float fsio_table_8x8_f32t_linear[FSIO_TABLE_8 * FSIO_TABLE_8];
|
typedef float fsio_table_8x8_f32t_linear[FSIO_TABLE_8 * FSIO_TABLE_8];
|
||||||
|
|
||||||
bool acceptCanRx(int sid DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
bool acceptCanRx(int sid DECLARE_ENGINE_PARAMETER_SUFFIX) {
|
||||||
|
@ -156,7 +158,6 @@ static void processCanRxImu(const CANRxFrame& frame, efitick_t nowNt) {
|
||||||
engine->sensors.accelerometer.z = accZ * MM5_10_ACC_QUANT;
|
engine->sensors.accelerometer.z = accZ * MM5_10_ACC_QUANT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void processCanRxMessage(const CANRxFrame &frame, efitick_t nowNt) {
|
void processCanRxMessage(const CANRxFrame &frame, efitick_t nowNt) {
|
||||||
|
@ -173,6 +174,8 @@ void processCanRxMessage(const CANRxFrame &frame, efitick_t nowNt) {
|
||||||
// todo: convert to CanListener or not?
|
// todo: convert to CanListener or not?
|
||||||
processCanRxImu(frame, nowNt);
|
processCanRxImu(frame, nowNt);
|
||||||
|
|
||||||
|
processLuaCan(frame);
|
||||||
|
|
||||||
#if EFI_CANBUS_SLAVE
|
#if EFI_CANBUS_SLAVE
|
||||||
if (CAN_EID(frame) == CONFIG(verboseCanBaseAddress) + CAN_SENSOR_1_OFFSET) {
|
if (CAN_EID(frame) == CONFIG(verboseCanBaseAddress) + CAN_SENSOR_1_OFFSET) {
|
||||||
int16_t mapScaled = *reinterpret_cast<const int16_t*>(&frame.data8[0]);
|
int16_t mapScaled = *reinterpret_cast<const int16_t*>(&frame.data8[0]);
|
||||||
|
|
|
@ -116,43 +116,6 @@ static void* myAlloc(void* /*ud*/, void* ptr, size_t /*osize*/, size_t nsize) {
|
||||||
}
|
}
|
||||||
#endif // EFI_PROD_CODE
|
#endif // EFI_PROD_CODE
|
||||||
|
|
||||||
class LuaHandle final {
|
|
||||||
public:
|
|
||||||
LuaHandle() : LuaHandle(nullptr) { }
|
|
||||||
LuaHandle(lua_State* ptr) : m_ptr(ptr) { }
|
|
||||||
|
|
||||||
// Don't allow copying!
|
|
||||||
LuaHandle(const LuaHandle&) = delete;
|
|
||||||
LuaHandle& operator=(const LuaHandle&) = delete;
|
|
||||||
|
|
||||||
// Allow moving!
|
|
||||||
LuaHandle(LuaHandle&& rhs) {
|
|
||||||
m_ptr = rhs.m_ptr;
|
|
||||||
rhs.m_ptr = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Move assignment operator
|
|
||||||
LuaHandle& operator=(LuaHandle&& rhs) {
|
|
||||||
m_ptr = rhs.m_ptr;
|
|
||||||
rhs.m_ptr = nullptr;
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Destruction cleans up lua state
|
|
||||||
~LuaHandle() {
|
|
||||||
if (m_ptr) {
|
|
||||||
efiPrintf("LUA: Tearing down instance...");
|
|
||||||
lua_close(m_ptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
operator lua_State*() const { return m_ptr; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
lua_State* m_ptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
static int luaTickPeriodMs;
|
static int luaTickPeriodMs;
|
||||||
|
|
||||||
static int lua_setTickRate(lua_State* l) {
|
static int lua_setTickRate(lua_State* l) {
|
||||||
|
@ -328,7 +291,12 @@ static bool runOneLua(lua_Alloc alloc, const char* script) {
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!needsReset && !chThdShouldTerminateX()) {
|
while (!needsReset && !chThdShouldTerminateX()) {
|
||||||
// First, check if there is a pending interactive command entered by the user
|
#if EFI_CAN_SUPPORT
|
||||||
|
// First, process any pending can RX messages
|
||||||
|
doLuaCanRx(ls);
|
||||||
|
#endif // EFI_CAN_SUPPORT
|
||||||
|
|
||||||
|
// Next, check if there is a pending interactive command entered by the user
|
||||||
doInteractive(ls);
|
doInteractive(ls);
|
||||||
|
|
||||||
invokeTick(ls);
|
invokeTick(ls);
|
||||||
|
@ -336,6 +304,10 @@ static bool runOneLua(lua_Alloc alloc, const char* script) {
|
||||||
chThdSleepMilliseconds(luaTickPeriodMs);
|
chThdSleepMilliseconds(luaTickPeriodMs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if EFI_CAN_SUPPORT
|
||||||
|
resetLuaCanRx();
|
||||||
|
#endif // EFI_CAN_SUPPORT
|
||||||
|
|
||||||
// De-init pins, they will reinit next start of the script.
|
// De-init pins, they will reinit next start of the script.
|
||||||
luaDeInitPins();
|
luaDeInitPins();
|
||||||
|
|
||||||
|
@ -367,6 +339,10 @@ static LuaThread luaThread;
|
||||||
|
|
||||||
void startLua() {
|
void startLua() {
|
||||||
#if LUA_USER_HEAP > 1
|
#if LUA_USER_HEAP > 1
|
||||||
|
#if EFI_CAN_SUPPORT
|
||||||
|
initLuaCanRx();
|
||||||
|
#endif // EFI_CAN_SUPPORT
|
||||||
|
|
||||||
luaThread.Start();
|
luaThread.Start();
|
||||||
|
|
||||||
addConsoleActionS("lua", [](const char* str){
|
addConsoleActionS("lua", [](const char* str){
|
||||||
|
|
|
@ -4,6 +4,7 @@ LUA_EXT=$(PROJECT_DIR)/ext/lua
|
||||||
ALLCPPSRC += $(LUA_DIR)/lua.cpp \
|
ALLCPPSRC += $(LUA_DIR)/lua.cpp \
|
||||||
$(LUA_DIR)/lua_hooks.cpp \
|
$(LUA_DIR)/lua_hooks.cpp \
|
||||||
$(LUA_DIR)/system_lua.cpp \
|
$(LUA_DIR)/system_lua.cpp \
|
||||||
|
$(LUA_DIR)/lua_can_rx.cpp \
|
||||||
|
|
||||||
ALLINC += $(LUA_DIR) $(LUA_DIR)/luaaa $(LUA_EXT)
|
ALLINC += $(LUA_DIR) $(LUA_DIR)/luaaa $(LUA_EXT)
|
||||||
ALLCSRC += \
|
ALLCSRC += \
|
||||||
|
|
|
@ -0,0 +1,141 @@
|
||||||
|
#include "pch.h"
|
||||||
|
|
||||||
|
#if EFI_CAN_SUPPORT
|
||||||
|
|
||||||
|
#include "rusefi_lua.h"
|
||||||
|
#include "can.h"
|
||||||
|
|
||||||
|
static constexpr size_t maxFilterCount = 16;
|
||||||
|
|
||||||
|
size_t filterCount = 0;
|
||||||
|
int32_t luaCanRxIds[maxFilterCount] = {0};
|
||||||
|
|
||||||
|
static bool shouldRxCanFrame(const CANRxFrame& frame) {
|
||||||
|
for (size_t i = 0; i < filterCount; i++) {
|
||||||
|
if (CAN_EID(frame) == luaCanRxIds[i]) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr size_t canFrameCount = 32;
|
||||||
|
static CANRxFrame canFrames[canFrameCount];
|
||||||
|
// CAN frame buffers that are not in use
|
||||||
|
chibios_rt::Mailbox<CANRxFrame*, canFrameCount> freeBuffers;
|
||||||
|
// CAN frame buffers that are waiting to be processed by the lua thread
|
||||||
|
chibios_rt::Mailbox<CANRxFrame*, canFrameCount> filledBuffers;
|
||||||
|
|
||||||
|
void processLuaCan(const CANRxFrame& frame) {
|
||||||
|
// Filter the frame if we aren't listening for it
|
||||||
|
if (!shouldRxCanFrame(frame)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CANRxFrame* frameBuffer;
|
||||||
|
msg_t msg;
|
||||||
|
|
||||||
|
{
|
||||||
|
// Acquire a buffer under lock
|
||||||
|
chibios_rt::CriticalSectionLocker csl;
|
||||||
|
msg = freeBuffers.fetchI(&frameBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg != MSG_OK) {
|
||||||
|
// all buffers are already in use, this frame will be dropped!
|
||||||
|
// TODO: warn the user
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy the frame in to the buffer
|
||||||
|
*frameBuffer = frame;
|
||||||
|
|
||||||
|
{
|
||||||
|
// Push the frame in to the queue under lock
|
||||||
|
chibios_rt::CriticalSectionLocker csl;
|
||||||
|
filledBuffers.postI(frameBuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handleCanFrame(LuaHandle& ls, CANRxFrame* frame) {
|
||||||
|
lua_getglobal(ls, "onCanRx");
|
||||||
|
if (lua_isnil(ls, -1)) {
|
||||||
|
// no rx function, ignore
|
||||||
|
efiPrintf("LUA CAN rx missing function onCanRx");
|
||||||
|
lua_settop(ls, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: push arguments to function!
|
||||||
|
UNUSED(frame);
|
||||||
|
|
||||||
|
int status = lua_pcall(ls, 0, 0, 0);
|
||||||
|
|
||||||
|
if (0 != status) {
|
||||||
|
// error calling CAN rx hook function
|
||||||
|
auto errMsg = lua_tostring(ls, -1);
|
||||||
|
efiPrintf("LUA CAN RX error %s", errMsg);
|
||||||
|
lua_pop(ls, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_settop(ls, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool doOneLuaCanRx(LuaHandle& ls) {
|
||||||
|
CANRxFrame* frame;
|
||||||
|
|
||||||
|
msg_t msg = filledBuffers.fetch(&frame, TIME_IMMEDIATE);
|
||||||
|
|
||||||
|
if (msg == MSG_TIMEOUT) {
|
||||||
|
// No new CAN messages rx'd, nothing more to do.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg != MSG_OK) {
|
||||||
|
// Message was otherwise not OK
|
||||||
|
// TODO: what do here?
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We've accepted the frame, process it in Lua.
|
||||||
|
handleCanFrame(ls, frame);
|
||||||
|
|
||||||
|
// We're done, return this frame to the free list
|
||||||
|
msg = freeBuffers.post(frame, TIME_IMMEDIATE);
|
||||||
|
efiAssertVoid(OBD_PCM_Processor_Fault, msg == MSG_OK, "lua can post to free buffer fail");
|
||||||
|
|
||||||
|
// We processed a frame so we should check again
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void doLuaCanRx(LuaHandle& ls) {
|
||||||
|
// While it processed a frame, continue checking
|
||||||
|
while (doOneLuaCanRx(ls)) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
void initLuaCanRx() {
|
||||||
|
// Push all CAN frames in to the free buffer
|
||||||
|
for (size_t i = 0; i < canFrameCount; i++) {
|
||||||
|
freeBuffers.post(&canFrames[i], TIME_INFINITE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void resetLuaCanRx() {
|
||||||
|
// Clear all lua filters - reloading the script will reinit them
|
||||||
|
memset(luaCanRxIds, 0, sizeof(luaCanRxIds));
|
||||||
|
filterCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void addLuaCanRxFilter(int32_t eid) {
|
||||||
|
if (filterCount >= maxFilterCount) {
|
||||||
|
firmwareError(OBD_PCM_Processor_Fault, "Too many Lua CAN RX filters");
|
||||||
|
}
|
||||||
|
|
||||||
|
efiPrintf("Added Lua CAN RX filter: %d", eid);
|
||||||
|
|
||||||
|
luaCanRxIds[filterCount] = eid;
|
||||||
|
filterCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // EFI_CAN_SUPPORT
|
|
@ -1,11 +1,10 @@
|
||||||
#include "pch.h"
|
#include "pch.h"
|
||||||
|
|
||||||
#include "lua.hpp"
|
#include "rusefi_lua.h"
|
||||||
#include "lua_hooks.h"
|
#include "lua_hooks.h"
|
||||||
|
|
||||||
#include "fuel_math.h"
|
#include "fuel_math.h"
|
||||||
#include "airmass.h"
|
#include "airmass.h"
|
||||||
#include "utlist.h"
|
|
||||||
#include "lua_airmass.h"
|
#include "lua_airmass.h"
|
||||||
#include "can_msg_tx.h"
|
#include "can_msg_tx.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
|
@ -339,39 +338,17 @@ static int lua_setFuelMult(lua_State* l) {
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // EFI_UNIT_TEST
|
#endif // EFI_UNIT_TEST
|
||||||
|
|
||||||
|
#if EFI_CAN_SUPPORT
|
||||||
|
static int lua_canRxAdd(lua_State* l) {
|
||||||
|
auto eid = luaL_checkinteger(l, 1);
|
||||||
|
addLuaCanRxFilter(eid);
|
||||||
|
|
||||||
struct LuaCanReciever;
|
return 0;
|
||||||
|
}
|
||||||
// linked list of all CAN receivers
|
#endif // EFI_CAN_SUPPORT
|
||||||
static LuaCanReciever *list;
|
|
||||||
|
|
||||||
struct LuaCanReciever {
|
|
||||||
|
|
||||||
LuaCanReciever *next;
|
|
||||||
|
|
||||||
#if EFI_PROD_CODE
|
|
||||||
cyclic_buffer<CANRxFrame> pending;
|
|
||||||
#endif // EFI_PROD_CODE
|
|
||||||
|
|
||||||
~LuaCanReciever() {
|
|
||||||
LuaCanReciever *current, *tmp;
|
|
||||||
// find self in list and remove self
|
|
||||||
LL_FOREACH_SAFE(list, current, tmp)
|
|
||||||
{
|
|
||||||
if (current == this) {
|
|
||||||
LL_DELETE(list, current);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LuaCanReciever() {
|
|
||||||
LL_PREPEND(list, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
struct LuaSensor : public StoredValueSensor {
|
struct LuaSensor : public StoredValueSensor {
|
||||||
LuaSensor() : LuaSensor("Invalid") { }
|
LuaSensor() : LuaSensor("Invalid") { }
|
||||||
|
@ -405,11 +382,6 @@ void configureRusefiLuaHooks(lua_State* l) {
|
||||||
.fun("reset", static_cast<void (Timer::*)() >(&Timer::reset ))
|
.fun("reset", static_cast<void (Timer::*)() >(&Timer::reset ))
|
||||||
.fun("getElapsedSeconds", static_cast<float(Timer::*)()const>(&Timer::getElapsedSeconds));
|
.fun("getElapsedSeconds", static_cast<float(Timer::*)()const>(&Timer::getElapsedSeconds));
|
||||||
|
|
||||||
LuaClass<LuaCanReciever> luaCanReciever(l, "CanReciever");
|
|
||||||
luaCanReciever
|
|
||||||
.ctor()
|
|
||||||
;
|
|
||||||
|
|
||||||
LuaClass<LuaSensor> luaSensor(l, "Sensor");
|
LuaClass<LuaSensor> luaSensor(l, "Sensor");
|
||||||
luaSensor
|
luaSensor
|
||||||
.ctor<const char*>()
|
.ctor<const char*>()
|
||||||
|
@ -444,5 +416,9 @@ void configureRusefiLuaHooks(lua_State* l) {
|
||||||
|
|
||||||
lua_register(l, "setFuelAdd", lua_setFuelAdd);
|
lua_register(l, "setFuelAdd", lua_setFuelAdd);
|
||||||
lua_register(l, "setFuelMult", lua_setFuelMult);
|
lua_register(l, "setFuelMult", lua_setFuelMult);
|
||||||
#endif
|
|
||||||
|
#if EFI_CAN_SUPPORT
|
||||||
|
lua_register(l, "canRxAdd", lua_canRxAdd);
|
||||||
|
#endif // EFI_CAN_SUPPORT
|
||||||
|
#endif // not EFI_UNIT_TEST
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,45 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "lua.hpp"
|
||||||
|
|
||||||
|
class LuaHandle final {
|
||||||
|
public:
|
||||||
|
LuaHandle() : LuaHandle(nullptr) { }
|
||||||
|
LuaHandle(lua_State* ptr) : m_ptr(ptr) { }
|
||||||
|
|
||||||
|
// Don't allow copying!
|
||||||
|
LuaHandle(const LuaHandle&) = delete;
|
||||||
|
LuaHandle& operator=(const LuaHandle&) = delete;
|
||||||
|
|
||||||
|
// Allow moving!
|
||||||
|
LuaHandle(LuaHandle&& rhs) {
|
||||||
|
m_ptr = rhs.m_ptr;
|
||||||
|
rhs.m_ptr = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move assignment operator
|
||||||
|
LuaHandle& operator=(LuaHandle&& rhs) {
|
||||||
|
m_ptr = rhs.m_ptr;
|
||||||
|
rhs.m_ptr = nullptr;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destruction cleans up lua state
|
||||||
|
~LuaHandle() {
|
||||||
|
if (m_ptr) {
|
||||||
|
efiPrintf("LUA: Tearing down instance...");
|
||||||
|
lua_close(m_ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
operator lua_State*() const { return m_ptr; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
lua_State* m_ptr;
|
||||||
|
};
|
||||||
|
|
||||||
void startLua();
|
void startLua();
|
||||||
|
|
||||||
#if EFI_UNIT_TEST
|
#if EFI_UNIT_TEST
|
||||||
|
@ -12,3 +51,16 @@ float testLuaReturnsNumber(const char* script);
|
||||||
int testLuaReturnsInteger(const char* script);
|
int testLuaReturnsInteger(const char* script);
|
||||||
void testLuaExecString(const char* script);
|
void testLuaExecString(const char* script);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if EFI_CAN_SUPPORT
|
||||||
|
// Lua CAN rx feature
|
||||||
|
void initLuaCanRx();
|
||||||
|
// Called when the user script is unloaded, resets any CAN rx filters
|
||||||
|
void resetLuaCanRx();
|
||||||
|
// Adds a frame ID to listen to
|
||||||
|
void addLuaCanRxFilter(int32_t eid);
|
||||||
|
// Called from the Lua loop to process any pending CAN frames
|
||||||
|
void doLuaCanRx(LuaHandle& ls);
|
||||||
|
// Called from the CAN RX thread to queue a frame for Lua consumption
|
||||||
|
void processLuaCan(const CANRxFrame& frame);
|
||||||
|
#endif // not EFI_CAN_SUPPORT
|
||||||
|
|
|
@ -120,9 +120,9 @@ constexpr size_t lineBufferCount = 24;
|
||||||
static LogLineBuffer lineBuffers[lineBufferCount];
|
static LogLineBuffer lineBuffers[lineBufferCount];
|
||||||
|
|
||||||
// freeBuffers contains a queue of buffers that are not in use
|
// freeBuffers contains a queue of buffers that are not in use
|
||||||
chibios_rt::Mailbox<LogLineBuffer*, lineBufferCount> freeBuffers;
|
static chibios_rt::Mailbox<LogLineBuffer*, lineBufferCount> freeBuffers;
|
||||||
// filledBuffers contains a queue of buffers currently waiting to be written to the output buffer
|
// filledBuffers contains a queue of buffers currently waiting to be written to the output buffer
|
||||||
chibios_rt::Mailbox<LogLineBuffer*, lineBufferCount> filledBuffers;
|
static chibios_rt::Mailbox<LogLineBuffer*, lineBufferCount> filledBuffers;
|
||||||
|
|
||||||
class LoggingBufferFlusher : public ThreadController<256> {
|
class LoggingBufferFlusher : public ThreadController<256> {
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
#include "pch.h"
|
||||||
#include "rusefi_lua.h"
|
#include "rusefi_lua.h"
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue