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.
23 enum MenuModelOutputsItems
{
27 ITEM_OUTPUTS_DIRECTION
,
29 #if defined(PPM_LIMITS_SYMETRICAL)
30 ITEM_OUTPUTS_SYMETRICAL
,
33 ITEM_OUTPUTS_MAXROW
= ITEM_OUTPUTS_COUNT
-1
36 #if defined(PPM_UNIT_US)
37 #define LIMITS_MIN_POS 12*FW+1
38 #define PREC_THRESHOLD 804
40 #define LIMITS_MIN_POS 12*FW-2
41 #define PREC_THRESHOLD 0
44 #define LIMITS_OFFSET_POS 8*FW-1
46 #if defined(PPM_LIMITS_SYMETRICAL)
47 #if defined(PPM_CENTER_ADJUSTABLE)
48 #define LIMITS_MAX_POS 15*FW+3
49 #define LIMITS_REVERT_POS 16*FW-1
50 #define LIMITS_PPM_CENTER_POS 20*FW+1
52 #define LIMITS_DIRECTION_POS 12*FW+4
53 #define LIMITS_MAX_POS 16*FW+4
54 #define LIMITS_REVERT_POS 17*FW
57 #if defined(PPM_CENTER_ADJUSTABLE)
58 #define LIMITS_MAX_POS 16*FW
59 #define LIMITS_REVERT_POS 17*FW-2
60 #define LIMITS_PPM_CENTER_POS 21*FW+2
62 #define LIMITS_MAX_POS 17*FW
63 #define LIMITS_REVERT_POS 18*FW
64 #define LIMITS_DIRECTION_POS 12*FW+5
68 #define LIMITS_CURVE_POS 17*FW+1
69 #define LIMITS_MIN_MAX_OFFSET 1000
70 #define CONVERT_US_MIN_MAX(x) ((int16_t(x)*128)/25)
71 #define MIN_MAX_ATTR attr
73 #if defined(PPM_UNIT_US)
74 #define SET_MIN_MAX(x, val) x = ((val)*250)/128
75 #define MIN_MAX_DISPLAY(x) CONVERT_US_MIN_MAX(x)
77 #define MIN_MAX_DISPLAY(x) (x)
78 #define SET_MIN_MAX(x, val) x = (val)
81 enum MenuModelOutputsOneItems
{
82 ITEM_OUTPUTONE_CH_NAME
,
83 ITEM_OUTPUTONE_OFFSET
,
88 #if defined(PPM_CENTER_ADJUSTABLE)
89 ITEM_OUTPUTONE_PPM_CENTER
,
91 #if defined(PPM_LIMITS_SYMETRICAL)
92 ITEM_OUTPUTONE_SYMETRICAL
,
97 #define LIMITS_ONE_2ND_COLUMN (13*FW)
99 void menuModelLimitsOne(event_t event
)
101 title(STR_MENULIMITS
);
102 LimitData
* ld
= limitAddress(s_currIdx
);
104 putsChn(11*FW
, 0, s_currIdx
+1, 0);
105 lcdDrawNumber(19*FW
, 0, PPM_CH_CENTER(s_currIdx
)+channelOutputs
[s_currIdx
]/2, RIGHT
);
106 lcdDrawText(19*FW
, 0, STR_US
);
108 SUBMENU_NOTITLE(ITEM_OUTPUTONE_MAXROW
, { 0, 0, 0, 0, 0, 0 , 0 /*, 0...*/ });
110 int8_t sub
= menuVerticalPosition
;
112 for (uint8_t k
=0; k
<LCD_LINES
-1; k
++) {
113 coord_t y
= MENU_HEADER_HEIGHT
+ 1 + k
*FH
;
114 uint8_t i
= k
+ menuVerticalOffset
;
115 uint8_t attr
= (sub
==i
? (s_editMode
>0 ? BLINK
|INVERS
: INVERS
) : 0);
116 uint8_t active
= (attr
&& s_editMode
> 0) ;
117 int limit
= (g_model
.extendedLimits
? LIMIT_EXT_MAX
: 1000);
120 case ITEM_OUTPUTONE_CH_NAME
:
121 editSingleName(LIMITS_ONE_2ND_COLUMN
, y
, STR_NAME
, ld
->name
, sizeof(ld
->name
), event
, attr
);
124 case ITEM_OUTPUTONE_OFFSET
:
125 lcdDrawTextAlignedLeft(y
, TR_LIMITS_HEADERS_SUBTRIM
);
126 ld
->offset
= GVAR_MENU_ITEM(LIMITS_ONE_2ND_COLUMN
, y
, ld
->offset
, -1000, 1000, PREC1
| attr
, 0, event
);
129 case ITEM_OUTPUTONE_MIN
:
130 lcdDrawTextAlignedLeft(y
, STR_MIN
);
131 if (GV_IS_GV_VALUE(ld
->min
, -GV_RANGELARGE
, GV_RANGELARGE
) || (attr
&& event
== EVT_KEY_LONG(KEY_ENTER
))) {
132 ld
->min
= GVAR_MENU_ITEM(LIMITS_ONE_2ND_COLUMN
, y
, ld
->min
, -LIMIT_EXT_MAX
, LIMIT_EXT_MAX
, attr
|PREC1
, 0, event
);
135 lcdDrawNumber(LIMITS_ONE_2ND_COLUMN
, y
, MIN_MAX_DISPLAY(ld
->min
-LIMITS_MIN_MAX_OFFSET
), attr
|PREC1
);
137 ld
->min
= LIMITS_MIN_MAX_OFFSET
+ checkIncDec(event
, ld
->min
-LIMITS_MIN_MAX_OFFSET
, -limit
, 0, EE_MODEL
, NULL
, stops1000
);
141 case ITEM_OUTPUTONE_MAX
:
142 lcdDrawTextAlignedLeft(y
, STR_MAX
);
143 if (GV_IS_GV_VALUE(ld
->max
, -GV_RANGELARGE
, GV_RANGELARGE
) || (attr
&& event
== EVT_KEY_LONG(KEY_ENTER
))) {
144 ld
->max
= GVAR_MENU_ITEM(LIMITS_ONE_2ND_COLUMN
, y
, ld
->max
, -LIMIT_EXT_MAX
, LIMIT_EXT_MAX
, attr
|PREC1
, 0, event
);
147 lcdDrawNumber(LIMITS_ONE_2ND_COLUMN
, y
, MIN_MAX_DISPLAY(ld
->max
+LIMITS_MIN_MAX_OFFSET
), attr
|PREC1
);
149 ld
->max
= -LIMITS_MIN_MAX_OFFSET
+ checkIncDec(event
, ld
->max
+LIMITS_MIN_MAX_OFFSET
, 0, +limit
, EE_MODEL
, NULL
, stops1000
);
153 case ITEM_OUTPUTONE_DIR
:
155 lcdDrawTextAlignedLeft(y
, TR_LIMITS_HEADERS_DIRECTION
);
156 lcdDrawTextAtIndex(LIMITS_ONE_2ND_COLUMN
, y
, STR_MMMINV
, ld
->revert
, attr
);
158 CHECK_INCDEC_MODELVAR_ZERO(event
, ld
->revert
, 1);
163 case ITEM_OUTPUTONE_CURVE
:
164 lcdDrawTextAlignedLeft(y
, STR_CURVE
);
165 drawCurveName(LIMITS_ONE_2ND_COLUMN
, y
, ld
->curve
, attr
);
167 CHECK_INCDEC_MODELVAR(event
, ld
->curve
, -MAX_CURVES
, +MAX_CURVES
);
171 #if defined(PPM_CENTER_ADJUSTABLE)
172 case ITEM_OUTPUTONE_PPM_CENTER
:
173 lcdDrawTextAlignedLeft(y
, TR_LIMITS_HEADERS_PPMCENTER
);
174 lcdDrawNumber(LIMITS_ONE_2ND_COLUMN
, y
, PPM_CENTER
+ld
->ppmCenter
, attr
);
176 CHECK_INCDEC_MODELVAR(event
, ld
->ppmCenter
, -PPM_CENTER_MAX
, +PPM_CENTER_MAX
);
181 #if defined(PPM_LIMITS_SYMETRICAL)
182 case ITEM_OUTPUTONE_SYMETRICAL
:
183 lcdDrawTextAlignedLeft(y
, TR_LIMITS_HEADERS_SUBTRIMMODE
);
184 lcdDrawChar(LIMITS_ONE_2ND_COLUMN
, y
, ld
->symetrical
? '=' : '\306', attr
);
186 CHECK_INCDEC_MODELVAR_ZERO(event
, ld
->symetrical
, 1);
194 void onLimitsMenu(const char *result
)
196 s_currIdx
= menuVerticalPosition
- HEADER_LINE
;
197 if (result
== STR_RESET
) {
198 LimitData
*ld
= limitAddress(s_currIdx
);
205 storageDirty(EE_MODEL
);
207 else if (result
== STR_COPY_STICKS_TO_OFS
) {
208 copySticksToOffset(s_currIdx
);
209 storageDirty(EE_MODEL
);
211 else if (result
== STR_COPY_TRIMS_TO_OFS
) {
212 copyTrimsToOffset(s_currIdx
);
213 storageDirty(EE_MODEL
);
215 else if (result
== STR_EDIT
) {
216 pushMenu(menuModelLimitsOne
);
220 void menuModelLimits(event_t event
)
222 uint8_t sub
= menuVerticalPosition
- HEADER_LINE
;
224 if (sub
< MAX_OUTPUT_CHANNELS
) {
225 lcdDrawNumber(13*FW
, 0, PPM_CH_CENTER(sub
)+channelOutputs
[sub
]/2, RIGHT
);
226 lcdDrawText(13*FW
, 0, STR_US
);
229 SIMPLE_MENU(STR_MENULIMITS
, menuTabModel
, MENU_MODEL_OUTPUTS
, HEADER_LINE
+MAX_OUTPUT_CHANNELS
+1);
231 for (uint8_t i
=0; i
<LCD_LINES
-1; i
++) {
232 coord_t y
= MENU_HEADER_HEIGHT
+ 1 + i
*FH
;
233 uint8_t k
= i
+menuVerticalOffset
;
234 LcdFlags attr
= (sub
==MAX_OUTPUT_CHANNELS
) ? INVERS
: 0;
236 if (sub
==k
&& event
==EVT_KEY_FIRST(KEY_ENTER
) && !READ_ONLY() && (k
!= MAX_OUTPUT_CHANNELS
) ) {
239 POPUP_MENU_ADD_ITEM(STR_EDIT
);
240 POPUP_MENU_ADD_ITEM(STR_RESET
);
241 POPUP_MENU_ADD_ITEM(STR_COPY_TRIMS_TO_OFS
);
242 POPUP_MENU_ADD_ITEM(STR_COPY_STICKS_TO_OFS
);
243 POPUP_MENU_START(onLimitsMenu
);
246 if (k
== MAX_OUTPUT_CHANNELS
) {
247 // last line available - add the "copy trim menu" line
248 lcdDrawText(CENTER_OFS
, y
, STR_TRIMS2OFFSETS
, NO_HIGHLIGHT() ? 0 : attr
);
251 if (event
== EVT_KEY_LONG(KEY_ENTER
)) {
252 START_NO_HIGHLIGHT();
254 moveTrimsToOffsets(); // if highlighted and menu pressed - move trims to offsets
260 LimitData
* ld
= limitAddress(k
);
262 if (ld
->name
[0] == 0) {
263 putsChn(0, y
, k
+1, (sub
==k
) ? INVERS
: 0);
266 lcdDrawSizedText(0, y
, ld
->name
, sizeof(ld
->name
), ((sub
==k
) ? INVERS
: 0) | ZCHAR
| LEFT
);
269 for (uint8_t j
=0; j
<ITEM_OUTPUTS_COUNT
; j
++) {
271 case ITEM_OUTPUTS_OFFSET
:
272 #if defined(PPM_UNIT_US)
273 lcdDrawNumber(LIMITS_OFFSET_POS
, y
, ((int32_t)ld
->offset
*128) / 25, PREC1
|RIGHT
);
276 if (GV_IS_GV_VALUE(ld
->offset
, -GV_RANGELARGE
, GV_RANGELARGE
)) {
277 drawGVarName(LIMITS_OFFSET_POS
, y
, ld
->offset
, attr
|PREC1
|RIGHT
);
281 if (abs(ld
->offset
) >= 1000) {
282 lcdDrawNumber(LIMITS_OFFSET_POS
, y
, ld
->offset
/10, RIGHT
);
285 lcdDrawNumber(LIMITS_OFFSET_POS
, y
, ld
->offset
, PREC1
|RIGHT
);
290 case ITEM_OUTPUTS_MIN
:
292 if (GV_IS_GV_VALUE(ld
->min
, -GV_RANGELARGE
, GV_RANGELARGE
)) {
293 drawGVarName(LIMITS_MIN_POS
, y
, ld
->min
, attr
|PREC1
|RIGHT
);
297 if (ld
->min
<= PREC_THRESHOLD
) {
298 lcdDrawNumber(LIMITS_MIN_POS
, y
, MIN_MAX_DISPLAY(ld
->min
-LIMITS_MIN_MAX_OFFSET
)/10, RIGHT
);
301 lcdDrawNumber(LIMITS_MIN_POS
, y
, MIN_MAX_DISPLAY(ld
->min
-LIMITS_MIN_MAX_OFFSET
), attr
|PREC1
|RIGHT
);
305 case ITEM_OUTPUTS_MAX
:
307 if (GV_IS_GV_VALUE(ld
->max
, -GV_RANGELARGE
, GV_RANGELARGE
)) {
308 drawGVarName(LIMITS_MAX_POS
, y
, ld
->max
, attr
|PREC1
|RIGHT
);
312 if (ld
->max
>= -PREC_THRESHOLD
) {
313 lcdDrawNumber(LIMITS_MAX_POS
, y
, MIN_MAX_DISPLAY(ld
->max
+LIMITS_MIN_MAX_OFFSET
)/10, RIGHT
);
316 lcdDrawNumber(LIMITS_MAX_POS
, y
, MIN_MAX_DISPLAY(ld
->max
+LIMITS_MIN_MAX_OFFSET
), attr
|PREC1
|RIGHT
);
320 case ITEM_OUTPUTS_DIRECTION
:
321 lcdDrawChar(LIMITS_REVERT_POS
, y
, ld
->revert
? 127 : 126, 0);
324 case ITEM_OUTPUTS_CURVE
:
325 drawCurveName(LIMITS_CURVE_POS
, y
, ld
->curve
, 0);
328 case ITEM_OUTPUTS_SYMETRICAL
:
329 lcdDrawChar(LCD_W
-FW
, y
, ld
->symetrical
? '=' : '\306', 0);