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:
parent
dece77ddf1
commit
ada1ba6b56
|
@ -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
|
||||||
|
|
|
@ -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++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue