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 "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]);
|
||||
|
|
|
@ -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){
|
||||
|
|
|
@ -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 += \
|
||||
|
|
|
@ -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 "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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#include "pch.h"
|
||||
#include "rusefi_lua.h"
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
|
|
Loading…
Reference in New Issue