Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Enhance config system #626

Open
wants to merge 25 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
61222e6
Refector config module, add test cases for config module
howard0su Jan 21, 2019
78146aa
Convert Tx to new configure model
howard0su Jan 21, 2019
14135c6
Fix warning
howard0su Jan 21, 2019
45f788a
fix style
howard0su Jan 21, 2019
12eeddd
Fix build on non-touch Tx
howard0su Jan 21, 2019
fdddded
Fix write on devo7e
howard0su Jan 21, 2019
f81065c
Convert RTC field to the structure
howard0su Jan 22, 2019
6a23a59
Add font and color tests
howard0su Jan 23, 2019
914193e
Move model configuraiton to the shared routings
howard0su Feb 5, 2019
8c26fab
Fix build and test
howard0su Feb 8, 2019
8e63734
introduce defaults array for write ini
howard0su Feb 8, 2019
d734651
shortcut unsupported types
howard0su Feb 8, 2019
d8c703a
fix build
howard0su Feb 8, 2019
ea841c8
No localized string invovles in tx write
howard0su Feb 9, 2019
94100a9
Defaults can be shorter than the list
howard0su Feb 9, 2019
cc2d9ba
Support string callback
howard0su Feb 12, 2019
648cee3
Use the code to handle old format of color setting
howard0su Feb 12, 2019
0eb3716
Naming the code to handle back compatiablity as legacy
howard0su Feb 12, 2019
465258e
remove MATCH_ macro and add STR_CALL2 support
howard0su Feb 13, 2019
a892c9f
Convert more cases to data driven
howard0su Feb 13, 2019
93b3cb3
Fix bug in write ini file
howard0su Feb 13, 2019
2f21798
fix regression
howard0su Feb 13, 2019
d5202a1
Add tests to test against old model code
howard0su Feb 19, 2019
b3051d1
remove duplicate Protocol entry
howard0su Feb 22, 2019
863df0f
Fix the tests
howard0su Feb 22, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
291 changes: 291 additions & 0 deletions src/config/config.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,291 @@
/*
This project is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Deviation is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Deviation. If not, see <http://www.gnu.org/licenses/>.
*/

#include "common.h"
#include "gui/gui.h"
#include "config.h"
#include "display.h"
#include "mixer.h"
#include "tx.h"

#include <stdlib.h>
#include <string.h>

typedef const char* StringCallback(int value);
typedef const char* StringCallback2(char* buffer, int value);

extern u8 FONT_GetFromString(const char *);

static u16 get_color(const char *value) {
u8 r, g, b;
u32 color = strtol(value, NULL, 16);
r = 0xff & (color >> 16);
g = 0xff & (color >> 8);
b = 0xff & (color >> 0);
return RGB888_to_RGB565(r, g, b);
}

static u8 get_button(const char *value)
{
u8 i;
for (i = 0; i <= NUM_TX_BUTTONS; i++) {
if (strcasecmp(INPUT_ButtonName(i), value) == 0) {
return i;
}
}
printf("Could not parse Button %s\n", value);
return 0;
}


static s8 mapstrcasecmp(const char *s1, const char *s2)
{
int i = 0;
while (1) {
if (s1[i] == s2[i]
|| (s2[i] >= 'a' && s1[i] + ('a'-'A') == s2[i])
|| (s1[i] >= 'a' && s2[i] + ('a'-'A') == s1[i])
|| (s2[i] == ' ' && s1[i] == '_')
|| (s1[i] == ' ' && s2[i] == '_'))
{
if (s1[i] == '\0')
return 0;
i++;
continue;
}
return (s1[i] < s2[i] ? -1 : 1);
}
}

u8 get_source(const char *value)
{
unsigned i;
unsigned val;
const char *ptr = (value[0] == '!') ? value + 1 : value;
const char *tmp;
char cmp[10];
for (i = 0; i <= NUM_SOURCES; i++) {
if (mapstrcasecmp(INPUT_SourceNameReal(cmp, i), ptr) == 0) {
#if defined(HAS_SWITCHES_NOSTOCK) && HAS_SWITCHES_NOSTOCK
#define SWITCH_NOSTOCK ((1 << INP_HOLD0) | (1 << INP_HOLD1) | \
(1 << INP_FMOD0) | (1 << INP_FMOD1))
if ((Transmitter.ignore_src & SWITCH_NOSTOCK) == SWITCH_NOSTOCK) {
if (mapstrcasecmp("FMODE0", ptr) == 0 ||
mapstrcasecmp("FMODE1", ptr) == 0 ||
mapstrcasecmp("HOLD0", ptr) == 0 ||
mapstrcasecmp("HOLD1", ptr) == 0)
break;
}
#endif // HAS_SWITCHES_NOSTOCK
return ((ptr == value) ? 0 : 0x80) | i;
}
}
for (i = 0; i < 4; i++) {
if (mapstrcasecmp(tx_stick_names[i], ptr) == 0) {
return ((ptr == value) ? 0 : 0x80) | (i + 1);
}
}
i = 0;
while ((tmp = INPUT_MapSourceName(i++, &val))) {
if (mapstrcasecmp(tmp, ptr) == 0) {
return ((ptr == value) ? 0 : 0x80) | val;
}
}
printf("Could not parse Source %s\n", value);
return 0;
}

int assign_int(void* ptr, const struct struct_map *map, int map_size, const char* name, const char* value) {
for (int i = 0; i < map_size; i++) {
howard0su marked this conversation as resolved.
Show resolved Hide resolved
if (strcasecmp(name, map[i].str) == 0) {
int size = map[i].offset >> 12;
int offset = map[i].offset & 0xFFF;
switch (size) {
case TYPE_S8:
*((s8 *)((u8*)ptr + offset)) = atoi(value); break;
case TYPE_S16:
*((s16 *)((u8*)ptr + offset)) = atoi(value); break;
case TYPE_S32:
*((s32 *)((u8*)ptr + offset)) = atoi(value); break;

case TYPE_U8:
*((u8 *)((u8*)ptr + offset)) = atoi(value); break;
case TYPE_U16:
*((u16 *)((u8*)ptr + offset)) = atoi(value); break;
case TYPE_U32:
*((u32 *)((u8*)ptr + offset)) = atoi(value); break;

case TYPE_COLOR:
*((u16 *)((u8*)ptr + offset)) = get_color(value); break;
case TYPE_FONT:
*((u8 *)((u8*)ptr + offset)) = FONT_GetFromString(value); break;
case TYPE_BUTTON:
*((u8 *)((u8*)ptr + offset)) = get_button(value); break;
case TYPE_SOURCE:
*((u8 *)((u8*)ptr + offset)) = get_source(value); break;

case TYPE_STR_LIST: {
// get the list
i++; // next entry is additional info for string list
const char* const *list = (const char* const *)map[i].str;
unsigned length = map[i].offset;
for (unsigned j = 0; j < length; j++) {
if (list[j] && strcasecmp(value, list[j]) == 0) {
*((u8 *)((u8*)ptr + offset)) = j;
return 1;
}
}
printf("unknow value %s for %s\n", value, name);
break;
}
case TYPE_STR_CALL: {
i++;
unsigned j;
StringCallback *callback = (StringCallback*)map[i].str;

// If the length is larger than 256, upper part is start index
if (map[i].offset & 0xFF00) {
j = (map[i].offset & 0xFF00) >> 8;
} else {
j = 0;
}

for (; j < (map[i].offset & 0xFF); j++)
{
if (mapstrcasecmp(value, callback(j)) == 0) {
*((u8 *)((u8*)ptr + offset)) = j;
return 1;
}
}
printf("unknow value %s for %s\n", value, name);
break;
}
case TYPE_STR_CALL2: {
i++;
char strbuf[30];
unsigned j;
StringCallback2 *callback = (StringCallback2*)map[i].str;
// If the length is larger than 256, upper part is start index
if (map[i].offset & 0xFF00) {
j = (map[i].offset & 0xFF00) >> 8;
} else {
j = 0;
}
for (; j < (map[i].offset & 0xFF); j++)
{
if (mapstrcasecmp(value, callback(strbuf, j)) == 0) {
*((u8 *)((u8*)ptr + offset)) = j;
return 1;
}
}
printf("unknow value %s for %s\n", value, name);
break;
}
default:
printf("Unknown type: %d\n", size);
break;
}
return 1;
}
}
return 0;
}

int write_int2(void* ptr, const struct struct_map *map, int map_size,
const u16* defaults, int defaults_size, FILE* fh) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you rename this? from its name i'd expect it to write a single int, but it actually writes a whole struct of them. 'write_ints_from_map' or something more descriptive

Copy link
Contributor Author

@howard0su howard0su Feb 12, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. I will do it later. assign_int -> parse_ini_map, write_int ->write_ini_map, write_int2 ->write_ini_map_defaults

for (int i = 0; i < map_size; i++) {
int size = map[i].offset >> 12;
int offset = map[i].offset & 0xFFF;
int value;

switch (size) {
case TYPE_S8:
value = *((s8 *)((u8*)ptr + offset)); break;
case TYPE_S16:
value = *((s16 *)((u8*)ptr + offset)); break;
case TYPE_S32:
value = *((s32 *)((u8*)ptr + offset)); break;

case TYPE_U8:
value = *((u8 *)((u8*)ptr + offset)); break;
case TYPE_U16:
value = *((u16 *)((u8*)ptr + offset)); break;
case TYPE_U32:
value = *((u32 *)((u8*)ptr + offset)); break;

case TYPE_STR_LIST:
case TYPE_STR_CALL:
case TYPE_STR_CALL2:
i++; // next entry is additional info for string list
value = *((u8 *)((u8*)ptr + offset));
break;

case TYPE_BUTTON:
case TYPE_SOURCE:
value = *((u8 *)((u8*)ptr + offset)); break;

default:
continue; // unsupported type
}

if (defaults == DEFAULTS_ZERO) {
if (value == 0) continue;
} else if (defaults == DEFAULTS_ALWAYS) {
// always write out
} else if (defaults != NULL) {
if (i < defaults_size && value == defaults[i]) continue;
}

switch (size)
{
case TYPE_STR_LIST: {
const char* const *list = (const char* const *)map[i].str;
fprintf(fh, "%s=%s\n", map[i - 1].str, list[value]);
break;
}
case TYPE_BUTTON:
fprintf(fh, "%s=%s\n", map[i].str, INPUT_ButtonName(value));
break;
case TYPE_SOURCE: {
char tmpstr[20];
fprintf(fh, "%s=%s\n", map[i].str, INPUT_SourceNameReal(tmpstr, value));
break;
}
case TYPE_STR_CALL: {
StringCallback *callback = (StringCallback*)map[i].str;
fprintf(fh, "%s=%s\n", map[i - 1].str, callback(value));
break;
}
case TYPE_STR_CALL2: {
char strbuf[30];
StringCallback2 *callback = (StringCallback2*)map[i].str;
fprintf(fh, "%s=%s\n", map[i - 1].str, callback(strbuf, value));
break;
}
default:
fprintf(fh, "%s=%d\n", map[i].str, value);
}
}

return 1;
}

int write_int(void* ptr, const struct struct_map *map, int map_size, FILE* fh) {
return write_int2(ptr, map, map_size, DEFAULTS_ALWAYS, 0, fh);
}

#define TESTNAME config
#include "tests.h"

64 changes: 64 additions & 0 deletions src/config/config.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
This project is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Deviation is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Deviation. If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef __CONFIG_H_
#define __CONFIG_H_

#include <stddef.h>

enum {
TYPE_U8 = 0,
TYPE_U16 = 1,
TYPE_U32 = 3,

TYPE_S8 = 4,
TYPE_S16 = 5,
TYPE_S32 = 7,

TYPE_STR_LIST = 8,
TYPE_STR_CALL = 9,
TYPE_STR_CALL2 = 10,

TYPE_COLOR = 11,
TYPE_FONT = 12,
TYPE_SOURCE = 13,
TYPE_BUTTON = 14,
};

struct struct_map {const char *str; u16 offset;};
#define ARRAYSIZE(x) (sizeof(x) / sizeof(x[0]))
#define OFFSET(s, v) (offsetof(s, v) | ((sizeof(((s*)0)->v) - 1) << 12))
#define OFFSETS(s, v) (offsetof(s, v) | ((sizeof(((s*)0)->v) + 3) << 12))
#define OFFSET_COL(s, v) (offsetof(s, v) | (TYPE_COLOR << 12))
#define OFFSET_FON(s, v) (offsetof(s, v) | (TYPE_FONT << 12))
#define OFFSET_STRLIST(s, v, StrList, StrListSize) \
(offsetof(s, v) | (TYPE_STR_LIST << 12)) }, { (const char*)StrList, StrListSize
#define OFFSET_STRCALL(s, v, StrCallback, N) \
(offsetof(s, v) | (TYPE_STR_CALL << 12)) }, { (const char*)StrCallback, N
#define OFFSET_STRCALL2(s, v, StrCallback, N) \
(offsetof(s, v) | (TYPE_STR_CALL2 << 12)) }, { (const char*)StrCallback, N
#define OFFSET_SRC(s, v) (offsetof(s, v) | (TYPE_SOURCE << 12))
#define OFFSET_BUT(s, v) (offsetof(s, v) | (TYPE_BUTTON << 12))

int assign_int(void* ptr, const struct struct_map *map, int map_size,
const char* name, const char* value);
int write_int(void* ptr, const struct struct_map *map, int map_size, FILE* fh);

#define DEFAULTS_ZERO (const u16*)0x01
#define DEFAULTS_ALWAYS (const u16*)0x02
int write_int2(void* ptr, const struct struct_map *map, int map_size,
const u16* defaults, int defaults_size, FILE* fh);

#endif
Loading