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
- counter-noise measure for custom skipped trigger wheels #4375
- Write hard faults to backup ram, print on next boot #4324
- Many more options for Lua CAN rx filters/callbacks #4387
### 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

View File

@ -6,23 +6,35 @@
static constexpr size_t maxFilterCount = 48;
size_t filterCount = 0;
int32_t luaCanRxIds[maxFilterCount] = {0};
struct Filter {
int32_t Id;
int32_t Mask;
static bool shouldRxCanFrame(const CANRxFrame& frame) {
int Bus;
int Callback;
};
size_t filterCount = 0;
Filter filters[maxFilterCount];
static Filter* getFilterForFrame(size_t busIndex, const CANRxFrame& frame) {
for (size_t i = 0; i < filterCount; i++) {
int32_t id = luaCanRxIds[i];
if (CAN_ID(frame) == id) {
return true;
auto& filter = filters[i];
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
struct CanFrameData {
uint8_t BusIndex;
int Callback;
CANRxFrame Frame;
};
@ -34,8 +46,10 @@ chibios_rt::Mailbox<CanFrameData*, canFrameCount> freeBuffers;
chibios_rt::Mailbox<CanFrameData*, canFrameCount> filledBuffers;
void processLuaCan(const size_t busIndex, const CANRxFrame& frame) {
auto filter = getFilterForFrame(busIndex, frame);
// Filter the frame if we aren't listening for it
if (!shouldRxCanFrame(frame)) {
if (!filter) {
return;
}
@ -57,6 +71,7 @@ void processLuaCan(const size_t busIndex, const CANRxFrame& frame) {
// Copy the frame in to the buffer
frameBuffer->BusIndex = busIndex;
frameBuffer->Frame = frame;
frameBuffer->Callback = filter->Callback;
{
// 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) {
lua_getglobal(ls, "onCanRx");
if (data->Callback == -1) {
// No callback, use catch-all function
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)) {
// no rx function, ignore
efiPrintf("LUA CAN rx missing function onCanRx");
@ -144,18 +166,21 @@ void initLuaCanRx() {
void resetLuaCanRx() {
// Clear all lua filters - reloading the script will reinit them
memset(luaCanRxIds, 0, sizeof(luaCanRxIds));
filterCount = 0;
}
void addLuaCanRxFilter(int32_t eid) {
void addLuaCanRxFilter(int32_t eid, uint32_t mask, int bus, int callback) {
if (filterCount >= maxFilterCount) {
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++;
}

View File

@ -448,6 +448,113 @@ private:
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) {
LuaClass<Timer> luaTimer(l, "Timer");
luaTimer
@ -707,12 +814,8 @@ void configureRusefiLuaHooks(lua_State* l) {
#if EFI_CAN_SUPPORT
lua_register(l, "canRxAdd", [](lua_State* l) {
auto eid = luaL_checkinteger(l, 1);
addLuaCanRxFilter(eid);
return 0;
});
lua_register(l, "canRxAdd", lua_canRxAdd);
lua_register(l, "canRxAddMask", lua_canRxAddMask);
#endif // EFI_CAN_SUPPORT
#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
void resetLuaCanRx();
// 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
void doLuaCanRx(LuaHandle& ls);
// Called from the CAN RX thread to queue a frame for Lua consumption