diff --git a/Font5x7.c b/Font5x7.c index 63f66bd..0a3a828 100644 --- a/Font5x7.c +++ b/Font5x7.c @@ -10,14 +10,17 @@ */ #define FONT_GET_DATA(ch) (&x5x7_bits[ch*7]) -#define FONT_GET_WIDTH(ch) (7-x5x7_bits[ch*7]&3) +#define FONT_GET_WIDTH(ch) (8-x5x7_bits[ch*7]&7) #define FONT_GET_HEIGHT 7 -#define CHAR5x7_WIDTH_MASK 0x03 -#define CHAR5x7_WIDTH_4px 0x03 -#define CHAR5x7_WIDTH_5px 0x02 -#define CHAR5x7_WIDTH_6px 0x01 -#define CHAR5x7_WIDTH_7px 0x00 +#define CHAR5x7_WIDTH_1px 0x07 +#define CHAR5x7_WIDTH_2px 0x06 +#define CHAR5x7_WIDTH_3px 0x05 +#define CHAR5x7_WIDTH_4px 0x04 +#define CHAR5x7_WIDTH_5px 0x03 +#define CHAR5x7_WIDTH_6px 0x02 +#define CHAR5x7_WIDTH_7px 0x01 +#define CHAR5x7_WIDTH_8px 0x00 /* Font character bitmap data. */ const uint8_t x5x7_bits[127*7] = @@ -100,23 +103,23 @@ const uint8_t x5x7_bits[127*7] = 0b00100000, /* Character (0x04): - width=7 + width=6 +--------+ | | - | ** | - | ** | - | * * | - | * * | - |* * | - |****** | + | * | + | * | + | * * | + | * * | + |* * | + |***** | +--------+ */ - 0b00000000|CHAR5x7_WIDTH_7px, - 0b00110000, - 0b00110000, - 0b01001000, - 0b01001000, - 0b10000100, - 0b11111100, + 0b00000000|CHAR5x7_WIDTH_6px, + 0b00100000, + 0b00100000, + 0b01010000, + 0b01010000, + 0b10001000, + 0b11111000, /* Character (0x05): width=5 @@ -575,22 +578,22 @@ const uint8_t x5x7_bits[127*7] = 0b10011000, /* Character (0x1d): - width=7 + width=6 +--------+ | | | | - | * * | - | * * | - | ** ** | - | * * * | + |* * | + |* * | + |** ** | + |* * * | |* | +--------+ */ - 0b00000000|CHAR5x7_WIDTH_7px, + 0b00000000|CHAR5x7_WIDTH_6px, 0b00000000, - 0b01000100, - 0b01000100, - 0b01101100, - 0b01010100, + 0b10001000, + 0b10001000, + 0b11011000, + 0b10101000, 0b10000000, /* Character (0x1e): @@ -632,7 +635,7 @@ const uint8_t x5x7_bits[127*7] = 0b00000000, /* Character (0x20): ' ' - width=4 + width=3 +--------+ | | | | @@ -642,7 +645,7 @@ const uint8_t x5x7_bits[127*7] = | | | | +--------+ */ - 0b00000000|CHAR5x7_WIDTH_4px, + 0b00000000|CHAR5x7_WIDTH_3px, 0b00000000, 0b00000000, 0b00000000, @@ -651,7 +654,7 @@ const uint8_t x5x7_bits[127*7] = 0b00000000, /* Character (0x21): '!' - width=4 + width=3 +--------+ | * | | * | @@ -661,7 +664,7 @@ const uint8_t x5x7_bits[127*7] = | | | * | +--------+ */ - 0b01000000|CHAR5x7_WIDTH_4px, + 0b01000000|CHAR5x7_WIDTH_3px, 0b01000000, 0b01000000, 0b01000000, @@ -870,7 +873,7 @@ const uint8_t x5x7_bits[127*7] = | * | |* | +--------+ */ - 0b00000000|CHAR5x7_WIDTH_4px, + 0b00000000|CHAR5x7_WIDTH_3px, 0b00000000, 0b00000000, 0b00000000, @@ -908,7 +911,7 @@ const uint8_t x5x7_bits[127*7] = |** | |** | +--------+ */ - 0b00000000|CHAR5x7_WIDTH_4px, + 0b00000000|CHAR5x7_WIDTH_3px, 0b00000000, 0b00000000, 0b00000000, diff --git a/chprintf.c b/chprintf.c new file mode 100644 index 0000000..8c75b29 --- /dev/null +++ b/chprintf.c @@ -0,0 +1,534 @@ +/* + ChibiOS - Copyright (C) 2006..2016 Giovanni Di Sirio + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +/* + Concepts and parts of this file have been contributed by Fabio Utzig, + chvprintf() added by Brent Roman. + */ + +/** + * @file chprintf.c + * @brief Mini printf-like functionality. + * + * @addtogroup chprintf + * @{ + */ + +#include "hal.h" +#include "chprintf.h" +#include "memstreams.h" +#include + +// Enable [flags], support: +// ' ' Prepends a space for positive signed-numeric types. positive = ' ', negative = '-'. This flag is ignored if the + flag exists. +//#define CHPRINTF_USE_SPACE_FLAG + +#define MAX_FILLER 11 +#define FLOAT_PRECISION 9 + +#pragma pack(push, 2) + +static const uint32_t pow10[FLOAT_PRECISION+1] = { + 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 +}; +// Prefixes for values bigger then 1000.0 +// 1 1e3, 1e6, 1e9, 1e12, 1e15, 1e18, 1e21, 1e24 +static char bigPrefix[] = {' ', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y', 0}; +// Prefixes for values less then 1.0 +// 1e-3, 1e-6, 1e-9, 1e-12, 1e-15, 1e-18, 1e-21, 1e-24 +static char smallPrefix[]= { 'm', 0x1d, 'n', 'p', 'f', 'a', 'z', 'y', 0}; + +#pragma pack(pop) + +//86066 5116 11456 102622 190de build/ch.elf +static char *long_to_string_with_divisor(char *p, + uint32_t num, + uint32_t radix, + uint32_t precision) { + char *q = p + MAX_FILLER; + char *b = q; + // convert to string from end buffer to begin + do { + uint8_t c = num % radix; + num /= radix; + *--q = c + ((c > 9) ? 'A' : '0'); + }while((precision && --precision) || num); + // copy string at begin + int i = (int)(b - q); + do + *p++ = *q++; + while (--i); + return p; +} + +// default prescision = 13 +// g.mmm kkk hhh +#define MAX_FREQ_PRESCISION 13 +#define FREQ_PSET 1 +#define FREQ_NO_SPACE 2 +#define FREQ_PREFIX_SPACE 4 + +static char *ulong_freq(char *p, uint32_t freq, uint32_t precision){ + uint8_t flag = FREQ_PSET; + if (precision == 0) + flag|=FREQ_PREFIX_SPACE; + if (precision == 0 || precision > MAX_FREQ_PRESCISION) + precision = MAX_FREQ_PRESCISION; + char *q = p + MAX_FREQ_PRESCISION; + char *b = q; + // Prefix counter + uint32_t s = 0; + // Set format (every 3 digits add ' ' up to GHz) + uint32_t format=0b00100100100; + do { +#if 0 + uint8_t c = freq % 10; + freq/= 10; +#else + // Fast and compact division uint32_t on 10, using shifts, result: + // c = freq % 10 + // freq = freq / 10; + uint32_t c = freq; + freq>>=1; + freq+=freq>>1; + freq+=freq>>4; + freq+=freq>>8; + freq+=freq>>16; // freq = 858993459*freq/1073741824 = freq * 0,799999999813735485076904296875 + freq>>=3; // freq/=8; freq = freq * 0,09999999997671693563461303710938 + c-= freq*10; // freq*10 = (freq*4+freq)*2 = ((freq<<2)+freq)<<1 + while (c>=10) {freq++;c-=10;} +#endif + *--q = c + '0'; + if (freq==0) + break; + // Add spaces, calculate prefix + if (format&1) {*--q = ' '; s++;} + format>>=1; + } while (1); + s = bigPrefix[s]; + + // Get string size + uint32_t i = (b - q); + // Limit string size, max size is - precision + if (precision && i > precision) { + i = precision; + flag|=FREQ_NO_SPACE; + } + // copy string + // Replace first ' ' by '.', remove ' ' if size too big + do{ + char c = *q++; + // replace first ' ' on '.' + if (c == ' ') { + if (flag&FREQ_PSET){ + c = '.'; + flag&=~FREQ_PSET; + } + else if (flag&FREQ_NO_SPACE) + c = *q++; + } + *p++ = c; + }while (--i); + // Put pref (amd space before it if need) + if (flag&FREQ_PREFIX_SPACE && s!=' ') + *p++ = ' '; + *p++ = s; + return p; +} + +#if CHPRINTF_USE_FLOAT +static char *ftoa(char *p, float num, uint32_t precision) { + // Check precision limit + if (precision > FLOAT_PRECISION) + precision = FLOAT_PRECISION; + uint32_t multi = pow10[precision]; + uint32_t l = num; + // Round value + uint32_t k = ((num-l)*multi+0.5); + // Fix rounding error if get + if (k>=multi){k-=multi;l++;} + p = long_to_string_with_divisor(p, l, 10, 0); + if (precision && k){ + *p++ = '.'; + p=long_to_string_with_divisor(p, k, 10, precision); + // remove zeros at end + while (p[-1]=='0') p--; + if (p[-1]=='.') p--; + } + return p; +} + +static char *ftoaS(char *p, float num, uint32_t precision) { + char prefix=0; + char *ptr; + if (num > 1000.0){ + for (ptr = bigPrefix+1; *ptr && num > 1000.0; num/=1000, ptr++) + ; + prefix = ptr[-1]; + } + else if (num < 1){ + for (ptr = smallPrefix; *ptr && num < 1.0; num*=1000, ptr++) + ; + prefix = num > 1e-3 ? ptr[-1] : 0; + } + // Auto set prescision + uint32_t l = num; + if (l < 10) + precision+=2; + else if (l < 100) + precision+=1; + p=ftoa(p, num, precision); + if (prefix) + *p++ = prefix; + return p; +} +#endif + +/** + * @brief System formatted output function. + * @details This function implements a minimal @p vprintf()-like functionality + * with output on a @p BaseSequentialStream. + * The general parameters format is: %[-][width|*][.precision|*][l|L]p. + * The following parameter types (p) are supported: + * - x hexadecimal integer. + * - X hexadecimal long. + * - o octal integer. + * - O octal long. + * - d decimal signed integer. + * - D decimal signed long. + * - u decimal unsigned integer. + * - U decimal unsigned long. + * - c character. + * - s string. + * . + * + * @param[in] chp pointer to a @p BaseSequentialStream implementing object + * @param[in] fmt formatting string + * @param[in] ap list of parameters + * @return The number of bytes that would have been + * written to @p chp if no stream error occurs + * + * @api + */ +#define IS_LONG 1 +#define LEFT_ALIGN 2 +#define POSITIVE 4 +#define NEGATIVE 8 +#define PAD_ZERO 16 +#define PLUS_SPACE 32 +#define DEFAULT_PRESCISION 64 + +int chvprintf(BaseSequentialStream *chp, const char *fmt, va_list ap) { + char *p, *s, c, filler=' '; + int precision, width; + int n = 0; + uint32_t state; + union { + uint32_t u; + int32_t l; + float f; + }value; +#if CHPRINTF_USE_FLOAT + char tmpbuf[2*MAX_FILLER + 1]; +#else + char tmpbuf[MAX_FREQ_PRESCISION + 1]; +#endif + + while (true) { + c = *fmt++; + if (c == 0) + return n; + if (c != '%') { + streamPut(chp, (uint8_t)c); + n++; + continue; + } + // Parse %[flags][width][.precision][length]type + p = tmpbuf; + s = tmpbuf; + state = 0; + width = 0; + precision = 0; + + // Get [flags], support: + // '-' Left-align the output of this placeholder. (The default is to right-align the output.) + // '+' Prepends a plus for positive signed-numeric types. positive = '+', negative = '-'. + // ' ' Prepends a space for positive signed-numeric types. positive = ' ', negative = '-'. This flag is ignored if the + flag exists. + // '0' When the 'width' option is specified, prepends zeros for numeric types. (The default prepends spaces.) + while (true){ + if (*fmt == '-') + state|=LEFT_ALIGN; + else if (*fmt == '+') + state|=POSITIVE; + else if (*fmt == '0') + state|=PAD_ZERO; +#ifdef CHPRINTF_USE_SPACE_FLAG + else if (*fmt == ' ') + state|=PLUS_SPACE; +#endif + else + break; + fmt++; + } + // Get [width] - The Width field specifies a minimum number of characters to output + // if set *, get width as argument + while (true) { + c = *fmt++; + if (c >= '0' && c <= '9') + c -= '0'; + else if (c == '*') + c = va_arg(ap, int); + else + break; + width = width * 10 + c; + } + // Get [.precision] + if (c == '.') { + while (true) { + c = *fmt++; + if (c >= '0' && c <= '9') + c -= '0'; + else if (c == '*') + c = va_arg(ap, int); + else + break; + precision = precision * 10 + c; + } + } + else + state|=DEFAULT_PRESCISION; + //Get [length] + /* + if (c == 'l' || c == 'L') { + state|=IS_LONG; + if (*fmt) + c = *fmt++; + } + else if((c >= 'A') && (c <= 'Z')) + state|=IS_LONG; + */ + // Parse type + switch (c) { + case 'c': + state&=~PAD_ZERO; + *p++ = va_arg(ap, int); + break; + case 's': + state&=~PAD_ZERO; + if ((s = va_arg(ap, char *)) == 0) + s = "(null)"; + if (state&DEFAULT_PRESCISION) + precision = 32767; + for (p = s; *p && (--precision >= 0); p++) + ; + break; + case 'D': + case 'd': + case 'I': + case 'i':/* + if (state & IS_LONG) + value.l = va_arg(ap, long); + else*/ + value.l = va_arg(ap, uint32_t); + if (value.l < 0) { + state|=NEGATIVE; + *p++ = '-'; + value.l = -value.l; + } + else if (state & POSITIVE) + *p++ = '+'; +#ifdef CHPRINTF_USE_SPACE_FLAG + else if (state & PLUS_SPACE) + *p++ = ' '; +#endif + p = long_to_string_with_divisor(p, value.l, 10, 0); + break; + case 'q': + value.u = va_arg(ap, uint32_t); + p=ulong_freq(p, value.u, precision); + break; +#if CHPRINTF_USE_FLOAT + case 'F': + case 'f': + value.f = va_arg(ap, double); + if (value.f < 0) { + state|=NEGATIVE; + *p++ = '-'; + value.f = -value.f; + } + else if (state & POSITIVE) + *p++ = '+'; +#ifdef CHPRINTF_USE_SPACE_FLAG + else if (state & PLUS_SPACE) + *p++ = ' '; +#endif + if (value.f == INFINITY){ + *p++ = 0x19; + break; + } + p = (c=='F') ? ftoaS(p, value.f, precision) : ftoa(p, value.f, state&DEFAULT_PRESCISION ? FLOAT_PRECISION : precision); + break; +#endif + case 'X': + case 'x': + c = 16; + goto unsigned_common; + case 'U': + case 'u': + c = 10; + goto unsigned_common; + case 'O': + case 'o': + c = 8; +unsigned_common:/* + if (state & IS_LONG) + value.u = va_arg(ap, unsigned long); + else*/ + value.u = va_arg(ap, uint32_t); + p = long_to_string_with_divisor(p, value.u, c, 0); + break; + default: + *p++ = c; + break; + } + // Now need print buffer s[{sign}XXXXXXXXXXXX]p and align it on width + // Check filler width (if buffer less then width) and prepare filler if need fill + if ((width -=(int)(p - s)) < 0) + width = 0; + else + filler = (state&PAD_ZERO) ? '0' : ' '; + // if left align, put sign digit, and fill + // [{sign}ffffffXXXXXXXXXXXX] + if (!(state&LEFT_ALIGN)) { + // Put '+' or '-' or ' ' first if need + if ((state&(NEGATIVE|POSITIVE|PLUS_SPACE)) && (state&PAD_ZERO)) { + streamPut(chp, (uint8_t)*s++); + n++; + } + // fill from left + while (width){ + streamPut(chp, (uint8_t)filler); + n++; + width--; + } + } + // put data + while (s < p) { + streamPut(chp, (uint8_t)*s++); + n++; + } + // Put filler from right (if need) + while (width) { + streamPut(chp, (uint8_t)filler); + n++; + width--; + } + } +} + +/** + * @brief System formatted output function. + * @details This function implements a minimal @p printf() like functionality + * with output on a @p BaseSequentialStream. + * The general parameters format is: %[-][width|*][.precision|*][l|L]p. + * The following parameter types (p) are supported: + * - x hexadecimal integer. + * - X hexadecimal long. + * - o octal integer. + * - O octal long. + * - d decimal signed integer. + * - D decimal signed long. + * - u decimal unsigned integer. + * - U decimal unsigned long. + * - c character. + * - s string. + * . + * + * @param[in] chp pointer to a @p BaseSequentialStream implementing object + * @param[in] fmt formatting string + * + * @api + */ +int chprintf(BaseSequentialStream *chp, const char *fmt, ...) { + va_list ap; + int formatted_bytes; + + va_start(ap, fmt); + formatted_bytes = chvprintf(chp, fmt, ap); + va_end(ap); + + return formatted_bytes; +} + +/** + * @brief System formatted output function. + * @details This function implements a minimal @p vprintf()-like functionality + * with output on a @p BaseSequentialStream. + * The general parameters format is: %[-][width|*][.precision|*][l|L]p. + * The following parameter types (p) are supported: + * - x hexadecimal integer. + * - X hexadecimal long. + * - o octal integer. + * - O octal long. + * - d decimal signed integer. + * - D decimal signed long. + * - u decimal unsigned integer. + * - U decimal unsigned long. + * - c character. + * - s string. + * . + * @post @p str is NUL-terminated, unless @p size is 0. + * + * @param[in] str pointer to a buffer + * @param[in] size maximum size of the buffer + * @param[in] fmt formatting string + * @return The number of characters (excluding the + * terminating NUL byte) that would have been + * stored in @p str if there was room. + * + * @api + */ +int chsnprintf(char *str, size_t size, const char *fmt, ...) { + va_list ap; + MemoryStream ms; + BaseSequentialStream *chp; + size_t size_wo_nul; + int retval; + + if (size > 0) + size_wo_nul = size - 1; + else + size_wo_nul = 0; + + /* Memory stream object to be used as a string writer, reserving one + byte for the final zero.*/ + msObjectInit(&ms, (uint8_t *)str, size_wo_nul, 0); + + /* Performing the print operation using the common code.*/ + chp = (BaseSequentialStream *)(void *)&ms; + va_start(ap, fmt); + retval = chvprintf(chp, fmt, ap); + va_end(ap); + + /* Terminate with a zero, unless size==0.*/ + if (ms.eos < size) + str[ms.eos] = 0; + + /* Return number of bytes that would have been written.*/ + return retval; +} + +/** @} */ diff --git a/main.c b/main.c index caf2f60..795d187 100644 --- a/main.c +++ b/main.c @@ -38,7 +38,7 @@ static void apply_error_term_at(int i); static void apply_edelay_at(int i); static void cal_interpolate(int s); void update_frequencies(void); -void set_frequencies(uint32_t start, uint32_t stop, int16_t points); +void set_frequencies(uint32_t start, uint32_t stop, uint16_t points); bool sweep(bool break_on_operation); @@ -57,7 +57,6 @@ int8_t cal_auto_interpolate = TRUE; uint16_t redraw_request = 0; // contains REDRAW_XXX flags int16_t vbat = 0; - static THD_WORKING_AREA(waThread1, 640); static THD_FUNCTION(Thread1, arg) { @@ -308,28 +307,94 @@ int set_frequency(uint32_t freq) return delay; } +// Use macro, std isdigit more big +#define _isdigit(c) (c >= '0' && c <= '9') +// Rewrite universal standart str to value functions to more compact +// +// Convert string to int32 +int32_t my_atoi(const char *p){ + int32_t value = 0; + uint32_t c; + bool neg = false; + + if (*p == '-') {neg = true; p++;} + if (*p == '+') p++; + while ((c = *p++ - '0') < 10) + value = value * 10 + c; + return neg ? -value : value; +} + +// Convert string to uint32 +uint32_t my_atoui(const char *p){ + uint32_t value = 0; + uint32_t c; + if (*p == '+') p++; + while ((c = *p++ - '0') < 10) + value = value * 10 + c; + return value; +} + +double +my_atof(const char *p) +{ + int neg = FALSE; + if (*p == '-') + neg = TRUE; + if (*p == '-' || *p == '+') + p++; + double x = my_atoi(p); + while (_isdigit((int)*p)) + p++; + if (*p == '.') { + double d = 1.0f; + p++; + while (_isdigit((int)*p)) { + d /= 10; + x += d * (*p - '0'); + p++; + } + } + if (*p == 'e' || *p == 'E') { + p++; + int exp = my_atoi(p); + while (exp > 0) { + x *= 10; + exp--; + } + while (exp < 0) { + x /= 10; + exp++; + } + } + if (neg) + x = -x; + return x; +} + static void cmd_offset(BaseSequentialStream *chp, int argc, char *argv[]) { if (argc != 1) { chprintf(chp, "usage: offset {frequency offset(Hz)}\r\n"); return; } - frequency_offset = atoi(argv[0]); + frequency_offset = my_atoui(argv[0]); set_frequency(frequency); } static void cmd_freq(BaseSequentialStream *chp, int argc, char *argv[]) { - int freq; if (argc != 1) { - chprintf(chp, "usage: freq {frequency(Hz)}\r\n"); - return; + goto usage; } + uint32_t freq = my_atoui(argv[0]); + pause_sweep(); chMtxLock(&mutex); - freq = atoi(argv[0]); set_frequency(freq); chMtxUnlock(&mutex); + return; +usage: + chprintf(chp, "usage: freq {frequency(Hz)}\r\n"); } static void cmd_power(BaseSequentialStream *chp, int argc, char *argv[]) @@ -338,7 +403,7 @@ static void cmd_power(BaseSequentialStream *chp, int argc, char *argv[]) chprintf(chp, "usage: power {0-3|-1}\r\n"); return; } - drive_strength = atoi(argv[0]); + drive_strength = my_atoi(argv[0]); set_frequency(frequency); } @@ -360,20 +425,20 @@ static void cmd_dac(BaseSequentialStream *chp, int argc, char *argv[]) chprintf(chp, "current value: %d\r\n", config.dac_value); return; } - value = atoi(argv[0]); + value = my_atoi(argv[0]); config.dac_value = value; dacPutChannelX(&DACD2, 0, value); } static void cmd_threshold(BaseSequentialStream *chp, int argc, char *argv[]) { - int value; + uint32_t value; if (argc != 1) { chprintf(chp, "usage: threshold {frequency in harmonic mode}\r\n"); chprintf(chp, "current: %d\r\n", config.harmonic_freq_threshold); return; } - value = atoi(argv[0]); + value = my_atoui(argv[0]); config.harmonic_freq_threshold = value; } @@ -490,7 +555,7 @@ static void cmd_data(BaseSequentialStream *chp, int argc, char *argv[]) int sel = 0; if (argc == 1) - sel = atoi(argv[0]); + sel = my_atoi(argv[0]); if (sel == 0 || sel == 1) { chMtxLock(&mutex); for (i = 0; i < sweep_points; i++) { @@ -517,7 +582,7 @@ static void cmd_dump(BaseSequentialStream *chp, int argc, char *argv[]) int len; if (argc == 1) - dump_selection = atoi(argv[0]); + dump_selection = my_atoi(argv[0]); wait_dsp(3); @@ -679,22 +744,22 @@ bool sweep(bool break_on_operation) static void cmd_scan(BaseSequentialStream *chp, int argc, char *argv[]) { - int32_t start, stop; + uint32_t start, stop; int16_t points = sweep_points; if (argc != 2 && argc != 3) { - chprintf(chp, "usage: sweep {start(Hz)} {stop(Hz)} [points]\r\n"); + chprintf(chp, "usage: scan {start(Hz)} {stop(Hz)} [points]\r\n"); return; } - start = atoi(argv[0]); - stop = atoi(argv[1]); + start = my_atoui(argv[0]); + stop = my_atoui(argv[1]); if (start == 0 || stop == 0 || start > stop) { chprintf(chp, "frequency range is invalid\r\n"); return; } if (argc == 3) { - points = atoi(argv[2]); + points = my_atoi(argv[2]); if (points <= 0 || points > sweep_points) { chprintf(chp, "sweep points exceeds range\r\n"); return; @@ -747,13 +812,21 @@ update_marker_index(void) } void -set_frequencies(uint32_t start, uint32_t stop, int16_t points) +set_frequencies(uint32_t start, uint32_t stop, uint16_t points) { - int i; - float span = stop - start; - for (i = 0; i < points; i++) { - float offset = i * span / (float)(points - 1); - frequencies[i] = start + (uint32_t)offset; + uint32_t i; + uint32_t step = (points - 1); + uint32_t span = stop - start; + uint32_t delta = span / step; + uint32_t error = span % step; + uint32_t f = start, df = step>>1; + for (i = 0; i <= step; i++, f+=delta) { + frequencies[i] = f; + df+=error; + if (df >=step) { + f++; + df-=step; + } } // disable at out of sweep range for (; i < sweep_points; i++) @@ -811,45 +884,35 @@ void set_sweep_frequency(int type, uint32_t freq) { int cal_applied = cal_status & CALSTAT_APPLY; -/* // negative value indicate overflow, do nothing - if (freq < 0) - return;*/ + + // Check frequency for out of bounds (minimum SPAN can be any value) + if (type!=ST_SPAN && freq < START_MIN) + freq = START_MIN; + if (freq > STOP_MAX) + freq = STOP_MAX; + switch (type) { case ST_START: freq_mode_startstop(); - if (freq < START_MIN) - freq = START_MIN; - if (freq > STOP_MAX) - freq = STOP_MAX; if (frequency0 != freq) { ensure_edit_config(); frequency0 = freq; // if start > stop then make start = stop if (frequency1 < freq) frequency1 = freq; - update_frequencies(); } break; case ST_STOP: freq_mode_startstop(); - if (freq > STOP_MAX) - freq = STOP_MAX; - if (freq < START_MIN) - freq = START_MIN; if (frequency1 != freq) { ensure_edit_config(); frequency1 = freq; // if start > stop then make start = stop if (frequency0 > freq) frequency0 = freq; - update_frequencies(); } break; case ST_CENTER: - if (freq < START_MIN) - freq = START_MIN; - if (freq > STOP_MAX) - freq = STOP_MAX; freq_mode_centerspan(); uint32_t center = frequency0/2 + frequency1/2; if (center != freq) { @@ -863,12 +926,9 @@ set_sweep_frequency(int type, uint32_t freq) } frequency0 = freq + span/2; frequency1 = freq - span/2; - update_frequencies(); } break; case ST_SPAN: - if (freq > STOP_MAX) - freq = STOP_MAX; freq_mode_centerspan(); if (frequency0 - frequency1 != freq) { ensure_edit_config(); @@ -881,24 +941,18 @@ set_sweep_frequency(int type, uint32_t freq) } frequency1 = center - freq/2; frequency0 = center + freq/2; - update_frequencies(); } break; case ST_CW: - if (freq < START_MIN) - freq = START_MIN; - if (freq > STOP_MAX) - freq = STOP_MAX; freq_mode_centerspan(); if (frequency0 != freq || frequency1 != freq) { ensure_edit_config(); frequency0 = freq; frequency1 = freq; - update_frequencies(); } break; } - + update_frequencies(); if (cal_auto_interpolate && cal_applied) cal_interpolate(lastsaveid); } @@ -926,7 +980,6 @@ get_sweep_frequency(int type) return 0; } - static void cmd_sweep(BaseSequentialStream *chp, int argc, char *argv[]) { if (argc == 0) { @@ -935,40 +988,34 @@ static void cmd_sweep(BaseSequentialStream *chp, int argc, char *argv[]) } else if (argc > 3) { goto usage; } - if (argc >= 2) { - if (strcmp(argv[0], "start") == 0) { - int32_t value = atoi(argv[1]); - set_sweep_frequency(ST_START, value); - return; - } else if (strcmp(argv[0], "stop") == 0) { - int32_t value = atoi(argv[1]); - set_sweep_frequency(ST_STOP, value); - return; - } else if (strcmp(argv[0], "center") == 0) { - int32_t value = atoi(argv[1]); - set_sweep_frequency(ST_CENTER, value); - return; - } else if (strcmp(argv[0], "span") == 0) { - int32_t value = atoi(argv[1]); - set_sweep_frequency(ST_SPAN, value); - return; - } else if (strcmp(argv[0], "cw") == 0) { - int32_t value = atoi(argv[1]); - set_sweep_frequency(ST_CW, value); - return; - } - } + uint32_t value0 = 0; + uint32_t value1 = 0; + if (argc >=1) value0 = my_atoui(argv[0]); + if (argc >=2) value1 = my_atoui(argv[1]); - if (argc >= 1) { - int32_t value = atoi(argv[0]); - if (value == 0) + // Parse sweep {start|stop|center|span|cw} {freq(Hz)} + if (argc == 2 && value0 == 0) { + int type; + if (strcmp(argv[0], "start") == 0) + type = ST_START; + else if (strcmp(argv[0], "stop") == 0) + type = ST_STOP; + else if (strcmp(argv[0], "center") == 0) + type = ST_CENTER; + else if (strcmp(argv[0], "span") == 0) + type = ST_SPAN; + else if (strcmp(argv[0], "cw") == 0) + type = ST_CW; + else goto usage; - set_sweep_frequency(ST_START, value); - } - if (argc >= 2) { - int32_t value = atoi(argv[1]); - set_sweep_frequency(ST_STOP, value); + set_sweep_frequency(type, value1); + return; } + // Parse sweep {start(Hz)} [stop(Hz)] + if (value0) + set_sweep_frequency(ST_START, value0); + if (value1) + set_sweep_frequency(ST_STOP, value1); return; usage: chprintf(chp, "usage: sweep {start(Hz)} [stop(Hz)]\r\n"); @@ -1365,7 +1412,7 @@ static void cmd_cal(BaseSequentialStream *chp, int argc, char *argv[]) } else if (strcmp(cmd, "in") == 0) { int s = 0; if (argc > 1) - s = atoi(argv[1]); + s = my_atoi(argv[1]); cal_interpolate(s); redraw_request |= REDRAW_CAL_STATUS; return; @@ -1382,7 +1429,7 @@ static void cmd_save(BaseSequentialStream *chp, int argc, char *argv[]) if (argc != 1) goto usage; - int id = atoi(argv[0]); + int id = my_atoi(argv[0]); if (id < 0 || id >= SAVEAREA_MAX) goto usage; caldata_save(id); @@ -1399,7 +1446,7 @@ static void cmd_recall(BaseSequentialStream *chp, int argc, char *argv[]) if (argc != 1) goto usage; - int id = atoi(argv[0]); + int id = my_atoi(argv[0]); if (id < 0 || id >= SAVEAREA_MAX) goto usage; @@ -1507,46 +1554,9 @@ float get_trace_refpos(int t) return trace[t].refpos; } -float -my_atof(const char *p) -{ - int neg = FALSE; - if (*p == '-') - neg = TRUE; - if (*p == '-' || *p == '+') - p++; - float x = atoi(p); - while (isdigit((int)*p)) - p++; - if (*p == '.') { - float d = 1.0f; - p++; - while (isdigit((int)*p)) { - d /= 10; - x += d * (*p - '0'); - p++; - } - } - if (*p == 'e' || *p == 'E') { - p++; - int exp = atoi(p); - while (exp > 0) { - x *= 10; - exp--; - } - while (exp < 0) { - x /= 10; - exp++; - } - } - if (neg) - x = -x; - return x; -} - typedef struct { - char *tracename; - uint8_t type; + char *tracename; + uint8_t type; } type_list; static void cmd_trace(BaseSequentialStream *chp, int argc, char *argv[]) @@ -1574,7 +1584,7 @@ static void cmd_trace(BaseSequentialStream *chp, int argc, char *argv[]) goto exit; } - t = atoi(argv[0]); + t = my_atoi(argv[0]); if (t < 0 || t >= 4) goto usage; if (argc == 1) { @@ -1585,27 +1595,27 @@ static void cmd_trace(BaseSequentialStream *chp, int argc, char *argv[]) } if (argc > 1) { - static const type_list t_list[] = { - {"logmag", TRC_LOGMAG}, - {"phase", TRC_PHASE}, - {"polar", TRC_POLAR}, - {"smith", TRC_SMITH}, - {"delay", TRC_DELAY}, - {"linear", TRC_LINEAR}, - {"swr", TRC_SWR}, - {"real", TRC_REAL}, - {"imag", TRC_IMAG}, - {"r", TRC_R}, - {"x", TRC_X}, - {"off", TRC_OFF}, - }; - for (uint16_t i=0; i= 3) { + static const type_list t_list[] = { + {"logmag", TRC_LOGMAG}, + {"phase", TRC_PHASE}, + {"polar", TRC_POLAR}, + {"smith", TRC_SMITH}, + {"delay", TRC_DELAY}, + {"linear", TRC_LINEAR}, + {"swr", TRC_SWR}, + {"real", TRC_REAL}, + {"imag", TRC_IMAG}, + {"r", TRC_R}, + {"x", TRC_X}, + {"off", TRC_OFF}, + }; + for (uint16_t i=0; i= 3) { //trace[t].scale = my_atof(argv[2]); set_trace_scale(t, my_atof(argv[2])); goto exit; @@ -1619,7 +1629,7 @@ static void cmd_trace(BaseSequentialStream *chp, int argc, char *argv[]) } check_ch_num: if (argc > 2) { - int src = atoi(argv[2]); + int src = my_atoi(argv[2]); if (src != 0 && src != 1) goto usage; trace[t].channel = src; @@ -1676,7 +1686,7 @@ static void cmd_marker(BaseSequentialStream *chp, int argc, char *argv[]) return; } - t = atoi(argv[0])-1; + t = my_atoi(argv[0])-1; if (t < 0 || t >= 4) goto usage; if (argc == 1) { @@ -1700,7 +1710,7 @@ static void cmd_marker(BaseSequentialStream *chp, int argc, char *argv[]) } else { // select active marker and move to index markers[t].enabled = TRUE; - int index = atoi(argv[1]); + int index = my_atoi(argv[1]); markers[t].index = index; markers[t].frequency = frequencies[index]; active_marker = t; @@ -1839,7 +1849,7 @@ static void cmd_test(BaseSequentialStream *chp, int argc, char *argv[]) int i; int mode = 0; if (argc >= 1) - mode = atoi(argv[0]); + mode = my_atoi(argv[0]); for (i = 0; i < 20; i++) { palClearPad(GPIOC, GPIOC_LED); @@ -1879,9 +1889,9 @@ static void cmd_gain(BaseSequentialStream *chp, int argc, char *argv[]) chprintf(chp, "usage: gain {lgain(0-95)} [rgain(0-95)]\r\n"); return; } - rvalue = atoi(argv[0]); + rvalue = my_atoi(argv[0]); if (argc == 2) - lvalue = atoi(argv[1]); + lvalue = my_atoi(argv[1]); tlv320aic3204_set_gain(lvalue, rvalue); } @@ -1892,7 +1902,7 @@ static void cmd_port(BaseSequentialStream *chp, int argc, char *argv[]) chprintf(chp, "usage: port {0:TX 1:RX}\r\n"); return; } - port = atoi(argv[0]); + port = my_atoi(argv[0]); tlv320aic3204_select(port); } diff --git a/nanovna.h b/nanovna.h index 800b4e1..a1b490c 100644 --- a/nanovna.h +++ b/nanovna.h @@ -78,7 +78,7 @@ enum { void set_sweep_frequency(int type, uint32_t frequency); uint32_t get_sweep_frequency(int type); -float my_atof(const char *p); +double my_atof(const char *p); void toggle_sweep(void); @@ -152,7 +152,7 @@ extern int16_t area_height; extern const uint8_t x5x7_bits []; #define FONT_GET_DATA(ch) (&x5x7_bits[ch*7]) -#define FONT_GET_WIDTH(ch) (7-(x5x7_bits[ch*7]&3)) +#define FONT_GET_WIDTH(ch) (8-(x5x7_bits[ch*7]&7)) #define FONT_GET_HEIGHT 7 extern const uint16_t numfont16x22[]; @@ -330,7 +330,7 @@ typedef struct { uint32_t magic; uint32_t _frequency0; uint32_t _frequency1; - int16_t _sweep_points; + uint16_t _sweep_points; uint16_t _cal_status; uint32_t _frequencies[POINTS_COUNT]; diff --git a/plot.c b/plot.c index 14e992e..f5ef8ea 100644 --- a/plot.c +++ b/plot.c @@ -8,8 +8,6 @@ #define SWAP(x,y) do { int z=x; x = y; y = z; } while(0) static void cell_draw_marker_info(int m, int n, int w, int h); -void frequency_string(char *buf, size_t len, uint32_t freq, char *prefix); -void frequency_string_short(char *buf, size_t len, int32_t freq, char prefix); void markmap_all_markers(void); /* indicate dirty cells */ @@ -501,6 +499,22 @@ groupdelay_from_array(int i, float array[POINTS_COUNT][2]) return groupdelay(array[bottom], array[top], deltaf); } +static float +gamma2resistance(const float v[2]) +{ + float z0 = 50; + float d = z0 / ((1-v[0])*(1-v[0])+v[1]*v[1]); + return ((1+v[0])*(1-v[0]) - v[1]*v[1]) * d; +} + +static float +gamma2reactance(const float v[2]) +{ + float z0 = 50; + float d = z0 / ((1-v[0])*(1-v[0])+v[1]*v[1]); + return 2*v[1] * d; +} + uint32_t trace_into_index(int x, int t, int i, float array[POINTS_COUNT][2]) { @@ -550,65 +564,6 @@ trace_into_index(int x, int t, int i, float array[POINTS_COUNT][2]) return INDEX(x +CELLOFFSETX, y, i); } -static int -string_value_with_prefix(char *buf, int len, float val, char unit) -{ - char prefix; - int n = 0; - if (val < 0) { - val = -val; - *buf = '-'; - n++; - len--; - } - if (val == INFINITY){ - prefix = S_INFINITY[0]; - } - else { - if (val < 1e-12) { - prefix = 'f'; - val *= 1e15; - } else if (val < 1e-9) { - prefix = 'p'; - val *= 1e12; - } else if (val < 1e-6) { - prefix = 'n'; - val *= 1e9; - } else if (val < 1e-3) { - prefix = S_MICRO[0]; - val *= 1e6; - } else if (val < 1) { - prefix = 'm'; - val *= 1e3; - } else if (val < 1e3) { - prefix = 0; - } else if (val < 1e6) { - prefix = 'k'; - val /= 1e3; - } else if (val < 1e9) { - prefix = 'M'; - val /= 1e6; - } else { - prefix = 'G'; - val /= 1e9; - } - - if (val < 10) { - n += chsnprintf(&buf[n], len, "%.2f", val); - } else if (val < 100) { - n += chsnprintf(&buf[n], len, "%.1f", val); - } else { - n += chsnprintf(&buf[n], len, "%d", (int)val); - } - } - if (prefix) - buf[n++] = prefix; - if (unit) - buf[n++] = unit; - buf[n] = '\0'; - return n; -} - #define PI2 6.283184 static void @@ -619,8 +574,8 @@ format_smith_value(char *buf, int len, const float coeff[2], uint32_t frequency) float d = z0 / ((1-coeff[0])*(1-coeff[0])+coeff[1]*coeff[1]); float zr = ((1+coeff[0])*(1-coeff[0]) - coeff[1]*coeff[1]) * d; float zi = 2*coeff[1] * d; - int n; - + char prefix; + float value; switch (marker_smith_format) { case MS_LIN: chsnprintf(buf, len, "%.2f %.1f" S_DEGREE, linear(coeff), phase(coeff)); @@ -634,109 +589,81 @@ format_smith_value(char *buf, int len, const float coeff[2], uint32_t frequency) chsnprintf(buf, len, "%.1fdB %.1f" S_DEGREE, v, phase(coeff)); } break; - case MS_REIM: - n = string_value_with_prefix(buf, len, coeff[0], '\0'); - if (coeff[1] >= 0) buf[n++] = '+'; - string_value_with_prefix(buf+n, len-n, coeff[1], 'j'); + chsnprintf(buf, len, "%F%+Fj", coeff[0], coeff[1]); break; case MS_RX: - n = string_value_with_prefix(buf, len, zr, S_OHM[0]); - if (zi >= 0) - buf[n++] = ' '; - string_value_with_prefix(buf+n, len-n, zi, 'j'); + chsnprintf(buf, len, "%F"S_OHM"%+Fj", zr, zi); break; case MS_RLC: - n = string_value_with_prefix(buf, len, zr, S_OHM[0]); - buf[n++] = ' '; - - char prefix; - float value; if (zi < 0){// Capacity - prefix = 'F'; - value = -1 / (PI2 * frequency * zi); + prefix = 'F'; + value = -1 / (PI2 * frequency * zi); } else { - prefix = 'H'; - value = zi / (PI2 * frequency); + prefix = 'H'; + value = zi / (PI2 * frequency); } - string_value_with_prefix(buf+n, len-n, value, prefix); + chsnprintf(buf, len, "%F"S_OHM" %F%c", zr, value, prefix); break; } } -static void -gamma2resistance(char *buf, int len, const float coeff[2]) -{ - float z0 = 50; - float d = z0 / ((1-coeff[0])*(1-coeff[0])+coeff[1]*coeff[1]); - float zr = ((1+coeff[0])*(1-coeff[0]) - coeff[1]*coeff[1]) * d; - string_value_with_prefix(buf, len, zr, S_OHM[0]); -} - -static void -gamma2reactance(char *buf, int len, const float coeff[2]) -{ - float z0 = 50; - float d = z0 / ((1-coeff[0])*(1-coeff[0])+coeff[1]*coeff[1]); - float zi = 2*coeff[1] * d; - string_value_with_prefix(buf, len, zi, S_OHM[0]); -} - static void trace_get_value_string(int t, char *buf, int len, float array[POINTS_COUNT][2], int i) { float *coeff = array[i]; float v; + char *format; switch (trace[t].type) { case TRC_LOGMAG: + format = "%.2fdB"; v = logmag(coeff); - if (v == -INFINITY) - chsnprintf(buf, len, "-"S_INFINITY" dB"); - else - chsnprintf(buf, len, "%.2fdB", v); break; case TRC_PHASE: + format = "%.3f"S_DEGREE; v = phase(coeff); - chsnprintf(buf, len, "%.2f" S_DEGREE, v); break; case TRC_DELAY: + format = "%.2Fs"; v = groupdelay_from_array(i, array); - string_value_with_prefix(buf, len, v, 's'); break; case TRC_LINEAR: + format = "%.4f"; v = linear(coeff); - chsnprintf(buf, len, "%.2f", v); break; case TRC_SWR: + format = "%.4f"; v = swr(coeff); - if (v == INFINITY) - chsnprintf(buf, len, S_INFINITY); - else - chsnprintf(buf, len, "%.2f", v); + break; + case TRC_REAL: + format = "%.4f"; + v = coeff[0]; + break; + case TRC_IMAG: + format = "%.4fj"; + v = coeff[1]; + break; + case TRC_R: + format = "%.2F"S_OHM; + v = gamma2resistance(coeff); + break; + case TRC_X: + format = "%.2F"S_OHM; + v = gamma2reactance(coeff); break; case TRC_SMITH: format_smith_value(buf, len, coeff, frequencies[i]); - break; - case TRC_REAL: - chsnprintf(buf, len, "%.2f", coeff[0]); - break; - case TRC_IMAG: - chsnprintf(buf, len, "%.2fj", coeff[1]); - break; - case TRC_R: - gamma2resistance(buf, len, coeff); - break; - case TRC_X: - gamma2reactance(buf, len, coeff); - break; - //case TRC_ADMIT: + return; + //case TRC_ADMIT: case TRC_POLAR: - chsnprintf(buf, len, "%.2f %.2fj", coeff[0], coeff[1]); - break; + chsnprintf(buf, len, "%.2f%+.2fj", coeff[0], coeff[1]); + default: + return; } + chsnprintf(buf, len, format, v); } static void @@ -745,78 +672,80 @@ trace_get_value_string_delta(int t, char *buf, int len, float array[POINTS_COUNT float *coeff = array[index]; float *coeff_ref = array[index_ref]; float v; + char *format; switch (trace[t].type) { case TRC_LOGMAG: + format = S_DELTA"%.2fdB"; v = logmag(coeff) - logmag(coeff_ref); - if (v == -INFINITY) - chsnprintf(buf, len, S_DELTA "-"S_INFINITY" dB"); - else - chsnprintf(buf, len, S_DELTA "%.2fdB", v); break; case TRC_PHASE: + format = S_DELTA"%.2f"S_DEGREE; v = phase(coeff) - phase(coeff_ref); - chsnprintf(buf, len, S_DELTA "%.2f" S_DEGREE, v); break; case TRC_DELAY: + format = "%.2Fs"; v = groupdelay_from_array(index, array) - groupdelay_from_array(index_ref, array); - string_value_with_prefix(buf, len, v, 's'); break; case TRC_LINEAR: + format = S_DELTA"%.3f"; v = linear(coeff) - linear(coeff_ref); - chsnprintf(buf, len, S_DELTA "%.2f", v); break; case TRC_SWR: - v = swr(coeff) - swr(coeff_ref); - chsnprintf(buf, len, S_DELTA "%.2f", v); + format = S_DELTA"%.3f"; + v = swr(coeff); + if (v!=INFINITY) + v-=swr(coeff_ref); break; case TRC_SMITH: format_smith_value(buf, len, coeff, frequencies[index]); - break; + return; case TRC_REAL: - chsnprintf(buf, len, S_DELTA "%.2f", coeff[0] - coeff_ref[0]); + format = S_DELTA"%.3f"; + v = coeff[0] - coeff_ref[0]; break; case TRC_IMAG: - chsnprintf(buf, len, S_DELTA "%.2fj", coeff[1] - coeff_ref[1]); + format = S_DELTA"%.3fj"; + v = coeff[1] - coeff_ref[1]; break; case TRC_R: - gamma2resistance(buf, len, coeff); + format = "%.2F"S_OHM; + v = gamma2resistance(coeff); break; case TRC_X: - gamma2reactance(buf, len, coeff); + format = "%.2F"S_OHM; + v = gamma2reactance(coeff); break; //case TRC_ADMIT: case TRC_POLAR: - chsnprintf(buf, len, "%.2f %.2fj", coeff[0], coeff[1]); - break; + chsnprintf(buf, len, "%.2f%+.2fj", coeff[0], coeff[1]); + return; + default: + return; } + chsnprintf(buf, len, format, v); } static int trace_get_info(int t, char *buf, int len) { - strcpy(buf, get_trace_typename(t)); - int n = strlen(buf); - char *p = buf + n; - len -= n; + const char *name = get_trace_typename(t); + float scale = get_trace_scale(t); switch (trace[t].type) { case TRC_LOGMAG: - n += chsnprintf(p, len, " %ddB/", (int)get_trace_scale(t)); - break; + return chsnprintf(buf, len, "%s %ddB/", name, (int)scale); case TRC_PHASE: - n += chsnprintf(p, len, " %d" S_DEGREE "/", (int)get_trace_scale(t)); - break; + return chsnprintf(buf, len, "%s %d" S_DEGREE "/", name, (int)scale); case TRC_SMITH: //case TRC_ADMIT: case TRC_POLAR: - if (get_trace_scale(t) != 1.0) - n += chsnprintf(p, len, " %.1fFS", get_trace_scale(t)); - break; + if (scale != 1.0) + return chsnprintf(buf, len, "%s %.1fFS", name, scale); + else + return chsnprintf(buf, len, name); default: - strcat(p, " "); - string_value_with_prefix(p+1, len-1 , get_trace_scale(t), '/'); - break; + return chsnprintf(buf, len, "%s %F/", name, scale); } - return n; + return 0; } static float time_of_index(int idx) { @@ -1584,43 +1513,32 @@ request_to_draw_cells_behind_numeric_input(void) int -cell_drawchar(int w, int h, uint8_t ch, int x, int y, int invert) +cell_drawchar(int w, int h, uint8_t ch, int x, int y) { - uint8_t bits; - int c, r, ch_size; - const uint8_t *char_buf = FONT_GET_DATA(ch); - ch_size=FONT_GET_WIDTH(ch); - if (y <= -FONT_GET_HEIGHT || y >= h || x <= -ch_size || x >= w) - return ch_size; - for(c = 0; c < FONT_GET_HEIGHT; c++) { - bits = *char_buf++; - if ((y + c) < 0 || (y + c) >= h) - continue; - if (invert) - bits = ~bits; - for (r = 0; r < ch_size; r++) { - if ((x+r) >= 0 && (x+r) < w && (0x80 & bits)) - spi_buffer[(y+c)*w + (x+r)] = foreground_color; - bits <<= 1; - } - } - return ch_size; + uint8_t bits; + int c, r, ch_size; + const uint8_t *char_buf = FONT_GET_DATA(ch); + ch_size=FONT_GET_WIDTH(ch); + if (y <= -FONT_GET_HEIGHT || y >= h || x <= -ch_size || x >= w) + return ch_size; + for(c = 0; c < FONT_GET_HEIGHT; c++) { + bits = *char_buf++; + if ((y + c) < 0 || (y + c) >= h) + continue; + for (r = 0; r < ch_size; r++) { + if ((x+r) >= 0 && (x+r) < w && (0x80 & bits)) + spi_buffer[(y+c)*w + (x+r)] = foreground_color; + bits <<= 1; + } + } + return ch_size; } void cell_drawstring(int w, int h, char *str, int x, int y) { while (*str) { - x += cell_drawchar(w, h, *str, x, y, FALSE); - str++; - } -} - -void -cell_drawstring_invert(int w, int h, char *str, int x, int y, int invert) -{ - while (*str) { - x += cell_drawchar(w, h, *str, x, y, invert); + x += cell_drawchar(w, h, *str, x, y); str++; } } @@ -1628,7 +1546,7 @@ cell_drawstring_invert(int w, int h, char *str, int x, int y, int invert) static void cell_draw_marker_info(int m, int n, int w, int h) { - char buf[24]; + char buf[32]; int t; if (n != 0) return; @@ -1646,27 +1564,27 @@ cell_draw_marker_info(int m, int n, int w, int h) int ypos = 1 + (j/2)*8; xpos -= m * CELLWIDTH -CELLOFFSETX; ypos -= n * CELLHEIGHT; - - setForegroundColor(config.trace_color[t]); - if (mk == active_marker) - cell_drawstring(w, h, S_SARROW, xpos, ypos); - xpos += 5; + + setForegroundColor(config.trace_color[t]); + if (mk == active_marker) + cell_drawstring(w, h, S_SARROW, xpos, ypos); + xpos += 5; chsnprintf(buf, sizeof buf, "M%d", mk+1); cell_drawstring(w, h, buf, xpos, ypos); - - xpos += 13; + xpos += 13; //trace_get_info(t, buf, sizeof buf); - int32_t freq = frequencies[markers[mk].index]; + uint32_t freq = frequencies[markers[mk].index]; if (uistat.marker_delta && mk != active_marker) { - freq -= frequencies[markers[active_marker].index]; - frequency_string_short(buf, sizeof buf, freq, S_DELTA[0]); + uint32_t freq1 = frequencies[markers[active_marker].index]; + uint32_t delta = freq > freq1 ? freq - freq1 : freq1 - freq; + chsnprintf(buf, sizeof buf, S_DELTA"%.9qHz", delta); } else { - frequency_string_short(buf, sizeof buf, freq, 0); + chsnprintf(buf, sizeof buf, "%.10qHz", freq); } cell_drawstring(w, h, buf, xpos, ypos); - xpos += 64; + xpos += 67; if (uistat.marker_delta && mk != active_marker) - trace_get_value_string_delta(t, buf, sizeof buf, measured[trace[t].channel], markers[mk].index, markers[active_marker].index); + trace_get_value_string_delta(t, buf, sizeof buf, measured[trace[t].channel], markers[mk].index, markers[active_marker].index); else trace_get_value_string(t, buf, sizeof buf, measured[trace[t].channel], markers[mk].index); setForegroundColor(DEFAULT_FG_COLOR); @@ -1677,24 +1595,21 @@ cell_draw_marker_info(int m, int n, int w, int h) // draw marker delta if (!uistat.marker_delta && previous_marker >= 0 && active_marker != previous_marker && markers[previous_marker].enabled) { int idx0 = markers[previous_marker].index; - int xpos = 185; + int xpos = 180; int ypos = 1 + (j/2)*8; xpos -= m * CELLWIDTH -CELLOFFSETX; ypos -= n * CELLHEIGHT; - strcpy(buf, S_DELTA "1-1:"); - buf[1] += active_marker; - buf[3] += previous_marker; + chsnprintf(buf, sizeof buf, S_DELTA"%d-%d", active_marker+1, previous_marker+1); setForegroundColor(DEFAULT_FG_COLOR); cell_drawstring(w, h, buf, xpos, ypos); - xpos += 29; + xpos += 24; if ((domain_mode & DOMAIN_MODE) == DOMAIN_FREQ) { - frequency_string_short(buf, sizeof buf, frequencies[idx] - frequencies[idx0], 0); + uint32_t freq = frequencies[idx]; + uint32_t freq1 = frequencies[idx0]; + uint32_t delta = freq > freq1 ? freq - freq1 : freq1 - freq; + chsnprintf(buf, sizeof buf, "%c%.13qHz", freq >= freq1 ? '+' : '-', delta); } else { - //chsnprintf(buf, sizeof buf, "%d ns %.1f m", (uint16_t)(time_of_index(idx) * 1e9 - time_of_index(idx0) * 1e9), - // distance_of_index(idx) - distance_of_index(idx0)); - int n = string_value_with_prefix(buf, sizeof buf, time_of_index(idx) - time_of_index(idx0), 's'); - buf[n++] = ' '; - string_value_with_prefix(&buf[n], sizeof buf - n, distance_of_index(idx) - distance_of_index(idx0), 'm'); + chsnprintf(buf, sizeof buf, "%Fs (%Fm)", time_of_index(idx) - time_of_index(idx0), distance_of_index(idx) - distance_of_index(idx0)); } cell_drawstring(w, h, buf, xpos, ypos); } @@ -1706,23 +1621,17 @@ cell_draw_marker_info(int m, int n, int w, int h) int ypos = 1 + (j/2)*8; xpos -= m * CELLWIDTH -CELLOFFSETX; ypos -= n * CELLHEIGHT; -// setForegroundColor(config.trace_color[t]); -// strcpy(buf, "CH0"); -// buf[2] += trace[t].channel; - //chsnprintf(buf, sizeof buf, "CH%d", trace[t].channel); -// cell_drawstring_invert(w, h, buf, xpos, ypos, t == uistat.current_trace); -// xpos += 20; setForegroundColor(config.trace_color[t]); if (t == uistat.current_trace) - cell_drawstring(w, h, S_SARROW, xpos, ypos); + cell_drawstring(w, h, S_SARROW, xpos, ypos); xpos += 5; chsnprintf(buf, sizeof buf, "CH%d", trace[t].channel); cell_drawstring(w, h, buf, xpos, ypos); xpos += 19; - trace_get_info(t, buf, sizeof buf); + int n = trace_get_info(t, buf, sizeof buf); cell_drawstring(w, h, buf, xpos, ypos); - xpos += (strlen(buf) + 1) * 5; + xpos += n * 5 + 2; //xpos += 60; trace_get_value_string(t, buf, sizeof buf, measured[trace[t].channel], idx); setForegroundColor(DEFAULT_FG_COLOR); @@ -1736,27 +1645,18 @@ cell_draw_marker_info(int m, int n, int w, int h) xpos -= m * CELLWIDTH -CELLOFFSETX; ypos -= n * CELLHEIGHT; setForegroundColor(DEFAULT_FG_COLOR); -// strcpy(buf, "1:"); -// buf[0] += active_marker; -// xpos += 5; -// setForegroundColor(0xffff); -// cell_drawstring_invert(w, h, buf, xpos, ypos, uistat.lever_mode == LM_MARKER); -// xpos += 14; - setForegroundColor(DEFAULT_FG_COLOR); if (uistat.lever_mode == LM_MARKER) - cell_drawstring(w, h, S_SARROW, xpos, ypos); + cell_drawstring(w, h, S_SARROW, xpos, ypos); xpos += 5; chsnprintf(buf, sizeof buf, "M%d:", active_marker+1); cell_drawstring(w, h, buf, xpos, ypos); - xpos += 19; + xpos += 19; if ((domain_mode & DOMAIN_MODE) == DOMAIN_FREQ) { - frequency_string(buf, sizeof buf, frequencies[idx], ""); + //frequency_string(buf, sizeof buf, frequencies[idx], ""); + chsnprintf(buf, sizeof buf, "%16qHz", frequencies[idx]); } else { - //chsnprintf(buf, sizeof buf, "%d ns %.1f m", (uint16_t)(time_of_index(idx) * 1e9), distance_of_index(idx)); - int n = string_value_with_prefix(buf, sizeof buf, time_of_index(idx), 's'); - buf[n++] = ' '; - string_value_with_prefix(&buf[n], sizeof buf-n, distance_of_index(idx), 'm'); + chsnprintf(buf, sizeof buf, "%Fs (%Fm)", time_of_index(idx), distance_of_index(idx)); } cell_drawstring(w, h, buf, xpos, ypos); } @@ -1767,85 +1667,32 @@ cell_draw_marker_info(int m, int n, int w, int h) int ypos = 1 + ((j+1)/2)*8; xpos -= m * CELLWIDTH -CELLOFFSETX; ypos -= n * CELLHEIGHT; - chsnprintf(buf, sizeof buf, "Edelay"); - cell_drawstring(w, h, buf, xpos, ypos); - xpos += 7 * 5; - int n = string_value_with_prefix(buf, sizeof buf, electrical_delay * 1e-12, 's'); - cell_drawstring(w, h, buf, xpos, ypos); - xpos += n * 5 + 5; + float light_speed_ps = 299792458e-12; //(m/ps) - string_value_with_prefix(buf, sizeof buf, electrical_delay * light_speed_ps * velocity_factor, 'm'); + chsnprintf(buf, sizeof buf, "Edelay %Fs %Fm", electrical_delay * 1e-12, + electrical_delay * light_speed_ps * velocity_factor); cell_drawstring(w, h, buf, xpos, ypos); } } -void -frequency_string(char *buf, size_t len, uint32_t freq, char *prefix) -{ -/* if (freq < 0) { - freq = -freq; - *buf++ = '-'; - len -= 1; - }*/ - if (freq < 1000) { - chsnprintf(buf, len, "%s%d Hz", prefix, (int)freq); - } else if (freq < 1000000U) { - chsnprintf(buf, len, "%s%d.%03d kHz", prefix, - (freq / 1000U), - (freq % 1000U)); - } else { - chsnprintf(buf, len, "%s%d.%03d %03d MHz", prefix, - (freq / 1000000U), - ((freq / 1000U) % 1000U), - (freq % 1000U)); - } -} - -void -frequency_string_short(char *b, size_t len, int32_t freq, char prefix) -{ - char *buf = b; - if (prefix) { - *buf++ = prefix; - len -= 1; - } - if (freq < 0) { - freq = -freq; - *buf++ = '-'; - len -= 1; - } - if (freq < 1000) { - chsnprintf(buf, len, "%d Hz", (int)freq); - } else if (freq < 1000000) { - chsnprintf(buf, len, "%d.%03dkHz", - (int)(freq / 1000), - (int)(freq % 1000)); - } else { - chsnprintf(buf, len, "%d.%06d", - (int)(freq / 1000000), - (int)(freq % 1000000)); - strcpy(b+9, "MHz"); - } -} - void draw_frequencies(void) { - char buf1[24];buf1[0]=' '; - char buf2[24];buf2[0]=0; + char buf1[32]; + char buf2[32];buf2[0]=0; if ((domain_mode & DOMAIN_MODE) == DOMAIN_FREQ) { if (frequency0 < frequency1) { - frequency_string(buf1+1, sizeof(buf1)-1, frequency0, "START "); - frequency_string(buf2, sizeof buf2, frequency1, "STOP "); + chsnprintf(buf1, sizeof(buf1), " START %16qHz", frequency0); + chsnprintf(buf2, sizeof(buf2), "STOP %16qHz", frequency1); } else if (frequency0 > frequency1) { - frequency_string(buf1+1, sizeof(buf1)-1, frequency0/2 + frequency1/2, "CENTER "); - frequency_string(buf2, sizeof buf2, frequency0 - frequency1, "SPAN "); + chsnprintf(buf1, sizeof(buf1), " CENTER %16qHz", frequency0/2 + frequency1/2); + chsnprintf(buf2, sizeof(buf2), "SPAN %16qHz", frequency0 - frequency1); } else { - frequency_string(buf1+1, sizeof(buf1)-1, frequency0, "CW "); + chsnprintf(buf1, sizeof(buf1), " CW %16qHz", frequency0); } } else { - chsnprintf(buf1+1, sizeof(buf1)-1, "START 0s"); - chsnprintf(buf2, sizeof buf2, "%s%dns (%.2fm)", "STOP ", (uint16_t)(time_of_index(POINTS_COUNT-1) * 1e9), distance_of_index(POINTS_COUNT-1)); + chsnprintf(buf1, sizeof(buf1), " START 0s"); + chsnprintf(buf2, sizeof(buf2), "STOP %Fs (%Fm)", time_of_index(POINTS_COUNT-1), distance_of_index(POINTS_COUNT-1)); } setForegroundColor(DEFAULT_FG_COLOR); setBackgroundColor(DEFAULT_BG_COLOR); @@ -1853,7 +1700,7 @@ draw_frequencies(void) if (uistat.lever_mode == LM_SPAN || uistat.lever_mode == LM_CENTER) buf1[0] = S_SARROW[0]; ili9341_drawstring(buf1, OFFSETX, 232); - ili9341_drawstring(buf2, 205, 232); + ili9341_drawstring(buf2, 200, 232); } void @@ -1906,28 +1753,30 @@ draw_cal_status(void) void draw_battery_status(void) { - uint8_t string_buf[25]; - // Set battery color - setForegroundColor(vbat < BATTERY_WARNING_LEVEL ? DEFAULT_LOW_BAT_COLOR : DEFAULT_NORMAL_BAT_COLOR); - setBackgroundColor(DEFAULT_BG_COLOR); -// chsnprintf(string_buf, sizeof string_buf, "V:%d", vbat); -// ili9341_drawstringV(string_buf, 1, 60); - // Prepare battery bitmap image - // Battery top - int x=0; - string_buf[x++] = 0b00111100; - string_buf[x++] = 0b00100100; - string_buf[x++] = 0b11111111; -// string_buf[x++] = 0b10000001; - // Fill battery status - for (int power=BATTERY_TOP_LEVEL; power > BATTERY_BOTTOM_LEVEL; power-=100) - string_buf[x++] = (power > vbat) ? 0b10000001 : // Empty line - 0b11111111; // Full line - // Battery bottom -// string_buf[x++] = 0b10000001; - string_buf[x++] = 0b11111111; - // Draw battery - blit8BitWidthBitmap(0, 1, 8, x, string_buf); + if (vbat<=0) + return; + uint8_t string_buf[25]; + // Set battery color + setForegroundColor(vbat < BATTERY_WARNING_LEVEL ? DEFAULT_LOW_BAT_COLOR : DEFAULT_NORMAL_BAT_COLOR); + setBackgroundColor(DEFAULT_BG_COLOR); +// chsnprintf(string_buf, sizeof string_buf, "V:%d", vbat); +// ili9341_drawstringV(string_buf, 1, 60); + // Prepare battery bitmap image + // Battery top + int x=0; + string_buf[x++] = 0b00111100; + string_buf[x++] = 0b00100100; + string_buf[x++] = 0b11111111; +// string_buf[x++] = 0b10000001; + // Fill battery status + for (int power=BATTERY_TOP_LEVEL; power > BATTERY_BOTTOM_LEVEL; power-=100) + string_buf[x++] = (power > vbat) ? 0b10000001 : // Empty line + 0b11111111; // Full line + // Battery bottom +// string_buf[x++] = 0b10000001; + string_buf[x++] = 0b11111111; + // Draw battery + blit8BitWidthBitmap(0, 1, 8, x, string_buf); } void diff --git a/ui.c b/ui.c index f35f504..c27b354 100644 --- a/ui.c +++ b/ui.c @@ -106,7 +106,7 @@ int awd_count; #define KP_DONE 1 #define KP_CANCEL 2 -char kp_buf[11]; +char kp_buf[NUMINPUT_LEN+1]; int8_t kp_index = 0; void ui_mode_normal(void); @@ -1791,7 +1791,7 @@ keypad_click(int key) { int c = keypads[key].c; if ((c >= KP_X1 && c <= KP_G) || c == KP_N || c == KP_P) { - float scale = 1; + int32_t scale = 1; if (c >= KP_X1 && c <= KP_G) { int n = c - KP_X1; while (n-- > 0) @@ -1800,7 +1800,7 @@ keypad_click(int key) scale *= 1000; } /* numeric input done */ - float value = my_atof(kp_buf) * scale; + double value = my_atof(kp_buf) * scale; switch (keypad_mode) { case KM_START: set_sweep_frequency(ST_START, value);