Merge companion and firmware notes, and get them from the server (#5530)
[opentx.git] / radio / src / strhelpers.cpp
blobedb575ffa757c12311523bdc4d27721fd314a64a
1 /*
2 * Copyright (C) OpenTX
4 * Based on code named
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.
21 #include "opentx.h"
23 #if !defined(BOOT)
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 ' ';
34 if (idx < 0) {
35 if (idx > -27) return 'a' - idx - 1;
36 idx = -idx;
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;
43 #endif
44 return ' ';
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);
53 #endif
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;
60 return 0;
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]);
76 do {
77 dest[size--] = '\0';
78 } while (size >= 0 && dest[size] == ' ');
79 return size+1;
81 #endif
83 #if defined(CPUARM)
84 unsigned int effectiveLen(const char * str, unsigned int size)
86 while (size > 0) {
87 if (str[size-1] != ' ')
88 return size;
89 size--;
91 return 0;
94 bool zexist(const char * str, uint8_t size)
96 for (int i=0; i<size; i++) {
97 if (str[i] != 0)
98 return true;
100 return false;
103 uint8_t zlen(const char * str, uint8_t size)
105 while (size > 0) {
106 if (str[size-1] != 0)
107 return size;
108 size--;
110 return 0;
113 char * strcat_zchar(char * dest, const char * name, uint8_t size, const char * defaultName, uint8_t defaultNameSize, uint8_t defaultIdx)
115 int8_t len = 0;
117 if (name) {
118 memcpy(dest, name, size);
119 dest[size] = '\0';
121 int8_t i = size-1;
123 while (i>=0) {
124 if (!len && dest[i])
125 len = i+1;
126 if (len) {
127 if (dest[i])
128 dest[i] = idx2char(dest[i]);
129 else
130 dest[i] = '_';
132 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;
143 return &dest[len];
145 #endif
146 #endif
148 #if defined(CPUARM) && !defined(BOOT)
149 char * getStringAtIndex(char * dest, const char * s, int idx)
151 uint8_t len = s[0];
152 strncpy(dest, s+1+len*idx, len);
153 dest[len] = '\0';
154 return dest;
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)
164 char * s = dest;
165 div_t qr;
167 if (tme < 0) {
168 tme = -tme;
169 *s++ = '-';
172 qr = div((int)tme, 60);
174 if (hours) {
175 div_t qr2 = div(qr.quot, 60);
176 *s++ = '0' + (qr2.quot / 10);
177 *s++ = '0' + (qr2.quot % 10);
178 *s++ = ':';
179 qr.quot = qr2.rem;
182 *s++ = '0' + (qr.quot / 10);
183 *s++ = '0' + (qr.quot % 10);
184 *s++ = ':';
185 *s++ = '0' + (qr.rem / 10);
186 *s++ = '0' + (qr.rem % 10);
187 *s = '\0';
189 return dest;
192 char * getCurveString(char * dest, int idx)
194 if (idx == 0) {
195 return getStringAtIndex(dest, STR_MMMINV, 0);
198 char * s = dest;
199 if (idx < 0) {
200 *s++ = '!';
201 idx = -idx;
204 if (ZEXIST(g_model.curves[idx - 1].name))
205 zchar2str(s, g_model.curves[idx - 1].name, LEN_CURVE_NAME);
206 else
207 strAppendStringWithIndex(s, STR_CV, idx);
209 return dest;
212 char * getGVarString(char * dest, int idx)
214 char * s = dest;
215 if (idx < 0) {
216 *s++ = '-';
217 idx = -idx-1;
220 if (ZEXIST(g_model.gvars[idx].name))
221 zchar2str(s, g_model.gvars[idx].name, LEN_GVAR_NAME);
222 else
223 strAppendStringWithIndex(s, STR_GV, idx+1);
225 return dest;
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);
237 char * s = dest;
238 if (idx < 0) {
239 *s++ = '!';
240 idx = -idx;
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);
249 #else
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
258 else {
259 *s++ = 'S';
260 #if defined(PCBX7)
261 if (swinfo.quot == 5)
262 *s++ = 'H';
263 else if (swinfo.quot == 4)
264 *s++ = 'F';
265 else
266 *s++ = 'A'+swinfo.quot;
267 #else
268 *s++ = 'A'+swinfo.quot;
269 #endif
271 *s++ = "\300-\301"[swinfo.rem];
272 *s = '\0';
274 #endif // PCBSKY9X
276 #if NUM_XPOTS > 0
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);
284 #endif
286 #if defined(PCBSKY9X)
287 else if (idx <= SWSRC_REa) {
288 getStringAtIndex(s, STR_VSWITCHES, IDX_TRIMS_IN_STR_VSWITCHES+idx-SWSRC_FIRST_TRIM);
290 #else
291 else if (idx <= SWSRC_LAST_TRIM) {
292 getStringAtIndex(s, STR_VSWITCHES, IDX_TRIMS_IN_STR_VSWITCHES+idx-SWSRC_FIRST_TRIM);
294 #endif
296 else if (idx <= SWSRC_LAST_LOGICAL_SWITCH) {
297 *s++ = 'L';
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) {
307 strcpy(s, "Tele");
309 else {
310 zchar2str(s, g_model.telemetrySensors[idx-SWSRC_FIRST_SENSOR].label, TELEM_LABEL_LEN);
313 return dest;
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;
323 *dest++ = '\314';
324 if (ZEXIST(g_model.inputNames[idx])) {
325 zchar2str(dest, g_model.inputNames[idx], LEN_INPUT_NAME);
326 dest[LEN_INPUT_NAME] = '\0';
328 else {
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) {
337 *dest++ = '\322';
338 // *dest++ = '1'+qr.quot;
339 strcpy(dest, scriptInputsOutputs[qr.quot].outputs[qr.rem].name);
341 #else
342 strcpy(dest, "N/A");
343 #endif
345 #endif
346 else if (idx <= MIXSRC_LAST_POT) {
347 idx -= MIXSRC_Rud;
348 if (ZEXIST(g_eeGeneral.anaNames[idx])) {
349 zchar2str(dest, g_eeGeneral.anaNames[idx], LEN_ANA_NAME);
350 dest[LEN_ANA_NAME] = '\0';
352 else {
353 getStringAtIndex(dest, STR_VSRCRAW, idx + 1);
356 else if (idx <= MIXSRC_LAST_TRIM) {
357 idx -= MIXSRC_Rud;
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';
366 else {
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';
390 else {
391 getStringAtIndex(dest, STR_VSRCRAW, idx-MIXSRC_Rud+1-MAX_LOGICAL_SWITCHES-MAX_TRAINER_CHANNELS-MAX_OUTPUT_CHANNELS-MAX_GVARS);
394 else {
395 idx -= MIXSRC_FIRST_TELEM;
396 div_t qr = div(idx, 3);
397 dest[0] = '\321';
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 ? '+' : '-');
400 dest[pos] = '\0';
403 return dest;
405 #endif
407 char * strAppendUnsigned(char * dest, uint32_t value, uint8_t digits, uint8_t radix)
409 if (digits == 0) {
410 unsigned int tmp = value;
411 digits = 1;
412 while (tmp >= radix) {
413 ++digits;
414 tmp /= radix;
417 uint8_t idx = digits;
418 while(idx > 0) {
419 uint32_t rem = value % radix;
420 dest[--idx] = (rem >= 10 ? 'A'-10 : '0') + rem;
421 value /= radix;
423 dest[digits] = '\0';
424 return &dest[digits];
427 char * strAppendSigned(char * dest, int32_t value, uint8_t digits, uint8_t radix)
429 if (value < 0) {
430 *dest++ = '-';
431 value = -value;
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++)) {
440 if (--len == 0) {
441 *dest = '\0';
442 return dest;
445 return dest - 1;
448 char * strSetCursor(char * dest, int position)
450 *dest++ = 0x1F;
451 *dest++ = position;
452 *dest = '\0';
453 return dest;
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 == '.')
462 break;
463 *dest++ = c;
465 return dest;
468 #if defined(RTCLOCK)
469 #include "rtc.h"
471 char * strAppendDate(char * str, bool time)
473 str[0] = '-';
474 struct gtm utm;
475 gettime(&utm);
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;
483 str[5] = '-';
484 qr = div(utm.tm_mon+1, 10);
485 str[7] = '0' + qr.rem;
486 str[6] = '0' + qr.quot;
487 str[8] = '-';
488 qr = div(utm.tm_mday, 10);
489 str[10] = '0' + qr.rem;
490 str[9] = '0' + qr.quot;
492 if (time) {
493 str[11] = '-';
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;
503 str[18] = '\0';
504 return &str[18];
506 else {
507 str[11] = '\0';
508 return &str[11];
511 #endif
512 #endif