From 83b9fd552b336efcc67155e3c4324cdc6bbd9b8e Mon Sep 17 00:00:00 2001 From: Edward Emelianov Date: Mon, 29 Sep 2025 22:12:31 +0300 Subject: [PATCH] OK; next stage: a pair of NTC, BME280, sensors' power management --- F3:F303/MLX90640-allsky/allsky.bin | Bin 25884 -> 26544 bytes F3:F303/MLX90640-allsky/i2c.c | 19 +- F3:F303/MLX90640-allsky/i2c.h | 1 - .../MLX90640-allsky/ir-allsky.creator.user | 2 +- F3:F303/MLX90640-allsky/main.c | 31 ++- F3:F303/MLX90640-allsky/mlx90640.c | 56 +---- F3:F303/MLX90640-allsky/mlx90640.h | 2 - F3:F303/MLX90640-allsky/mlxproc.c | 2 +- F3:F303/MLX90640-allsky/proto.c | 213 +++++++++++++----- F3:F303/MLX90640-allsky/proto.h | 8 +- F3:F303/MLX90640-allsky/strfunc.h | 5 - F3:F303/MLX90640-allsky/usart.c | 9 +- F3:F303/MLX90640-allsky/usart.h | 3 +- F3:F303/MLX90640-allsky/usb_dev.h | 2 +- F3:F303/MLX90640-allsky/version.inc | 4 +- 15 files changed, 198 insertions(+), 159 deletions(-) diff --git a/F3:F303/MLX90640-allsky/allsky.bin b/F3:F303/MLX90640-allsky/allsky.bin index 2ad859f8cda2660d18c464032f28ab707362242b..b8a8e40d1a59214b4d2f2af854e8e67c50ccc365 100755 GIT binary patch delta 7799 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 SOI}D+ataH=s@ATg #include "i2c.h" -#include "strfunc.h" // hexdump -#include "usb_dev.h" i2c_speed_t i2c_curspeed = I2C_SPEED_AMOUNT; extern volatile uint32_t Tms; @@ -45,7 +43,8 @@ static uint8_t dmaaddr = 0; // address to continuous read by DMA static inline int isI2Cbusy(){ cntr = Tms; do{ - if(Tms - cntr > I2C_TIMEOUT){ USND("Timeout, DMA transfer in progress?"); return 1;} + IWDG->KR = IWDG_REFRESH; + if(Tms - cntr > I2C_TIMEOUT) return 1; }while(I2Cbusy); return 0; } @@ -90,7 +89,6 @@ void i2c_setup(i2c_speed_t speed){ SCLL = 0x2; break; default: - USND("Wrong I2C speed!"); return; // wrong speed } RCC->AHBENR |= RCC_AHBENR_GPIOBEN; @@ -318,21 +316,8 @@ int i2c_scan_next_addr(uint8_t *addr){ return 1; } -// dump I2Cbuf -void i2c_bufdudump(){ - if(goterr){ - USND("DMARDERR"); - goterr = 0; - } - if(i2cbuflen < 1) return; - USND("DMARD="); - hexdump16(USB_sendstr, (uint16_t*)I2Cbuf, i2cbuflen); -} - // get DMA buffer with conversion to little-endian (if transfer was for 16-bit) uint16_t *i2c_dma_getbuf(uint16_t *len){ - //if(i2c_got_DMA) USND("DMA GOT!"); - //U("T="); U(u2str(Tms)); U("; cndtr: "); USND(u2str(DMA1_Channel7->CNDTR)); if(!i2c_got_DMA || i2cbuflen < 1) return NULL; i2c_got_DMA = 0; i2cbuflen >>= 1; // for hexdump16 - now buffer have uint16_t! diff --git a/F3:F303/MLX90640-allsky/i2c.h b/F3:F303/MLX90640-allsky/i2c.h index f525880..5715a82 100644 --- a/F3:F303/MLX90640-allsky/i2c.h +++ b/F3:F303/MLX90640-allsky/i2c.h @@ -48,7 +48,6 @@ uint16_t *i2c_read_reg16(uint8_t addr, uint16_t reg16, uint16_t nwords, uint8_t uint8_t i2c_write(uint8_t addr, uint16_t *data, uint8_t nwords); uint8_t i2c_write_dma16(uint8_t addr, uint16_t *data, uint8_t nwords); -void i2c_bufdudump(); int i2c_dma_haderr(); uint16_t *i2c_dma_getbuf(uint16_t *len); int i2c_getwords(uint16_t *buf, int bufsz); diff --git a/F3:F303/MLX90640-allsky/ir-allsky.creator.user b/F3:F303/MLX90640-allsky/ir-allsky.creator.user index 65f6698..bc2d899 100644 --- a/F3:F303/MLX90640-allsky/ir-allsky.creator.user +++ b/F3:F303/MLX90640-allsky/ir-allsky.creator.user @@ -1,6 +1,6 @@ - + EnvironmentId diff --git a/F3:F303/MLX90640-allsky/main.c b/F3:F303/MLX90640-allsky/main.c index e4fc63c..c2fc250 100644 --- a/F3:F303/MLX90640-allsky/main.c +++ b/F3:F303/MLX90640-allsky/main.c @@ -32,6 +32,8 @@ void sys_tick_handler(void){ ++Tms; } +const char *scanend = "SCANEND\n", *foundid = "FOUNDID="; + int main(void){ char inbuff[MAXSTRLEN+1]; if(StartHSE()){ @@ -58,33 +60,40 @@ int main(void){ int l = USB_receivestr(inbuff, MAXSTRLEN); if(l < 0) USB_sendstr("USBOVERFLOW\n"); else if(l){ - const char *ans = parse_cmd(inbuff); + const char *ans = parse_cmd(inbuff, SEND_USB); if(ans) USB_sendstr(ans); } - if(i2c_scanmode){ + if(i2c_scanmode){ // send this to both uint8_t addr; int ok = i2c_scan_next_addr(&addr); - if(addr == I2C_ADDREND) USND("SCANEND"); - else if(ok){ - U("FOUNDID="); - USND(uhex2str(addr)); + if(addr == I2C_ADDREND){ + USB_sendstr(scanend); USB_putbyte('\n'); + usart_sendstr(scanend); usart_putbyte('\n'); + }else if(ok){ + const char *straddr = uhex2str(addr); + USB_sendstr(foundid); USB_sendstr(straddr); USB_putbyte('\n'); + usart_sendstr(foundid); usart_sendstr(straddr); usart_putbyte('\n'); } } mlx_process(); - if(cartoon) for(int i = 0; i < N_SESORS; ++i){ + if(cartoon) for(int i = 0; i < N_SESORS; ++i){ // USB-only uint32_t Tnow = mlx_lastimT(i); if(Tnow != Tlastima[i]){ fp_t *im = mlx_getimage(i); if(im){ - U(Sensno); USND(i2str(i)); - U(Timage); USND(u2str(Tnow)); drawIma(im); + chsendfun(SEND_USB); + U(Sensno); UN(i2str(i)); + U(Timage); UN(u2str(Tnow)); drawIma(im); Tlastima[i] = Tnow; } } } usart_process(); - if(usart_ovr()) USND("USART_OVERFLOW\n"); + if(usart_ovr()) usart_sendstr("USART_OVERFLOW\n"); char *got = usart_getline(NULL); - if(got){ U("USART='"); U(got); USND("'"); } + if(got){ + const char *ans = parse_cmd(got, SEND_USART); + if(ans) usart_sendstr(ans); + } } } diff --git a/F3:F303/MLX90640-allsky/mlx90640.c b/F3:F303/MLX90640-allsky/mlx90640.c index 7b974af..73b3a76 100644 --- a/F3:F303/MLX90640-allsky/mlx90640.c +++ b/F3:F303/MLX90640-allsky/mlx90640.c @@ -34,52 +34,6 @@ static fp_t mlx_image[MLX_PIXNO] = {0}; // ready image // 10100 bytes: static MLX90640_params params; // calculated parameters (in heap, not stack!) for other functions -void dumpIma(const fp_t im[MLX_PIXNO]){ - for(int row = 0; row < MLX_H; ++row){ - for(int col = 0; col < MLX_W; ++col){ - printfl(*im++, 1); - USB_putbyte(' '); - } - newline(); - } -} - -#define GRAY_LEVELS (16) -// 16-level character set ordered by fill percentage (provided by user) -static const char* CHARS_16 = " .':;+*oxX#&%B$@"; -void drawIma(const fp_t im[MLX_PIXNO]){ - // Find min and max values - fp_t min_val = im[0], max_val = im[0]; - const fp_t *iptr = im; - for(int row = 0; row < MLX_H; ++row){ - for(int col = 0; col < MLX_W; ++col){ - fp_t cur = *iptr++; - if(cur < min_val) min_val = cur; - else if(cur > max_val) max_val = cur; - } - } - fp_t range = max_val - min_val; - U("RANGE="); USND(float2str(range, 3)); - U("MIN="); USND(float2str(min_val, 3)); - U("MAX="); USND(float2str(max_val, 3)); - if(fabsf(range) < 0.001) range = 1.; // solid fill -> blank - // Generate and print ASCII art - iptr = im; - for(int row = 0; row < MLX_H; ++row){ - for(int col = 0; col < MLX_W; ++col){ - fp_t normalized = ((*iptr++) - min_val) / range; - // Map to character index (0 to 15) - int index = (int)(normalized * GRAY_LEVELS); - // Ensure we stay within bounds - if(index < 0) index = 0; - else if(index > (GRAY_LEVELS-1)) index = (GRAY_LEVELS-1); - USB_putbyte(CHARS_16[index]); - } - newline(); - } - newline(); -} - /***************************************************************************** Calculate parameters & values *****************************************************************************/ @@ -109,7 +63,7 @@ MLX90640_params *get_parameters(const uint16_t dataarray[MLX_DMA_MAXLEN]){ uint16_t val = CREG_VAL(REG_VDD); i8 = (int8_t) (val >> 8); params.kVdd = i8 * 32; // keep sign - if(params.kVdd == 0){USND("kvdd=0"); return NULL;} + if(params.kVdd == 0){UN("kvdd=0"); return NULL;} i16 = val & 0xFF; params.vdd25 = ((i16 - 0x100) * 32) - (1<<13); val = CREG_VAL(REG_KVTPTAT); @@ -123,7 +77,7 @@ MLX90640_params *get_parameters(const uint16_t dataarray[MLX_DMA_MAXLEN]){ val = CREG_VAL(REG_APTATOCCS) >> 12; params.alphaPTAT = val / 4. + 8.; params.gainEE = (int16_t)CREG_VAL(REG_GAIN); - if(params.gainEE == 0){USND("gainee=0"); return NULL;} + if(params.gainEE == 0){UN("gainee=0"); return NULL;} int8_t occRow[MLX_H]; int8_t occColumn[MLX_W]; occacc(occRow, MLX_H, &CREG_VAL(REG_OCCROW14)); @@ -151,7 +105,7 @@ MLX90640_params *get_parameters(const uint16_t dataarray[MLX_DMA_MAXLEN]){ // so index of ktaavg is 2*(row&1)+(col&1) val = CREG_VAL(REG_KTAVSCALE); uint8_t scale1 = ((val & 0xFF)>>4) + 8, scale2 = (val&0xF); - if(scale1 == 0 || scale2 == 0){USND("scale1/2=0"); return NULL;} + if(scale1 == 0 || scale2 == 0){UN("scale1/2=0"); return NULL;} fp_t mul = (fp_t)(1<. */ +#include #include #include #include "i2c.h" #include "mlxproc.h" +#include "proto.h" #include "strfunc.h" #include "usart.h" #include "usb_dev.h" @@ -33,6 +35,34 @@ static uint8_t I2Caddress = 0x33 << 1; extern volatile uint32_t Tms; uint8_t cartoon = 0; // "cartoon" mode: refresh image each time we get new +// functions to send data over USB or USART: to change them use flag in `parse_cmd` +typedef struct{ + int (*S)(const char*); // send string + int (*P)(uint8_t); // put byte + int (*B)(const uint8_t*, int); // send raw bytes +} sendfun_t; + +static sendfun_t usbsend = { + .S = USB_sendstr, .P = USB_putbyte, .B = USB_send +}; +static sendfun_t usartsend = { + .S = usart_sendstr, .P = usart_putbyte, .B = usart_send +}; + +static sendfun_t *sendfun = &usbsend; + +void chsendfun(int sendto){ + if(sendto == SEND_USB) sendfun = &usbsend; + else sendfun = &usartsend; +} + +// newline +#define N() sendfun->P('\n') +#define printu(x) do{sendfun->S(u2str(x));}while(0) +#define printi(x) do{sendfun->S(i2str(x));}while(0) +#define printuhex(x) do{sendfun->S(uhex2str(x));}while(0) +#define printfl(x,n) do{sendfun->S(float2str(x, n));}while(0) + // common names for frequent keys const char *Timage = "TIMAGE="; const char *Sensno = "SENSNO="; @@ -47,11 +77,11 @@ const char *helpstring = "gn - get nth image 'as is' - float array of 768x4 bytes\n" "i0..4 - setup I2C with speed 10k, 100k, 400k, 1M or 2M (experimental!)\n" "l - list active sensors IDs\n" - "tn - show temperature map of nth image\n" + "mn - show temperature map of nth image\n" "p - pause MLX\n" - "s - stop MLX (and start from zero @ 'c'\n" + "s - stop MLX (and start from zero @ 'c')\n" "tn - show nth image aquisition time\n" - "C - \"cartoon\" mode on/off (show each new image)\n" + "C - \"cartoon\" mode on/off (show each new image) - USB only!!!\n" "Dn - dump MLX parameters for sensor number n\n" "G - get MLX state\n" "Ia addr [n] - set device address for interactive work or (with n) change address of n'th sensor\n" @@ -59,7 +89,7 @@ const char *helpstring = "Iw words - send words (hex/dec/oct/bin) to I2C\n" "Is - scan I2C bus\n" "T - print current Tms\n" - "Us - send string 's' to USART\n" + "Us - send string 's' to other interface\n" ; TRUE_INLINE const char *setupI2C(char *buf){ @@ -78,7 +108,7 @@ TRUE_INLINE const char *setupI2C(char *buf){ } i2c_setup((i2c_speed_t)speed); } - U("I2CSPEED="); USND(speeds[i2c_curspeed]); + sendfun->S("I2CSPEED="); sendfun->S(speeds[i2c_curspeed]); N(); return NULL; } @@ -89,11 +119,11 @@ TRUE_INLINE const char *chhwaddr(const char *buf){ if(nxt && nxt != buf){ if(!mlx_sethwaddr(I2Caddress, a)) return ERR; }else{ - USND("Wrong number"); + sendfun->S("Wrong number"); N(); return ERR; } }else{ - USND("Need address"); + sendfun->S("Need address"); N(); return ERR; } return OK; @@ -117,7 +147,7 @@ TRUE_INLINE const char *chaddr(const char *buf){ int n = getsensnum(nxt); if(n > -1) mlx_setaddr(n, addr); }else addr = I2Caddress >> 1; - U("I2CADDR="); USND(uhex2str(addr)); + sendfun->S("I2CADDR="); sendfun->S(uhex2str(addr)); N(); return NULL; } @@ -135,8 +165,8 @@ static const char *rdI2C(const char *buf){ char b[5]; u16s(*b16, b); b[4] = 0; - USND(b); - }else hexdump16(USB_sendstr, b16, N); + sendfun->S(b); N(); + }else hexdump16(sendfun->S, b16, N); return NULL; } @@ -156,7 +186,8 @@ static const char *wrI2C(const char *buf){ uint16_t N = readNnumbers(buf); if(N == 0) return ERR; for(int i = 0; i < N; ++i){ - U("byte "); U(u2str(i)); U(" :"); USND(uhex2str(locBuffer[i])); + sendfun->S("byte "); sendfun->S(u2str(i)); + sendfun->S(" :"); sendfun->S(uhex2str(locBuffer[i])); N(); } if(!i2c_write(I2Caddress, locBuffer, N)) return ERR; return OK; @@ -165,58 +196,58 @@ static const char *wrI2C(const char *buf){ static void dumpfarr(float *arr){ for(int row = 0; row < 24; ++row){ for(int col = 0; col < 32; ++col){ - printfl(*arr++, 2); USB_putbyte(' '); + printfl(*arr++, 2); sendfun->P(' '); } - newline(); + N(); } } // dump MLX parameters TRUE_INLINE void dumpparams(const char *buf){ int N = getsensnum(buf); - if(N < 0){ U(ERR); return; } + if(N < 0){ sendfun->S(ERR); return; } MLX90640_params *params = mlx_getparams(N); - if(!params){ U(ERR); return; } - U(Sensno); USND(i2str(N)); - U("\nkVdd="); printi(params->kVdd); - U("\nvdd25="); printi(params->vdd25); - U("\nKvPTAT="); printfl(params->KvPTAT, 4); - U("\nKtPTAT="); printfl(params->KtPTAT, 4); - U("\nvPTAT25="); printi(params->vPTAT25); - U("\nalphaPTAT="); printfl(params->alphaPTAT, 2); - U("\ngainEE="); printi(params->gainEE); - U("\nPixel offset parameters:\n"); + if(!params){ sendfun->S(ERR); return; } + sendfun->S(Sensno); sendfun->S(i2str(N)); N(); + sendfun->S("\nkVdd="); printi(params->kVdd); + sendfun->S("\nvdd25="); printi(params->vdd25); + sendfun->S("\nKvPTAT="); printfl(params->KvPTAT, 4); + sendfun->S("\nKtPTAT="); printfl(params->KtPTAT, 4); + sendfun->S("\nvPTAT25="); printi(params->vPTAT25); + sendfun->S("\nalphaPTAT="); printfl(params->alphaPTAT, 2); + sendfun->S("\ngainEE="); printi(params->gainEE); + sendfun->S("\nPixel offset parameters:\n"); float *offset = params->offset; for(int row = 0; row < 24; ++row){ for(int col = 0; col < 32; ++col){ - printfl(*offset++, 2); USB_putbyte(' '); + printfl(*offset++, 2); sendfun->P(' '); } - newline(); + N(); } - U("K_talpha:\n"); + sendfun->S("K_talpha:\n"); dumpfarr(params->kta); - U("Kv: "); + sendfun->S("Kv: "); for(int i = 0; i < 4; ++i){ - printfl(params->kv[i], 2); USB_putbyte(' '); + printfl(params->kv[i], 2); sendfun->P(' '); } - U("\ncpOffset="); - printi(params->cpOffset[0]); U(", "); printi(params->cpOffset[1]); - U("\ncpKta="); printfl(params->cpKta, 2); - U("\ncpKv="); printfl(params->cpKv, 2); - U("\ntgc="); printfl(params->tgc, 2); - U("\ncpALpha="); printfl(params->cpAlpha[0], 2); - U(", "); printfl(params->cpAlpha[1], 2); - U("\nKsTa="); printfl(params->KsTa, 2); - U("\nAlpha:\n"); + sendfun->S("\ncpOffset="); + printi(params->cpOffset[0]); sendfun->S(", "); printi(params->cpOffset[1]); + sendfun->S("\ncpKta="); printfl(params->cpKta, 2); + sendfun->S("\ncpKv="); printfl(params->cpKv, 2); + sendfun->S("\ntgc="); printfl(params->tgc, 2); + sendfun->S("\ncpALpha="); printfl(params->cpAlpha[0], 2); + sendfun->S(", "); printfl(params->cpAlpha[1], 2); + sendfun->S("\nKsTa="); printfl(params->KsTa, 2); + sendfun->S("\nAlpha:\n"); dumpfarr(params->alpha); - U("\nCT3="); printfl(params->CT[1], 2); - U("\nCT4="); printfl(params->CT[2], 2); + sendfun->S("\nCT3="); printfl(params->CT[1], 2); + sendfun->S("\nCT4="); printfl(params->CT[2], 2); for(int i = 0; i < 4; ++i){ - U("\nKsTo"); USB_putbyte('0'+i); USB_putbyte('='); + sendfun->S("\nKsTo"); sendfun->P('0'+i); sendfun->P('='); printfl(params->KsTo[i], 2); - U("\nalphacorr"); USB_putbyte('0'+i); USB_putbyte('='); + sendfun->S("\nalphacorr"); sendfun->P('0'+i); sendfun->P('='); printfl(params->alphacorr[i], 2); } - newline(); + N(); } // get MLX state TRUE_INLINE void getst(){ @@ -228,8 +259,8 @@ TRUE_INLINE void getst(){ [MLX_RELAX] = "do nothing" }; mlx_state_t s = mlx_state(); - U("MLXSTATE="); - USND(states[s]); + sendfun->S("MLXSTATE="); + sendfun->S(states[s]); N(); } // `draw`==1 - draw, ==0 - show T map, 2 - send raw float array with prefix 'SENSNO=x\nTimage=y\n' and postfix "ENDIMAGE\n" @@ -239,8 +270,8 @@ static const char *drawimg(const char *buf, int draw){ uint32_t T = mlx_lastimT(sensno); fp_t *img = mlx_getimage(sensno); if(img){ - U(Sensno); USND(u2str(sensno)); - U(Timage); USND(u2str(T)); + sendfun->S(Sensno); sendfun->S(u2str(sensno)); N(); + sendfun->S(Timage); sendfun->S(u2str(T)); N(); switch(draw){ case 0: dumpIma(img); @@ -255,12 +286,12 @@ static const char *drawimg(const char *buf, int draw){ // send by portions of 256 bytes (as image is larger than ringbuffer) while(_2send){ uint32_t portion = (_2send > 256) ? 256 : _2send; - USB_send(d, portion); + sendfun->B(d, portion); _2send -= portion; d += portion; } } - USND("ENDIMAGE"); + sendfun->S("ENDIMAGE"); N(); } return NULL; } @@ -270,26 +301,35 @@ static const char *drawimg(const char *buf, int draw){ TRUE_INLINE void listactive(){ int N = mlx_nactive(); - if(!N){ USND("No active sensors found!"); return; } + if(!N){ sendfun->S("No active sensors found!\n"); return; } uint8_t *ids = mlx_activeids(); - U("Found "); USB_putbyte('0'+N); USND(" active sensors:"); + sendfun->S("Found "); sendfun->P('0'+N); + sendfun->S(" active sensors:"); N(); for(int i = 0; i < N_SESORS; ++i) if(ids[i]){ - U("SENSID"); U(u2str(i)); USB_putbyte('='); - U(uhex2str(ids[i] >> 1)); - newline(); + sendfun->S("SENSID"); + sendfun->S(u2str(i)); sendfun->P('='); + sendfun->S(uhex2str(ids[i] >> 1)); + N(); } } static void getimt(const char *buf){ int sensno = getsensnum(buf); if(sensno > -1){ - U(Timage); USND(u2str(mlx_lastimT(sensno))); - }else U(ERR); + sendfun->S(Timage); sendfun->S(u2str(mlx_lastimT(sensno))); N(); + }else sendfun->S(ERR); } -const char *parse_cmd(char *buf){ +/** + * @brief parse_cmd - user string parser + * @param buf - user data + * @param isusb - ==1 to send answer over usb, else send over USART1 + * @return answer OK/ERR or NULL + */ +const char *parse_cmd(char *buf, int sendto){ if(!buf || !*buf) return NULL; + chsendfun(sendto); if(buf[1]){ switch(*buf){ // "long" commands case 'a': @@ -325,7 +365,9 @@ const char *parse_cmd(char *buf){ } break; case 'U': - if(usart_sendstr(buf + 1) && usart_putchar('\n')) return OK; + if(sendto == SEND_USB) chsendfun(SEND_USART); + else chsendfun(SEND_USB); + if(sendfun->S(buf + 1) && N()) return OK; return ERR; default: return ERR; @@ -345,18 +387,18 @@ const char *parse_cmd(char *buf){ case 's': mlx_stop(); return OK; case 'C': + if(sendto != SEND_USB) return ERR; cartoon = !cartoon; return OK; case 'G': getst(); break; case 'T': - U("T="); - USND(u2str(Tms)); + sendfun->S("T="); sendfun->S(u2str(Tms)); N(); break; case '?': // help case 'h': case 'H': - U(helpstring); + sendfun->S(helpstring); break; default: return ERR; @@ -364,3 +406,52 @@ const char *parse_cmd(char *buf){ } return NULL; } + +// dump image as temperature matrix +void dumpIma(const fp_t im[MLX_PIXNO]){ + for(int row = 0; row < MLX_H; ++row){ + for(int col = 0; col < MLX_W; ++col){ + printfl(*im++, 1); + sendfun->P(' '); + } + N(); + } +} + +#define GRAY_LEVELS (16) +// 16-level character set ordered by fill percentage (provided by user) +static const char* CHARS_16 = " .':;+*oxX#&%B$@"; +// draw image in ASCII-art +void drawIma(const fp_t im[MLX_PIXNO]){ + // Find min and max values + fp_t min_val = im[0], max_val = im[0]; + const fp_t *iptr = im; + for(int row = 0; row < MLX_H; ++row){ + for(int col = 0; col < MLX_W; ++col){ + fp_t cur = *iptr++; + if(cur < min_val) min_val = cur; + else if(cur > max_val) max_val = cur; + } + } + fp_t range = max_val - min_val; + sendfun->S("RANGE="); sendfun->S(float2str(range, 3)); + sendfun->S("\nMIN="); sendfun->S(float2str(min_val, 3)); + sendfun->S("\nMAX="); sendfun->S(float2str(max_val, 3)); N(); + if(fabsf(range) < 0.001) range = 1.; // solid fill -> blank + // Generate and print ASCII art + iptr = im; + for(int row = 0; row < MLX_H; ++row){ + for(int col = 0; col < MLX_W; ++col){ + fp_t normalized = ((*iptr++) - min_val) / range; + // Map to character index (0 to 15) + int index = (int)(normalized * GRAY_LEVELS); + // Ensure we stay within bounds + if(index < 0) index = 0; + else if(index > (GRAY_LEVELS-1)) index = (GRAY_LEVELS-1); + sendfun->P(CHARS_16[index]); + } + N(); + } + N(); +} + diff --git a/F3:F303/MLX90640-allsky/proto.h b/F3:F303/MLX90640-allsky/proto.h index c65b78d..398ba7a 100644 --- a/F3:F303/MLX90640-allsky/proto.h +++ b/F3:F303/MLX90640-allsky/proto.h @@ -20,5 +20,11 @@ extern const char *Timage, *Sensno; +#define SEND_USB (1) +#define SEND_USART (0) + extern uint8_t cartoon; -char *parse_cmd(char *buf); +void chsendfun(int sendto); +const char *parse_cmd(char *buf, int sendto); +void dumpIma(const fp_t im[MLX_PIXNO]); +void drawIma(const fp_t im[MLX_PIXNO]); diff --git a/F3:F303/MLX90640-allsky/strfunc.h b/F3:F303/MLX90640-allsky/strfunc.h index 899d713..960eb73 100644 --- a/F3:F303/MLX90640-allsky/strfunc.h +++ b/F3:F303/MLX90640-allsky/strfunc.h @@ -23,11 +23,6 @@ #include "usb_dev.h" -#define printu(x) do{USB_sendstr(u2str(x));}while(0) -#define printi(x) do{USB_sendstr(i2str(x));}while(0) -#define printuhex(x) do{USB_sendstr(uhex2str(x));}while(0) -#define printfl(x,n) do{USB_sendstr(float2str(x, n));}while(0) - void u16s(uint16_t n, char *buf); void hexdump16(int (*sendfun)(const char *s), uint16_t *arr, uint16_t len); void hexdump(int (*sendfun)(const char *s), uint8_t *arr, uint16_t len); diff --git a/F3:F303/MLX90640-allsky/usart.c b/F3:F303/MLX90640-allsky/usart.c index 239539f..8e766e0 100644 --- a/F3:F303/MLX90640-allsky/usart.c +++ b/F3:F303/MLX90640-allsky/usart.c @@ -85,11 +85,12 @@ static int transmit_tbuf(){ } // return 0 if can't write to ringbuffer -int usart_putchar(const char ch){ - int r = RB_write(&dmarb, (uint8_t*)&ch, 1); +int usart_putbyte(uint8_t ch){ + int r = RB_write(&dmarb, &ch, 1); if(r != 1){ - if(transmit_tbuf()) r = RB_write(&dmarb, (uint8_t*)&ch, 1); + if(transmit_tbuf()) r = RB_write(&dmarb, &ch, 1); } + if(r < 0) r = 0; return r; } @@ -163,7 +164,7 @@ void usart1_exti25_isr(){ USART1->ICR = USART_ICR_CMCF; // clear character match flag register int l = UARTBUFSZI - DMA1_Channel5->CNDTR - 1; // substitute '\n' with '\0', omit empty strings! if(l > 0){ - if(recvdata){ // user didn't read old data - mark as buffer overflow + if(recvdatalen){ // user didn't read old data - mark as buffer overflow bufovr = 1; } recvdata = rbuf[rbufno]; diff --git a/F3:F303/MLX90640-allsky/usart.h b/F3:F303/MLX90640-allsky/usart.h index 1b1907d..b9f2dbc 100644 --- a/F3:F303/MLX90640-allsky/usart.h +++ b/F3:F303/MLX90640-allsky/usart.h @@ -32,6 +32,7 @@ int usart_ovr(); // RX overfull occured void usart_process(); // send next data portion int usart_setup(uint32_t speed); // set USART1 with given speed char *usart_getline(int *len); // read from rbin to buf +int usart_send(const uint8_t *data, int len); int usart_sendstr(const char *str); -int usart_putchar(const char ch); +int usart_putbyte(uint8_t ch); void usart_stop(); diff --git a/F3:F303/MLX90640-allsky/usb_dev.h b/F3:F303/MLX90640-allsky/usb_dev.h index b8a0808..a85227c 100644 --- a/F3:F303/MLX90640-allsky/usb_dev.h +++ b/F3:F303/MLX90640-allsky/usb_dev.h @@ -47,7 +47,7 @@ void linecoding_handler(usb_LineCoding *lc); #define RBINSZ (128) #define newline() USB_putbyte('\n') -#define USND(s) do{USB_sendstr(s); USB_putbyte('\n');}while(0) +#define UN(s) do{USB_sendstr(s); USB_putbyte('\n');}while(0) #define U(s) USB_sendstr(s) int USB_sendall(); diff --git a/F3:F303/MLX90640-allsky/version.inc b/F3:F303/MLX90640-allsky/version.inc index 7b1ccba..3b34625 100644 --- a/F3:F303/MLX90640-allsky/version.inc +++ b/F3:F303/MLX90640-allsky/version.inc @@ -1,2 +1,2 @@ -#define BUILD_NUMBER "1" -#define BUILD_DATE "2025-09-28" +#define BUILD_NUMBER "15" +#define BUILD_DATE "2025-09-29"