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