This commit is contained in:
Edward Emelianov 2024-01-05 23:38:43 +03:00
parent 7d8cbd55cf
commit 9ecce531cb
10 changed files with 404 additions and 254 deletions

Binary file not shown.

View File

@ -118,6 +118,7 @@ PP - push-pull, OD - open drain, I - floating input, A - analog input, AFn - alt
## DMA usage ## DMA usage
### DMA1 ### DMA1
Channel1 - ADC1.
### DMA2 ### DMA2

View File

@ -68,16 +68,15 @@ void adc_setup(){
// ADC1: channels 1-4,10,16; ADC2: channel 1 // ADC1: channels 1-4,10,16; ADC2: channel 1
ADC1->SMPR1 = ADC_SMPR1_SMP1 | ADC_SMPR1_SMP2 | ADC_SMPR1_SMP3 | ADC_SMPR1_SMP4; ADC1->SMPR1 = ADC_SMPR1_SMP1 | ADC_SMPR1_SMP2 | ADC_SMPR1_SMP3 | ADC_SMPR1_SMP4;
ADC1->SMPR2 = ADC_SMPR2_SMP16; ADC1->SMPR2 = ADC_SMPR2_SMP16;
// 11 conversions in group: 1...10->16 // 5 conversions in group: 1..4,16
ADC1->SQR1 = (1<<6) | (2<<12) | (3<<18) | (4<<24) | (NUMBER_OF_ADC_CHANNELS-1); ADC1->SQR1 = (1<<6) | (2<<12) | (3<<18) | (4<<24) | (NUMBER_OF_ADC_CHANNELS-1);
ADC1->SQR2 = (16<<0); ADC1->SQR2 = (16<<0);
ADC2->SMPR1 = ADC_SMPR1_SMP1; ADC2->SMPR1 = ADC_SMPR1_SMP1;
ADC2->SQR1 = (1<<6) | (NUMBER_OF_ADC2_CHANNELS-1);
// configure DMA for ADC // configure DMA for ADC
ADC1->CFGR = ADC_CFGR_CONT | ADC_CFGR_DMAEN | ADC_CFGR_DMACFG; ADC1->CFGR = ADC_CFGR_CONT | ADC_CFGR_DMAEN | ADC_CFGR_DMACFG;
DMA1_Channel1->CPAR = (uint32_t) (&(ADC1->DR)); DMA1_Channel1->CPAR = (uint32_t) (&(ADC1->DR));
DMA1_Channel1->CMAR = (uint32_t)(ADC_array); DMA1_Channel1->CMAR = (uint32_t)(ADC_array);
DMA1_Channel1->CNDTR = NUMBER_OF_ADC1_CHANNELS * 9; DMA1_Channel1->CNDTR = NUMBER_OF_ADC_CHANNELS * 9;
DMA1_Channel1->CCR |= DMA_CCR_MINC | DMA_CCR_MSIZE_0 | DMA_CCR_PSIZE_0 | DMA_CCR_CIRC; DMA1_Channel1->CCR |= DMA_CCR_MINC | DMA_CCR_MSIZE_0 | DMA_CCR_PSIZE_0 | DMA_CCR_CIRC;
DMA1_Channel1->CCR |= DMA_CCR_EN; DMA1_Channel1->CCR |= DMA_CCR_EN;
enADC(ADC1); enADC(ADC1);
@ -93,12 +92,8 @@ uint16_t getADCval(int nch){
#define PIX_SORT(a,b) { if ((a)>(b)) PIX_SWAP((a),(b)); } #define PIX_SORT(a,b) { if ((a)>(b)) PIX_SWAP((a),(b)); }
#define PIX_SWAP(a,b) { temp=(a);(a)=(b);(b)=temp; } #define PIX_SWAP(a,b) { temp=(a);(a)=(b);(b)=temp; }
uint16_t p[9]; uint16_t p[9];
int addr = nch, adval = NUMBER_OF_ADC1_CHANNELS; int addr = nch;
if(nch >= NUMBER_OF_ADC1_CHANNELS){ for(int i = 0; i < 9; ++i, addr += NUMBER_OF_ADC_CHANNELS) // first we should prepare array for optmed
adval = NUMBER_OF_ADC2_CHANNELS;
addr += ADC2START - NUMBER_OF_ADC1_CHANNELS;
}
for(int i = 0; i < 9; ++i, addr += adval) // first we should prepare array for optmed
p[i] = ADC_array[addr]; p[i] = ADC_array[addr];
PIX_SORT(p[1], p[2]) ; PIX_SORT(p[4], p[5]) ; PIX_SORT(p[7], p[8]) ; PIX_SORT(p[1], p[2]) ; PIX_SORT(p[4], p[5]) ; PIX_SORT(p[7], p[8]) ;
PIX_SORT(p[0], p[1]) ; PIX_SORT(p[3], p[4]) ; PIX_SORT(p[6], p[7]) ; PIX_SORT(p[0], p[1]) ; PIX_SORT(p[3], p[4]) ; PIX_SORT(p[6], p[7]) ;
@ -120,61 +115,10 @@ float getADCvoltage(uint16_t ADCval){
// return MCU temperature (degrees of celsius) // return MCU temperature (degrees of celsius)
float getMCUtemp(){ float getMCUtemp(){
float temperature = ADCvals[ADC_TSENS] - (float) *TEMP30_CAL_ADDR; float temperature = ADC_array[ADC_TSENS] - (float) *TEMP30_CAL_ADDR;
temperature *= (110.f - 30.f); temperature *= (110.f - 30.f);
temperature /= (float)(*TEMP110_CAL_ADDR - *TEMP30_CAL_ADDR); temperature /= (float)(*TEMP110_CAL_ADDR - *TEMP30_CAL_ADDR);
temperature += 30.f; temperature += 30.f;
return(temperature); return(temperature);
} }
// calculate R (Ohms) by given `ADCval` for main 10 ADC channels with 1k in upper arm of divider
float calcR(uint16_t ADCval){
return 1000.f/(4096.f/((float)ADCval) - 1.f);
}
/****** R(T, K):
T -= 273.15; % convert to K
_A = 3.9083e-03;
_B = -5.7750e-07;
_C = 0.;
if(T < 0.); _C = -4.1830e-12; endif
R = 1000.*(1 + _A*T + _B*T.^2 - _C.*T.^3*100. + _C.*T.^4);
=====> for T=[70:400] Kelvins
function T = pt1000Tapp(R)
k1 = 27.645;
k2 = 0.235268;
k3 = 1.0242e-05;
k4 = 0.;
if(R < 1000)
k1 = 31.067;
k2 = 2.2272e-01;
k3 = 2.5251e-05;
k4 = -5.9001e-09;
endif
T = k1 + k2*R + k3*R.^2 + k4*R.^3;
endfunction
mean(T-Tapp)= -3.3824e-04
std(T-Tapp')= 3.2089e-03
max(abs(T-Tapp'))= 0.011899
********/
// approximate calculation of T (K) for platinum 1k PTC
float calcT(uint16_t ADCval){
float R = calcR(ADCval);
if(R < 1000.){
return (31.067 + R * (2.2272e-01 + R * (2.5251e-05 - R * 5.9001e-09)));
}
return (27.645 + R * (0.235268 + R * 1.0242e-05));
}
// MPX5050: V=VS(P x 0.018 + 0.04); for 3v3 ADU=4096(P*0.018+0.04) ====>
// 0.018P=ADU/4096-0.04,
// P(kPa) = 55.556*(ADU/4096-0.04)
float calcPres5050(){
float adu = (float)ADCvals[ADC_EXT]/4096. - 0.04;
return 55.556*adu;
}

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject> <!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 12.0.0, 2023-12-03T20:20:42. --> <!-- Written by QtCreator 12.0.1, 2024-01-05T23:37:25. -->
<qtcreator> <qtcreator>
<data> <data>
<variable>EnvironmentId</variable> <variable>EnvironmentId</variable>

View File

@ -7,6 +7,8 @@ proto.c
proto.h proto.h
ringbuffer.c ringbuffer.c
ringbuffer.h ringbuffer.h
strfunc.c
strfunc.h
usart.c usart.c
usart.h usart.h
usb.c usb.c

View File

@ -18,149 +18,19 @@
#include "adc.h" #include "adc.h"
#include "proto.h" #include "proto.h"
#include "strfunc.h"
#include "usart.h" #include "usart.h"
#include "usb.h" #include "usb.h"
#include "version.inc" #include "version.inc"
uint8_t starttest = 0;
char *omit_spaces(const char *buf){
while(*buf){
if(*buf > ' ') break;
++buf;
}
return (char*)buf;
}
// In case of overflow return `buf` and N==0xffffffff
// read decimal number & return pointer to next non-number symbol
static char *getdec(const char *buf, uint32_t *N){
char *start = (char*)buf;
uint32_t num = 0;
while(*buf){
char c = *buf;
if(c < '0' || c > '9'){
break;
}
if(num > 429496729 || (num == 429496729 && c > '5')){ // overflow
*N = 0xffffff;
return start;
}
num *= 10;
num += c - '0';
++buf;
}
*N = num;
return (char*)buf;
}
// read hexadecimal number (without 0x prefix!)
static char *gethex(const char *buf, uint32_t *N){
char *start = (char*)buf;
uint32_t num = 0;
while(*buf){
char c = *buf;
uint8_t M = 0;
if(c >= '0' && c <= '9'){
M = '0';
}else if(c >= 'A' && c <= 'F'){
M = 'A' - 10;
}else if(c >= 'a' && c <= 'f'){
M = 'a' - 10;
}
if(M){
if(num & 0xf0000000){ // overflow
*N = 0xffffff;
return start;
}
num <<= 4;
num += c - M;
}else{
break;
}
++buf;
}
*N = num;
return (char*)buf;
}
// read octal number (without 0 prefix!)
static char *getoct(const char *buf, uint32_t *N){
char *start = (char*)buf;
uint32_t num = 0;
while(*buf){
char c = *buf;
if(c < '0' || c > '7'){
break;
}
if(num & 0xe0000000){ // overflow
*N = 0xffffff;
return start;
}
num <<= 3;
num += c - '0';
++buf;
}
*N = num;
return (char*)buf;
}
// read binary number (without b prefix!)
static char *getbin(const char *buf, uint32_t *N){
char *start = (char*)buf;
uint32_t num = 0;
while(*buf){
char c = *buf;
if(c < '0' || c > '1'){
break;
}
if(num & 0x80000000){ // overflow
*N = 0xffffff;
return start;
}
num <<= 1;
if(c == '1') num |= 1;
++buf;
}
*N = num;
return (char*)buf;
}
/**
* @brief getnum - read uint32_t from string (dec, hex or bin: 127, 0x7f, 0b1111111)
* @param buf - buffer with number and so on
* @param N - the number read
* @return pointer to first non-number symbol in buf
* (if it is == buf, there's no number or if *N==0xffffffff there was overflow)
*/
char *getnum(const char *txt, uint32_t *N){
char *nxt = NULL;
char *s = omit_spaces(txt);
if(*s == '0'){ // hex, oct or 0
if(s[1] == 'x' || s[1] == 'X'){ // hex
nxt = gethex(s+2, N);
if(nxt == s+2) nxt = (char*)txt;
}else if(s[1] > '0'-1 && s[1] < '8'){ // oct
nxt = getoct(s+1, N);
if(nxt == s+1) nxt = (char*)txt;
}else{ // 0
nxt = s+1;
*N = 0;
}
}else if(*s == 'b' || *s == 'B'){
nxt = getbin(s+1, N);
if(nxt == s+1) nxt = (char*)txt;
}else{
nxt = getdec(s, N);
if(nxt == s) nxt = (char*)txt;
}
return nxt;
}
const char* helpmsg = const char* helpmsg =
"https://github.com/eddyem/stm32samples/tree/master/F3:F303/CANbus4BTA build#" BUILD_NUMBER " @ " BUILD_DATE "\n" "https://github.com/eddyem/stm32samples/tree/master/F3:F303/CANbus4BTA build#" BUILD_NUMBER " @ " BUILD_DATE "\n"
"'a' - print ADC values\n"
"'i' - print USB->ISTR state\n" "'i' - print USB->ISTR state\n"
"'p' - toggle USB pullup\n" "'p' - toggle USB pullup\n"
"'N' - read number (dec, 0xhex, 0oct, bbin) and show it in decimal\n" "'N' - read number (dec, 0xhex, 0oct, bbin) and show it in decimal\n"
"'R' - software reset\n" "'R' - software reset\n"
"'T' - test usb sending a very large message\n" "'T' - get MCU T\n"
"'U' - get USB status\n" "'U' - get USB status\n"
"'W' - test watchdog\n" "'W' - test watchdog\n"
; ;
@ -168,6 +38,11 @@ const char* helpmsg =
static char stbuf[256], *bptr = NULL; static char stbuf[256], *bptr = NULL;
static int blen = 0; static int blen = 0;
static void initbuf(){bptr = stbuf; blen = 255; *bptr = 0;} static void initbuf(){bptr = stbuf; blen = 255; *bptr = 0;}
static void bufputchar(char c){
if(blen == 0) return;
*bptr++ = c; --blen;
*bptr = 0;
}
static void add2buf(const char *s){ static void add2buf(const char *s){
while(blen && *s){ while(blen && *s){
*bptr++ = *s++; *bptr++ = *s++;
@ -181,34 +56,37 @@ const char *parse_cmd(const char *buf){
initbuf(); initbuf();
if(buf[1] == '\n' || !buf[1]){ // one symbol commands if(buf[1] == '\n' || !buf[1]){ // one symbol commands
switch(*buf){ switch(*buf){
case 'a':
for(int i = 0; i < ADC_TSENS; ++i){
bufputchar('A'); bufputchar(i+'0'); bufputchar('=');
add2buf(u2str(getADCval(i))); bufputchar('\n');
}
return stbuf;
break;
case 'i': case 'i':
add2buf("USB->ISTR="); add2buf("USB->ISTR=");
add2buf(u2hexstr(USB->ISTR)); add2buf(uhex2str(USB->ISTR));
add2buf(", USB->CNTR="); add2buf(", USB->CNTR=");
add2buf(u2hexstr(USB->CNTR)); add2buf(uhex2str(USB->CNTR));
add2buf("\n");
break; break;
case 'p': case 'p':
pin_toggle(USBPU_port, USBPU_pin); pin_toggle(USBPU_port, USBPU_pin);
add2buf("USB pullup is "); add2buf("USB pullup is ");
if(pin_read(USBPU_port, USBPU_pin)) add2buf("off\n"); if(pin_read(USBPU_port, USBPU_pin)) add2buf("off");
else add2buf("on\n"); else add2buf("on");
break; break;
case 'R': case 'R':
USB_sendstr("Soft reset\n"); USB_sendstr("Soft reset\n");
usart_send("Soft reset\n");
NVIC_SystemReset(); NVIC_SystemReset();
break; break;
case 'T': case 'T':
add2buf("STARTT="); add2buf("T=");
add2buf(u2str(Tms)); add2buf("\n"); add2buf(float2str(getMCUtemp(), 1));
starttest = 10;
break; break;
case 'U': case 'U':
add2buf("USB status: "); add2buf("USB status: ");
if(usbON) add2buf("ON"); if(usbON) add2buf("ON");
else add2buf("OFF"); else add2buf("OFF");
add2buf("\n");
break; break;
case 'W': case 'W':
USB_sendstr("Wait for reboot\n"); USB_sendstr("Wait for reboot\n");
@ -218,10 +96,11 @@ const char *parse_cmd(const char *buf){
default: default:
return helpmsg; return helpmsg;
} }
bufputchar('\n');
return stbuf; return stbuf;
} }
uint32_t Num = 0; uint32_t Num = 0;
char *nxt; const char *nxt;
switch(*buf){ // long messages switch(*buf){ // long messages
case 'N': case 'N':
++buf; ++buf;
@ -242,41 +121,3 @@ const char *parse_cmd(const char *buf){
} }
return stbuf; return stbuf;
} }
// return string with number `val`
char *u2str(uint32_t val){
static char strbuf[11];
char *bufptr = &strbuf[10];
*bufptr = 0;
if(!val){
*(--bufptr) = '0';
}else{
while(val){
*(--bufptr) = val % 10 + '0';
val /= 10;
}
}
return bufptr;
}
char *u2hexstr(uint32_t val){
static char strbuf[11] = "0x";
char *sptr = strbuf + 2;
uint8_t *ptr = (uint8_t*)&val + 3;
int8_t i, j, z=1;
for(i = 0; i < 4; ++i, --ptr){
if(*ptr == 0){ // omit leading zeros
if(i == 3) z = 0;
if(z) continue;
}
else z = 0;
for(j = 1; j > -1; --j){
uint8_t half = (*ptr >> (4*j)) & 0x0f;
if(half < 10) *sptr++ = half + '0';
else *sptr++ = half - 10 + 'a';
}
}
*sptr = 0;
return strbuf;
}

View File

@ -20,11 +20,5 @@
#include <stm32f3.h> #include <stm32f3.h>
extern uint8_t starttest;
const char *parse_cmd(const char *buf); const char *parse_cmd(const char *buf);
char *omit_spaces(const char *buf);
char *getnum(const char *buf, uint32_t *N);
char *u2str(uint32_t val);
char *u2hexstr(uint32_t val);

View File

@ -0,0 +1,337 @@
/*
* This file is part of the canbus4bta project.
* Copyright 2024 Edward V. Emelianov <edward.emelianoff@gmail.com>.
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stm32f3.h>
#include <math.h>
#include <string.h>
/**
* @brief hexdump - dump hex array by 16 bytes in string
* @param sendfun - function to send data
* @param arr - array to dump
* @param len - length of `arr`
*/
void hexdump(int (*sendfun)(const char *s), uint8_t *arr, uint16_t len){
char buf[52], *bptr = buf;
for(uint16_t l = 0; l < len; ++l, ++arr){
for(int16_t j = 1; j > -1; --j){
register uint8_t half = (*arr >> (4*j)) & 0x0f;
if(half < 10) *bptr++ = half + '0';
else *bptr++ = half - 10 + 'a';
}
if(l % 16 == 15){
*bptr++ = '\n';
*bptr = 0;
sendfun(buf);
bptr = buf;
}else *bptr++ = ' ';
}
if(bptr != buf){
*bptr++ = '\n';
*bptr = 0;
sendfun(buf);
}
}
/**
* @brief _2str - convert value into string buffer
* @param val - |value|
* @param minus - ==0 if value > 0
* @return buffer with number
*/
static char *_2str(uint32_t val, uint8_t minus){
static char strbuf[12];
char *bufptr = &strbuf[11];
*bufptr = 0;
if(!val){
*(--bufptr) = '0';
}else{
while(val){
uint32_t x = val / 10;
*(--bufptr) = (val - 10*x) + '0';
val = x;
//*(--bufptr) = val % 10 + '0';
//val /= 10;
}
}
if(minus) *(--bufptr) = '-';
return bufptr;
}
// return string with number `val`
char *u2str(uint32_t val){
return _2str(val, 0);
}
char *i2str(int32_t i){
uint8_t minus = 0;
uint32_t val;
if(i < 0){
minus = 1;
val = -i;
}else val = i;
return _2str(val, minus);
}
/**
* @brief uhex2str - print 32bit unsigned int as hex
* @param val - value
* @return string with number
*/
char *uhex2str(uint32_t val){
static char buf[12] = "0x";
int npos = 2;
uint8_t *ptr = (uint8_t*)&val + 3;
int8_t i, j, z=1;
for(i = 0; i < 4; ++i, --ptr){
if(*ptr == 0){ // omit leading zeros
if(i == 3) z = 0;
if(z) continue;
}
else z = 0;
for(j = 1; j > -1; --j){
uint8_t half = (*ptr >> (4*j)) & 0x0f;
if(half < 10) buf[npos++] = half + '0';
else buf[npos++] = half - 10 + 'a';
}
}
buf[npos] = 0;
return buf;
}
/**
* @brief omit_spaces - eliminate leading spaces and other trash in string
* @param buf - string
* @return - pointer to first character in `buf` > ' '
*/
const char *omit_spaces(const char *buf){
while(*buf){
if(*buf > ' ') break;
++buf;
}
return buf;
}
/**
* @brief getdec - read decimal number & return pointer to next non-number symbol
* @param buf - string
* @param N - number read
* @return Next non-number symbol. In case of overflow return `buf` and N==0xffffffff
*/
static const char *getdec(const char *buf, uint32_t *N){
char *start = (char*)buf;
uint32_t num = 0;
while(*buf){
char c = *buf;
if(c < '0' || c > '9'){
break;
}
if(num > 429496729 || (num == 429496729 && c > '5')){ // overflow
*N = 0xffffff;
return start;
}
num *= 10;
num += c - '0';
++buf;
}
*N = num;
return buf;
}
// read hexadecimal number (without 0x prefix!)
static const char *gethex(const char *buf, uint32_t *N){
const char *start = buf;
uint32_t num = 0;
while(*buf){
char c = *buf;
uint8_t M = 0;
if(c >= '0' && c <= '9'){
M = '0';
}else if(c >= 'A' && c <= 'F'){
M = 'A' - 10;
}else if(c >= 'a' && c <= 'f'){
M = 'a' - 10;
}
if(M){
if(num & 0xf0000000){ // overflow
*N = 0xffffff;
return start;
}
num <<= 4;
num += c - M;
}else{
break;
}
++buf;
}
*N = num;
return buf;
}
// read octal number (without 0 prefix!)
static const char *getoct(const char *buf, uint32_t *N){
const char *start = (char*)buf;
uint32_t num = 0;
while(*buf){
char c = *buf;
if(c < '0' || c > '7'){
break;
}
if(num & 0xe0000000){ // overflow
*N = 0xffffff;
return start;
}
num <<= 3;
num += c - '0';
++buf;
}
*N = num;
return buf;
}
// read binary number (without b prefix!)
static const char *getbin(const char *buf, uint32_t *N){
const char *start = (char*)buf;
uint32_t num = 0;
while(*buf){
char c = *buf;
if(c < '0' || c > '1'){
break;
}
if(num & 0x80000000){ // overflow
*N = 0xffffff;
return start;
}
num <<= 1;
if(c == '1') num |= 1;
++buf;
}
*N = num;
return buf;
}
/**
* @brief getnum - read uint32_t from string (dec, hex or bin: 127, 0x7f, 0b1111111)
* @param buf - buffer with number and so on
* @param N - the number read
* @return pointer to first non-number symbol in buf
* (if it is == buf, there's no number or if *N==0xffffffff there was overflow)
*/
const char *getnum(const char *txt, uint32_t *N){
const char *nxt = NULL;
const char *s = omit_spaces(txt);
if(*s == '0'){ // hex, oct or 0
if(s[1] == 'x' || s[1] == 'X'){ // hex
nxt = gethex(s+2, N);
if(nxt == s+2) nxt = (char*)txt;
}else if(s[1] > '0'-1 && s[1] < '8'){ // oct
nxt = getoct(s+1, N);
if(nxt == s+1) nxt = (char*)txt;
}else{ // 0
nxt = s+1;
*N = 0;
}
}else if(*s == 'b' || *s == 'B'){
nxt = getbin(s+1, N);
if(nxt == s+1) nxt = (char*)txt;
}else{
nxt = getdec(s, N);
if(nxt == s) nxt = (char*)txt;
}
return nxt;
}
// get signed integer
const char *getint(const char *txt, int32_t *I){
const char *s = omit_spaces(txt);
int32_t sign = 1;
uint32_t U;
if(*s == '-'){
sign = -1;
++s;
}
const char *nxt = getnum(s, &U);
if(nxt == s) return txt;
if(U & 0x80000000) return txt; // overfull
*I = sign * (int32_t)U;
return nxt;
}
// be careful: if pow10 would be bigger you should change str[] size!
static const float pwr10[] = {1.f, 10.f, 100.f, 1000.f, 10000.f};
static const float rounds[] = {0.5f, 0.05f, 0.005f, 0.0005f, 0.00005f};
#define P10L (sizeof(pwr10)/sizeof(uint32_t) - 1)
char *float2str(float x, uint8_t prec){
static char str[16] = {0}; // -117.5494E-36\0 - 14 symbols max!
if(prec > P10L) prec = P10L;
if(isnan(x)){ memcpy(str, "NAN", 4); return str;}
else{
int i = isinf(x);
if(i){memcpy(str, "-INF", 5); if(i == 1) return str+1; else return str;}
}
char *s = str + 14; // go to end of buffer
uint8_t minus = 0;
if(x < 0){
x = -x;
minus = 1;
}
int pow = 0; // xxxEpow
// now convert float to 1.xxxE3y
while(x > 1000.f){
x /= 1000.f;
pow += 3;
}
if(x > 0.) while(x < 1.){
x *= 1000.f;
pow -= 3;
}
// print Eyy
if(pow){
uint8_t m = 0;
if(pow < 0){pow = -pow; m = 1;}
while(pow){
register int p10 = pow/10;
*s-- = '0' + (pow - 10*p10);
pow = p10;
}
if(m) *s-- = '-';
*s-- = 'E';
}
// now our number is in [1, 1000]
uint32_t units;
if(prec){
units = (uint32_t) x;
uint32_t decimals = (uint32_t)((x-units+rounds[prec])*pwr10[prec]);
// print decimals
while(prec){
register int d10 = decimals / 10;
*s-- = '0' + (decimals - 10*d10);
decimals = d10;
--prec;
}
// decimal point
*s-- = '.';
}else{ // without decimal part
units = (uint32_t) (x + 0.5);
}
// print main units
if(units == 0) *s-- = '0';
else while(units){
register uint32_t u10 = units / 10;
*s-- = '0' + (units - 10*u10);
units = u10;
}
if(minus) *s-- = '-';
return s+1;
}

View File

@ -0,0 +1,31 @@
/*
* This file is part of the canbus4bta project.
* Copyright 2024 Edward V. Emelianov <edward.emelianoff@gmail.com>.
*
* This program 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.
*
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <stdint.h>
#include <string.h>
void hexdump(int (*sendfun)(const char *s), uint8_t *arr, uint16_t len);
char *u2str(uint32_t val);
char *i2str(int32_t i);
char *uhex2str(uint32_t val);
char *float2str(float x, uint8_t prec);
const char *getnum(const char *txt, uint32_t *N);
const char *omit_spaces(const char *buf);
const char *getint(const char *txt, int32_t *I);

View File

@ -1,2 +1,2 @@
#define BUILD_NUMBER "2" #define BUILD_NUMBER "9"
#define BUILD_DATE "2023-12-03" #define BUILD_DATE "2024-01-05"