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 * `rfProtocol` (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
, "rfProtocol", module
.rfProtocol
);
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
, "rfProtocol")) {
149 module
.rfProtocol
= 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
337 @status current Introduced in 2.0.0, `switch` added in TODO
339 static int luaModelGetInput(lua_State
*L
)
341 unsigned int chn
= luaL_checkunsigned(L
, 1);
342 unsigned int idx
= luaL_checkunsigned(L
, 2);
343 unsigned int first
= getFirstInput(chn
);
344 unsigned int count
= getInputsCountFromFirst(chn
, first
);
346 ExpoData
* expo
= expoAddress(first
+idx
);
348 lua_pushtablezstring(L
, "name", expo
->name
);
349 lua_pushtableinteger(L
, "source", expo
->srcRaw
);
350 lua_pushtableinteger(L
, "weight", expo
->weight
);
351 lua_pushtableinteger(L
, "offset", expo
->offset
);
352 lua_pushtableinteger(L
, "switch", expo
->swtch
);
361 @function model.insertInput(input, line, value)
363 Insert an Input at specified line
365 @param input (unsigned number) input number (use 0 for Input1)
367 @param line (unsigned number) input line (use 0 for first line)
369 @param value (table) input data, see model.getInput()
371 @status current Introduced in 2.0.0, `switch` added in TODO
373 static int luaModelInsertInput(lua_State
*L
)
375 unsigned int chn
= luaL_checkunsigned(L
, 1);
376 unsigned int idx
= luaL_checkunsigned(L
, 2);
378 unsigned int first
= getFirstInput(chn
);
379 unsigned int count
= getInputsCountFromFirst(chn
, first
);
381 if (chn
<MAX_INPUTS
&& getExposCount()<MAX_EXPOS
&& idx
<=count
) {
385 ExpoData
* expo
= expoAddress(idx
);
386 luaL_checktype(L
, -1, LUA_TTABLE
);
387 for (lua_pushnil(L
); lua_next(L
, -2); lua_pop(L
, 1)) {
388 luaL_checktype(L
, -2, LUA_TSTRING
); // key is string
389 const char * key
= luaL_checkstring(L
, -2);
390 if (!strcmp(key
, "name")) {
391 const char * name
= luaL_checkstring(L
, -1);
392 str2zchar(expo
->name
, name
, sizeof(expo
->name
));
394 else if (!strcmp(key
, "source")) {
395 expo
->srcRaw
= luaL_checkinteger(L
, -1);
397 else if (!strcmp(key
, "weight")) {
398 expo
->weight
= luaL_checkinteger(L
, -1);
400 else if (!strcmp(key
, "offset")) {
401 expo
->offset
= luaL_checkinteger(L
, -1);
403 else if (!strcmp(key
, "switch")) {
404 expo
->swtch
= luaL_checkinteger(L
, -1);
413 @function model.deleteInput(input, line)
415 Delete line from specified input
417 @param input (unsigned number) input number (use 0 for Input1)
419 @param line (unsigned number) input line (use 0 for first line)
421 @status current Introduced in 2.0.0
423 static int luaModelDeleteInput(lua_State
*L
)
425 unsigned int chn
= luaL_checkunsigned(L
, 1);
426 unsigned int idx
= luaL_checkunsigned(L
, 2);
428 int first
= getFirstInput(chn
);
429 unsigned int count
= getInputsCountFromFirst(chn
, first
);
432 deleteExpo(first
+idx
);
439 @function model.deleteInputs()
443 @status current Introduced in 2.0.0
445 static int luaModelDeleteInputs(lua_State
*L
)
452 @function model.defaultInputs()
454 Set all inputs to defaults
456 @status current Introduced in 2.0.0
458 static int luaModelDefaultInputs(lua_State
*L
)
464 static unsigned int getFirstMix(unsigned int chn
)
466 for (unsigned int i
=0; i
<MAX_MIXERS
; i
++) {
467 MixData
* mix
= mixAddress(i
);
468 if (!mix
->srcRaw
|| mix
->destCh
>=chn
) {
475 static unsigned int getMixesCountFromFirst(unsigned int chn
, unsigned int first
)
477 unsigned int count
= 0;
478 for (unsigned int i
=first
; i
<MAX_MIXERS
; i
++) {
479 MixData
* mix
= mixAddress(i
);
480 if (!mix
->srcRaw
|| mix
->destCh
!=chn
) break;
486 static unsigned int getMixesCount(unsigned int chn
)
488 return getMixesCountFromFirst(chn
, getFirstMix(chn
));
492 @function model.getMixesCount(channel)
494 Get the number of Mixer lines that the specified Channel has
496 @param channel (unsigned number) channel number (use 0 for CH1)
498 @retval number number of mixes for requested channel
500 @status current Introduced in 2.0.0
502 static int luaModelGetMixesCount(lua_State
*L
)
504 unsigned int chn
= luaL_checkunsigned(L
, 1);
505 unsigned int count
= getMixesCount(chn
);
506 lua_pushinteger(L
, count
);
511 @function model.getMix(channel, line)
513 Get configuration for specified Mix
515 @param channel (unsigned number) channel number (use 0 for CH1)
517 @param line (unsigned number) mix number (use 0 for first line(mix))
519 @retval nil requested channel or line does not exist
521 @retval table mix data:
522 * `name` (string) mix line name
523 * `source` (number) source index
524 * `weight` (number) weight (1024 == 100%) value or GVAR1..9 = 4096..4011, -GVAR1..9 = 4095..4087
525 * `offset` (number) offset value or GVAR1..9 = 4096..4011, -GVAR1..9 = 4095..4087
526 * `switch` (number) switch index
527 * `multiplex` (number) multiplex (0 = ADD, 1 = MULTIPLY, 2 = REPLACE)
528 * `curveType` (number) curve type (function, expo, custom curve)
529 * `curveValue` (number) curve index
530 * `flightModes` (number) bit-mask of active flight modes
531 * `carryTrim` (boolean) carry trim
532 * `mixWarn` (number) warning (0 = off, 1 = 1 beep, .. 3 = 3 beeps)
533 * `delayUp` (number) delay up (time in 1/10 s)
534 * `delayDown` (number) delay down
535 * `speedUp` (number) speed up
536 * `speedDown` (number) speed down
538 @status current Introduced in 2.0.0, parameters below `multiplex` added in 2.0.13
540 static int luaModelGetMix(lua_State
*L
)
542 unsigned int chn
= luaL_checkunsigned(L
, 1);
543 unsigned int idx
= luaL_checkunsigned(L
, 2);
544 unsigned int first
= getFirstMix(chn
);
545 unsigned int count
= getMixesCountFromFirst(chn
, first
);
547 MixData
* mix
= mixAddress(first
+idx
);
549 lua_pushtablezstring(L
, "name", mix
->name
);
550 lua_pushtableinteger(L
, "source", mix
->srcRaw
);
551 lua_pushtableinteger(L
, "weight", mix
->weight
);
552 lua_pushtableinteger(L
, "offset", mix
->offset
);
553 lua_pushtableinteger(L
, "switch", mix
->swtch
);
554 lua_pushtableinteger(L
, "curveType", mix
->curve
.type
);
555 lua_pushtableinteger(L
, "curveValue", mix
->curve
.value
);
556 lua_pushtableinteger(L
, "multiplex", mix
->mltpx
);
557 lua_pushtableinteger(L
, "flightModes", mix
->flightModes
);
558 lua_pushtableboolean(L
, "carryTrim", mix
->carryTrim
);
559 lua_pushtableinteger(L
, "mixWarn", mix
->mixWarn
);
560 lua_pushtableinteger(L
, "delayUp", mix
->delayUp
);
561 lua_pushtableinteger(L
, "delayDown", mix
->delayDown
);
562 lua_pushtableinteger(L
, "speedUp", mix
->speedUp
);
563 lua_pushtableinteger(L
, "speedDown", mix
->speedDown
);
572 @function model.insertMix(channel, line, value)
574 Insert a mixer line into Channel
576 @param channel (unsigned number) channel number (use 0 for CH1)
578 @param line (unsigned number) mix number (use 0 for first line(mix))
580 @param value (table) see model.getMix() for table format
582 @status current Introduced in 2.0.0, parameters below `multiplex` added in 2.0.13
584 static int luaModelInsertMix(lua_State
*L
)
586 unsigned int chn
= luaL_checkunsigned(L
, 1);
587 unsigned int idx
= luaL_checkunsigned(L
, 2);
589 unsigned int first
= getFirstMix(chn
);
590 unsigned int count
= getMixesCountFromFirst(chn
, first
);
592 if (chn
<MAX_OUTPUT_CHANNELS
&& getMixesCount()<MAX_MIXERS
&& idx
<=count
) {
596 MixData
*mix
= mixAddress(idx
);
597 luaL_checktype(L
, -1, LUA_TTABLE
);
598 for (lua_pushnil(L
); lua_next(L
, -2); lua_pop(L
, 1)) {
599 luaL_checktype(L
, -2, LUA_TSTRING
); // key is string
600 const char * key
= luaL_checkstring(L
, -2);
601 if (!strcmp(key
, "name")) {
602 const char * name
= luaL_checkstring(L
, -1);
603 str2zchar(mix
->name
, name
, sizeof(mix
->name
));
605 else if (!strcmp(key
, "source")) {
606 mix
->srcRaw
= luaL_checkinteger(L
, -1);
608 else if (!strcmp(key
, "weight")) {
609 mix
->weight
= luaL_checkinteger(L
, -1);
611 else if (!strcmp(key
, "offset")) {
612 mix
->offset
= luaL_checkinteger(L
, -1);
614 else if (!strcmp(key
, "switch")) {
615 mix
->swtch
= luaL_checkinteger(L
, -1);
617 else if (!strcmp(key
, "curveType")) {
618 mix
->curve
.type
= luaL_checkinteger(L
, -1);
620 else if (!strcmp(key
, "curveValue")) {
621 mix
->curve
.value
= luaL_checkinteger(L
, -1);
623 else if (!strcmp(key
, "multiplex")) {
624 mix
->mltpx
= luaL_checkinteger(L
, -1);
626 else if (!strcmp(key
, "flightModes")) {
627 mix
->flightModes
= luaL_checkinteger(L
, -1);
629 else if (!strcmp(key
, "carryTrim")) {
630 mix
->carryTrim
= lua_toboolean(L
, -1);
632 else if (!strcmp(key
, "mixWarn")) {
633 mix
->mixWarn
= luaL_checkinteger(L
, -1);
635 else if (!strcmp(key
, "delayUp")) {
636 mix
->delayUp
= luaL_checkinteger(L
, -1);
638 else if (!strcmp(key
, "delayDown")) {
639 mix
->delayDown
= luaL_checkinteger(L
, -1);
641 else if (!strcmp(key
, "speedUp")) {
642 mix
->speedUp
= luaL_checkinteger(L
, -1);
644 else if (!strcmp(key
, "speedDown")) {
645 mix
->speedDown
= luaL_checkinteger(L
, -1);
654 @function model.deleteMix(channel, line)
656 Delete mixer line from specified Channel
658 @param channel (unsigned number) channel number (use 0 for CH1)
660 @param line (unsigned number) mix number (use 0 for first line(mix))
662 @status current Introduced in 2.0.0
664 static int luaModelDeleteMix(lua_State
*L
)
666 unsigned int chn
= luaL_checkunsigned(L
, 1);
667 unsigned int idx
= luaL_checkunsigned(L
, 2);
669 unsigned int first
= getFirstMix(chn
);
670 unsigned int count
= getMixesCountFromFirst(chn
, first
);
673 deleteMix(first
+idx
);
680 @function model.deleteMixes()
684 @status current Introduced in 2.0.0
686 static int luaModelDeleteMixes(lua_State
*L
)
688 memset(g_model
.mixData
, 0, sizeof(g_model
.mixData
));
693 @function model.getLogicalSwitch(switch)
695 Get Logical Switch parameters
697 @param switch (unsigned number) logical switch number (use 0 for LS1)
699 @retval nil requested logical switch does not exist
701 @retval table logical switch data:
702 * `func` (number) function index
703 * `v1` (number) V1 value (index)
704 * `v2` (number) V2 value (index or value)
705 * `v3` (number) V3 value (index or value)
706 * `and` (number) AND switch index
707 * `delay` (number) delay (time in 1/10 s)
708 * `duration` (number) duration (time in 1/10 s)
710 @status current Introduced in 2.0.0
712 static int luaModelGetLogicalSwitch(lua_State
*L
)
714 unsigned int idx
= luaL_checkunsigned(L
, 1);
715 if (idx
< MAX_LOGICAL_SWITCHES
) {
716 LogicalSwitchData
* sw
= lswAddress(idx
);
718 lua_pushtableinteger(L
, "func", sw
->func
);
719 lua_pushtableinteger(L
, "v1", sw
->v1
);
720 lua_pushtableinteger(L
, "v2", sw
->v2
);
721 lua_pushtableinteger(L
, "v3", sw
->v3
);
722 lua_pushtableinteger(L
, "and", sw
->andsw
);
723 lua_pushtableinteger(L
, "delay", sw
->delay
);
724 lua_pushtableinteger(L
, "duration", sw
->duration
);
733 @function model.setLogicalSwitch(switch, value)
735 Set Logical Switch parameters
737 @param switch (unsigned number) logical switch number (use 0 for LS1)
739 @param value (table) see model.getLogicalSwitch() for table format
741 @notice If a parameter is missing from the value, then
742 that parameter remains unchanged.
744 @notice To set the `and` member (which is Lua keyword)
745 use the following syntax: `model.setLogicalSwitch(30, {func=4,v1=1,v2=-99, ["and"]=24})`
747 @status current Introduced in 2.0.0
749 static int luaModelSetLogicalSwitch(lua_State
*L
)
751 unsigned int idx
= luaL_checkunsigned(L
, 1);
752 if (idx
< MAX_LOGICAL_SWITCHES
) {
753 LogicalSwitchData
* sw
= lswAddress(idx
);
754 memclear(sw
, sizeof(LogicalSwitchData
));
755 luaL_checktype(L
, -1, LUA_TTABLE
);
756 for (lua_pushnil(L
); lua_next(L
, -2); lua_pop(L
, 1)) {
757 luaL_checktype(L
, -2, LUA_TSTRING
); // key is string
758 const char * key
= luaL_checkstring(L
, -2);
759 if (!strcmp(key
, "func")) {
760 sw
->func
= luaL_checkinteger(L
, -1);
762 else if (!strcmp(key
, "v1")) {
763 sw
->v1
= luaL_checkinteger(L
, -1);
765 else if (!strcmp(key
, "v2")) {
766 sw
->v2
= luaL_checkinteger(L
, -1);
768 else if (!strcmp(key
, "v3")) {
769 sw
->v3
= luaL_checkinteger(L
, -1);
771 else if (!strcmp(key
, "and")) {
772 sw
->andsw
= luaL_checkinteger(L
, -1);
774 else if (!strcmp(key
, "delay")) {
775 sw
->delay
= luaL_checkinteger(L
, -1);
777 else if (!strcmp(key
, "duration")) {
778 sw
->duration
= luaL_checkinteger(L
, -1);
781 storageDirty(EE_MODEL
);
788 @function model.getCurve(curve)
792 @param curve (unsigned number) curve number (use 0 for Curve1)
794 @retval nil requested curve does not exist
796 @retval table curve data:
797 * `name` (string) name
798 * `type` (number) type
799 * `smooth` (boolean) smooth
800 * `points` (number) number of points
801 * `y` (table) table of Y values:
802 * `key` is point number (zero based)
804 * `x` (table) **only included for custom curve type**:
805 * `key` is point number (zero based)
808 Note that functions returns the tables starting with index 0 contrary to LUA's
809 usual index starting with 1
811 @status current Introduced in 2.0.12
813 static int luaModelGetCurve(lua_State
*L
)
815 unsigned int idx
= luaL_checkunsigned(L
, 1);
816 if (idx
< MAX_CURVES
) {
817 CurveData
& curveData
= g_model
.curves
[idx
];
819 lua_pushtablezstring(L
, "name", curveData
.name
);
820 lua_pushtableinteger(L
, "type", curveData
.type
);
821 lua_pushtableboolean(L
, "smooth", curveData
.smooth
);
822 lua_pushtableinteger(L
, "points", curveData
.points
+ 5);
823 lua_pushstring(L
, "y");
825 int8_t * point
= curveAddress(idx
);
826 for (int i
=0; i
< curveData
.points
+ 5; i
++) {
827 lua_pushinteger(L
, i
);
828 lua_pushinteger(L
, *point
++);
832 if (curveData
.type
== CURVE_TYPE_CUSTOM
) {
833 lua_pushstring(L
, "x");
835 lua_pushinteger(L
, 0);
836 lua_pushinteger(L
, -100);
838 for (int i
=0; i
< curveData
.points
+ 3; i
++) {
839 lua_pushinteger(L
, i
+1);
840 lua_pushinteger(L
, *point
++);
843 lua_pushinteger(L
, curveData
.points
+ 4);
844 lua_pushinteger(L
, 100);
856 @function model.setCurve(curve, params)
860 @param curve (unsigned number) curve number (use 0 for Curve1)
862 @param params see model.getCurve return format for table format. setCurve uses standard
863 lua array indexing and arrays start at index 1
865 The first and last x value must -100 and 100 and x values must be monotonically increasing
867 @retval 0 - Everything okay
868 1 - Wrong number of points
869 2 - Invalid Curve number
870 3 - Cuve does not fit anymore
871 4 - point of out of index
872 5 - x value not monotonically increasing
873 6 - y value not in range [-100;100]
874 7 - extra values for y are set
875 8 - extra values for x are set
877 @status current Introduced in 2.2.0
879 Example setting a 4-point custom curve:
882 params["x"] = {-100, -34, 77, 100}
883 params["y"] = {-70, 20, -89, -100}
884 params["smooth"] = true
886 val = model.setCurve(2, params)
888 setting a 6-point standard smoothed curve
890 val = model.setCurve(3, {smooth=true, y={-100, -50, 0, 50, 100, 80}})
894 static int luaModelSetCurve(lua_State
*L
)
896 unsigned int curveIdx
= luaL_checkunsigned(L
, 1);
898 if (curveIdx
>= MAX_CURVES
) {
899 lua_pushinteger(L
, 2);
902 int8_t xPoints
[MAX_POINTS_PER_CURVE
];
903 int8_t yPoints
[MAX_POINTS_PER_CURVE
];
905 // Init to invalid values
906 memset(xPoints
, -127, sizeof(xPoints
));
907 memset(yPoints
, -127, sizeof(yPoints
));
910 CurveData
&destCurveData
= g_model
.curves
[curveIdx
];
911 CurveData newCurveData
;
912 memclear(&newCurveData
, sizeof(CurveData
));
914 luaL_checktype(L
, -1, LUA_TTABLE
);
915 for (lua_pushnil(L
); lua_next(L
, -2); lua_pop(L
, 1)) {
916 luaL_checktype(L
, -2, LUA_TSTRING
); // key is string
917 const char *key
= luaL_checkstring(L
, -2);
918 if (!strcmp(key
, "name")) {
919 const char *name
= luaL_checkstring(L
, -1);
920 str2zchar(newCurveData
.name
, name
, sizeof(newCurveData
.name
));
922 else if (!strcmp(key
, "type")) {
923 newCurveData
.type
= luaL_checkinteger(L
, -1);
925 else if (!strcmp(key
, "smooth")) {
926 // Earlier version of this api expected a 0/1 integer instead of a boolean
927 // Still accept a 0/1 here
928 if (lua_isboolean(L
,-1))
929 newCurveData
.smooth
= lua_toboolean(L
, -1);
931 newCurveData
.smooth
= luaL_checkinteger(L
, -1);
933 else if (!strcmp(key
, "x") || !strcmp(key
, "y")) {
934 luaL_checktype(L
, -1, LUA_TTABLE
);
935 bool isX
= !strcmp(key
, "x");
937 for (lua_pushnil(L
); lua_next(L
, -2); lua_pop(L
, 1)) {
938 int idx
= luaL_checkinteger(L
, -2)-1;
939 if (idx
< 0 || idx
> MAX_POINTS_PER_CURVE
) {
940 lua_pushinteger(L
, 4);
943 int8_t val
= luaL_checkinteger(L
, -1);
944 if (val
< -100 || val
> 100) {
945 lua_pushinteger(L
, 6);
955 // Check how many points are set
959 } while (yPoints
[numPoints
]!=-127 && numPoints
< MAX_POINTS_PER_CURVE
);
960 newCurveData
.points
= numPoints
- 5;
962 if (numPoints
< MIN_POINTS_PER_CURVE
|| numPoints
> MAX_POINTS_PER_CURVE
) {
963 lua_pushinteger(L
, 1);
967 if (newCurveData
.type
== CURVE_TYPE_CUSTOM
) {
969 // The rest of the points are checked by the monotonic condition
970 for (unsigned int i
=numPoints
; i
< sizeof(xPoints
);i
++)
972 if (xPoints
[i
] != -127)
974 lua_pushinteger(L
, 8);
979 // Check first and last point
980 if (xPoints
[0] != -100 || xPoints
[newCurveData
.points
+ 4] != 100) {
981 lua_pushinteger(L
, 5);
985 // Check that x values are increasing
986 for (int i
= 1; i
< numPoints
; i
++) {
987 if (xPoints
[i
- 1] > xPoints
[i
]) {
988 lua_pushinteger(L
, 5);
994 // Check that ypoints have the right number of points set
995 for (int i
=0; i
< 5 + newCurveData
.points
;i
++)
997 if (yPoints
[i
] == -127)
999 lua_pushinteger(L
, 7);
1004 // Calculate size of curve we replace
1005 int oldCurveMemSize
;
1006 if (destCurveData
.type
== CURVE_TYPE_STANDARD
) {
1007 oldCurveMemSize
= 5 + destCurveData
.points
;
1010 oldCurveMemSize
= 8 + 2 * destCurveData
.points
;
1013 // Calculate own size
1014 int newCurveMemSize
;
1015 if (newCurveData
.type
== CURVE_TYPE_STANDARD
)
1016 newCurveMemSize
= 5 + newCurveData
.points
;
1018 newCurveMemSize
= 8 + 2 * newCurveData
.points
;
1020 int shift
= newCurveMemSize
- oldCurveMemSize
;
1022 // Also checks if new curve size would fit
1023 if (!moveCurve(curveIdx
, shift
)) {
1024 lua_pushinteger(L
, 3);
1025 TRACE("curve shift is %d", shift
);
1029 // Curve fits into mem, fill new curve
1030 destCurveData
= newCurveData
;
1032 int8_t *point
= curveAddress(curveIdx
);
1033 for (int i
= 0; i
< destCurveData
.points
+ 5; i
++) {
1034 *point
++ = yPoints
[i
];
1037 if (destCurveData
.type
== CURVE_TYPE_CUSTOM
) {
1038 for (int i
= 1; i
< destCurveData
.points
+ 4; i
++) {
1039 *point
++ = xPoints
[i
];
1042 storageDirty(EE_MODEL
);
1044 lua_pushinteger(L
, 0);
1049 @function model.getCustomFunction(function)
1051 Get Custom Function parameters
1053 @param function (unsigned number) custom function number (use 0 for CF1)
1055 @retval nil requested custom function does not exist
1057 @retval table custom function data:
1058 * `switch` (number) switch index
1059 * `func` (number) function index
1060 * `name` (string) Name of track to play (only returned only returned if action is play track, sound or script)
1061 * `value` (number) value (only returned only returned if action is **not** play track, sound or script)
1062 * `mode` (number) mode (only returned only returned if action is **not** play track, sound or script)
1063 * `param` (number) parameter (only returned only returned if action is **not** play track, sound or script)
1064 * `active` (number) 0 = disabled, 1 = enabled
1066 @status current Introduced in 2.0.0, TODO rename function
1068 static int luaModelGetCustomFunction(lua_State
*L
)
1070 unsigned int idx
= luaL_checkunsigned(L
, 1);
1071 if (idx
< MAX_SPECIAL_FUNCTIONS
) {
1072 CustomFunctionData
* cfn
= &g_model
.customFn
[idx
];
1074 lua_pushtableinteger(L
, "switch", CFN_SWITCH(cfn
));
1075 lua_pushtableinteger(L
, "func", CFN_FUNC(cfn
));
1076 if (CFN_FUNC(cfn
) == FUNC_PLAY_TRACK
|| CFN_FUNC(cfn
) == FUNC_BACKGND_MUSIC
|| CFN_FUNC(cfn
) == FUNC_PLAY_SCRIPT
) {
1077 lua_pushtablenzstring(L
, "name", cfn
->play
.name
);
1080 lua_pushtableinteger(L
, "value", cfn
->all
.val
);
1081 lua_pushtableinteger(L
, "mode", cfn
->all
.mode
);
1082 lua_pushtableinteger(L
, "param", cfn
->all
.param
);
1084 lua_pushtableinteger(L
, "active", CFN_ACTIVE(cfn
));
1093 @function model.setCustomFunction(function, value)
1095 Set Custom Function parameters
1097 @param function (unsigned number) custom function number (use 0 for CF1)
1099 @param value (table) custom function parameters, see model.getCustomFunction() for table format
1101 @notice If a parameter is missing from the value, then
1102 that parameter remains unchanged.
1104 @status current Introduced in 2.0.0, TODO rename function
1106 static int luaModelSetCustomFunction(lua_State
*L
)
1108 unsigned int idx
= luaL_checkunsigned(L
, 1);
1109 if (idx
< MAX_SPECIAL_FUNCTIONS
) {
1110 CustomFunctionData
* cfn
= &g_model
.customFn
[idx
];
1111 memclear(cfn
, sizeof(CustomFunctionData
));
1112 luaL_checktype(L
, -1, LUA_TTABLE
);
1113 for (lua_pushnil(L
); lua_next(L
, -2); lua_pop(L
, 1)) {
1114 luaL_checktype(L
, -2, LUA_TSTRING
); // key is string
1115 const char * key
= luaL_checkstring(L
, -2);
1116 if (!strcmp(key
, "switch")) {
1117 CFN_SWITCH(cfn
) = luaL_checkinteger(L
, -1);
1119 else if (!strcmp(key
, "func")) {
1120 CFN_FUNC(cfn
) = luaL_checkinteger(L
, -1);
1122 else if (!strcmp(key
, "name")) {
1123 const char * name
= luaL_checkstring(L
, -1);
1124 strncpy(cfn
->play
.name
, name
, sizeof(cfn
->play
.name
));
1126 else if (!strcmp(key
, "value")) {
1127 cfn
->all
.val
= luaL_checkinteger(L
, -1);
1129 else if (!strcmp(key
, "mode")) {
1130 cfn
->all
.mode
= luaL_checkinteger(L
, -1);
1132 else if (!strcmp(key
, "param")) {
1133 cfn
->all
.param
= luaL_checkinteger(L
, -1);
1135 else if (!strcmp(key
, "active")) {
1136 CFN_ACTIVE(cfn
) = luaL_checkinteger(L
, -1);
1139 storageDirty(EE_MODEL
);
1146 @function model.getOutput(index)
1148 Get servo parameters
1150 @param index (unsigned number) output number (use 0 for CH1)
1152 @retval nil requested output does not exist
1154 @retval table output parameters:
1155 * `name` (string) name
1156 * `min` (number) Minimum % * 10
1157 * `max` (number) Maximum % * 10
1158 * `offset` (number) Subtrim * 10
1159 * `ppmCenter` (number) offset from PPM Center. 0 = 1500
1160 * `symetrical` (number) linear Subtrim 0 = Off, 1 = On
1161 * `revert` (number) irection 0 = ---, 1 = INV
1163 * (number) Curve number (0 for Curve1)
1164 * or `nil` if no curve set
1166 @status current Introduced in 2.0.0
1168 static int luaModelGetOutput(lua_State
*L
)
1170 unsigned int idx
= luaL_checkunsigned(L
, 1);
1171 if (idx
< MAX_OUTPUT_CHANNELS
) {
1172 LimitData
* limit
= limitAddress(idx
);
1174 lua_pushtablezstring(L
, "name", limit
->name
);
1175 lua_pushtableinteger(L
, "min", limit
->min
-1000);
1176 lua_pushtableinteger(L
, "max", limit
->max
+1000);
1177 lua_pushtableinteger(L
, "offset", limit
->offset
);
1178 lua_pushtableinteger(L
, "ppmCenter", limit
->ppmCenter
);
1179 lua_pushtableinteger(L
, "symetrical", limit
->symetrical
);
1180 lua_pushtableinteger(L
, "revert", limit
->revert
);
1182 lua_pushtableinteger(L
, "curve", limit
->curve
-1);
1191 @function model.setOutput(index, value)
1193 Set servo parameters
1195 @param index (unsigned number) channel number (use 0 for CH1)
1197 @param value (table) servo parameters, see model.getOutput() for table format
1199 @notice If a parameter is missing from the value, then
1200 that parameter remains unchanged.
1202 @status current Introduced in 2.0.0
1204 static int luaModelSetOutput(lua_State
*L
)
1206 unsigned int idx
= luaL_checkunsigned(L
, 1);
1207 if (idx
< MAX_OUTPUT_CHANNELS
) {
1208 LimitData
* limit
= limitAddress(idx
);
1209 memclear(limit
, sizeof(LimitData
));
1210 luaL_checktype(L
, -1, LUA_TTABLE
);
1211 for (lua_pushnil(L
); lua_next(L
, -2); lua_pop(L
, 1)) {
1212 luaL_checktype(L
, -2, LUA_TSTRING
); // key is string
1213 const char * key
= luaL_checkstring(L
, -2);
1214 if (!strcmp(key
, "name")) {
1215 const char * name
= luaL_checkstring(L
, -1);
1216 str2zchar(limit
->name
, name
, sizeof(limit
->name
));
1218 else if (!strcmp(key
, "min")) {
1219 limit
->min
= luaL_checkinteger(L
, -1)+1000;
1221 else if (!strcmp(key
, "max")) {
1222 limit
->max
= luaL_checkinteger(L
, -1)-1000;
1224 else if (!strcmp(key
, "offset")) {
1225 limit
->offset
= luaL_checkinteger(L
, -1);
1227 else if (!strcmp(key
, "ppmCenter")) {
1228 limit
->ppmCenter
= luaL_checkinteger(L
, -1);
1230 else if (!strcmp(key
, "symetrical")) {
1231 limit
->symetrical
= luaL_checkinteger(L
, -1);
1233 else if (!strcmp(key
, "revert")) {
1234 limit
->revert
= luaL_checkinteger(L
, -1);
1236 else if (!strcmp(key
, "curve")) {
1237 limit
->curve
= luaL_checkinteger(L
, -1) + 1;
1240 storageDirty(EE_MODEL
);
1247 @function model.getGlobalVariable(index, flight_mode)
1249 Return current global variable value
1251 @notice a simple warning or notice
1253 @param index zero based global variable index, use 0 for GV1, 8 for GV9
1255 @param flight_mode Flight mode number (0 = FM0, 8 = FM8)
1257 @retval nil requested global variable does not exist
1259 @retval number current value of global variable
1264 -- get GV3 (index = 2) from Flight mode 0 (FM0)
1265 val = model.getGlobalVariable(2, 0)
1268 static int luaModelGetGlobalVariable(lua_State
*L
)
1270 unsigned int idx
= luaL_checkunsigned(L
, 1);
1271 unsigned int phase
= luaL_checkunsigned(L
, 2);
1272 if (phase
< MAX_FLIGHT_MODES
&& idx
< MAX_GVARS
)
1273 lua_pushinteger(L
, g_model
.flightModeData
[phase
].gvars
[idx
]);
1280 @function model.setGlobalVariable(index, flight_mode, value)
1282 Sets current global variable value. See also model.getGlobalVariable()
1284 @param index zero based global variable index, use 0 for GV1, 8 for GV9
1286 @param flight_mode Flight mode number (0 = FM0, 8 = FM8)
1288 @param value new value for global variable. Permitted range is
1291 @notice Global variable can only store integer values,
1292 any floating point value is converted into integer value
1293 by truncating everything behind a floating point.
1295 static int luaModelSetGlobalVariable(lua_State
*L
)
1297 unsigned int idx
= luaL_checkunsigned(L
, 1);
1298 unsigned int phase
= luaL_checkunsigned(L
, 2);
1299 int value
= luaL_checkinteger(L
, 3);
1300 if (phase
< MAX_FLIGHT_MODES
&& idx
< MAX_GVARS
&& value
>= -GVAR_MAX
&& value
<= GVAR_MAX
) {
1301 g_model
.flightModeData
[phase
].gvars
[idx
] = value
;
1302 storageDirty(EE_MODEL
);
1307 const luaL_Reg modelLib
[] = {
1308 { "getInfo", luaModelGetInfo
},
1309 { "setInfo", luaModelSetInfo
},
1310 { "getModule", luaModelGetModule
},
1311 { "setModule", luaModelSetModule
},
1312 { "getTimer", luaModelGetTimer
},
1313 { "setTimer", luaModelSetTimer
},
1314 { "resetTimer", luaModelResetTimer
},
1315 { "getInputsCount", luaModelGetInputsCount
},
1316 { "getInput", luaModelGetInput
},
1317 { "insertInput", luaModelInsertInput
},
1318 { "deleteInput", luaModelDeleteInput
},
1319 { "deleteInputs", luaModelDeleteInputs
},
1320 { "defaultInputs", luaModelDefaultInputs
},
1321 { "getMixesCount", luaModelGetMixesCount
},
1322 { "getMix", luaModelGetMix
},
1323 { "insertMix", luaModelInsertMix
},
1324 { "deleteMix", luaModelDeleteMix
},
1325 { "deleteMixes", luaModelDeleteMixes
},
1326 { "getLogicalSwitch", luaModelGetLogicalSwitch
},
1327 { "setLogicalSwitch", luaModelSetLogicalSwitch
},
1328 { "getCustomFunction", luaModelGetCustomFunction
},
1329 { "setCustomFunction", luaModelSetCustomFunction
},
1330 { "getCurve", luaModelGetCurve
},
1331 { "setCurve", luaModelSetCurve
},
1332 { "getOutput", luaModelGetOutput
},
1333 { "setOutput", luaModelSetOutput
},
1334 { "getGlobalVariable", luaModelGetGlobalVariable
},
1335 { "setGlobalVariable", luaModelSetGlobalVariable
},
1336 { NULL
, NULL
} /* sentinel */