5 * th9x - http://code.google.com/p/th9x
6 * er9x - http://code.google.com/p/er9x
7 * gruvin9x - http://code.google.com/p/gruvin9x
9 * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License version 2 as
13 * published by the Free Software Foundation.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
28 @function model.getInfo()
30 Get current Model information
32 @retval table model information:
33 * `name` (string) model name
34 * `bitmap` (string) bitmap name (not present on X7)
36 @status current Introduced in 2.0.6, changed in 2.2.0
38 static int luaModelGetInfo(lua_State
*L
)
41 lua_pushtablezstring(L
, "name", g_model
.header
.name
);
43 lua_pushtablenzstring(L
, "bitmap", g_model
.header
.bitmap
);
49 @function model.setInfo(value)
51 Set the current Model information
53 @param value model information data, see model.getInfo()
55 @notice If a parameter is missing from the value, then
56 that parameter remains unchanged.
58 @status current Introduced in 2.0.6, changed in TODO
60 static int luaModelSetInfo(lua_State
*L
)
62 luaL_checktype(L
, -1, LUA_TTABLE
);
63 for (lua_pushnil(L
); lua_next(L
, -2); lua_pop(L
, 1)) {
64 luaL_checktype(L
, -2, LUA_TSTRING
); // key is string
65 const char * key
= luaL_checkstring(L
, -2);
66 if (!strcmp(key
, "name")) {
67 const char * name
= luaL_checkstring(L
, -1);
68 str2zchar(g_model
.header
.name
, name
, sizeof(g_model
.header
.name
));
70 memcpy(modelHeaders
[g_eeGeneral
.currModel
].name
, g_model
.header
.name
, sizeof(g_model
.header
.name
));
74 else if (!strcmp(key
, "bitmap")) {
75 const char * name
= luaL_checkstring(L
, -1);
76 strncpy(g_model
.header
.bitmap
, name
, sizeof(g_model
.header
.bitmap
));
80 storageDirty(EE_MODEL
);
85 @function model.getModule(index)
87 Get RF module parameters
95 @param index (number) module index (0 for internal, 1 for external)
97 @retval nil requested module does not exist
99 @retval table module parameters:
100 * `subType` (number) protocol index
101 * `modelId` (number) receiver number
102 * `firstChannel` (number) start channel (0 is CH1)
103 * `channelsCount` (number) number of channels sent to module
105 @status current Introduced in TODO
107 static int luaModelGetModule(lua_State
*L
)
109 unsigned int idx
= luaL_checkunsigned(L
, 1);
110 if (idx
< NUM_MODULES
) {
111 ModuleData
& module
= g_model
.moduleData
[idx
];
113 lua_pushtableinteger(L
, "subType", module
.subType
);
114 lua_pushtableinteger(L
, "modelId", g_model
.header
.modelId
[idx
]);
115 lua_pushtableinteger(L
, "firstChannel", module
.channelsStart
);
116 lua_pushtableinteger(L
, "channelsCount", module
.channelsCount
+ 8);
125 @function model.setModule(index, value)
127 Set RF module parameters
129 @param index (number) module index (0 for internal, 1 for external)
131 @param value module parameters, see model.getModule()
133 @notice If a parameter is missing from the value, then
134 that parameter remains unchanged.
136 @status current Introduced in TODO
138 static int luaModelSetModule(lua_State
*L
)
140 unsigned int idx
= luaL_checkunsigned(L
, 1);
142 if (idx
< NUM_MODULES
) {
143 ModuleData
& module
= g_model
.moduleData
[idx
];
144 luaL_checktype(L
, -1, LUA_TTABLE
);
145 for (lua_pushnil(L
); lua_next(L
, -2); lua_pop(L
, 1)) {
146 luaL_checktype(L
, -2, LUA_TSTRING
); // key is string
147 const char * key
= luaL_checkstring(L
, -2);
148 if (!strcmp(key
, "subType")) {
149 module
.subType
= luaL_checkinteger(L
, -1);
151 else if (!strcmp(key
, "modelId")) {
152 g_model
.header
.modelId
[idx
] = luaL_checkinteger(L
, -1);
154 modelHeaders
[g_eeGeneral
.currModel
].modelId
[idx
] = g_model
.header
.modelId
[idx
];
157 else if (!strcmp(key
, "firstChannel")) {
158 module
.channelsStart
= luaL_checkinteger(L
, -1);
160 else if (!strcmp(key
, "channelsCount")) {
161 module
.channelsCount
= luaL_checkinteger(L
, -1) - 8;
164 storageDirty(EE_MODEL
);
170 @function model.getTimer(timer)
172 Get model timer parameters
174 @param timer (number) timer index (0 for Timer 1)
176 @retval nil requested timer does not exist
178 @retval table timer parameters:
179 * `mode` (number) timer trigger source: off, abs, stk, stk%, sw/!sw, !m_sw/!m_sw
180 * `start` (number) start value [seconds], 0 for up timer, 0> down timer
181 * `value` (number) current value [seconds]
182 * `countdownBeep` (number) countdown beep (0 = silent, 1 = beeps, 2 = voice)
183 * `minuteBeep` (boolean) minute beep
184 * `persistent` (number) persistent timer
186 @status current Introduced in 2.0.0
188 static int luaModelGetTimer(lua_State
*L
)
190 unsigned int idx
= luaL_checkunsigned(L
, 1);
191 if (idx
< MAX_TIMERS
) {
192 TimerData
& timer
= g_model
.timers
[idx
];
194 lua_pushtableinteger(L
, "mode", timer
.mode
);
195 lua_pushtableinteger(L
, "start", timer
.start
);
196 lua_pushtableinteger(L
, "value", timersStates
[idx
].val
);
197 lua_pushtableinteger(L
, "countdownBeep", timer
.countdownBeep
);
198 lua_pushtableboolean(L
, "minuteBeep", timer
.minuteBeep
);
199 lua_pushtableinteger(L
, "persistent", timer
.persistent
);
208 @function model.setTimer(timer, value)
210 Set model timer parameters
212 @param timer (number) timer index (0 for Timer 1)
214 @param value timer parameters, see model.getTimer()
216 @notice If a parameter is missing from the value, then
217 that parameter remains unchanged.
219 @status current Introduced in 2.0.0
221 static int luaModelSetTimer(lua_State
*L
)
223 unsigned int idx
= luaL_checkunsigned(L
, 1);
225 if (idx
< MAX_TIMERS
) {
226 TimerData
& timer
= g_model
.timers
[idx
];
227 luaL_checktype(L
, -1, LUA_TTABLE
);
228 for (lua_pushnil(L
); lua_next(L
, -2); lua_pop(L
, 1)) {
229 luaL_checktype(L
, -2, LUA_TSTRING
); // key is string
230 const char * key
= luaL_checkstring(L
, -2);
231 if (!strcmp(key
, "mode")) {
232 timer
.mode
= luaL_checkinteger(L
, -1);
234 else if (!strcmp(key
, "start")) {
235 timer
.start
= luaL_checkinteger(L
, -1);
237 else if (!strcmp(key
, "value")) {
238 timersStates
[idx
].val
= luaL_checkinteger(L
, -1);
240 else if (!strcmp(key
, "countdownBeep")) {
241 timer
.countdownBeep
= luaL_checkinteger(L
, -1);
243 else if (!strcmp(key
, "minuteBeep")) {
244 timer
.minuteBeep
= lua_toboolean(L
, -1);
246 else if (!strcmp(key
, "persistent")) {
247 timer
.persistent
= luaL_checkinteger(L
, -1);
250 storageDirty(EE_MODEL
);
256 @function model.resetTimer(timer)
258 Reset model timer to a startup value
260 @param timer (number) timer index (0 for Timer 1)
262 @status current Introduced in TODO
264 static int luaModelResetTimer(lua_State
*L
)
266 unsigned int idx
= luaL_checkunsigned(L
, 1);
267 if (idx
< MAX_TIMERS
) {
273 static unsigned int getFirstInput(unsigned int chn
)
275 for (unsigned int i
=0; i
<MAX_EXPOS
; i
++) {
276 ExpoData
* expo
= expoAddress(i
);
277 if (!expo
->srcRaw
|| expo
->chn
>= chn
) {
284 static unsigned int getInputsCountFromFirst(unsigned int chn
, unsigned int first
)
286 unsigned int count
= 0;
287 for (unsigned int i
=first
; i
<MAX_EXPOS
; i
++) {
288 ExpoData
* expo
= expoAddress(i
);
289 if (!expo
->srcRaw
|| expo
->chn
!=chn
) break;
295 static unsigned int getInputsCount(unsigned int chn
)
297 return getInputsCountFromFirst(chn
, getFirstInput(chn
));
301 @function model.getInputsCount(input)
303 Return number of lines for given input
305 @param input (unsigned number) input number (use 0 for Input1)
307 @retval number number of configured lines for given input
309 @status current Introduced in 2.0.0
311 static int luaModelGetInputsCount(lua_State
*L
)
313 unsigned int chn
= luaL_checkunsigned(L
, 1);
314 int count
= getInputsCount(chn
);
315 lua_pushinteger(L
, count
);
320 @function model.getInput(input, line)
322 Return input data for given input and line number
324 @param input (unsigned number) input number (use 0 for Input1)
326 @param line (unsigned number) input line (use 0 for first line)
328 @retval nil requested input or line does not exist
330 @retval table input data:
331 * `name` (string) input line name
332 * `source` (number) input source index
333 * `weight` (number) input weight
334 * `offset` (number) input offset
335 * `switch` (number) input switch index
336 * `curveType` (number) curve type (function, expo, custom curve)
337 * `curveValue` (number) curve index
338 * `carryTrim` (boolean) input trims applied
340 @status current Introduced in 2.0.0, curveType/curveValue/carryTrim added in 2.3
342 static int luaModelGetInput(lua_State
*L
)
344 unsigned int chn
= luaL_checkunsigned(L
, 1);
345 unsigned int idx
= luaL_checkunsigned(L
, 2);
346 unsigned int first
= getFirstInput(chn
);
347 unsigned int count
= getInputsCountFromFirst(chn
, first
);
349 ExpoData
* expo
= expoAddress(first
+idx
);
351 lua_pushtablezstring(L
, "name", expo
->name
);
352 lua_pushtableinteger(L
, "source", expo
->srcRaw
);
353 lua_pushtableinteger(L
, "weight", expo
->weight
);
354 lua_pushtableinteger(L
, "offset", expo
->offset
);
355 lua_pushtableinteger(L
, "switch", expo
->swtch
);
356 lua_pushtableinteger(L
, "curveType", expo
->curve
.type
);
357 lua_pushtableinteger(L
, "curveValue", expo
->curve
.value
);
358 lua_pushtableinteger(L
, "carryTrim", expo
->carryTrim
);
367 @function model.insertInput(input, line, value)
369 Insert an Input at specified line
371 @param input (unsigned number) input number (use 0 for Input1)
373 @param line (unsigned number) input line (use 0 for first line)
375 @param value (table) input data, see model.getInput()
377 @status current Introduced in 2.0.0, curveType/curveValue/carryTrim added in 2.3
379 static int luaModelInsertInput(lua_State
*L
)
381 unsigned int chn
= luaL_checkunsigned(L
, 1);
382 unsigned int idx
= luaL_checkunsigned(L
, 2);
384 unsigned int first
= getFirstInput(chn
);
385 unsigned int count
= getInputsCountFromFirst(chn
, first
);
387 if (chn
<MAX_INPUTS
&& getExposCount()<MAX_EXPOS
&& idx
<=count
) {
391 ExpoData
* expo
= expoAddress(idx
);
392 luaL_checktype(L
, -1, LUA_TTABLE
);
393 for (lua_pushnil(L
); lua_next(L
, -2); lua_pop(L
, 1)) {
394 luaL_checktype(L
, -2, LUA_TSTRING
); // key is string
395 const char * key
= luaL_checkstring(L
, -2);
396 if (!strcmp(key
, "name")) {
397 const char * name
= luaL_checkstring(L
, -1);
398 str2zchar(expo
->name
, name
, sizeof(expo
->name
));
400 else if (!strcmp(key
, "source")) {
401 expo
->srcRaw
= luaL_checkinteger(L
, -1);
403 else if (!strcmp(key
, "weight")) {
404 expo
->weight
= luaL_checkinteger(L
, -1);
406 else if (!strcmp(key
, "offset")) {
407 expo
->offset
= luaL_checkinteger(L
, -1);
409 else if (!strcmp(key
, "switch")) {
410 expo
->swtch
= luaL_checkinteger(L
, -1);
412 else if (!strcmp(key
, "curveType")) {
413 expo
->curve
.type
= luaL_checkinteger(L
, -1);
415 else if (!strcmp(key
, "curveValue")) {
416 expo
->curve
.value
= luaL_checkinteger(L
, -1);
418 else if (!strcmp(key
, "carryTrim")) {
419 expo
->carryTrim
= lua_toboolean(L
, -1);
428 @function model.deleteInput(input, line)
430 Delete line from specified input
432 @param input (unsigned number) input number (use 0 for Input1)
434 @param line (unsigned number) input line (use 0 for first line)
436 @status current Introduced in 2.0.0
438 static int luaModelDeleteInput(lua_State
*L
)
440 unsigned int chn
= luaL_checkunsigned(L
, 1);
441 unsigned int idx
= luaL_checkunsigned(L
, 2);
443 int first
= getFirstInput(chn
);
444 unsigned int count
= getInputsCountFromFirst(chn
, first
);
447 deleteExpo(first
+idx
);
454 @function model.deleteInputs()
458 @status current Introduced in 2.0.0
460 static int luaModelDeleteInputs(lua_State
*L
)
467 @function model.defaultInputs()
469 Set all inputs to defaults
471 @status current Introduced in 2.0.0
473 static int luaModelDefaultInputs(lua_State
*L
)
479 static unsigned int getFirstMix(unsigned int chn
)
481 for (unsigned int i
=0; i
<MAX_MIXERS
; i
++) {
482 MixData
* mix
= mixAddress(i
);
483 if (!mix
->srcRaw
|| mix
->destCh
>=chn
) {
490 static unsigned int getMixesCountFromFirst(unsigned int chn
, unsigned int first
)
492 unsigned int count
= 0;
493 for (unsigned int i
=first
; i
<MAX_MIXERS
; i
++) {
494 MixData
* mix
= mixAddress(i
);
495 if (!mix
->srcRaw
|| mix
->destCh
!=chn
) break;
501 static unsigned int getMixesCount(unsigned int chn
)
503 return getMixesCountFromFirst(chn
, getFirstMix(chn
));
507 @function model.getMixesCount(channel)
509 Get the number of Mixer lines that the specified Channel has
511 @param channel (unsigned number) channel number (use 0 for CH1)
513 @retval number number of mixes for requested channel
515 @status current Introduced in 2.0.0
517 static int luaModelGetMixesCount(lua_State
*L
)
519 unsigned int chn
= luaL_checkunsigned(L
, 1);
520 unsigned int count
= getMixesCount(chn
);
521 lua_pushinteger(L
, count
);
526 @function model.getMix(channel, line)
528 Get configuration for specified Mix
530 @param channel (unsigned number) channel number (use 0 for CH1)
532 @param line (unsigned number) mix number (use 0 for first line(mix))
534 @retval nil requested channel or line does not exist
536 @retval table mix data:
537 * `name` (string) mix line name
538 * `source` (number) source index
539 * `weight` (number) weight (1024 == 100%) value or GVAR1..9 = 4096..4011, -GVAR1..9 = 4095..4087
540 * `offset` (number) offset value or GVAR1..9 = 4096..4011, -GVAR1..9 = 4095..4087
541 * `switch` (number) switch index
542 * `multiplex` (number) multiplex (0 = ADD, 1 = MULTIPLY, 2 = REPLACE)
543 * `curveType` (number) curve type (function, expo, custom curve)
544 * `curveValue` (number) curve index
545 * `flightModes` (number) bit-mask of active flight modes
546 * `carryTrim` (boolean) carry trim
547 * `mixWarn` (number) warning (0 = off, 1 = 1 beep, .. 3 = 3 beeps)
548 * `delayUp` (number) delay up (time in 1/10 s)
549 * `delayDown` (number) delay down
550 * `speedUp` (number) speed up
551 * `speedDown` (number) speed down
553 @status current Introduced in 2.0.0, parameters below `multiplex` added in 2.0.13
555 static int luaModelGetMix(lua_State
*L
)
557 unsigned int chn
= luaL_checkunsigned(L
, 1);
558 unsigned int idx
= luaL_checkunsigned(L
, 2);
559 unsigned int first
= getFirstMix(chn
);
560 unsigned int count
= getMixesCountFromFirst(chn
, first
);
562 MixData
* mix
= mixAddress(first
+idx
);
564 lua_pushtablezstring(L
, "name", mix
->name
);
565 lua_pushtableinteger(L
, "source", mix
->srcRaw
);
566 lua_pushtableinteger(L
, "weight", mix
->weight
);
567 lua_pushtableinteger(L
, "offset", mix
->offset
);
568 lua_pushtableinteger(L
, "switch", mix
->swtch
);
569 lua_pushtableinteger(L
, "curveType", mix
->curve
.type
);
570 lua_pushtableinteger(L
, "curveValue", mix
->curve
.value
);
571 lua_pushtableinteger(L
, "multiplex", mix
->mltpx
);
572 lua_pushtableinteger(L
, "flightModes", mix
->flightModes
);
573 lua_pushtableboolean(L
, "carryTrim", mix
->carryTrim
);
574 lua_pushtableinteger(L
, "mixWarn", mix
->mixWarn
);
575 lua_pushtableinteger(L
, "delayUp", mix
->delayUp
);
576 lua_pushtableinteger(L
, "delayDown", mix
->delayDown
);
577 lua_pushtableinteger(L
, "speedUp", mix
->speedUp
);
578 lua_pushtableinteger(L
, "speedDown", mix
->speedDown
);
587 @function model.insertMix(channel, line, value)
589 Insert a mixer line into Channel
591 @param channel (unsigned number) channel number (use 0 for CH1)
593 @param line (unsigned number) mix number (use 0 for first line(mix))
595 @param value (table) see model.getMix() for table format
597 @status current Introduced in 2.0.0, parameters below `multiplex` added in 2.0.13
599 static int luaModelInsertMix(lua_State
*L
)
601 unsigned int chn
= luaL_checkunsigned(L
, 1);
602 unsigned int idx
= luaL_checkunsigned(L
, 2);
604 unsigned int first
= getFirstMix(chn
);
605 unsigned int count
= getMixesCountFromFirst(chn
, first
);
607 if (chn
<MAX_OUTPUT_CHANNELS
&& getMixesCount()<MAX_MIXERS
&& idx
<=count
) {
611 MixData
*mix
= mixAddress(idx
);
612 luaL_checktype(L
, -1, LUA_TTABLE
);
613 for (lua_pushnil(L
); lua_next(L
, -2); lua_pop(L
, 1)) {
614 luaL_checktype(L
, -2, LUA_TSTRING
); // key is string
615 const char * key
= luaL_checkstring(L
, -2);
616 if (!strcmp(key
, "name")) {
617 const char * name
= luaL_checkstring(L
, -1);
618 str2zchar(mix
->name
, name
, sizeof(mix
->name
));
620 else if (!strcmp(key
, "source")) {
621 mix
->srcRaw
= luaL_checkinteger(L
, -1);
623 else if (!strcmp(key
, "weight")) {
624 mix
->weight
= luaL_checkinteger(L
, -1);
626 else if (!strcmp(key
, "offset")) {
627 mix
->offset
= luaL_checkinteger(L
, -1);
629 else if (!strcmp(key
, "switch")) {
630 mix
->swtch
= luaL_checkinteger(L
, -1);
632 else if (!strcmp(key
, "curveType")) {
633 mix
->curve
.type
= luaL_checkinteger(L
, -1);
635 else if (!strcmp(key
, "curveValue")) {
636 mix
->curve
.value
= luaL_checkinteger(L
, -1);
638 else if (!strcmp(key
, "multiplex")) {
639 mix
->mltpx
= luaL_checkinteger(L
, -1);
641 else if (!strcmp(key
, "flightModes")) {
642 mix
->flightModes
= luaL_checkinteger(L
, -1);
644 else if (!strcmp(key
, "carryTrim")) {
645 mix
->carryTrim
= lua_toboolean(L
, -1);
647 else if (!strcmp(key
, "mixWarn")) {
648 mix
->mixWarn
= luaL_checkinteger(L
, -1);
650 else if (!strcmp(key
, "delayUp")) {
651 mix
->delayUp
= luaL_checkinteger(L
, -1);
653 else if (!strcmp(key
, "delayDown")) {
654 mix
->delayDown
= luaL_checkinteger(L
, -1);
656 else if (!strcmp(key
, "speedUp")) {
657 mix
->speedUp
= luaL_checkinteger(L
, -1);
659 else if (!strcmp(key
, "speedDown")) {
660 mix
->speedDown
= luaL_checkinteger(L
, -1);
669 @function model.deleteMix(channel, line)
671 Delete mixer line from specified Channel
673 @param channel (unsigned number) channel number (use 0 for CH1)
675 @param line (unsigned number) mix number (use 0 for first line(mix))
677 @status current Introduced in 2.0.0
679 static int luaModelDeleteMix(lua_State
*L
)
681 unsigned int chn
= luaL_checkunsigned(L
, 1);
682 unsigned int idx
= luaL_checkunsigned(L
, 2);
684 unsigned int first
= getFirstMix(chn
);
685 unsigned int count
= getMixesCountFromFirst(chn
, first
);
688 deleteMix(first
+idx
);
695 @function model.deleteMixes()
699 @status current Introduced in 2.0.0
701 static int luaModelDeleteMixes(lua_State
*L
)
703 memset(g_model
.mixData
, 0, sizeof(g_model
.mixData
));
708 @function model.getLogicalSwitch(switch)
710 Get Logical Switch parameters
712 @param switch (unsigned number) logical switch number (use 0 for LS1)
714 @retval nil requested logical switch does not exist
716 @retval table logical switch data:
717 * `func` (number) function index
718 * `v1` (number) V1 value (index)
719 * `v2` (number) V2 value (index or value)
720 * `v3` (number) V3 value (index or value)
721 * `and` (number) AND switch index
722 * `delay` (number) delay (time in 1/10 s)
723 * `duration` (number) duration (time in 1/10 s)
725 @status current Introduced in 2.0.0
727 static int luaModelGetLogicalSwitch(lua_State
*L
)
729 unsigned int idx
= luaL_checkunsigned(L
, 1);
730 if (idx
< MAX_LOGICAL_SWITCHES
) {
731 LogicalSwitchData
* sw
= lswAddress(idx
);
733 lua_pushtableinteger(L
, "func", sw
->func
);
734 lua_pushtableinteger(L
, "v1", sw
->v1
);
735 lua_pushtableinteger(L
, "v2", sw
->v2
);
736 lua_pushtableinteger(L
, "v3", sw
->v3
);
737 lua_pushtableinteger(L
, "and", sw
->andsw
);
738 lua_pushtableinteger(L
, "delay", sw
->delay
);
739 lua_pushtableinteger(L
, "duration", sw
->duration
);
748 @function model.setLogicalSwitch(switch, value)
750 Set Logical Switch parameters
752 @param switch (unsigned number) logical switch number (use 0 for LS1)
754 @param value (table) see model.getLogicalSwitch() for table format
756 @notice If a parameter is missing from the value, then
757 that parameter remains unchanged.
759 @notice To set the `and` member (which is Lua keyword)
760 use the following syntax: `model.setLogicalSwitch(30, {func=4,v1=1,v2=-99, ["and"]=24})`
762 @status current Introduced in 2.0.0
764 static int luaModelSetLogicalSwitch(lua_State
*L
)
766 unsigned int idx
= luaL_checkunsigned(L
, 1);
767 if (idx
< MAX_LOGICAL_SWITCHES
) {
768 LogicalSwitchData
* sw
= lswAddress(idx
);
769 memclear(sw
, sizeof(LogicalSwitchData
));
770 luaL_checktype(L
, -1, LUA_TTABLE
);
771 for (lua_pushnil(L
); lua_next(L
, -2); lua_pop(L
, 1)) {
772 luaL_checktype(L
, -2, LUA_TSTRING
); // key is string
773 const char * key
= luaL_checkstring(L
, -2);
774 if (!strcmp(key
, "func")) {
775 sw
->func
= luaL_checkinteger(L
, -1);
777 else if (!strcmp(key
, "v1")) {
778 sw
->v1
= luaL_checkinteger(L
, -1);
780 else if (!strcmp(key
, "v2")) {
781 sw
->v2
= luaL_checkinteger(L
, -1);
783 else if (!strcmp(key
, "v3")) {
784 sw
->v3
= luaL_checkinteger(L
, -1);
786 else if (!strcmp(key
, "and")) {
787 sw
->andsw
= luaL_checkinteger(L
, -1);
789 else if (!strcmp(key
, "delay")) {
790 sw
->delay
= luaL_checkinteger(L
, -1);
792 else if (!strcmp(key
, "duration")) {
793 sw
->duration
= luaL_checkinteger(L
, -1);
796 storageDirty(EE_MODEL
);
803 @function model.getCurve(curve)
807 @param curve (unsigned number) curve number (use 0 for Curve1)
809 @retval nil requested curve does not exist
811 @retval table curve data:
812 * `name` (string) name
813 * `type` (number) type
814 * `smooth` (boolean) smooth
815 * `points` (number) number of points
816 * `y` (table) table of Y values:
817 * `key` is point number (zero based)
819 * `x` (table) **only included for custom curve type**:
820 * `key` is point number (zero based)
823 Note that functions returns the tables starting with index 0 contrary to LUA's
824 usual index starting with 1
826 @status current Introduced in 2.0.12
828 static int luaModelGetCurve(lua_State
*L
)
830 unsigned int idx
= luaL_checkunsigned(L
, 1);
831 if (idx
< MAX_CURVES
) {
832 CurveData
& curveData
= g_model
.curves
[idx
];
834 lua_pushtablezstring(L
, "name", curveData
.name
);
835 lua_pushtableinteger(L
, "type", curveData
.type
);
836 lua_pushtableboolean(L
, "smooth", curveData
.smooth
);
837 lua_pushtableinteger(L
, "points", curveData
.points
+ 5);
838 lua_pushstring(L
, "y");
840 int8_t * point
= curveAddress(idx
);
841 for (int i
=0; i
< curveData
.points
+ 5; i
++) {
842 lua_pushinteger(L
, i
);
843 lua_pushinteger(L
, *point
++);
847 if (curveData
.type
== CURVE_TYPE_CUSTOM
) {
848 lua_pushstring(L
, "x");
850 lua_pushinteger(L
, 0);
851 lua_pushinteger(L
, -100);
853 for (int i
=0; i
< curveData
.points
+ 3; i
++) {
854 lua_pushinteger(L
, i
+1);
855 lua_pushinteger(L
, *point
++);
858 lua_pushinteger(L
, curveData
.points
+ 4);
859 lua_pushinteger(L
, 100);
871 @function model.setCurve(curve, params)
875 @param curve (unsigned number) curve number (use 0 for Curve1)
877 @param params see model.getCurve return format for table format. setCurve uses standard
878 lua array indexing and arrays start at index 1
880 The first and last x value must -100 and 100 and x values must be monotonically increasing
882 @retval 0 - Everything okay
883 1 - Wrong number of points
884 2 - Invalid Curve number
885 3 - Cuve does not fit anymore
886 4 - point of out of index
887 5 - x value not monotonically increasing
888 6 - y value not in range [-100;100]
889 7 - extra values for y are set
890 8 - extra values for x are set
892 @status current Introduced in 2.2.0
894 Example setting a 4-point custom curve:
897 params["x"] = {-100, -34, 77, 100}
898 params["y"] = {-70, 20, -89, -100}
899 params["smooth"] = true
901 val = model.setCurve(2, params)
903 setting a 6-point standard smoothed curve
905 val = model.setCurve(3, {smooth=true, y={-100, -50, 0, 50, 100, 80}})
909 static int luaModelSetCurve(lua_State
*L
)
911 unsigned int curveIdx
= luaL_checkunsigned(L
, 1);
913 if (curveIdx
>= MAX_CURVES
) {
914 lua_pushinteger(L
, 2);
917 int8_t xPoints
[MAX_POINTS_PER_CURVE
];
918 int8_t yPoints
[MAX_POINTS_PER_CURVE
];
920 // Init to invalid values
921 memset(xPoints
, -127, sizeof(xPoints
));
922 memset(yPoints
, -127, sizeof(yPoints
));
925 CurveData
&destCurveData
= g_model
.curves
[curveIdx
];
926 CurveData newCurveData
;
927 memclear(&newCurveData
, sizeof(CurveData
));
929 luaL_checktype(L
, -1, LUA_TTABLE
);
930 for (lua_pushnil(L
); lua_next(L
, -2); lua_pop(L
, 1)) {
931 luaL_checktype(L
, -2, LUA_TSTRING
); // key is string
932 const char *key
= luaL_checkstring(L
, -2);
933 if (!strcmp(key
, "name")) {
934 const char *name
= luaL_checkstring(L
, -1);
935 str2zchar(newCurveData
.name
, name
, sizeof(newCurveData
.name
));
937 else if (!strcmp(key
, "type")) {
938 newCurveData
.type
= luaL_checkinteger(L
, -1);
940 else if (!strcmp(key
, "smooth")) {
941 // Earlier version of this api expected a 0/1 integer instead of a boolean
942 // Still accept a 0/1 here
943 if (lua_isboolean(L
,-1))
944 newCurveData
.smooth
= lua_toboolean(L
, -1);
946 newCurveData
.smooth
= luaL_checkinteger(L
, -1);
948 else if (!strcmp(key
, "x") || !strcmp(key
, "y")) {
949 luaL_checktype(L
, -1, LUA_TTABLE
);
950 bool isX
= !strcmp(key
, "x");
952 for (lua_pushnil(L
); lua_next(L
, -2); lua_pop(L
, 1)) {
953 int idx
= luaL_checkinteger(L
, -2)-1;
954 if (idx
< 0 || idx
> MAX_POINTS_PER_CURVE
) {
955 lua_pushinteger(L
, 4);
958 int8_t val
= luaL_checkinteger(L
, -1);
959 if (val
< -100 || val
> 100) {
960 lua_pushinteger(L
, 6);
970 // Check how many points are set
974 } while (yPoints
[numPoints
]!=-127 && numPoints
< MAX_POINTS_PER_CURVE
);
975 newCurveData
.points
= numPoints
- 5;
977 if (numPoints
< MIN_POINTS_PER_CURVE
|| numPoints
> MAX_POINTS_PER_CURVE
) {
978 lua_pushinteger(L
, 1);
982 if (newCurveData
.type
== CURVE_TYPE_CUSTOM
) {
984 // The rest of the points are checked by the monotonic condition
985 for (unsigned int i
=numPoints
; i
< sizeof(xPoints
);i
++)
987 if (xPoints
[i
] != -127)
989 lua_pushinteger(L
, 8);
994 // Check first and last point
995 if (xPoints
[0] != -100 || xPoints
[newCurveData
.points
+ 4] != 100) {
996 lua_pushinteger(L
, 5);
1000 // Check that x values are increasing
1001 for (int i
= 1; i
< numPoints
; i
++) {
1002 if (xPoints
[i
- 1] > xPoints
[i
]) {
1003 lua_pushinteger(L
, 5);
1009 // Check that ypoints have the right number of points set
1010 for (int i
=0; i
< 5 + newCurveData
.points
;i
++)
1012 if (yPoints
[i
] == -127)
1014 lua_pushinteger(L
, 7);
1019 // Calculate size of curve we replace
1020 int oldCurveMemSize
;
1021 if (destCurveData
.type
== CURVE_TYPE_STANDARD
) {
1022 oldCurveMemSize
= 5 + destCurveData
.points
;
1025 oldCurveMemSize
= 8 + 2 * destCurveData
.points
;
1028 // Calculate own size
1029 int newCurveMemSize
;
1030 if (newCurveData
.type
== CURVE_TYPE_STANDARD
)
1031 newCurveMemSize
= 5 + newCurveData
.points
;
1033 newCurveMemSize
= 8 + 2 * newCurveData
.points
;
1035 int shift
= newCurveMemSize
- oldCurveMemSize
;
1037 // Also checks if new curve size would fit
1038 if (!moveCurve(curveIdx
, shift
)) {
1039 lua_pushinteger(L
, 3);
1040 TRACE("curve shift is %d", shift
);
1044 // Curve fits into mem, fill new curve
1045 destCurveData
= newCurveData
;
1047 int8_t *point
= curveAddress(curveIdx
);
1048 for (int i
= 0; i
< destCurveData
.points
+ 5; i
++) {
1049 *point
++ = yPoints
[i
];
1052 if (destCurveData
.type
== CURVE_TYPE_CUSTOM
) {
1053 for (int i
= 1; i
< destCurveData
.points
+ 4; i
++) {
1054 *point
++ = xPoints
[i
];
1057 storageDirty(EE_MODEL
);
1059 lua_pushinteger(L
, 0);
1064 @function model.getCustomFunction(function)
1066 Get Custom Function parameters
1068 @param function (unsigned number) custom function number (use 0 for CF1)
1070 @retval nil requested custom function does not exist
1072 @retval table custom function data:
1073 * `switch` (number) switch index
1074 * `func` (number) function index
1075 * `name` (string) Name of track to play (only returned only returned if action is play track, sound or script)
1076 * `value` (number) value (only returned only returned if action is **not** play track, sound or script)
1077 * `mode` (number) mode (only returned only returned if action is **not** play track, sound or script)
1078 * `param` (number) parameter (only returned only returned if action is **not** play track, sound or script)
1079 * `active` (number) 0 = disabled, 1 = enabled
1081 @status current Introduced in 2.0.0, TODO rename function
1083 static int luaModelGetCustomFunction(lua_State
*L
)
1085 unsigned int idx
= luaL_checkunsigned(L
, 1);
1086 if (idx
< MAX_SPECIAL_FUNCTIONS
) {
1087 CustomFunctionData
* cfn
= &g_model
.customFn
[idx
];
1089 lua_pushtableinteger(L
, "switch", CFN_SWITCH(cfn
));
1090 lua_pushtableinteger(L
, "func", CFN_FUNC(cfn
));
1091 if (CFN_FUNC(cfn
) == FUNC_PLAY_TRACK
|| CFN_FUNC(cfn
) == FUNC_BACKGND_MUSIC
|| CFN_FUNC(cfn
) == FUNC_PLAY_SCRIPT
) {
1092 lua_pushtablenzstring(L
, "name", cfn
->play
.name
);
1095 lua_pushtableinteger(L
, "value", cfn
->all
.val
);
1096 lua_pushtableinteger(L
, "mode", cfn
->all
.mode
);
1097 lua_pushtableinteger(L
, "param", cfn
->all
.param
);
1099 lua_pushtableinteger(L
, "active", CFN_ACTIVE(cfn
));
1108 @function model.setCustomFunction(function, value)
1110 Set Custom Function parameters
1112 @param function (unsigned number) custom function number (use 0 for CF1)
1114 @param value (table) custom function parameters, see model.getCustomFunction() for table format
1116 @notice If a parameter is missing from the value, then
1117 that parameter remains unchanged.
1119 @status current Introduced in 2.0.0, TODO rename function
1121 static int luaModelSetCustomFunction(lua_State
*L
)
1123 unsigned int idx
= luaL_checkunsigned(L
, 1);
1124 if (idx
< MAX_SPECIAL_FUNCTIONS
) {
1125 CustomFunctionData
* cfn
= &g_model
.customFn
[idx
];
1126 memclear(cfn
, sizeof(CustomFunctionData
));
1127 luaL_checktype(L
, -1, LUA_TTABLE
);
1128 for (lua_pushnil(L
); lua_next(L
, -2); lua_pop(L
, 1)) {
1129 luaL_checktype(L
, -2, LUA_TSTRING
); // key is string
1130 const char * key
= luaL_checkstring(L
, -2);
1131 if (!strcmp(key
, "switch")) {
1132 CFN_SWITCH(cfn
) = luaL_checkinteger(L
, -1);
1134 else if (!strcmp(key
, "func")) {
1135 CFN_FUNC(cfn
) = luaL_checkinteger(L
, -1);
1137 else if (!strcmp(key
, "name")) {
1138 const char * name
= luaL_checkstring(L
, -1);
1139 strncpy(cfn
->play
.name
, name
, sizeof(cfn
->play
.name
));
1141 else if (!strcmp(key
, "value")) {
1142 cfn
->all
.val
= luaL_checkinteger(L
, -1);
1144 else if (!strcmp(key
, "mode")) {
1145 cfn
->all
.mode
= luaL_checkinteger(L
, -1);
1147 else if (!strcmp(key
, "param")) {
1148 cfn
->all
.param
= luaL_checkinteger(L
, -1);
1150 else if (!strcmp(key
, "active")) {
1151 CFN_ACTIVE(cfn
) = luaL_checkinteger(L
, -1);
1154 storageDirty(EE_MODEL
);
1161 @function model.getOutput(index)
1163 Get servo parameters
1165 @param index (unsigned number) output number (use 0 for CH1)
1167 @retval nil requested output does not exist
1169 @retval table output parameters:
1170 * `name` (string) name
1171 * `min` (number) Minimum % * 10
1172 * `max` (number) Maximum % * 10
1173 * `offset` (number) Subtrim * 10
1174 * `ppmCenter` (number) offset from PPM Center. 0 = 1500
1175 * `symetrical` (number) linear Subtrim 0 = Off, 1 = On
1176 * `revert` (number) irection 0 = ---, 1 = INV
1178 * (number) Curve number (0 for Curve1)
1179 * or `nil` if no curve set
1181 @status current Introduced in 2.0.0
1183 static int luaModelGetOutput(lua_State
*L
)
1185 unsigned int idx
= luaL_checkunsigned(L
, 1);
1186 if (idx
< MAX_OUTPUT_CHANNELS
) {
1187 LimitData
* limit
= limitAddress(idx
);
1189 lua_pushtablezstring(L
, "name", limit
->name
);
1190 lua_pushtableinteger(L
, "min", limit
->min
-1000);
1191 lua_pushtableinteger(L
, "max", limit
->max
+1000);
1192 lua_pushtableinteger(L
, "offset", limit
->offset
);
1193 lua_pushtableinteger(L
, "ppmCenter", limit
->ppmCenter
);
1194 lua_pushtableinteger(L
, "symetrical", limit
->symetrical
);
1195 lua_pushtableinteger(L
, "revert", limit
->revert
);
1197 lua_pushtableinteger(L
, "curve", limit
->curve
-1);
1206 @function model.setOutput(index, value)
1208 Set servo parameters
1210 @param index (unsigned number) channel number (use 0 for CH1)
1212 @param value (table) servo parameters, see model.getOutput() for table format
1214 @notice If a parameter is missing from the value, then
1215 that parameter remains unchanged.
1217 @status current Introduced in 2.0.0
1219 static int luaModelSetOutput(lua_State
*L
)
1221 unsigned int idx
= luaL_checkunsigned(L
, 1);
1222 if (idx
< MAX_OUTPUT_CHANNELS
) {
1223 LimitData
* limit
= limitAddress(idx
);
1224 memclear(limit
, sizeof(LimitData
));
1225 luaL_checktype(L
, -1, LUA_TTABLE
);
1226 for (lua_pushnil(L
); lua_next(L
, -2); lua_pop(L
, 1)) {
1227 luaL_checktype(L
, -2, LUA_TSTRING
); // key is string
1228 const char * key
= luaL_checkstring(L
, -2);
1229 if (!strcmp(key
, "name")) {
1230 const char * name
= luaL_checkstring(L
, -1);
1231 str2zchar(limit
->name
, name
, sizeof(limit
->name
));
1233 else if (!strcmp(key
, "min")) {
1234 limit
->min
= luaL_checkinteger(L
, -1)+1000;
1236 else if (!strcmp(key
, "max")) {
1237 limit
->max
= luaL_checkinteger(L
, -1)-1000;
1239 else if (!strcmp(key
, "offset")) {
1240 limit
->offset
= luaL_checkinteger(L
, -1);
1242 else if (!strcmp(key
, "ppmCenter")) {
1243 limit
->ppmCenter
= luaL_checkinteger(L
, -1);
1245 else if (!strcmp(key
, "symetrical")) {
1246 limit
->symetrical
= luaL_checkinteger(L
, -1);
1248 else if (!strcmp(key
, "revert")) {
1249 limit
->revert
= luaL_checkinteger(L
, -1);
1251 else if (!strcmp(key
, "curve")) {
1252 limit
->curve
= luaL_checkinteger(L
, -1) + 1;
1255 storageDirty(EE_MODEL
);
1262 @function model.getGlobalVariable(index [, flight_mode])
1264 Return current global variable value
1266 @notice a simple warning or notice
1268 @param index zero based global variable index, use 0 for GV1, 8 for GV9
1270 @param flight_mode Flight mode number (0 = FM0, 8 = FM8)
1272 @retval nil requested global variable does not exist
1274 @retval number current value of global variable
1279 -- get GV3 (index = 2) from Flight mode 0 (FM0)
1280 val = model.getGlobalVariable(2, 0)
1283 static int luaModelGetGlobalVariable(lua_State
*L
)
1285 unsigned int idx
= luaL_checkunsigned(L
, 1);
1286 unsigned int phase
= luaL_checkunsigned(L
, 2);
1287 if (phase
< MAX_FLIGHT_MODES
&& idx
< MAX_GVARS
)
1288 lua_pushinteger(L
, g_model
.flightModeData
[phase
].gvars
[idx
]);
1295 @function model.setGlobalVariable(index, flight_mode, value)
1297 Sets current global variable value. See also model.getGlobalVariable()
1299 @param index zero based global variable index, use 0 for GV1, 8 for GV9
1301 @param flight_mode Flight mode number (0 = FM0, 8 = FM8)
1303 @param value new value for global variable. Permitted range is
1306 @notice Global variable can only store integer values,
1307 any floating point value is converted into integer value
1308 by truncating everything behind a floating point.
1310 static int luaModelSetGlobalVariable(lua_State
*L
)
1312 unsigned int idx
= luaL_checkunsigned(L
, 1);
1313 unsigned int phase
= luaL_checkunsigned(L
, 2);
1314 int value
= luaL_checkinteger(L
, 3);
1315 if (phase
< MAX_FLIGHT_MODES
&& idx
< MAX_GVARS
&& value
>= -GVAR_MAX
&& value
<= GVAR_MAX
) {
1316 g_model
.flightModeData
[phase
].gvars
[idx
] = value
;
1317 storageDirty(EE_MODEL
);
1323 @function model.getSensor(sensor)
1325 Get Telemetry Sensor parameters
1327 @param sensor (unsigned number) sensor number (use 0 for sensor 1)
1329 @retval nil requested logical switch does not exist
1331 @retval table logical switch data:
1332 * `func` (number) function index
1333 * `v1` (number) V1 value (index)
1334 * `v2` (number) V2 value (index or value)
1335 * `v3` (number) V3 value (index or value)
1336 * `and` (number) AND switch index
1337 * `delay` (number) delay (time in 1/10 s)
1338 * `duration` (number) duration (time in 1/10 s)
1340 @status current Introduced in 2.3.0
1342 static int luaModelGetSensor(lua_State
*L
)
1344 unsigned int idx
= luaL_checkunsigned(L
, 1);
1345 if (idx
< MAX_TELEMETRY_SENSORS
) {
1346 TelemetrySensor
& sensor
= g_model
.telemetrySensors
[idx
];
1348 lua_pushtableinteger(L
, "type", sensor
.type
);
1349 lua_pushtablezstring(L
, "name", sensor
.label
);
1350 lua_pushtableinteger(L
, "unit", sensor
.unit
);
1351 lua_pushtableinteger(L
, "prec", sensor
.prec
);
1352 if (sensor
.type
== TELEM_TYPE_CUSTOM
) {
1353 lua_pushtableinteger(L
, "id", sensor
.id
);
1354 lua_pushtableinteger(L
, "instance", sensor
.instance
);
1357 lua_pushtableinteger(L
, "formula", sensor
.formula
);
1366 const luaL_Reg modelLib
[] = {
1367 { "getInfo", luaModelGetInfo
},
1368 { "setInfo", luaModelSetInfo
},
1369 { "getModule", luaModelGetModule
},
1370 { "setModule", luaModelSetModule
},
1371 { "getTimer", luaModelGetTimer
},
1372 { "setTimer", luaModelSetTimer
},
1373 { "resetTimer", luaModelResetTimer
},
1374 { "getInputsCount", luaModelGetInputsCount
},
1375 { "getInput", luaModelGetInput
},
1376 { "insertInput", luaModelInsertInput
},
1377 { "deleteInput", luaModelDeleteInput
},
1378 { "deleteInputs", luaModelDeleteInputs
},
1379 { "defaultInputs", luaModelDefaultInputs
},
1380 { "getMixesCount", luaModelGetMixesCount
},
1381 { "getMix", luaModelGetMix
},
1382 { "insertMix", luaModelInsertMix
},
1383 { "deleteMix", luaModelDeleteMix
},
1384 { "deleteMixes", luaModelDeleteMixes
},
1385 { "getLogicalSwitch", luaModelGetLogicalSwitch
},
1386 { "setLogicalSwitch", luaModelSetLogicalSwitch
},
1387 { "getCustomFunction", luaModelGetCustomFunction
},
1388 { "setCustomFunction", luaModelSetCustomFunction
},
1389 { "getCurve", luaModelGetCurve
},
1390 { "setCurve", luaModelSetCurve
},
1391 { "getOutput", luaModelGetOutput
},
1392 { "setOutput", luaModelSetOutput
},
1393 { "getGlobalVariable", luaModelGetGlobalVariable
},
1394 { "setGlobalVariable", luaModelSetGlobalVariable
},
1395 { "getSensor", luaModelGetSensor
},
1396 { NULL
, NULL
} /* sentinel */