rusEFI
The most advanced open source ECU
lua_hooks.cpp
Go to the documentation of this file.
1 #include "pch.h"
2 
3 #include "rusefi_lua.h"
4 #include "lua_hooks.h"
5 
6 #include "lua_biquad.h"
7 #include "fuel_math.h"
8 #include "airmass.h"
9 #include "lua_airmass.h"
10 #include "value_lookup.h"
11 #include "can_filter.h"
12 #include "tunerstudio.h"
13 #include "lua_pid.h"
14 
15 #if EFI_PROD_CODE && HW_HELLEN
16 #include "hellen_meta.h"
17 #endif
18 
19 #if EFI_DAC
20 #include "dac.h"
21 #endif // EFI_DAC
22 
23 #if EFI_CAN_SUPPORT || EFI_UNIT_TEST
24 #include "can_msg_tx.h"
25 #endif // EFI_CAN_SUPPORT
26 #include "settings.h"
27 #include <new>
28 
29 // We don't want to try and use the STL on a microcontroller
30 #define LUAAA_WITHOUT_CPP_STDLIB
31 #include "luaaa.hpp"
32 #include "lua_hooks_util.h"
33 using namespace luaaa;
34 
35 #include "script_impl.h"
36 #include "trigger_emulator_algo.h"
37 
38 #if EFI_PROD_CODE
39 #include "electronic_throttle.h"
40 #endif // EFI_PROD_CODE
41 
42 #if EFI_SENT_SUPPORT
43 #include "sent.h"
44 #endif // EFI_SENT_SUPPORT
45 
46 static int lua_vin(lua_State* l) {
47  auto zeroBasedCharIndex = luaL_checkinteger(l, 1);
48  if (zeroBasedCharIndex < 0 || zeroBasedCharIndex > VIN_NUMBER_SIZE) {
49  lua_pushnil(l);
50  } else {
51  char value = engineConfiguration->vinNumber[zeroBasedCharIndex];
52  lua_pushnumber(l, value);
53  }
54  return 1;
55 }
56 
57 static int lua_readpin(lua_State* l) {
58 #if EFI_PROD_CODE
59  const char * msg = luaL_checkstring(l, 1);
61  if (!isBrainPinValid(pin)) {
62  efiPrintf("LUA: invalid pin [%s]", msg);
63  lua_pushnil(l);
64  } else {
65  int physicalValue = palReadPad(getHwPort("read", pin), getHwPin("read", pin));
66  lua_pushnumber(l, physicalValue);
67  }
68 #endif
69  return 1;
70 }
71 
72 static int getSensor(lua_State* l, SensorType type) {
73  auto result = Sensor::get(type);
74 
75  if (result) {
76  // return value if valid
77  lua_pushnumber(l, result.Value);
78  } else {
79  // return nil if invalid
80  lua_pushnil(l);
81  }
82 
83  return 1;
84 }
85 
86 static int lua_getAuxAnalog(lua_State* l) {
87  // todo: shall we use HUMAN_INDEX since UI goes from 1 and Lua loves going from 1?
88  auto zeroBasedSensorIndex = luaL_checkinteger(l, 1);
89 
90  auto type = static_cast<SensorType>(zeroBasedSensorIndex + static_cast<int>(SensorType::AuxAnalog1));
91 
92  return getSensor(l, type);
93 }
94 
95 static int lua_getSensorByIndex(lua_State* l) {
96  auto zeroBasedSensorIndex = luaL_checkinteger(l, 1);
97 
98  return getSensor(l, static_cast<SensorType>(zeroBasedSensorIndex));
99 }
100 
101 static SensorType findSensorByName(lua_State* l, const char* name) {
102  SensorType type = findSensorTypeByName(name);
103 
104  if (l && type == SensorType::Invalid) {
105  luaL_error(l, "Invalid sensor type: %s", name);
106  }
107 
108  return type;
109 }
110 
111 static int lua_getSensorByName(lua_State* l) {
112  auto sensorName = luaL_checklstring(l, 1, nullptr);
113  SensorType type = findSensorByName(l, sensorName);
114 
115  return getSensor(l, type);
116 }
117 
118 static int lua_getSensorRaw(lua_State* l) {
119  auto zeroBasedSensorIndex = luaL_checkinteger(l, 1);
120 
121  lua_pushnumber(l, Sensor::getRaw(static_cast<SensorType>(zeroBasedSensorIndex)));
122  return 1;
123 }
124 
125 static int lua_hasSensor(lua_State* l) {
126  auto zeroBasedSensorIndex = luaL_checkinteger(l, 1);
127 
128  lua_pushboolean(l, Sensor::hasSensor(static_cast<SensorType>(zeroBasedSensorIndex)));
129  return 1;
130 }
131 
132 /**
133  * @return number of elements
134  */
135 static uint32_t getArray(lua_State* l, int paramIndex, uint8_t *data, uint32_t size) {
136  uint32_t result = 0;
137 
138  luaL_checktype(l, paramIndex, LUA_TTABLE);
139  while (true) {
140  lua_pushnumber(l, result + 1);
141  auto elementType = lua_gettable(l, paramIndex);
142  auto val = lua_tonumber(l, -1);
143  lua_pop(l, 1);
144 
145  if (elementType == LUA_TNIL) {
146  // we're done, this is the end of the array.
147  break;
148  }
149 
150  if (elementType != LUA_TNUMBER) {
151  // We're not at the end, but this isn't a number!
152  luaL_error(l, "Unexpected data at position %d: %s", result, lua_tostring(l, -1));
153  }
154 
155  // This element is valid, increment DLC
156  result++;
157 
158  if (result > size) {
159  luaL_error(l, "Input array longer than buffer");
160  }
161 
162  data[result - 1] = val;
163  }
164  return result;
165 }
166 
167 #if EFI_CAN_SUPPORT || EFI_UNIT_TEST
168 
170  lua_Integer channel = luaL_checkinteger(l, 1);
171  // TODO: support multiple channels
172  luaL_argcheck(l, channel == 1 || channel == 2, 1, "only buses 1 and 2 currently supported");
173  return channel - HUMAN_OFFSET;
174 }
175 
176 static int lua_txCan(lua_State* l) {
178  int bus;
179  int id;
180  int ext;
181  int dataIndex;
182  if (lua_gettop(l) == 2) {
183  bus = 0;
184  id = luaL_checkinteger(l, 1);
185  ext = 0;
186  dataIndex = 2;
187  } else {
189  id = luaL_checkinteger(l, 2);
190  ext = luaL_checkinteger(l, 3);
191  dataIndex = 4;
192  }
193 
194  // Check that ID is valid based on std vs. ext
195  if (ext == 0) {
196  luaL_argcheck(l, id <= 0x7FF, 2, "ID specified is greater than max std ID");
197  } else {
198  luaL_argcheck(l, id <= 0x1FFF'FFFF, 2, "ID specified is greater than max ext ID");
199  }
200 
201  // conform ext parameter to true/false
202  CanTxMessage msg(CanCategory::LUA, id, 8, bus, ext == 0 ? false : true);
203 
204  // Unfortunately there is no way to inspect the length of a table,
205  // so we have to just iterate until we run out of numbers
206  uint8_t dlc = 0;
207 
208  // todo: reduce code duplication with getArray
209  luaL_checktype(l, dataIndex, LUA_TTABLE);
210  while (true) {
211  lua_pushnumber(l, dlc + 1);
212  auto elementType = lua_gettable(l, dataIndex);
213  auto val = lua_tonumber(l, -1);
214  lua_pop(l, 1);
215 
216  if (elementType == LUA_TNIL) {
217  // we're done, this is the end of the array.
218  break;
219  }
220 
221  if (elementType != LUA_TNUMBER) {
222  // We're not at the end, but this isn't a number!
223  luaL_error(l, "Unexpected CAN data at position %d: %s", dlc, lua_tostring(l, -1));
224  }
225 
226  // This element is valid, increment DLC
227  dlc++;
228 
229  if (dlc > 8) {
230  luaL_error(l, "CAN frame length cannot be longer than 8");
231  }
232 
233  msg[dlc - 1] = val;
234  }
235 
236  msg.setDlc(dlc);
237 
238  // no return value
239  return 0;
240 }
241 #endif // EFI_CAN_SUPPORT
242 
244 
246  return luaAirmass;
247 }
248 
249 #if !EFI_UNIT_TEST
250 static SimplePwm pwms[LUA_PWM_COUNT];
251 
252 struct P {
253  SimplePwm& pwm;
254  lua_Integer idx;
255 };
256 
257 static P luaL_checkPwmIndex(lua_State* l, int pos) {
258  auto channel = luaL_checkinteger(l, pos);
259 
260  // todo: what a mess :( CAN buses start at 1 and PWM channels start at 0 :(
261  // Ensure channel is valid
262  if (channel < 0 || channel >= LUA_PWM_COUNT) {
263  luaL_error(l, "setPwmDuty invalid channel %d", channel);
264  }
265 
266  return { pwms[channel], channel };
267 }
268 
269 #ifndef PWM_FREQ_PWM
270 #define PWM_FREQ_PWM 1000
271 #endif
272 
273 void startPwm(int index, float freq, float duty) {
274  // clamp to 1..1000 hz, this line would turn 0hz on/off PWM into 1hz behind the scenes
275  freq = clampF(1, freq, 1000);
276 
278 
280  &pwms[index], "lua", &engine->executor,
281  pwmPin, &enginePins.luaOutputPins[index],
282  freq, duty
283  );
284 
285  efiPrintf("LUA PWM on %s at %f initial duty",
286  hwPortname(pwmPin),
287  PERCENT_MULT * duty);
288 }
289 
290 static int lua_startPwm(lua_State* l) {
291  auto p = luaL_checkPwmIndex(l, 1);
292  auto freq = luaL_checknumber(l, 2);
293  auto duty = luaL_checknumber(l, 3);
294 
295  if (duty < 0 || duty > PWM_MAX_DUTY) {
296  luaL_error(l, "Duty parameter should be from 0 to 1 got %f", duty);
297  return 0;
298  }
299 
300  startPwm(p.idx, freq, duty);
301 
302  return 0;
303 }
304 
306  // Simply de-init all pins - when the script runs again, they will be re-init'd
307  for (size_t i = 0; i < efi::size(enginePins.luaOutputPins); i++) {
309  }
310 }
311 
312 void setPwmDuty(int index, float duty) {
313  // clamp to 0..1
314  duty = clampF(0, duty, 1);
315 
317 }
318 
319 static int lua_setPwmDuty(lua_State* l) {
320  auto p = luaL_checkPwmIndex(l, 1);
321  auto duty = luaL_checknumber(l, 2);
322  setPwmDuty(p.idx, duty);
323 
324  return 0;
325 }
326 
327 static int lua_setPwmFreq(lua_State* l) {
328  auto p = luaL_checkPwmIndex(l, 1);
329  auto freq = luaL_checknumber(l, 2);
330 
331  // clamp to 1..1000 hz
332  freq = clampF(1, freq, 1000);
333 
334  p.pwm.setFrequency(freq);
335 
336  return 0;
337 }
338 
339 static int lua_fan(lua_State* l) {
340  lua_pushboolean(l, enginePins.fanRelay.getLogicValue());
341  return 1;
342 }
343 
344 static int lua_getDigital(lua_State* l) {
345  auto idx = luaL_checkinteger(l, 1);
346 
347  bool state = false;
348 
349  switch (idx) {
350  case 0: state = engine->engineState.clutchDownState; break;
351  case 1: state = engine->engineState.clutchUpState; break;
352  case 2: state = engine->engineState.brakePedalState; break;
353  case 3: state = engine->module<AcController>().unmock().acButtonState; break;
354  default:
355  // Return nil to indicate invalid parameter
356  lua_pushnil(l);
357  return 1;
358  }
359 
360  lua_pushboolean(l, state);
361  return 1;
362 }
363 
364 bool getAuxDigital(int index) {
365 #if EFI_PROD_CODE
367 #else
368  return false;
369 #endif
370 }
371 
372 static int lua_getAuxDigital(lua_State* l) {
373  auto idx = luaL_checkinteger(l, 1);
374  if (idx < 0 || idx >= LUA_DIGITAL_INPUT_COUNT) {
375  // Return nil to indicate invalid parameter
376  lua_pushnil(l);
377  return 1;
378  }
379 
381  // Return nil to indicate invalid pin
382  lua_pushnil(l);
383  return 1;
384  }
385 
386 #if !EFI_SIMULATOR
387  bool state = getAuxDigital(idx);
388  lua_pushboolean(l, state);
389 #endif // !EFI_SIMULATOR
390 
391  return 1;
392 }
393 
394 static int lua_setDebug(lua_State* l) {
395  // wrong debug mode, ignore
396  if (engineConfiguration->debugMode != DBG_LUA) {
397  return 0;
398  }
399 
400  auto idx = luaL_checkinteger(l, 1);
401  auto val = luaL_checknumber(l, 2);
402 
403  // invalid index, ignore
404  if (idx < 1 || idx > 7) {
405  return 0;
406  }
407 
408  auto firstDebugField = &engine->outputChannels.debugFloatField1;
409  firstDebugField[idx - 1] = val;
410 
411  return 0;
412 }
413 
414 #if EFI_ENGINE_CONTROL
415 static auto lua_getAirmassResolveMode(lua_State* l) {
416  if (lua_gettop(l) == 0) {
417  // zero args, return configured mode
419  } else {
420  return static_cast<engine_load_mode_e>(luaL_checkinteger(l, 1));
421  }
422 }
423 
424 static int lua_getAirmass(lua_State* l) {
425  auto airmassMode = lua_getAirmassResolveMode(l);
426  auto airmass = getAirmassModel(airmassMode);
427 
428  if (!airmass) {
429  return luaL_error(l, "null airmass");
430  }
431 
433  auto result = airmass->getAirmass(rpm, false).CylinderAirmass;
434 
435  lua_pushnumber(l, result);
436  return 1;
437 }
438 
439 static int lua_setAirmass(lua_State* l) {
440  float airmass = luaL_checknumber(l, 1);
441  float engineLoadPercent = luaL_checknumber(l, 2);
442 
443  airmass = clampF(0, airmass, 10);
444  engineLoadPercent = clampF(0, engineLoadPercent, 1000);
445 
446  luaAirmass.setAirmass({airmass, engineLoadPercent});
447 
448  return 0;
449 }
450 #endif // EFI_ENGINE_CONTROL
451 
452 #endif // EFI_UNIT_TEST
453 
454 // TODO: PR this back in to https://github.com/gengyong/luaaa
455 namespace LUAAA_NS {
456  template<typename TCLASS, typename ...ARGS>
457  struct PlacementConstructorCaller<TCLASS, lua_State*, ARGS...>
458  {
459  // this speciailization passes the Lua state to the constructor as first argument, as it shouldn't
460  // participate in the index generation as it's not a normal parameter passed via the Lua stack.
461 
462  static TCLASS * Invoke(lua_State * state, void * mem)
463  {
464  return InvokeImpl(state, mem, typename make_indices<sizeof...(ARGS)>::type());
465  }
466 
467  private:
468  template<std::size_t ...Ns>
469  static TCLASS * InvokeImpl(lua_State * state, void * mem, indices<Ns...>)
470  {
471  (void)state;
472  return new(mem) TCLASS(state, LuaStack<ARGS>::get(state, Ns + 1)...);
473  }
474  };
475 }
476 
477 struct LuaSensor final : public StoredValueSensor {
478  LuaSensor() : LuaSensor(nullptr, "Invalid") { }
479 
480  ~LuaSensor() {
481  unregister();
482  }
483 
484  LuaSensor(lua_State* l, const char* name)
485  : StoredValueSensor(findSensorByName(l, name), MS2NT(100))
486  {
487  // do a soft collision check to avoid a fatal error from the hard check in Register()
488  if (l && Sensor::hasSensor(type())) {
489  luaL_error(l, "Tried to create a Lua sensor of type %s, but one was already registered.", getSensorName());
490  } else {
491  Register();
492  efiPrintf("LUA registered sensor of type %s", getSensorName());
493  }
494  }
495 
496  bool isRedundant() const override {
497  return m_isRedundant;
498  }
499 
500  // do we need method defined exactly on LuaSensor for Luaa to be happy?
501  void setTimeout(int timeoutMs) override {
503  }
504 
505  void setRedundant(bool value) {
506  m_isRedundant = value;
507  }
508 
509  void set(float value) {
510  setValidValue(value, getTimeNowNt());
511  }
512 
513  void invalidate() {
515  }
516 
517  void showInfo(const char* sensorName) const override {
518  const auto value = get();
519  efiPrintf("Sensor \"%s\": Lua sensor: Valid: %s Converted value %.2f", sensorName, boolToString(value.Valid), value.Value);
520  }
521 
522 private:
523  bool m_isRedundant = false;
524 };
525 
526 static bool isFunction(lua_State* l, int idx) {
527  return lua_type(l, idx) == LUA_TFUNCTION;
528 }
529 
530 int getLuaFunc(lua_State* l) {
531  if (!isFunction(l, 1)) {
532  return luaL_error(l, "expected function");
533  } else {
534  return luaL_ref(l, LUA_REGISTRYINDEX);
535  }
536 }
537 
538 #if EFI_CAN_SUPPORT
539 int lua_canRxAdd(lua_State* l) {
540  uint32_t eid;
541 
542  // defaults if not passed
543  int bus = ANY_BUS;
544  int callback = NO_CALLBACK;
545 
546  switch (lua_gettop(l)) {
547  case 1:
548  // handle canRxAdd(id)
549  eid = luaL_checkinteger(l, 1);
550  break;
551 
552  case 2:
553  if (isFunction(l, 2)) {
554  // handle canRxAdd(id, callback)
555  eid = luaL_checkinteger(l, 1);
556  lua_remove(l, 1);
557  callback = getLuaFunc(l);
558  } else {
559  // handle canRxAdd(bus, id)
561  eid = luaL_checkinteger(l, 2);
562  }
563 
564  break;
565  case 3:
566  // handle canRxAdd(bus, id, callback)
568  eid = luaL_checkinteger(l, 2);
569  lua_remove(l, 1);
570  lua_remove(l, 1);
571  callback = getLuaFunc(l);
572  break;
573  default:
574  return luaL_error(l, "Wrong number of arguments to canRxAdd. Got %d, expected 1, 2, or 3.");
575  }
576 
577  addLuaCanRxFilter(eid, FILTER_SPECIFIC, bus, callback);
578 
579  return 0;
580 }
581 
582 int lua_canRxAddMask(lua_State* l) {
583  uint32_t eid;
584  uint32_t mask;
585 
586  // defaults if not passed
587  int bus = ANY_BUS;
588  int callback = NO_CALLBACK;
589 
590  switch (lua_gettop(l)) {
591  case 2:
592  // handle canRxAddMask(id, mask)
593  eid = luaL_checkinteger(l, 1);
594  mask = luaL_checkinteger(l, 2);
595  break;
596 
597  case 3:
598  if (isFunction(l, 3)) {
599  // handle canRxAddMask(id, mask, callback)
600  eid = luaL_checkinteger(l, 1);
601  mask = luaL_checkinteger(l, 2);
602  lua_remove(l, 1);
603  lua_remove(l, 1);
604  callback = getLuaFunc(l);
605  } else {
606  // handle canRxAddMask(bus, id, mask)
608  eid = luaL_checkinteger(l, 2);
609  mask = luaL_checkinteger(l, 3);
610  }
611 
612  break;
613  case 4:
614  // handle canRxAddMask(bus, id, mask, callback)
616  eid = luaL_checkinteger(l, 2);
617  mask = luaL_checkinteger(l, 3);
618  lua_remove(l, 1);
619  lua_remove(l, 1);
620  lua_remove(l, 1);
621  callback = getLuaFunc(l);
622  break;
623  default:
624  return luaL_error(l, "Wrong number of arguments to canRxAddMask. Got %d, expected 2, 3, or 4.");
625  }
626 
627  addLuaCanRxFilter(eid, mask, bus, callback);
628 
629  return 0;
630 }
631 #endif // EFI_CAN_SUPPORT
632 
633 static int lua_vincpy(lua_State* l) {
634  luaL_checktype(l, 1, LUA_TTABLE);
635  size_t sourceIndex = luaL_checknumber(l, 2);
636  size_t destinationIndex = luaL_checknumber(l, 3);
637  size_t size = luaL_checknumber(l, 4);
638  for (size_t i = 0;i<size;i++) {
639  lua_pushnumber(l, engineConfiguration->vinNumber[sourceIndex + i]);
640  lua_rawseti(l, 1, destinationIndex + i);
641  }
642  return 0;
643 }
644 
645 BOARD_WEAK void boardConfigureLuaHooks(lua_State* lState) { }
646 
647 void configureRusefiLuaHooks(lua_State* lState) {
648  boardConfigureLuaHooks(lState);
649 
650  LuaClass<LuaBiQuad> biQuard(lState, "Biquad");
651  biQuard
652  .ctor()
653  .fun("filter", &LuaBiQuad::filter)
654  .fun("configureLowpass", &LuaBiQuad::configureLowpass);
655 
656  LuaClass<Timer> luaTimer(lState, "Timer");
657  luaTimer
658  .ctor()
659  .fun("reset", static_cast<void (Timer::*)() >(&Timer::reset ))
660  .fun("getElapsedSeconds", static_cast<float(Timer::*)()const>(&Timer::getElapsedSeconds));
661 
662  LuaClass<LuaSensor> luaSensor(lState, "Sensor");
663  luaSensor
664  .ctor<lua_State*, const char*>()
665  .fun("set", &LuaSensor::set)
666  .fun("setRedundant", &LuaSensor::setRedundant)
667  .fun("setTimeout", &LuaSensor::setTimeout)
668  .fun("invalidate", &LuaSensor::invalidate);
669 
670  LuaClass<LuaPid> luaPid(lState, "Pid");
671  luaPid
672  .ctor<float, float, float, float, float>()
673  .fun("get", &LuaPid::get)
674  .fun("setOffset", &LuaPid::setOffset)
675  .fun("reset", &LuaPid::reset);
676 
677  LuaClass<LuaIndustrialPid> luaIndustrialPid(lState, "IndustrialPid");
678  luaIndustrialPid
679  .ctor<float, float, float, float, float>()
680  .fun("get", &LuaIndustrialPid::get)
681  .fun("setOffset", &LuaIndustrialPid::setOffset)
682  .fun("setDerivativeFilterLoss", &LuaIndustrialPid::setDerivativeFilterLoss)
683  .fun("setAntiwindupFreq", &LuaIndustrialPid::setAntiwindupFreq)
684  .fun("reset", &LuaIndustrialPid::reset);
685 
687 
688  lua_register(lState, "readPin", lua_readpin);
689  lua_register(lState, "vin", lua_vin);
690  lua_register(lState, "vincpy", lua_vincpy);
691  lua_register(lState, "getAuxAnalog", lua_getAuxAnalog);
692  lua_register(lState, "getSensorByIndex", lua_getSensorByIndex);
693  lua_register(lState, "getSensor", lua_getSensorByName);
694  lua_register(lState, "getSensorRaw", lua_getSensorRaw);
695  lua_register(lState, "hasSensor", lua_hasSensor);
696  lua_register(lState, "table3d", [](lua_State* l) {
697  auto humanTableIdx = luaL_checkinteger(l, 1);
698  auto x = luaL_checknumber(l, 2);
699  auto y = luaL_checknumber(l, 3);
700 
701  // index table, compute table lookup
702  auto result = getscriptTable(humanTableIdx - HUMAN_OFFSET)->getValue(x, y);
703 
704  lua_pushnumber(l, result);
705  return 1;
706  });
707  // time since console or TunerStudio
708  lua_register(lState, "secondsSinceTsActivity", [](lua_State* l) {
709  lua_pushnumber(l, getSecondsSinceChannelsRequest());
710  return 1;
711  });
712 
713  lua_register(lState, "curve", [](lua_State* l) {
714  // index starting from 1
715  auto humanCurveIdx = luaL_checkinteger(l, 1);
716  auto x = luaL_checknumber(l, 2);
717 
718  auto result = getCurveValue(humanCurveIdx - HUMAN_OFFSET, x);
719 
720  lua_pushnumber(l, result);
721  return 1;
722  });
723 
724 #if EFI_SENT_SUPPORT
725  lua_register(lState, "getSentValue",
726  [](lua_State* l) {
727  auto humanIndex = luaL_checkinteger(l, 1);
728  auto value = getSentValue(humanIndex - 1);
729  lua_pushnumber(l, value);
730  return 1;
731  });
732 
733  lua_register(lState, "getSentValues",
734  [](lua_State* l) {
735  uint16_t sig0;
736  uint16_t sig1;
737  auto humanIndex = luaL_checkinteger(l, 1);
738  /*auto ret = */getSentValues(humanIndex - 1, &sig0, &sig1);
739  lua_pushnumber(l, sig0);
740  lua_pushnumber(l, sig1);
741  return 2;
742  });
743 #endif // EFI_SENT_SUPPORT
744 
745 #if EFI_LAUNCH_CONTROL
746  lua_register(lState, "setSparkSkipRatio", [](lua_State* l) {
747  auto targetSkipRatio = luaL_checknumber(l, 1);
748  engine->engineState.luaSoftSparkSkip = targetSkipRatio;
750  return 1;
751  });
752  lua_register(lState, "setSparkHardSkipRatio", [](lua_State* l) {
753  auto targetSkipRatio = luaL_checknumber(l, 1);
754  engine->engineState.luaHardSparkSkip = targetSkipRatio;
756  return 1;
757  });
758 #endif // EFI_LAUNCH_CONTROL
759 
760 #if EFI_EMULATE_POSITION_SENSORS && !EFI_UNIT_TEST
761  lua_register(lState, "selfStimulateRPM", [](lua_State* l) {
762  auto rpm = luaL_checkinteger(l, 1);
763  if (rpm < 1) {
765  return 0;
766  }
769  }
771  return 0;
772  });
773 #endif // EFI_UNIT_TEST
774 
775  /**
776  * same exact could be accomplished via LuaSensor just with more API
777  */
778  lua_register(lState, "setLuaGauge", [](lua_State* l) {
779  auto index = luaL_checkinteger(l, 1) - 1;
780  auto value = luaL_checknumber(l, 2);
781  if (index < 0 || index >= LUA_GAUGE_COUNT)
782  return 0;
783  extern StoredValueSensor luaGauges[LUA_GAUGE_COUNT];
784  luaGauges[index].setValidValue(value, getTimeNowNt());
785  return 0;
786  });
787 
788  lua_register(lState, "enableCanTx", [](lua_State* l) {
789  engine->allowCanTx = lua_toboolean(l, 1);
790  return 0;
791  });
792 
793 #if EFI_ELECTRONIC_THROTTLE_BODY && EFI_PROD_CODE
794  lua_register(lState, "getEtbTarget", [](lua_State* l) {
795  auto result = engine->etbControllers[0]->getCurrentTarget();
796  lua_pushnumber(l, result);
797  return 1;
798  });
799  lua_register(lState, "restartEtb", [](lua_State*) {
800  // this is about Lua sensor acting in place of real analog PPS sensor
801  // todo: smarter implementation
803  return 0;
804  });
805 #endif // EFI_ELECTRONIC_THROTTLE_BODY
806 
807  // checksum stuff
808  lua_register(lState, "crc8_j1850", [](lua_State* l) {
809  uint8_t data[8];
810  uint32_t length = getArray(l, 1, data, sizeof(data));
811  auto trimLength = luaL_checkinteger(l, 2);
812  int crc = crc8(data, minI(length, trimLength));
813 
814  lua_pushnumber(l, crc);
815  return 1;
816  });
817 
818 #if EFI_BOOST_CONTROL
819  lua_register(lState, "setBoostTargetAdd", [](lua_State* l) {
820  engine->module<BoostController>().unmock().luaTargetAdd = luaL_checknumber(l, 1);
821  return 0;
822  });
823  lua_register(lState, "setBoostTargetMult", [](lua_State* l) {
824  engine->module<BoostController>().unmock().luaTargetMult = luaL_checknumber(l, 1);
825  return 0;
826  });
827  lua_register(lState, "setBoostDutyAdd", [](lua_State* l) {
828  engine->module<BoostController>().unmock().luaOpenLoopAdd = luaL_checknumber(l, 1);
829  return 0;
830  });
831 #endif // EFI_BOOST_CONTROL
832 #if EFI_IDLE_CONTROL
833  lua_register(lState, "setIdleAdd", [](lua_State* l) {
834  engine->module<IdleController>().unmock().luaAdd = luaL_checknumber(l, 1);
835  return 0;
836  });
837 #endif
838  lua_register(lState, "setTimingAdd", [](lua_State* l) {
839  engine->ignitionState.luaTimingAdd = luaL_checknumber(l, 1);
840  return 0;
841  });
842  lua_register(lState, "setTimingMult", [](lua_State* l) {
843  engine->ignitionState.luaTimingMult = luaL_checknumber(l, 1);
844  return 0;
845  });
846  lua_register(lState, "setFuelAdd", [](lua_State* l) {
847  engine->engineState.lua.fuelAdd = luaL_checknumber(l, 1);
848  return 0;
849  });
850  lua_register(lState, "setFuelMult", [](lua_State* l) {
851  engine->engineState.lua.fuelMult = luaL_checknumber(l, 1);
852  return 0;
853  });
854 #if EFI_ELECTRONIC_THROTTLE_BODY && EFI_PROD_CODE
855  lua_register(lState, "setEtbAdd", [](lua_State* l) {
856  auto luaAdjustment = luaL_checknumber(l, 1);
857 
859 
860  return 0;
861  });
862 #endif // EFI_ELECTRONIC_THROTTLE_BODY
863 #if EFI_PROD_CODE
864  lua_register(lState, "setEtbDisabled", [](lua_State* l) {
865  engine->engineState.lua.luaDisableEtb = lua_toboolean(l, 1);
866  return 0;
867  });
868  lua_register(lState, "setIgnDisabled", [](lua_State* l) {
869  engine->engineState.lua.luaIgnCut = lua_toboolean(l, 1);
870  return 0;
871  });
872  lua_register(lState, "setFuelDisabled", [](lua_State* l) {
873  engine->engineState.lua.luaFuelCut = lua_toboolean(l, 1);
874  return 0;
875  });
876  lua_register(lState, "setDfcoDisabled", [](lua_State* l) {
877  engine->engineState.lua.disableDecelerationFuelCutOff = lua_toboolean(l, 1);
878  return 0;
879  });
880 #endif // EFI_PROD_CODE
881 
882  lua_register(lState, "setClutchUpState", [](lua_State* l) {
883  engine->engineState.lua.clutchUpState = lua_toboolean(l, 1);
884  return 0;
885  });
886  lua_register(lState, "setClutchDownState", [](lua_State* l) {
887  engine->engineState.lua.clutchDownState = lua_toboolean(l, 1);
888  return 0;
889  });
890  lua_register(lState, "setBrakePedalState", [](lua_State* l) {
891  engine->engineState.lua.brakePedalState = lua_toboolean(l, 1);
892  return 0;
893  });
894 
895  lua_register(lState, "setAcRequestState", [](lua_State* l) {
896  engine->engineState.lua.acRequestState = lua_toboolean(l, 1);
897  return 0;
898  });
899 
900  lua_register(lState, "getCalibration", [](lua_State* l) {
901  auto propertyName = luaL_checklstring(l, 1, nullptr);
902  auto result = getConfigValueByName(propertyName);
903  lua_pushnumber(l, result);
904  return 1;
905  });
906 
907 #if EFI_TUNER_STUDIO && (EFI_PROD_CODE || EFI_SIMULATOR)
908  lua_register(lState, "getOutput", [](lua_State* l) {
909  auto propertyName = luaL_checklstring(l, 1, nullptr);
910  // fresh values need to be requested explicitly, there is no periodic invocation of that method
912  auto result = getOutputValueByName(propertyName);
913  lua_pushnumber(l, result);
914  return 1;
915  });
916 #endif // EFI_PROD_CODE || EFI_SIMULATOR
917 
918 #if EFI_SHAFT_POSITION_INPUT
919  lua_register(lState, "getEngineState", [](lua_State* l) {
921  int luaStateCode;
922  if (state == STOPPED) {
923  luaStateCode = 0;
924  } else if (state == RUNNING) {
925  luaStateCode = 2;
926  } else {
927  // spinning-up or cranking
928  luaStateCode = 1;
929  }
930  lua_pushnumber(l, luaStateCode);
931  return 1;
932  });
933 #endif //EFI_SHAFT_POSITION_INPUT
934 
935  lua_register(lState, "setCalibration", [](lua_State* l) {
936  auto propertyName = luaL_checklstring(l, 1, nullptr);
937  auto value = luaL_checknumber(l, 2);
938  auto incrementVersion = lua_toboolean(l, 3);
939  bool isGoodName = setConfigValueByName(propertyName, value);
940  if (isGoodName) {
941  efiPrintf("LUA: applying [%s][%f]", propertyName, value);
942  } else {
943  efiPrintf("LUA: invalid calibration key [%s]", propertyName);
944  }
945  if (incrementVersion) {
947  }
948  return 0;
949  });
950  lua_register(lState, CMD_BURNCONFIG, [](lua_State* l) {
951  requestBurn();
952  return 0;
953  });
954 
955  lua_register(lState, "getGlobalConfigurationVersion", [](lua_State* l) {
956  lua_pushnumber(l, engine->getGlobalConfigurationVersion());
957  return 1;
958  });
959 
960  lua_register(lState, "setAcDisabled", [](lua_State* l) {
961  auto value = lua_toboolean(l, 1);
962  engine->module<AcController>().unmock().isDisabledByLua = value;
963  return 0;
964  });
965  lua_register(lState, "getTimeSinceAcToggleMs", [](lua_State* l) {
966  int result = US2MS(getTimeNowUs()) - engine->module<AcController>().unmock().acSwitchLastChangeTimeMs;
967  lua_pushnumber(l, result);
968  return 1;
969  });
970 
971 #if EFI_VEHICLE_SPEED
972  lua_register(lState, "getCurrentGear", [](lua_State* l) {
973  lua_pushinteger(l, Sensor::getOrZero(SensorType::DetectedGear));
974  return 1;
975  });
976 
977  lua_register(lState, "getRpmInGear", [](lua_State* l) {
978  auto idx = luaL_checkinteger(l, 1);
979  lua_pushinteger(l, engine->module<GearDetector>()->getRpmInGear(idx));
980  return 1;
981  });
982 #endif // EFI_VEHICLE_SPEED
983 
984 #if !EFI_UNIT_TEST
985  lua_register(lState, "startPwm", lua_startPwm);
986  lua_register(lState, "setPwmDuty", lua_setPwmDuty);
987  lua_register(lState, "setPwmFreq", lua_setPwmFreq);
988 
989  lua_register(lState, "getFan", lua_fan);
990  lua_register(lState, "getDigital", lua_getDigital);
991  lua_register(lState, "getAuxDigital", lua_getAuxDigital);
992  lua_register(lState, "setDebug", lua_setDebug);
993 #if EFI_ENGINE_CONTROL
994  lua_register(lState, "getAirmass", lua_getAirmass);
995  lua_register(lState, "setAirmass", lua_setAirmass);
996 #endif // EFI_ENGINE_CONTROL
997 
998  lua_register(lState, "isFirmwareError", [](lua_State* l) {
999  lua_pushboolean(l, hasFirmwareError());
1000  return 1;
1001  });
1002 #if EFI_SHAFT_POSITION_INPUT
1003  lua_register(lState, "stopEngine", [](lua_State*) {
1005  return 0;
1006  });
1007  lua_register(lState, "isEngineStopRequested", [](lua_State* l) {
1009  lua_pushboolean(l, result);
1010  return 1;
1011  });
1012  lua_register(lState, "getTimeSinceTriggerEventMs", [](lua_State* l) {
1013  int result = engine->triggerCentral.m_lastEventTimer.getElapsedUs() / 1000;
1014  lua_pushnumber(l, result);
1015  return 1;
1016  });
1017 #endif // EFI_SHAFT_POSITION_INPUT
1018 
1019 #if EFI_CAN_SUPPORT
1020  lua_register(lState, "canRxAdd", lua_canRxAdd);
1021  lua_register(lState, "canRxAddMask", lua_canRxAddMask);
1022 #endif // EFI_CAN_SUPPORT
1023 #endif // not EFI_UNIT_TEST
1024 
1025 #if EFI_CAN_SUPPORT || EFI_UNIT_TEST
1026  lua_register(lState, "txCan", lua_txCan);
1027 #endif
1028 
1029 #if EFI_VEHICLE_SPEED
1030  lua_register(lState, "resetOdometer", [](lua_State*) {
1031  engine->module<TripOdometer>()->reset();
1032  return 0;
1033  });
1034 #endif // EFI_VEHICLE_SPEED
1035 
1036 #if EFI_PROD_CODE && HW_HELLEN
1037  lua_register(lState, "hellenEnablePower", [](lua_State*) {
1038  hellenEnableEn("Lua");
1039  return 0;
1040  });
1041  lua_register(lState, "hellenDisablePower", [](lua_State*) {
1042  hellenDisableEn("Lua");
1043  return 0;
1044  });
1045 #endif // HW_HELLEN
1046 
1047 #if EFI_DAC
1048  lua_register(lState, "setDacVoltage", [](lua_State* l) {
1049  auto channel = luaL_checkinteger(l, 1);
1050  auto voltage = luaL_checknumber(l, 2);
1051  setDacVoltage(channel, voltage);
1052  return 0;
1053  });
1054 #endif // EFI_DAC
1055 
1056 }
uint16_t channel
Definition: adc_inputs.h:105
void addLuaCanRxFilter(int32_t eid, uint32_t mask, int bus, int callback)
Definition: can_filter.cpp:31
void setDlc(uint8_t dlc)
Definition: can_msg_tx.cpp:108
TriggerCentral triggerCentral
Definition: engine.h:286
IgnitionState ignitionState
Definition: engine.h:210
bool allowCanTx
Definition: engine.h:104
int getGlobalConfigurationVersion(void) const
Definition: engine.cpp:315
EngineState engineState
Definition: engine.h:312
RpmCalculator rpmCalculator
Definition: engine.h:273
constexpr auto & module()
Definition: engine.h:177
SingleTimerExecutor executor
Definition: engine.h:241
IEtbController * etbControllers[ETB_COUNT]
Definition: engine.h:118
TunerStudioOutputChannels outputChannels
Definition: engine.h:99
RegisteredOutputPin fanRelay
Definition: efi_gpio.h:86
OutputPin luaOutputPins[LUA_PWM_COUNT]
Definition: efi_gpio.h:98
void updateSparkSkip()
Definition: engine2.cpp:87
float getRpmInGear(size_t gear) const
virtual float getCurrentTarget() const =0
ShutdownController shutdownController
Definition: limp_manager.h:108
void setAirmass(AirmassResult airmass)
Definition: lua_airmass.h:11
void deInit()
Definition: efi_gpio.cpp:780
bool getLogicValue() const
Definition: efi_gpio.cpp:645
spinning_state_e getState() const
virtual bool hasSensor() const
Definition: sensor.h:150
virtual SensorResult get() const =0
virtual float getRaw() const
Definition: sensor.h:157
static float getOrZero(SensorType type)
Definition: sensor.h:92
bool isEngineStop(efitick_t nowNt) const
void setSimplePwmDutyCycle(float dutyCycle) override
Base class for sensors that compute a value on one thread, and want to make it available to consumers...
void setValidValue(float value, efitick_t timestamp)
virtual void setTimeout(int timeoutMs)
bool directSelfStimulation
virtual float getValue(float xColumn, float yRow) const =0
Gpio
void setDacVoltage(int channel, float voltage)
Definition: dac.cpp:59
EnginePins enginePins
Definition: efi_gpio.cpp:24
ioportid_t getHwPort(const char *msg, brain_pin_e brainPin)
brain_pin_e parseBrainPin(const char *str)
ioportmask_t getHwPin(const char *msg, brain_pin_e brainPin)
const char * boolToString(bool value)
Definition: efilib.cpp:18
efitick_t getTimeNowNt()
Definition: efitime.cpp:19
efitimeus_t getTimeNowUs()
Definition: efitime.cpp:26
void setEtbLuaAdjustment(percent_t pos)
void doInitElectronicThrottle()
LimpManager * getLimpManager()
Definition: engine.cpp:615
void incrementGlobalConfigurationVersion(const char *msg)
Engine * engine
AirmassModelBase * getAirmassModel(engine_load_mode_e mode)
Definition: fuel_math.cpp:153
void hellenEnableEn(const char *msg)
void hellenDisableEn(const char *msg)
StoredValueSensor luaGauges[]
Definition: init_aux.cpp:21
bool efiReadPin(brain_pin_e pin)
Definition: io_pins.cpp:89
static int lua_setPwmFreq(lua_State *l)
Definition: lua_hooks.cpp:327
void startPwm(int index, float freq, float duty)
Definition: lua_hooks.cpp:273
static auto lua_getAirmassResolveMode(lua_State *l)
Definition: lua_hooks.cpp:415
static int lua_readpin(lua_State *l)
Definition: lua_hooks.cpp:57
BOARD_WEAK void boardConfigureLuaHooks(lua_State *lState)
Definition: lua_hooks.cpp:645
int lua_canRxAddMask(lua_State *l)
Definition: lua_hooks.cpp:582
static int lua_txCan(lua_State *l)
Definition: lua_hooks.cpp:176
int getLuaFunc(lua_State *l)
Definition: lua_hooks.cpp:530
AirmassModelBase & getLuaAirmassModel()
Definition: lua_hooks.cpp:245
void setPwmDuty(int index, float duty)
Definition: lua_hooks.cpp:312
static int lua_setAirmass(lua_State *l)
Definition: lua_hooks.cpp:439
static SimplePwm pwms[LUA_PWM_COUNT]
Definition: lua_hooks.cpp:250
static int lua_getDigital(lua_State *l)
Definition: lua_hooks.cpp:344
bool getAuxDigital(int index)
Definition: lua_hooks.cpp:364
static int lua_getAuxDigital(lua_State *l)
Definition: lua_hooks.cpp:372
static SensorType findSensorByName(lua_State *l, const char *name)
Definition: lua_hooks.cpp:101
static LuaAirmass luaAirmass
Definition: lua_hooks.cpp:243
static int lua_getAuxAnalog(lua_State *l)
Definition: lua_hooks.cpp:86
static int lua_getSensorByIndex(lua_State *l)
Definition: lua_hooks.cpp:95
void configureRusefiLuaHooks(lua_State *lState)
Definition: lua_hooks.cpp:647
static int validateCanChannelAndConvertFromHumanIntoZeroIndex(lua_State *l)
Definition: lua_hooks.cpp:169
static int lua_fan(lua_State *l)
Definition: lua_hooks.cpp:339
static int lua_hasSensor(lua_State *l)
Definition: lua_hooks.cpp:125
static int lua_getSensorByName(lua_State *l)
Definition: lua_hooks.cpp:111
static int lua_getAirmass(lua_State *l)
Definition: lua_hooks.cpp:424
static int lua_setPwmDuty(lua_State *l)
Definition: lua_hooks.cpp:319
static int lua_getSensorRaw(lua_State *l)
Definition: lua_hooks.cpp:118
static int getSensor(lua_State *l, SensorType type)
Definition: lua_hooks.cpp:72
static bool isFunction(lua_State *l, int idx)
Definition: lua_hooks.cpp:526
void luaDeInitPins()
Definition: lua_hooks.cpp:305
int lua_canRxAdd(lua_State *l)
Definition: lua_hooks.cpp:539
static int lua_setDebug(lua_State *l)
Definition: lua_hooks.cpp:394
static int lua_startPwm(lua_State *l)
Definition: lua_hooks.cpp:290
static int lua_vin(lua_State *l)
Definition: lua_hooks.cpp:46
static uint32_t getArray(lua_State *l, int paramIndex, uint8_t *data, uint32_t size)
Definition: lua_hooks.cpp:135
static int lua_vincpy(lua_State *l)
Definition: lua_hooks.cpp:633
static P luaL_checkPwmIndex(lua_State *l, int pos)
Definition: lua_hooks.cpp:257
void configureRusefiLuaUtilHooks(lua_State *lState)
float getOutputValueByName(const char *name)
@ LuaOneCanTxFunction
engine_configuration_s * engineConfiguration
const char * hwPortname(brain_pin_e brainPin)
bool isBrainPinValid(brain_pin_e brainPin)
void startSimplePwmExt(SimplePwm *state, const char *msg, ExecutorInterface *executor, brain_pin_e brainPin, OutputPin *output, float frequency, float dutyCycle, pwm_gen_callback *callback)
spinning_state_e
@ RUNNING
@ STOPPED
engine_load_mode_e
Definition: rusefi_enums.h:148
float getCurveValue(int index, float key)
Definition: script_impl.cpp:64
ValueProvider3D * getscriptTable(int index)
Definition: script_impl.cpp:17
SensorType findSensorTypeByName(const char *name)
Definition: sensor.cpp:259
static ScState state
SensorType
Definition: sensor_type.h:18
luaAdjustment("ETB: luaAdjustment", SensorCategory.SENSOR_INPUTS, FieldType.INT, 1604, 1.0, 0.0, 3.0, "per")
int getSentValues(size_t index, uint16_t *sig0, uint16_t *sig1)
Definition: sent.cpp:625
float getSentValue(size_t index)
Definition: sent.cpp:609
This file is about configuring engine via the human-readable protocol.
void doScheduleStopEngine()
brain_pin_e pin
Definition: stm32_adc.cpp:15
void configureLowpass(float samplingFrequency, float cutoffFrequency)
Definition: lua_biquad.h:17
float filter(float input)
Definition: lua_biquad.h:9
void reset()
Definition: lua_pid.h:94
void setOffset(float offset)
Definition: lua_pid.h:79
void setDerivativeFilterLoss(float derivativeFilterLoss)
Definition: lua_pid.h:84
void setAntiwindupFreq(float antiwindupFreq)
Definition: lua_pid.h:89
float get(float target, float input)
Definition: lua_pid.h:68
float get(float target, float input)
Definition: lua_pid.h:23
void reset()
Definition: lua_pid.h:39
void setOffset(float offset)
Definition: lua_pid.h:34
scaled_channel< int16_t, 2, 1 > luaTargetAdd
switch_input_pin_e luaDigitalInputPins[LUA_DIGITAL_INPUT_COUNT]
static float duty
Definition: tachometer.cpp:17
composite packet size
void disableTriggerStimulator()
void setTriggerEmulatorRPM(int rpm)
void enableTriggerStimulator(bool incGlobalConfiguration)
void requestBurn()
void updateTunerStudioState()
int getSecondsSinceChannelsRequest()
bool setConfigValueByName(const char *name, float value)
float getConfigValueByName(const char *name)