/* fields.c */ #include #include #include #include #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); }