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 pm_char s_charTab
[] PROGMEM
= "_-.,";
26 char hex2zchar(uint8_t hex
)
28 return (hex
>= 10 ? hex
-9 : 27+hex
);
31 char idx2char(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 pgm_read_byte(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 #if defined(CPUARM) || defined(SIMU)
48 int8_t char2idx(char c
)
50 if (c
== '_') return 37;
51 #if LEN_SPECIAL_CHARS > 0
52 if ((int8_t)c
< 0 && c
+128 <= LEN_SPECIAL_CHARS
) return 41 + (c
+128);
54 if (c
>= 'a') return 'a' - c
- 1;
55 if (c
>= 'A') return c
- 'A' + 1;
56 if (c
>= '0') return c
- '0' + 27;
57 if (c
== '-') return 38;
58 if (c
== '.') return 39;
59 if (c
== ',') return 40;
63 void str2zchar(char * dest
, const char * src
, int size
)
65 memset(dest
, 0, size
);
66 for (int c
=0; c
<size
&& src
[c
]; c
++) {
67 dest
[c
] = char2idx(src
[c
]);
71 int zchar2str(char * dest
, const char * src
, int size
)
73 for (int c
=0; c
<size
; c
++) {
74 dest
[c
] = idx2char(src
[c
]);
78 } while (size
>= 0 && dest
[size
] == ' ');
84 unsigned int effectiveLen(const char * str
, unsigned int size
)
87 if (str
[size
-1] != ' ')
94 bool zexist(const char * str
, uint8_t size
)
96 for (int i
=0; i
<size
; i
++) {
103 uint8_t zlen(const char * str
, uint8_t size
)
106 if (str
[size
-1] != 0)
113 char * strcat_zchar(char * dest
, const char * name
, uint8_t size
, const char * defaultName
, uint8_t defaultNameSize
, uint8_t defaultIdx
)
118 memcpy(dest
, name
, size
);
128 dest
[i
] = idx2char(dest
[i
]);
136 if (len
== 0 && defaultName
) {
137 strcpy(dest
, defaultName
);
138 dest
[defaultNameSize
] = (char)((defaultIdx
/ 10) + '0');
139 dest
[defaultNameSize
+ 1] = (char)((defaultIdx
% 10) + '0');
140 len
= defaultNameSize
+ 2;
148 #if defined(CPUARM) && !defined(BOOT)
149 char * getStringAtIndex(char * dest
, const char * s
, int idx
)
152 strncpy(dest
, s
+1+len
*idx
, len
);
157 char * strAppendStringWithIndex(char * dest
, const char * s
, int idx
)
159 return strAppendUnsigned(strAppend(dest
, s
), abs(idx
));
162 char * getTimerString(char * dest
, putstime_t tme
, uint8_t hours
)
172 qr
= div((int)tme
, 60);
175 div_t qr2
= div(qr
.quot
, 60);
176 *s
++ = '0' + (qr2
.quot
/ 10);
177 *s
++ = '0' + (qr2
.quot
% 10);
182 *s
++ = '0' + (qr
.quot
/ 10);
183 *s
++ = '0' + (qr
.quot
% 10);
185 *s
++ = '0' + (qr
.rem
/ 10);
186 *s
++ = '0' + (qr
.rem
% 10);
192 char * getCurveString(char * dest
, int idx
)
195 return getStringAtIndex(dest
, STR_MMMINV
, 0);
204 if (ZEXIST(g_model
.curves
[idx
- 1].name
))
205 zchar2str(s
, g_model
.curves
[idx
- 1].name
, LEN_CURVE_NAME
);
207 strAppendStringWithIndex(s
, STR_CV
, idx
);
212 char * getGVarString(char * dest
, int idx
)
220 if (ZEXIST(g_model
.gvars
[idx
].name
))
221 zchar2str(s
, g_model
.gvars
[idx
].name
, LEN_GVAR_NAME
);
223 strAppendStringWithIndex(s
, STR_GV
, idx
+1);
228 char * getSwitchString(char * dest
, swsrc_t idx
)
230 if (idx
== SWSRC_NONE
) {
231 return getStringAtIndex(dest
, STR_VSWITCHES
, 0);
233 else if (idx
== SWSRC_OFF
) {
234 return getStringAtIndex(dest
, STR_OFFON
, 0);
243 #if defined(PCBSKY9X)
244 #define IDX_TRIMS_IN_STR_VSWITCHES (1+SWSRC_LAST_SWITCH)
245 #define IDX_ON_IN_STR_VSWITCHES (IDX_TRIMS_IN_STR_VSWITCHES+SWSRC_LAST_TRIM-SWSRC_FIRST_TRIM+2)
246 if (idx
<= SWSRC_LAST_SWITCH
) {
247 getStringAtIndex(s
, STR_VSWITCHES
, idx
);
250 #define IDX_TRIMS_IN_STR_VSWITCHES (1)
251 #define IDX_ON_IN_STR_VSWITCHES (IDX_TRIMS_IN_STR_VSWITCHES+SWSRC_LAST_TRIM-SWSRC_FIRST_TRIM+1)
252 if (idx
<= SWSRC_LAST_SWITCH
) {
253 div_t swinfo
= switchInfo(idx
);
254 if (ZEXIST(g_eeGeneral
.switchNames
[swinfo
.quot
])) {
255 s
+= zchar2str(s
, g_eeGeneral
.switchNames
[swinfo
.quot
], LEN_SWITCH_NAME
);
256 // TODO tous zchar2str
261 if (swinfo
.quot
== 5)
263 else if (swinfo
.quot
== 4)
266 *s
++ = 'A'+swinfo
.quot
;
268 *s
++ = 'A'+swinfo
.quot
;
271 *s
++ = "\300-\301"[swinfo
.rem
];
277 else if (idx
<= SWSRC_LAST_MULTIPOS_SWITCH
) {
278 div_t swinfo
= div(int(idx
- SWSRC_FIRST_MULTIPOS_SWITCH
), XPOTS_MULTIPOS_COUNT
);
279 char temp
[LEN_ANA_NAME
+1];
280 getSourceString(temp
, MIXSRC_FIRST_POT
+swinfo
.quot
);
281 temp
[LEN_ANA_NAME
]= '\0';
282 strAppendStringWithIndex(s
, temp
, swinfo
.rem
+1);
286 #if defined(PCBSKY9X)
287 else if (idx
<= SWSRC_REa
) {
288 getStringAtIndex(s
, STR_VSWITCHES
, IDX_TRIMS_IN_STR_VSWITCHES
+idx
-SWSRC_FIRST_TRIM
);
291 else if (idx
<= SWSRC_LAST_TRIM
) {
292 getStringAtIndex(s
, STR_VSWITCHES
, IDX_TRIMS_IN_STR_VSWITCHES
+idx
-SWSRC_FIRST_TRIM
);
296 else if (idx
<= SWSRC_LAST_LOGICAL_SWITCH
) {
298 strAppendUnsigned(s
, idx
-SWSRC_FIRST_LOGICAL_SWITCH
+1, 2);
300 else if (idx
<= SWSRC_ONE
) {
301 getStringAtIndex(s
, STR_VSWITCHES
, IDX_ON_IN_STR_VSWITCHES
+ idx
- SWSRC_ON
);
303 else if (idx
<= SWSRC_LAST_FLIGHT_MODE
) {
304 strAppendStringWithIndex(s
, STR_FP
, idx
-SWSRC_FIRST_FLIGHT_MODE
);
306 else if (idx
== SWSRC_TELEMETRY_STREAMING
) {
310 zchar2str(s
, g_model
.telemetrySensors
[idx
-SWSRC_FIRST_SENSOR
].label
, TELEM_LABEL_LEN
);
316 char * getSourceString(char * dest
, mixsrc_t idx
)
318 if (idx
== MIXSRC_NONE
) {
319 return getStringAtIndex(dest
, STR_VSRCRAW
, 0);
321 else if (idx
<= MIXSRC_LAST_INPUT
) {
322 idx
-= MIXSRC_FIRST_INPUT
;
324 if (ZEXIST(g_model
.inputNames
[idx
])) {
325 zchar2str(dest
, g_model
.inputNames
[idx
], LEN_INPUT_NAME
);
326 dest
[LEN_INPUT_NAME
] = '\0';
329 strAppendUnsigned(dest
, idx
+1, 2);
332 #if defined(LUA_INPUTS)
333 else if (idx
<= MIXSRC_LAST_LUA
) {
334 #if defined(LUA_MODEL_SCRIPTS)
335 div_t qr
= div(idx
-MIXSRC_FIRST_LUA
, MAX_SCRIPT_OUTPUTS
);
336 if (qr
.quot
< MAX_SCRIPTS
&& qr
.rem
< scriptInputsOutputs
[qr
.quot
].outputsCount
) {
338 // *dest++ = '1'+qr.quot;
339 strcpy(dest
, scriptInputsOutputs
[qr
.quot
].outputs
[qr
.rem
].name
);
346 else if (idx
<= MIXSRC_LAST_POT
) {
348 if (ZEXIST(g_eeGeneral
.anaNames
[idx
])) {
349 zchar2str(dest
, g_eeGeneral
.anaNames
[idx
], LEN_ANA_NAME
);
350 dest
[LEN_ANA_NAME
] = '\0';
353 getStringAtIndex(dest
, STR_VSRCRAW
, idx
+ 1);
356 else if (idx
<= MIXSRC_LAST_TRIM
) {
358 getStringAtIndex(dest
, STR_VSRCRAW
, idx
+ 1);
360 else if (idx
<= MIXSRC_LAST_SWITCH
) {
361 idx
-= MIXSRC_FIRST_SWITCH
;
362 if (ZEXIST(g_eeGeneral
.switchNames
[idx
])) {
363 zchar2str(dest
, g_eeGeneral
.switchNames
[idx
], LEN_SWITCH_NAME
);
364 dest
[LEN_SWITCH_NAME
] = '\0';
367 getStringAtIndex(dest
, STR_VSRCRAW
, idx
+ MIXSRC_FIRST_SWITCH
- MIXSRC_Rud
+ 1);
370 else if (idx
<= MIXSRC_LAST_LOGICAL_SWITCH
) {
371 getSwitchString(dest
, SWSRC_SW1
+ idx
- MIXSRC_SW1
);
373 else if (idx
<= MIXSRC_LAST_TRAINER
) {
374 strAppendStringWithIndex(dest
, STR_PPM_TRAINER
, idx
- MIXSRC_FIRST_TRAINER
+ 1);
376 else if (idx
<= MIXSRC_LAST_CH
) {
377 strAppendStringWithIndex(dest
, STR_CH
, idx
- MIXSRC_CH1
+ 1);
379 else if (idx
<= MIXSRC_LAST_GVAR
) {
380 strAppendStringWithIndex(dest
, STR_GV
, idx
- MIXSRC_GVAR1
+ 1);
382 else if (idx
< MIXSRC_FIRST_TIMER
) {
383 getStringAtIndex(dest
, STR_VSRCRAW
, idx
-MIXSRC_Rud
+1-MAX_LOGICAL_SWITCHES
-MAX_TRAINER_CHANNELS
-MAX_OUTPUT_CHANNELS
-MAX_GVARS
);
385 else if (idx
<= MIXSRC_LAST_TIMER
) {
386 if(ZEXIST(g_model
.timers
[idx
-MIXSRC_FIRST_TIMER
].name
)) {
387 zchar2str(dest
,g_model
.timers
[idx
-MIXSRC_FIRST_TIMER
].name
, LEN_TIMER_NAME
);
388 dest
[LEN_TIMER_NAME
] = '\0';
391 getStringAtIndex(dest
, STR_VSRCRAW
, idx
-MIXSRC_Rud
+1-MAX_LOGICAL_SWITCHES
-MAX_TRAINER_CHANNELS
-MAX_OUTPUT_CHANNELS
-MAX_GVARS
);
395 idx
-= MIXSRC_FIRST_TELEM
;
396 div_t qr
= div(idx
, 3);
398 int pos
= 1 + zchar2str(&dest
[1], g_model
.telemetrySensors
[qr
.quot
].label
, sizeof(g_model
.telemetrySensors
[qr
.quot
].label
));
399 if (qr
.rem
) dest
[pos
++] = (qr
.rem
==2 ? '+' : '-');
407 char * strAppendUnsigned(char * dest
, uint32_t value
, uint8_t digits
, uint8_t radix
)
410 unsigned int tmp
= value
;
412 while (tmp
>= radix
) {
417 uint8_t idx
= digits
;
419 uint32_t rem
= value
% radix
;
420 dest
[--idx
] = (rem
>= 10 ? 'A'-10 : '0') + rem
;
424 return &dest
[digits
];
427 char * strAppendSigned(char * dest
, int32_t value
, uint8_t digits
, uint8_t radix
)
433 return strAppendUnsigned(dest
, (uint32_t)value
, digits
, radix
);
436 #if defined(CPUARM) || defined(SDCARD)
437 char * strAppend(char * dest
, const char * source
, int len
)
439 while ((*dest
++ = *source
++)) {
448 char * strSetCursor(char * dest
, int position
)
456 char * strAppendFilename(char * dest
, const char * filename
, const int size
)
458 memset(dest
, 0, size
);
459 for (int i
=0; i
<size
; i
++) {
460 char c
= *filename
++;
461 if (c
== '\0' || c
== '.')
471 char * strAppendDate(char * str
, bool time
)
476 div_t qr
= div(utm
.tm_year
+TM_YEAR_BASE
, 10);
477 str
[4] = '0' + qr
.rem
;
478 qr
= div(qr
.quot
, 10);
479 str
[3] = '0' + qr
.rem
;
480 qr
= div(qr
.quot
, 10);
481 str
[2] = '0' + qr
.rem
;
482 str
[1] = '0' + qr
.quot
;
484 qr
= div(utm
.tm_mon
+1, 10);
485 str
[7] = '0' + qr
.rem
;
486 str
[6] = '0' + qr
.quot
;
488 qr
= div(utm
.tm_mday
, 10);
489 str
[10] = '0' + qr
.rem
;
490 str
[9] = '0' + qr
.quot
;
494 div_t qr
= div(utm
.tm_hour
, 10);
495 str
[13] = '0' + qr
.rem
;
496 str
[12] = '0' + qr
.quot
;
497 qr
= div(utm
.tm_min
, 10);
498 str
[15] = '0' + qr
.rem
;
499 str
[14] = '0' + qr
.quot
;
500 qr
= div(utm
.tm_sec
, 10);
501 str
[17] = '0' + qr
.rem
;
502 str
[16] = '0' + qr
.quot
;