You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
268 lines
4.7 KiB
268 lines
4.7 KiB
/* fields.c */ |
|
|
|
#include <stddef.h> |
|
#include <string.h> |
|
#include <avr/io.h> |
|
#include <avr/pgmspace.h> |
|
|
|
#include "common.h" |
|
#include "fields.h" |
|
#include "menu.h" |
|
#include "config.h" |
|
|
|
uint8_t field_row; // XXX ? |
|
uint8_t field_values[DISPLAY_CHARS]; |
|
|
|
static uint8_t field_index(char c) |
|
{ |
|
return ((uint8_t)(c) & (uint8_t)15)-1; |
|
} |
|
//#define field(c) fields[((uint8_t)(c) & (uint8_t)15)-1] |
|
#define field(c) fields[field_index(c)] |
|
|
|
uint8_t field_length(char c) |
|
{ |
|
return field(c).length; |
|
} |
|
|
|
bool field_is_text(char c) |
|
{ |
|
return field(c).display == NULL; |
|
} |
|
|
|
PGM_P field_text(char c, uint8_t n) |
|
{ |
|
return get_string(&field(c).display[n]); |
|
} |
|
|
|
uint8_t field_display_entries(char c) |
|
{ |
|
return field(c).display_entries; |
|
} |
|
|
|
bool is_field(char c) { |
|
return (c > 0) && (c < 32); |
|
} |
|
|
|
bool is_editable(char c) { |
|
return (c > 16) && (c < 32); |
|
} |
|
|
|
PGM_P get_string(PGM_P const *addr) |
|
{ |
|
PGM_P ptr; |
|
memcpy_P(&ptr, addr, sizeof(PGM_P)); |
|
return ptr; |
|
} |
|
|
|
uint8_t find_field(uint8_t n) |
|
{ |
|
char c; |
|
uint8_t index = 0; |
|
char type = 0; |
|
|
|
while ((c = menu_getchar(index)) != '\0') { |
|
index++; |
|
if (type && (type == c)) |
|
continue; |
|
if (is_field(c)) { |
|
type = c; |
|
if (n == 0) |
|
return index-1; |
|
n--; |
|
} else { |
|
type = 0; |
|
} |
|
} |
|
return 255; |
|
} |
|
|
|
uint8_t find_field_length_by_place(uint8_t index) |
|
{ |
|
uint8_t orig_index = index; |
|
char type = menu_getchar(index); |
|
uint8_t tlen = field_length(type); |
|
|
|
while (menu_getchar(index) == type) |
|
index += tlen; |
|
|
|
return index - orig_index; |
|
} |
|
|
|
uint8_t find_field_length(uint8_t index) |
|
{ |
|
return find_field_length_by_place(find_field(index)); |
|
} |
|
|
|
uint8_t find_field_number(uint8_t index) |
|
{ |
|
uint8_t n, p; |
|
for (n = 0; (p = find_field(n)) != 255; n++) |
|
{ |
|
if (p == index) |
|
return n; |
|
} |
|
return 255; |
|
} |
|
|
|
uint8_t find_editable_field(uint8_t index, bool left) |
|
{ |
|
int8_t increment = left?(-1):1; |
|
char c; |
|
uint8_t len; |
|
|
|
if (index >= 255) |
|
return 255; |
|
|
|
len = strlen_P(get_string(&menu_current_p->text[field_row])); |
|
|
|
if (left && (index >= len)) |
|
index = len-1; |
|
|
|
while ((c = menu_getchar(index)) != '\0') { |
|
if (is_editable(c)) |
|
return index; |
|
index += increment; |
|
} |
|
return 255; |
|
} |
|
|
|
void write_field_enum(uint8_t field, uint8_t val) |
|
{ |
|
uint8_t p = find_field(field); |
|
field_values[p] = val; |
|
} |
|
|
|
uint8_t read_field_enum(uint8_t field) |
|
{ |
|
uint8_t p = find_field(field); |
|
return field_values[p]; |
|
} |
|
|
|
uint16_t read_field_uint16(uint8_t field) |
|
{ |
|
uint8_t i; |
|
uint16_t val = 0; |
|
|
|
uint8_t p = find_field(field); |
|
uint8_t l = find_field_length(field); |
|
|
|
for (i = 0; i < l; i++) { |
|
val = val * 10; |
|
val += field_values[p+i]; |
|
} |
|
|
|
return val; |
|
} |
|
|
|
void write_field_uint16(uint8_t field, uint16_t val) |
|
{ |
|
uint8_t i; |
|
|
|
uint8_t p = find_field(field); |
|
uint8_t l = find_field_length(field); |
|
|
|
for (i = l; i; i--) { |
|
field_values[p+i-1] = val % 10; |
|
val = val / 10; |
|
} |
|
} |
|
|
|
void write_field_integer_part(uint8_t field, int32_t val) |
|
{ |
|
if (val < 0) |
|
val = -val; |
|
|
|
write_field_uint16(field, val >> 12); |
|
} |
|
|
|
void write_field_fractional_part(uint8_t field, int32_t val) |
|
{ |
|
uint8_t i; |
|
uint16_t v; |
|
|
|
uint8_t p = find_field(field); |
|
uint8_t l = find_field_length(field); |
|
|
|
if (val < 0) |
|
val = -val; |
|
|
|
v = val & 0xfff; |
|
|
|
for (i = 0; i < l; i++) { |
|
uint8_t digit; |
|
v = v * 10; |
|
digit = (v >> 12) % 10; |
|
v = v - (digit << 12); |
|
field_values[p+i] = digit; |
|
} |
|
} |
|
|
|
int32_t round_dp(int32_t n, uint8_t dp) |
|
{ |
|
int32_t rval = 0x800; |
|
int i; |
|
|
|
/* Round away from zero. Remove this bit |
|
* to round up |
|
*/ |
|
if (n < 0) |
|
rval = -rval; |
|
|
|
for (i = 0; i < dp; i++) |
|
rval = rval / 10; |
|
|
|
return n + rval; |
|
} |
|
|
|
uint32_t read_field_fracint(int8_t index, bool frac) |
|
{ |
|
int32_t val, v_int, v_frac; |
|
uint8_t sign = read_field_enum(index++); |
|
|
|
v_int = read_field_uint16(index++); |
|
|
|
if (frac) { |
|
uint8_t l_frac; |
|
v_frac = read_field_uint16(index); |
|
l_frac = find_field_length(index); |
|
|
|
v_frac = v_frac << 12; |
|
while (l_frac--) |
|
v_frac = v_frac / 10; |
|
} else { |
|
v_frac = 0; |
|
} |
|
|
|
val = (v_int << 12) + v_frac; |
|
|
|
if (sign == FIELD_SIGN_NEGATIVE) |
|
val = -val; |
|
|
|
return val; |
|
} |
|
|
|
void write_field_fracint(uint8_t index, bool sign, bool frac, int32_t val) |
|
{ |
|
uint8_t l_frac; |
|
|
|
l_frac = find_field_length(index+1+(sign?1:0)); |
|
|
|
val = round_dp(val, frac?l_frac:0); |
|
|
|
if (sign) |
|
write_field_enum(index++, (val<0)?FIELD_SIGN_NEGATIVE:FIELD_SIGN_POSITIVE); |
|
|
|
write_field_integer_part(index++, val); |
|
if (frac) |
|
write_field_fractional_part(index, val); |
|
} |
|
|
|
|
|
void write_field_temperature(uint8_t index, bool frac, temp_t k_temp) |
|
{ |
|
int32_t temp = temperature_from_kelvin(k_temp); |
|
write_field_fracint(index, TRUE, frac, temp); |
|
write_field_enum(index+2+(frac?1:0), config.units); |
|
} |
|
|
|
|