Lua rx callback (#4387)

* s

* mask, callback

* support 8 different signatures

* make the compiler happy about unrechable code

* s

* make the compiler happy about unreachable code

* guard

* changelog
This commit is contained in:
Matthew Kennedy 2022-07-27 23:27:18 -07:00 committed by GitHub
parent dece77ddf1
commit ada1ba6b56
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 150 additions and 20 deletions

View File

@ -30,6 +30,7 @@ Release template (copy/paste this for new release):
- microRusEFI and Proteus F4 have CAN OpenBLT bootloader #4199 #4230 - microRusEFI and Proteus F4 have CAN OpenBLT bootloader #4199 #4230
- counter-noise measure for custom skipped trigger wheels #4375 - counter-noise measure for custom skipped trigger wheels #4375
- Write hard faults to backup ram, print on next boot #4324 - Write hard faults to backup ram, print on next boot #4324
- Many more options for Lua CAN rx filters/callbacks #4387
### Fixed ### Fixed
- Lua CAN reception fixed for 11-bit IDs where the frame would be received, but a corrupt ID was passed to the handler function. #4321 - Lua CAN reception fixed for 11-bit IDs where the frame would be received, but a corrupt ID was passed to the handler function. #4321

View File

@ -6,23 +6,35 @@
static constexpr size_t maxFilterCount = 48; static constexpr size_t maxFilterCount = 48;
struct Filter {
int32_t Id;
int32_t Mask;
int Bus;
int Callback;
};
size_t filterCount = 0; size_t filterCount = 0;
int32_t luaCanRxIds[maxFilterCount] = {0}; Filter filters[maxFilterCount];
static bool shouldRxCanFrame(const CANRxFrame& frame) { static Filter* getFilterForFrame(size_t busIndex, const CANRxFrame& frame) {
for (size_t i = 0; i < filterCount; i++) { for (size_t i = 0; i < filterCount; i++) {
int32_t id = luaCanRxIds[i]; auto& filter = filters[i];
if (CAN_ID(frame) == id) {
return true; if ((CAN_ID(frame) & filter.Mask) == filter.Id) {
if (filter.Bus == -1 || filter.Bus == busIndex) {
return &filter;
}
} }
} }
return false; return nullptr;
} }
// Stores information about one received CAN frame: which bus, plus the actual frame // Stores information about one received CAN frame: which bus, plus the actual frame
struct CanFrameData { struct CanFrameData {
uint8_t BusIndex; uint8_t BusIndex;
int Callback;
CANRxFrame Frame; CANRxFrame Frame;
}; };
@ -34,8 +46,10 @@ chibios_rt::Mailbox<CanFrameData*, canFrameCount> freeBuffers;
chibios_rt::Mailbox<CanFrameData*, canFrameCount> filledBuffers; chibios_rt::Mailbox<CanFrameData*, canFrameCount> filledBuffers;
void processLuaCan(const size_t busIndex, const CANRxFrame& frame) { void processLuaCan(const size_t busIndex, const CANRxFrame& frame) {
auto filter = getFilterForFrame(busIndex, frame);
// Filter the frame if we aren't listening for it // Filter the frame if we aren't listening for it
if (!shouldRxCanFrame(frame)) { if (!filter) {
return; return;
} }
@ -57,6 +71,7 @@ void processLuaCan(const size_t busIndex, const CANRxFrame& frame) {
// Copy the frame in to the buffer // Copy the frame in to the buffer
frameBuffer->BusIndex = busIndex; frameBuffer->BusIndex = busIndex;
frameBuffer->Frame = frame; frameBuffer->Frame = frame;
frameBuffer->Callback = filter->Callback;
{ {
// Push the frame in to the queue under lock // Push the frame in to the queue under lock
@ -66,7 +81,14 @@ void processLuaCan(const size_t busIndex, const CANRxFrame& frame) {
} }
static void handleCanFrame(LuaHandle& ls, CanFrameData* data) { static void handleCanFrame(LuaHandle& ls, CanFrameData* data) {
if (data->Callback == -1) {
// No callback, use catch-all function
lua_getglobal(ls, "onCanRx"); lua_getglobal(ls, "onCanRx");
} else {
// Push the specified callback on to the stack
lua_rawgeti(ls, LUA_REGISTRYINDEX, data->Callback);
}
if (lua_isnil(ls, -1)) { if (lua_isnil(ls, -1)) {
// no rx function, ignore // no rx function, ignore
efiPrintf("LUA CAN rx missing function onCanRx"); efiPrintf("LUA CAN rx missing function onCanRx");
@ -144,18 +166,21 @@ void initLuaCanRx() {
void resetLuaCanRx() { void resetLuaCanRx() {
// Clear all lua filters - reloading the script will reinit them // Clear all lua filters - reloading the script will reinit them
memset(luaCanRxIds, 0, sizeof(luaCanRxIds));
filterCount = 0; filterCount = 0;
} }
void addLuaCanRxFilter(int32_t eid) { void addLuaCanRxFilter(int32_t eid, uint32_t mask, int bus, int callback) {
if (filterCount >= maxFilterCount) { if (filterCount >= maxFilterCount) {
firmwareError(OBD_PCM_Processor_Fault, "Too many Lua CAN RX filters"); firmwareError(OBD_PCM_Processor_Fault, "Too many Lua CAN RX filters");
} }
efiPrintf("Added Lua CAN RX filter: %d", eid); efiPrintf("Added Lua CAN RX filter id 0x%x mask 0x%x with%s custom function", eid, mask, (callback == -1 ? "out" : ""));
filters[filterCount].Id = eid;
filters[filterCount].Mask = mask;
filters[filterCount].Bus = bus;
filters[filterCount].Callback = callback;
luaCanRxIds[filterCount] = eid;
filterCount++; filterCount++;
} }

View File

@ -448,6 +448,113 @@ private:
pid_s m_params; pid_s m_params;
}; };
static bool isFunction(lua_State* l, int idx) {
return lua_type(l, idx) == LUA_TFUNCTION;
}
int getLuaFunc(lua_State* l) {
if (!isFunction(l, 1)) {
return luaL_error(l, "expected function");
} else {
return luaL_ref(l, LUA_REGISTRYINDEX);
}
}
#if EFI_CAN_SUPPORT
int lua_canRxAdd(lua_State* l) {
uint32_t eid;
// defaults if not passed
int bus = -1;
int callback = -1;
switch (lua_gettop(l)) {
case 1:
// handle canRxAdd(id)
eid = luaL_checkinteger(l, 1);
break;
case 2:
if (isFunction(l, 2)) {
// handle canRxAdd(id, callback)
eid = luaL_checkinteger(l, 1);
lua_remove(l, 1);
callback = getLuaFunc(l);
} else {
// handle canRxAdd(bus, id)
bus = luaL_checkinteger(l, 1);
eid = luaL_checkinteger(l, 2);
}
break;
case 3:
// handle canRxAdd(bus, id, callback)
bus = luaL_checkinteger(l, 1);
eid = luaL_checkinteger(l, 2);
lua_remove(l, 1);
lua_remove(l, 1);
callback = getLuaFunc(l);
break;
default:
return luaL_error(l, "Wrong number of arguments to canRxAdd. Got %d, expected 1, 2, or 3.");
}
addLuaCanRxFilter(eid, 0x1FFFFFFF, bus, callback);
return 0;
}
int lua_canRxAddMask(lua_State* l) {
uint32_t eid;
uint32_t mask;
// defaults if not passed
int bus = -1;
int callback = -1;
switch (lua_gettop(l)) {
case 2:
// handle canRxAddMask(id, mask)
eid = luaL_checkinteger(l, 1);
mask = luaL_checkinteger(l, 2);
break;
case 3:
if (isFunction(l, 3)) {
// handle canRxAddMask(id, mask, callback)
eid = luaL_checkinteger(l, 1);
mask = luaL_checkinteger(l, 2);
lua_remove(l, 1);
lua_remove(l, 1);
callback = getLuaFunc(l);
} else {
// handle canRxAddMask(bus, id, mask)
bus = luaL_checkinteger(l, 1);
eid = luaL_checkinteger(l, 2);
mask = luaL_checkinteger(l, 3);
}
break;
case 4:
// handle canRxAddMask(bus, id, mask, callback)
bus = luaL_checkinteger(l, 1);
eid = luaL_checkinteger(l, 2);
mask = luaL_checkinteger(l, 3);
lua_remove(l, 1);
lua_remove(l, 1);
lua_remove(l, 1);
callback = getLuaFunc(l);
break;
default:
return luaL_error(l, "Wrong number of arguments to canRxAddMask. Got %d, expected 2, 3, or 4.");
}
addLuaCanRxFilter(eid, mask, bus, callback);
return 0;
}
#endif // EFI_CAN_SUPPORT
void configureRusefiLuaHooks(lua_State* l) { void configureRusefiLuaHooks(lua_State* l) {
LuaClass<Timer> luaTimer(l, "Timer"); LuaClass<Timer> luaTimer(l, "Timer");
luaTimer luaTimer
@ -707,12 +814,8 @@ void configureRusefiLuaHooks(lua_State* l) {
#if EFI_CAN_SUPPORT #if EFI_CAN_SUPPORT
lua_register(l, "canRxAdd", [](lua_State* l) { lua_register(l, "canRxAdd", lua_canRxAdd);
auto eid = luaL_checkinteger(l, 1); lua_register(l, "canRxAddMask", lua_canRxAddMask);
addLuaCanRxFilter(eid);
return 0;
});
#endif // EFI_CAN_SUPPORT #endif // EFI_CAN_SUPPORT
#endif // not EFI_UNIT_TEST #endif // not EFI_UNIT_TEST
} }

View File

@ -61,7 +61,8 @@ void initLuaCanRx();
// Called when the user script is unloaded, resets any CAN rx filters // Called when the user script is unloaded, resets any CAN rx filters
void resetLuaCanRx(); void resetLuaCanRx();
// Adds a frame ID to listen to // Adds a frame ID to listen to
void addLuaCanRxFilter(int32_t eid); void addLuaCanRxFilter(int32_t eid, uint32_t mask, int bus, int callback);
// Called from the Lua loop to process any pending CAN frames // Called from the Lua loop to process any pending CAN frames
void doLuaCanRx(LuaHandle& ls); void doLuaCanRx(LuaHandle& ls);
// Called from the CAN RX thread to queue a frame for Lua consumption // Called from the CAN RX thread to queue a frame for Lua consumption