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.
24 const char s_charTab
[] = "_-.,";
26 char hex2zchar(uint8_t hex
)
28 return (hex
>= 10 ? hex
-9 : 27+hex
);
31 char zchar2char(int8_t idx
)
33 if (idx
== 0) return ' ';
35 if (idx
> -27) return 'a' - idx
- 1;
38 if (idx
< 27) return 'A' + idx
- 1;
39 if (idx
< 37) return '0' + idx
- 27;
40 if (idx
<= 40) return *(s_charTab
+idx
-37);
41 #if LEN_SPECIAL_CHARS > 0
42 if (idx
<= (LEN_STD_CHARS
+ LEN_SPECIAL_CHARS
)) return 'z' + 5 + idx
- 40;
47 char char2lower(char c
)
49 return (c
>= 'A' && c
<= 'Z') ? c
+ 32 : c
;
52 int8_t char2zchar(char c
)
54 if (c
== '_') return 37;
55 #if LEN_SPECIAL_CHARS > 0
56 if ((int8_t)c
< 0 && c
+128 <= LEN_SPECIAL_CHARS
) return 41 + (c
+128);
58 if (c
>= 'a') return 'a' - c
- 1;
59 if (c
>= 'A') return c
- 'A' + 1;
60 if (c
>= '0') return c
- '0' + 27;
61 if (c
== '-') return 38;
62 if (c
== '.') return 39;
63 if (c
== ',') return 40;
67 void str2zchar(char * dest
, const char * src
, int size
)
69 memset(dest
, 0, size
);
70 for (int c
=0; c
<size
&& src
[c
]; c
++) {
71 dest
[c
] = char2zchar(src
[c
]);
75 int zchar2str(char * dest
, const char * src
, int size
)
77 for (int c
=0; c
<size
; c
++) {
78 dest
[c
] = zchar2char(src
[c
]);
82 } while (size
>= 0 && dest
[size
] == ' ');
86 bool cmpStrWithZchar(const char * charString
, const char * zcharString
, int size
)
88 for (int i
=0; i
<size
; i
++) {
89 if (charString
[i
] != zchar2char(zcharString
[i
])) {
96 unsigned int effectiveLen(const char * str
, unsigned int size
)
99 if (str
[size
-1] != ' ')
106 bool zexist(const char * str
, uint8_t size
)
108 for (int i
=0; i
<size
; i
++) {
115 uint8_t zlen(const char * str
, uint8_t size
)
118 if (str
[size
-1] != 0)
125 char * strcat_zchar(char * dest
, const char * name
, uint8_t size
, const char * defaultName
, uint8_t defaultNameSize
, uint8_t defaultIdx
)
130 memcpy(dest
, name
, size
);
140 dest
[i
] = zchar2char(dest
[i
]);
148 if (len
== 0 && defaultName
) {
149 strcpy(dest
, defaultName
);
150 dest
[defaultNameSize
] = (char)((defaultIdx
/ 10) + '0');
151 dest
[defaultNameSize
+ 1] = (char)((defaultIdx
% 10) + '0');
152 len
= defaultNameSize
+ 2;
160 char * getStringAtIndex(char * dest
, const char * s
, int idx
)
163 strncpy(dest
, s
+1+len
*idx
, len
);
168 char * strAppendStringWithIndex(char * dest
, const char * s
, int idx
)
170 return strAppendUnsigned(strAppend(dest
, s
), abs(idx
));
173 char * getTimerString(char * dest
, int32_t tme
, uint8_t hours
)
183 qr
= div((int)tme
, 60);
186 div_t qr2
= div(qr
.quot
, 60);
187 *s
++ = '0' + (qr2
.quot
/ 10);
188 *s
++ = '0' + (qr2
.quot
% 10);
193 if (!hours
&& qr
.quot
> 99) {
194 *s
++ = '0' + (qr
.quot
/ 100);
195 qr
.quot
= qr
.quot
% 100;
198 *s
++ = '0' + (qr
.quot
/ 10);
199 *s
++ = '0' + (qr
.quot
% 10);
201 *s
++ = '0' + (qr
.rem
/ 10);
202 *s
++ = '0' + (qr
.rem
% 10);
208 char * getCurveString(char * dest
, int idx
)
211 return getStringAtIndex(dest
, STR_MMMINV
, 0);
220 if (ZEXIST(g_model
.curves
[idx
- 1].name
))
221 zchar2str(s
, g_model
.curves
[idx
- 1].name
, LEN_CURVE_NAME
);
223 strAppendStringWithIndex(s
, STR_CV
, idx
);
228 char * getGVarString(char * dest
, int idx
)
236 if (ZEXIST(g_model
.gvars
[idx
].name
))
237 zchar2str(s
, g_model
.gvars
[idx
].name
, LEN_GVAR_NAME
);
239 strAppendStringWithIndex(s
, STR_GV
, idx
+1);
244 #if !defined(PCBSKY9X)
245 char * getSwitchName(char * dest
, swsrc_t idx
)
247 div_t swinfo
= switchInfo(idx
);
248 if (ZEXIST(g_eeGeneral
.switchNames
[swinfo
.quot
])) {
249 dest
+= zchar2str(dest
, g_eeGeneral
.switchNames
[swinfo
.quot
], LEN_SWITCH_NAME
);
250 // TODO tous zchar2str
255 if (swinfo
.quot
>= 5)
256 *dest
++ = 'H' + swinfo
.quot
- 5;
257 else if (swinfo
.quot
== 4)
258 #if defined(RADIO_T12)
264 *dest
++ = 'A'+swinfo
.quot
;
266 *dest
++ = 'A' + swinfo
.quot
;
273 char * getSwitchPositionName(char * dest
, swsrc_t idx
)
275 if (idx
== SWSRC_NONE
) {
276 return getStringAtIndex(dest
, STR_VSWITCHES
, 0);
278 else if (idx
== SWSRC_OFF
) {
279 return getStringAtIndex(dest
, STR_OFFON
, 0);
288 #if defined(PCBSKY9X)
289 #define IDX_TRIMS_IN_STR_VSWITCHES (1+SWSRC_LAST_SWITCH)
290 #define IDX_ON_IN_STR_VSWITCHES (IDX_TRIMS_IN_STR_VSWITCHES+SWSRC_LAST_TRIM-SWSRC_FIRST_TRIM+2)
291 if (idx
<= SWSRC_LAST_SWITCH
) {
292 getStringAtIndex(s
, STR_VSWITCHES
, idx
);
295 #define IDX_TRIMS_IN_STR_VSWITCHES (1)
296 #define IDX_ON_IN_STR_VSWITCHES (IDX_TRIMS_IN_STR_VSWITCHES + SWSRC_LAST_TRIM - SWSRC_FIRST_TRIM + 1)
297 if (idx
<= SWSRC_LAST_SWITCH
) {
298 div_t swinfo
= switchInfo(idx
);
299 s
= getSwitchName(s
, idx
);
300 *s
++ = "\300-\301"[swinfo
.rem
];
306 else if (idx
<= SWSRC_LAST_MULTIPOS_SWITCH
) {
307 div_t swinfo
= div(int(idx
- SWSRC_FIRST_MULTIPOS_SWITCH
), XPOTS_MULTIPOS_COUNT
);
308 char temp
[LEN_ANA_NAME
+1];
309 getSourceString(temp
, MIXSRC_FIRST_POT
+swinfo
.quot
);
310 temp
[LEN_ANA_NAME
]= '\0';
311 strAppendStringWithIndex(s
, temp
, swinfo
.rem
+1);
315 #if defined(PCBSKY9X)
316 else if (idx
<= SWSRC_REa
) {
317 getStringAtIndex(s
, STR_VSWITCHES
, IDX_TRIMS_IN_STR_VSWITCHES
+idx
-SWSRC_FIRST_TRIM
);
320 else if (idx
<= SWSRC_LAST_TRIM
) {
321 getStringAtIndex(s
, STR_VSWITCHES
, IDX_TRIMS_IN_STR_VSWITCHES
+idx
-SWSRC_FIRST_TRIM
);
325 else if (idx
<= SWSRC_LAST_LOGICAL_SWITCH
) {
327 strAppendUnsigned(s
, idx
-SWSRC_FIRST_LOGICAL_SWITCH
+1, 2);
329 else if (idx
<= SWSRC_ONE
) {
330 getStringAtIndex(s
, STR_VSWITCHES
, IDX_ON_IN_STR_VSWITCHES
+ idx
- SWSRC_ON
);
332 else if (idx
<= SWSRC_LAST_FLIGHT_MODE
) {
333 strAppendStringWithIndex(s
, STR_FM
, idx
-SWSRC_FIRST_FLIGHT_MODE
);
335 else if (idx
== SWSRC_TELEMETRY_STREAMING
) {
338 else if (idx
== SWSRC_RADIO_ACTIVITY
) {
341 #if defined(DEBUG_LATENCY)
342 else if (idx
== SWSRC_LATENCY_TOGGLE
) {
347 zchar2str(s
, g_model
.telemetrySensors
[idx
-SWSRC_FIRST_SENSOR
].label
, TELEM_LABEL_LEN
);
353 char * getSourceString(char * dest
, mixsrc_t idx
)
355 if (idx
== MIXSRC_NONE
) {
356 return getStringAtIndex(dest
, STR_VSRCRAW
, 0);
358 else if (idx
<= MIXSRC_LAST_INPUT
) {
359 idx
-= MIXSRC_FIRST_INPUT
;
361 if (ZEXIST(g_model
.inputNames
[idx
])) {
362 zchar2str(dest
, g_model
.inputNames
[idx
], LEN_INPUT_NAME
);
363 dest
[LEN_INPUT_NAME
] = '\0';
366 strAppendUnsigned(dest
, idx
+1, 2);
369 #if defined(LUA_INPUTS)
370 else if (idx
<= MIXSRC_LAST_LUA
) {
371 #if defined(LUA_MODEL_SCRIPTS)
372 div_t qr
= div(idx
-MIXSRC_FIRST_LUA
, MAX_SCRIPT_OUTPUTS
);
373 if (qr
.quot
< MAX_SCRIPTS
&& qr
.rem
< scriptInputsOutputs
[qr
.quot
].outputsCount
) {
375 // *dest++ = '1'+qr.quot;
376 strcpy(dest
, scriptInputsOutputs
[qr
.quot
].outputs
[qr
.rem
].name
);
383 else if (idx
<= MIXSRC_LAST_POT
) {
385 if (ZEXIST(g_eeGeneral
.anaNames
[idx
])) {
386 zchar2str(dest
, g_eeGeneral
.anaNames
[idx
], LEN_ANA_NAME
);
387 dest
[LEN_ANA_NAME
] = '\0';
390 getStringAtIndex(dest
, STR_VSRCRAW
, idx
+ 1);
393 else if (idx
<= MIXSRC_LAST_TRIM
) {
395 getStringAtIndex(dest
, STR_VSRCRAW
, idx
+ 1);
397 else if (idx
<= MIXSRC_LAST_SWITCH
) {
398 idx
-= MIXSRC_FIRST_SWITCH
;
399 if (ZEXIST(g_eeGeneral
.switchNames
[idx
])) {
400 zchar2str(dest
, g_eeGeneral
.switchNames
[idx
], LEN_SWITCH_NAME
);
401 dest
[LEN_SWITCH_NAME
] = '\0';
404 getStringAtIndex(dest
, STR_VSRCRAW
, idx
+ MIXSRC_FIRST_SWITCH
- MIXSRC_Rud
+ 1);
407 else if (idx
<= MIXSRC_LAST_LOGICAL_SWITCH
) {
408 getSwitchPositionName(dest
, SWSRC_SW1
+ idx
- MIXSRC_SW1
);
410 else if (idx
<= MIXSRC_LAST_TRAINER
) {
411 strAppendStringWithIndex(dest
, STR_PPM_TRAINER
, idx
- MIXSRC_FIRST_TRAINER
+ 1);
413 else if (idx
<= MIXSRC_LAST_CH
) {
414 strAppendStringWithIndex(dest
, STR_CH
, idx
- MIXSRC_CH1
+ 1);
416 else if (idx
<= MIXSRC_LAST_GVAR
) {
417 strAppendStringWithIndex(dest
, STR_GV
, idx
- MIXSRC_GVAR1
+ 1);
419 else if (idx
< MIXSRC_FIRST_TIMER
) {
420 getStringAtIndex(dest
, STR_VSRCRAW
, idx
-MIXSRC_Rud
+1-MAX_LOGICAL_SWITCHES
-MAX_TRAINER_CHANNELS
-MAX_OUTPUT_CHANNELS
-MAX_GVARS
);
422 else if (idx
<= MIXSRC_LAST_TIMER
) {
423 if(ZEXIST(g_model
.timers
[idx
-MIXSRC_FIRST_TIMER
].name
)) {
424 zchar2str(dest
,g_model
.timers
[idx
-MIXSRC_FIRST_TIMER
].name
, LEN_TIMER_NAME
);
425 dest
[LEN_TIMER_NAME
] = '\0';
428 getStringAtIndex(dest
, STR_VSRCRAW
, idx
-MIXSRC_Rud
+1-MAX_LOGICAL_SWITCHES
-MAX_TRAINER_CHANNELS
-MAX_OUTPUT_CHANNELS
-MAX_GVARS
);
432 idx
-= MIXSRC_FIRST_TELEM
;
433 div_t qr
= div(idx
, 3);
435 int pos
= 1 + zchar2str(&dest
[1], g_model
.telemetrySensors
[qr
.quot
].label
, sizeof(g_model
.telemetrySensors
[qr
.quot
].label
));
436 if (qr
.rem
) dest
[pos
++] = (qr
.rem
==2 ? '+' : '-');
444 char * strAppendUnsigned(char * dest
, uint32_t value
, uint8_t digits
, uint8_t radix
)
447 unsigned int tmp
= value
;
449 while (tmp
>= radix
) {
454 uint8_t idx
= digits
;
456 div_t qr
= div(value
, radix
);
457 uint32_t rem
= value
% radix
;
458 dest
[--idx
] = (qr
.rem
>= 10 ? 'A' - 10 : '0') + qr
.rem
;
462 return &dest
[digits
];
465 char * strAppendSigned(char * dest
, int32_t value
, uint8_t digits
, uint8_t radix
)
471 return strAppendUnsigned(dest
, (uint32_t)value
, digits
, radix
);
474 char * strAppend(char * dest
, const char * source
, int len
)
476 while ((*dest
++ = *source
++)) {
485 char * strSetCursor(char * dest
, int position
)
493 char * strAppendFilename(char * dest
, const char * filename
, const int size
)
495 memset(dest
, 0, size
);
496 for (int i
=0; i
<size
; i
++) {
497 char c
= *filename
++;
498 if (c
== '\0' || c
== '.') {
510 char * strAppendDate(char * str
, bool time
)
515 div_t qr
= div(utm
.tm_year
+TM_YEAR_BASE
, 10);
516 str
[4] = '0' + qr
.rem
;
517 qr
= div(qr
.quot
, 10);
518 str
[3] = '0' + qr
.rem
;
519 qr
= div(qr
.quot
, 10);
520 str
[2] = '0' + qr
.rem
;
521 str
[1] = '0' + qr
.quot
;
523 qr
= div(utm
.tm_mon
+1, 10);
524 str
[7] = '0' + qr
.rem
;
525 str
[6] = '0' + qr
.quot
;
527 qr
= div(utm
.tm_mday
, 10);
528 str
[10] = '0' + qr
.rem
;
529 str
[9] = '0' + qr
.quot
;
533 div_t qr
= div(utm
.tm_hour
, 10);
534 str
[13] = '0' + qr
.rem
;
535 str
[12] = '0' + qr
.quot
;
536 qr
= div(utm
.tm_min
, 10);
537 str
[15] = '0' + qr
.rem
;
538 str
[14] = '0' + qr
.quot
;
539 qr
= div(utm
.tm_sec
, 10);
540 str
[17] = '0' + qr
.rem
;
541 str
[16] = '0' + qr
.quot
;