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:
Matthew Kennedy 2021-10-24 05:37:04 -07:00 committed by GitHub
parent fdc3a83838
commit 383d8caad9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 229 additions and 79 deletions

View File

@ -10,6 +10,8 @@
#include "pch.h"
#include "rusefi_lua.h"
typedef float fsio_table_8x8_f32t_linear[FSIO_TABLE_8 * FSIO_TABLE_8];
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;
}
}
}
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?
processCanRxImu(frame, nowNt);
processLuaCan(frame);
#if EFI_CANBUS_SLAVE
if (CAN_EID(frame) == CONFIG(verboseCanBaseAddress) + CAN_SENSOR_1_OFFSET) {
int16_t mapScaled = *reinterpret_cast<const int16_t*>(&frame.data8[0]);

View File

@ -116,43 +116,6 @@ static void* myAlloc(void* /*ud*/, void* ptr, size_t /*osize*/, size_t nsize) {
}
#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 lua_setTickRate(lua_State* l) {
@ -328,7 +291,12 @@ static bool runOneLua(lua_Alloc alloc, const char* script) {
}
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);
invokeTick(ls);
@ -336,6 +304,10 @@ static bool runOneLua(lua_Alloc alloc, const char* script) {
chThdSleepMilliseconds(luaTickPeriodMs);
}
#if EFI_CAN_SUPPORT
resetLuaCanRx();
#endif // EFI_CAN_SUPPORT
// De-init pins, they will reinit next start of the script.
luaDeInitPins();
@ -367,6 +339,10 @@ static LuaThread luaThread;
void startLua() {
#if LUA_USER_HEAP > 1
#if EFI_CAN_SUPPORT
initLuaCanRx();
#endif // EFI_CAN_SUPPORT
luaThread.Start();
addConsoleActionS("lua", [](const char* str){

View File

@ -4,6 +4,7 @@ LUA_EXT=$(PROJECT_DIR)/ext/lua
ALLCPPSRC += $(LUA_DIR)/lua.cpp \
$(LUA_DIR)/lua_hooks.cpp \
$(LUA_DIR)/system_lua.cpp \
$(LUA_DIR)/lua_can_rx.cpp \
ALLINC += $(LUA_DIR) $(LUA_DIR)/luaaa $(LUA_EXT)
ALLCSRC += \

View File

@ -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

View File

@ -1,11 +1,10 @@
#include "pch.h"
#include "lua.hpp"
#include "rusefi_lua.h"
#include "lua_hooks.h"
#include "fuel_math.h"
#include "airmass.h"
#include "utlist.h"
#include "lua_airmass.h"
#include "can_msg_tx.h"
#include "settings.h"
@ -339,39 +338,17 @@ static int lua_setFuelMult(lua_State* l) {
return 0;
}
#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;
// linked list of all CAN receivers
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);
}
};
return 0;
}
#endif // EFI_CAN_SUPPORT
struct LuaSensor : public StoredValueSensor {
LuaSensor() : LuaSensor("Invalid") { }
@ -405,11 +382,6 @@ void configureRusefiLuaHooks(lua_State* l) {
.fun("reset", static_cast<void (Timer::*)() >(&Timer::reset ))
.fun("getElapsedSeconds", static_cast<float(Timer::*)()const>(&Timer::getElapsedSeconds));
LuaClass<LuaCanReciever> luaCanReciever(l, "CanReciever");
luaCanReciever
.ctor()
;
LuaClass<LuaSensor> luaSensor(l, "Sensor");
luaSensor
.ctor<const char*>()
@ -444,5 +416,9 @@ void configureRusefiLuaHooks(lua_State* l) {
lua_register(l, "setFuelAdd", lua_setFuelAdd);
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
}

View File

@ -2,6 +2,45 @@
#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();
#if EFI_UNIT_TEST
@ -12,3 +51,16 @@ float testLuaReturnsNumber(const char* script);
int testLuaReturnsInteger(const char* script);
void testLuaExecString(const char* script);
#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

View File

@ -120,9 +120,9 @@ constexpr size_t lineBufferCount = 24;
static LogLineBuffer lineBuffers[lineBufferCount];
// 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
chibios_rt::Mailbox<LogLineBuffer*, lineBufferCount> filledBuffers;
static chibios_rt::Mailbox<LogLineBuffer*, lineBufferCount> filledBuffers;
class LoggingBufferFlusher : public ThreadController<256> {
public:

View File

@ -1,3 +1,4 @@
#include "pch.h"
#include "rusefi_lua.h"
#include <gtest/gtest.h>