mirror of
https://github.com/eddyem/stm32samples.git
synced 2026-05-07 13:26:56 +03:00
change proto to text strings; add simplest NTC measurement
This commit is contained in:
@@ -8,3 +8,5 @@ LDLIBS := -lm
|
|||||||
|
|
||||||
include ../makefile.f3
|
include ../makefile.f3
|
||||||
include ../../makefile.stm32
|
include ../../makefile.stm32
|
||||||
|
|
||||||
|
$(OBJDIR)/commproto.o: commproto.cpp $(VERSION_FILE)
|
||||||
|
|||||||
@@ -16,17 +16,26 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#ifdef EBUG
|
||||||
|
#include "strfunc.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "adc.h"
|
#include "adc.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief ADCx_array - arrays for ADC channels with median filtering:
|
* @brief ADCx_array - arrays for ADC channels with median filtering:
|
||||||
* ADC1:
|
* ADC1:
|
||||||
* 0 - Ch0 - ADC1_IN1
|
* 0 - Ch0 - ADC1_IN1 - NTC1
|
||||||
* 1 - Ch1 - ADC1_IN2
|
* 1 - Ch1 - ADC1_IN2 - NTC2
|
||||||
* 2 - internal Tsens - ADC1_IN16
|
* 2 - Ch2 - ADC1_IN3 - NTC3
|
||||||
* 3 - Vref - ADC1_IN18
|
* 3 - Ch3 - ADC1_IN4 - NTC4
|
||||||
|
* 4 - internal Tsens - ADC1_IN16
|
||||||
|
* 5 - Vref - ADC1_IN18
|
||||||
* ADC2:
|
* ADC2:
|
||||||
* 4 - AIN5/DAC_OUT1 - PA4 - DAC1_OUT1 (onboard heater?), PA5 - ADC2_IN2 (DAC output control)
|
* AIN5/DAC_OUT1 - PA4 - DAC1_OUT1 (onboard heater)
|
||||||
|
* 6 - PA5 - ADC2_IN2 (DAC output control)
|
||||||
*/
|
*/
|
||||||
static uint16_t ADC_array[NUMBER_OF_ADC_CHANNELS*9];
|
static uint16_t ADC_array[NUMBER_OF_ADC_CHANNELS*9];
|
||||||
|
|
||||||
@@ -65,17 +74,19 @@ TRUE_INLINE void enADC(ADC_TypeDef *chnl){
|
|||||||
* ADC1 - DMA1_ch1
|
* ADC1 - DMA1_ch1
|
||||||
* ADC2 - DMA2_ch1
|
* ADC2 - DMA2_ch1
|
||||||
*/
|
*/
|
||||||
// Setup ADC and DAC
|
// Setup ADC and DAC; ADC/DAC pins should be prepared in gpio_setup
|
||||||
void adc_setup(){
|
void adc_setup(){
|
||||||
RCC->AHBENR |= RCC_AHBENR_ADC12EN; // Enable clocking
|
RCC->AHBENR |= RCC_AHBENR_ADC12EN; // Enable clocking
|
||||||
ADC12_COMMON->CCR = ADC_CCR_TSEN | ADC_CCR_VREFEN | ADC_CCR_CKMODE; // enable Tsens and Vref, HCLK/4
|
ADC12_COMMON->CCR = ADC_CCR_TSEN | ADC_CCR_VREFEN | ADC_CCR_CKMODE; // enable Tsens and Vref, HCLK/4
|
||||||
calADC(ADC1);
|
calADC(ADC1);
|
||||||
calADC(ADC2);
|
calADC(ADC2);
|
||||||
// ADC1: channels 1,2,16,18; ADC2: channel 2
|
// ADC1: channels 1,2,3,4,16,18
|
||||||
ADC1->SMPR1 = ADC_SMPR1_SMP0 | ADC_SMPR1_SMP1;
|
ADC1->SMPR1 = ADC_SMPR1_SMP0 | ADC_SMPR1_SMP1 | ADC_SMPR1_SMP2 | ADC_SMPR1_SMP3;
|
||||||
ADC1->SMPR2 = ADC_SMPR2_SMP15 | ADC_SMPR2_SMP17;
|
ADC1->SMPR2 = ADC_SMPR2_SMP15 | ADC_SMPR2_SMP17;
|
||||||
// 4 conversions in group: 1->2->16->18
|
// 6 conversions in group: 1->2->3->4->16->18
|
||||||
ADC1->SQR1 = (1<<6) | (2<<12) | (16<<18) | (18<<24) | (NUMBER_OF_ADC1_CHANNELS-1);
|
ADC1->SQR1 = (1<<6) | (2<<12) | (3<<18) | (4<<24) | (NUMBER_OF_ADC1_CHANNELS-1);
|
||||||
|
ADC1->SQR2 = (16<<0) | (18<<6);
|
||||||
|
// ADC2: channel 2
|
||||||
ADC2->SMPR1 = ADC_SMPR1_SMP1;
|
ADC2->SMPR1 = ADC_SMPR1_SMP1;
|
||||||
ADC2->SQR1 = (2<<6) | (NUMBER_OF_ADC2_CHANNELS-1);
|
ADC2->SQR1 = (2<<6) | (NUMBER_OF_ADC2_CHANNELS-1);
|
||||||
// configure DMA for ADC
|
// configure DMA for ADC
|
||||||
@@ -109,7 +120,8 @@ void adc_setup(){
|
|||||||
* @param nch - number of channel
|
* @param nch - number of channel
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
uint16_t getADCval(int nch){
|
uint16_t getADCval(uint8_t nch){
|
||||||
|
if(nch >= NUMBER_OF_ADC_CHANNELS) return 0;
|
||||||
register uint16_t temp;
|
register uint16_t temp;
|
||||||
#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; }
|
||||||
@@ -131,7 +143,7 @@ uint16_t getADCval(int nch){
|
|||||||
}
|
}
|
||||||
|
|
||||||
// get voltage @input nch (V)
|
// get voltage @input nch (V)
|
||||||
float getADCvoltage(int nch){
|
float getADCvoltage(uint8_t nch){
|
||||||
float v = getADCval(nch);
|
float v = getADCval(nch);
|
||||||
v *= getVdd();
|
v *= getVdd();
|
||||||
v /= 4096.f; // 12bit ADC
|
v /= 4096.f; // 12bit ADC
|
||||||
@@ -155,3 +167,114 @@ float getVdd(){
|
|||||||
vdd /= getADCval(ADC_VREF);
|
vdd /= getADCval(ADC_VREF);
|
||||||
return vdd;
|
return vdd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// R lookup table for T=-10..59 degreesC
|
||||||
|
#if 0
|
||||||
|
T=[-10:59]+273.15;
|
||||||
|
R=1000*exp(3950*(1./T-1/298.15));
|
||||||
|
for i=1:length(T); printf("\t%.1f,\t// %d \n", R(i), T(i)-273.15); endfor
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static const float Rlut[] = {
|
||||||
|
5824.6, // -10
|
||||||
|
5502.8, // -9
|
||||||
|
5201.1, // -8
|
||||||
|
4917.9, // -7
|
||||||
|
4652.2, // -6
|
||||||
|
4402.6, // -5
|
||||||
|
4168.1, // -4
|
||||||
|
3947.7, // -3
|
||||||
|
3740.5, // -2
|
||||||
|
3545.5, // -1
|
||||||
|
3362.1, // 0
|
||||||
|
3189.3, // 1
|
||||||
|
3026.6, // 2
|
||||||
|
2873.3, // 3
|
||||||
|
2728.8, // 4
|
||||||
|
2592.5, // 5
|
||||||
|
2463.9, // 6
|
||||||
|
2342.5, // 7
|
||||||
|
2227.9, // 8
|
||||||
|
2119.7, // 9
|
||||||
|
2017.5, // 10
|
||||||
|
1920.8, // 11
|
||||||
|
1829.4, // 12
|
||||||
|
1743.0, // 13
|
||||||
|
1661.2, // 14
|
||||||
|
1583.7, // 15
|
||||||
|
1510.4, // 16
|
||||||
|
1440.9, // 17
|
||||||
|
1375.1, // 18
|
||||||
|
1312.7, // 19
|
||||||
|
1253.5, // 20
|
||||||
|
1197.4, // 21
|
||||||
|
1144.1, // 22
|
||||||
|
1093.6, // 23
|
||||||
|
1045.6, // 24
|
||||||
|
1000.0, // 25
|
||||||
|
956.7, // 26
|
||||||
|
915.5, // 27
|
||||||
|
876.4, // 28
|
||||||
|
839.1, // 29
|
||||||
|
803.7, // 30
|
||||||
|
770.0, // 31
|
||||||
|
737.9, // 32
|
||||||
|
707.4, // 33
|
||||||
|
678.3, // 34
|
||||||
|
650.6, // 35
|
||||||
|
624.1, // 36
|
||||||
|
598.9, // 37
|
||||||
|
574.9, // 38
|
||||||
|
552.0, // 39
|
||||||
|
530.1, // 40
|
||||||
|
509.3, // 41
|
||||||
|
489.4, // 42
|
||||||
|
470.3, // 43
|
||||||
|
452.2, // 44
|
||||||
|
434.8, // 45
|
||||||
|
418.2, // 46
|
||||||
|
402.4, // 47
|
||||||
|
387.2, // 48
|
||||||
|
372.7, // 49
|
||||||
|
358.8, // 50
|
||||||
|
345.5, // 51
|
||||||
|
332.8, // 52
|
||||||
|
320.7, // 53
|
||||||
|
309.0, // 54
|
||||||
|
297.8, // 55
|
||||||
|
287.1, // 56
|
||||||
|
276.9, // 57
|
||||||
|
267.1, // 58
|
||||||
|
257.7, // 59
|
||||||
|
};
|
||||||
|
|
||||||
|
#define LUTSZ (sizeof(Rlut) / sizeof(float))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief getNTCtemp - stupid LUT-search and linear approximation of T by R
|
||||||
|
* @param nch - channel of ADC for Tx
|
||||||
|
* @return temperature in degr.C
|
||||||
|
*/
|
||||||
|
float getNTCtemp(uint8_t nch){
|
||||||
|
if(nch > ADC_AIN4) return -300.f; // bad number
|
||||||
|
uint16_t val = getADCval(nch);
|
||||||
|
if(val < 5) return -400.f; // short cirquit
|
||||||
|
else if(val > 4090) return -500.f; // no NTC
|
||||||
|
float R = 1000.f / (4096.f / val - 1.f); // resistance of NTC
|
||||||
|
#ifdef EBUG
|
||||||
|
USB_sendstr("R="); USB_sendstr(float2str(R, 1)); newline();
|
||||||
|
#endif
|
||||||
|
int left = 0, right = LUTSZ-1;
|
||||||
|
if(R > Rlut[0]) right = 1;
|
||||||
|
else if(R < Rlut[LUTSZ-1]) left = LUTSZ-2;
|
||||||
|
while(right - left > 1){
|
||||||
|
int idx = left + (right - left) / 2;
|
||||||
|
float Rl = Rlut[idx];
|
||||||
|
if(Rl > R) left = idx + 1;
|
||||||
|
else right = idx - 1;
|
||||||
|
}
|
||||||
|
if(left >= (int)LUTSZ) return 60.f;
|
||||||
|
float Rleft = Rlut[left], Rright = Rlut[left+1];
|
||||||
|
float T = (float)left - 9.f - (R - Rright) / (Rleft - Rright);
|
||||||
|
return T;
|
||||||
|
}
|
||||||
|
|||||||
@@ -19,22 +19,27 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <stm32f3.h>
|
#include <stm32f3.h>
|
||||||
|
|
||||||
#define NUMBER_OF_ADC1_CHANNELS (4)
|
// 4 sensors on 1..4, TS (16) and Vdd (18)
|
||||||
|
#define NUMBER_OF_ADC1_CHANNELS (6)
|
||||||
#define NUMBER_OF_ADC2_CHANNELS (1)
|
#define NUMBER_OF_ADC2_CHANNELS (1)
|
||||||
// total number of channels - for array
|
// total number of channels - for array
|
||||||
#define NUMBER_OF_ADC_CHANNELS ((NUMBER_OF_ADC1_CHANNELS+NUMBER_OF_ADC2_CHANNELS))
|
#define NUMBER_OF_ADC_CHANNELS ((NUMBER_OF_ADC1_CHANNELS+NUMBER_OF_ADC2_CHANNELS))
|
||||||
|
|
||||||
// channels of ADC in array
|
// channels of ADC in array
|
||||||
#define ADC_AIN0 (0)
|
#define ADC_AIN1 (0)
|
||||||
#define ADC_AIN1 (1)
|
#define ADC_AIN2 (1)
|
||||||
#define ADC_TS (2)
|
#define ADC_AIN3 (2)
|
||||||
#define ADC_VREF (3)
|
#define ADC_AIN4 (3)
|
||||||
#define ADC_AIN5 (4)
|
#define ADC_NTCIN(x) ((x)-1)
|
||||||
|
#define ADC_TS (4)
|
||||||
|
#define ADC_VREF (5)
|
||||||
|
#define ADC_DACIN (6)
|
||||||
// starting index of ADC2
|
// starting index of ADC2
|
||||||
#define ADC2START (9*NUMBER_OF_ADC1_CHANNELS)
|
#define ADC2START (9*NUMBER_OF_ADC1_CHANNELS)
|
||||||
|
|
||||||
void adc_setup();
|
void adc_setup();
|
||||||
float getMCUtemp();
|
float getMCUtemp();
|
||||||
float getVdd();
|
float getVdd();
|
||||||
uint16_t getADCval(int nch);
|
uint16_t getADCval(uint8_t nch);
|
||||||
float getADCvoltage(int nch);
|
float getADCvoltage(uint8_t nch);
|
||||||
|
float getNTCtemp(uint8_t nch);
|
||||||
|
|||||||
Binary file not shown.
627
F3:F303/MLX90640-allsky/commproto.cpp
Normal file
627
F3:F303/MLX90640-allsky/commproto.cpp
Normal file
@@ -0,0 +1,627 @@
|
|||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
extern "C"{
|
||||||
|
#include <stm32f3.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#include "adc.h"
|
||||||
|
#include "commproto.h"
|
||||||
|
#include "hardware.h"
|
||||||
|
#include "i2c.h"
|
||||||
|
#include "mlxproc.h"
|
||||||
|
#include "strfunc.h"
|
||||||
|
#include "usart.h"
|
||||||
|
#include "usb_dev.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
// image aquisition time
|
||||||
|
const char* const Timage = "TIMAGE";
|
||||||
|
|
||||||
|
// Global senders to send info into other interface
|
||||||
|
static int (*usb_sender)(const char*) = nullptr;
|
||||||
|
static int (*usart_sender)(const char*) = nullptr;
|
||||||
|
static int (*usb_putb)(uint8_t) = nullptr;
|
||||||
|
static int (*usart_putb)(uint8_t) = nullptr;
|
||||||
|
static int (*usb_sendbin)(const uint8_t*, int) = nullptr;
|
||||||
|
static int (*usart_sendbin)(const uint8_t*, int) = nullptr;
|
||||||
|
|
||||||
|
// Function helpers
|
||||||
|
static int (*SEND)(const char*) = nullptr;
|
||||||
|
static int (*putb)(uint8_t) = nullptr;
|
||||||
|
static int (*sendbin)(const uint8_t*, int) = nullptr;
|
||||||
|
|
||||||
|
#define N() putb('\n')
|
||||||
|
#define printu(x) SEND(u2str(x))
|
||||||
|
#define printi(x) SEND(i2str(x))
|
||||||
|
#define printuhex(x) SEND(uhex2str(x))
|
||||||
|
#define printfl(x,n) SEND(float2str(x, n))
|
||||||
|
|
||||||
|
void set_senders(int (*usbs)(const char *),
|
||||||
|
int (*usbb)(uint8_t),
|
||||||
|
int (*usbbin)(const uint8_t *, int),
|
||||||
|
int (*usarts)(const char *),
|
||||||
|
int (*usartb)(uint8_t),
|
||||||
|
int (*usartbin)(const uint8_t *, int)){
|
||||||
|
usb_sender = usbs;
|
||||||
|
usb_putb = usbb;
|
||||||
|
usb_sendbin = usbbin;
|
||||||
|
usart_sender = usarts;
|
||||||
|
usart_putb = usartb;
|
||||||
|
usart_sendbin = usartbin;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Local buffer for I2C data
|
||||||
|
#define LOCBUFFSZ 32
|
||||||
|
static uint16_t locBuffer[LOCBUFFSZ];
|
||||||
|
// default I2C address of sensor
|
||||||
|
static uint8_t I2Caddress = 0x33 << 1;
|
||||||
|
extern volatile uint32_t Tms;
|
||||||
|
// show `cartoon` - continuously draw ASCII image of current sensor
|
||||||
|
uint8_t cartoon = 0;
|
||||||
|
|
||||||
|
// Command list
|
||||||
|
#define COMMAND_TABLE \
|
||||||
|
COMMAND(help, "show this help") \
|
||||||
|
COMMAND(ascii, "draw nth image in ASCII (n=0..4)") \
|
||||||
|
COMMAND(binary, "get nth image as text array of floats") \
|
||||||
|
COMMAND(listids, "list active sensors IDs") \
|
||||||
|
COMMAND(tempmap, "show temperature map of nth image") \
|
||||||
|
COMMAND(acqtime, "show nth image aquisition time") \
|
||||||
|
COMMAND(bmereinit, "reinit BME280") \
|
||||||
|
COMMAND(environ, "get environment parameters") \
|
||||||
|
COMMAND(state, "get MLX state") \
|
||||||
|
COMMAND(reset, "reset MCU") \
|
||||||
|
COMMAND(time, "print current Tms") \
|
||||||
|
COMMAND(iicaddr, "get/set I2C address (non-shifted)") \
|
||||||
|
COMMAND(mlxcont, "continue MLX") \
|
||||||
|
COMMAND(iicspeed, "get/set I2C speed (0..4)") \
|
||||||
|
COMMAND(mlxpause, "pause MLX") \
|
||||||
|
COMMAND(mlxstop, "stop MLX") \
|
||||||
|
COMMAND(adc, "get n'th ADC values") \
|
||||||
|
COMMAND(ntc, "get n'th NTC temperatures") \
|
||||||
|
COMMAND(cartoon, "toggle cartoon mode") \
|
||||||
|
COMMAND(mlxdump, "dump MLX parameters for sensor n") \
|
||||||
|
COMMAND(mlxaddr, "get/set MLX address of sensor n") \
|
||||||
|
COMMAND(readreg, "read I2C register: readreg reg [= nwords]") \
|
||||||
|
COMMAND(writedata, "write I2C data: writedata = val1 val2 ...") \
|
||||||
|
COMMAND(iicscan, "scan I2C bus") \
|
||||||
|
COMMAND(mcutemp, "get MCU temperature") \
|
||||||
|
COMMAND(mcuvdd, "get MCU Vdd") \
|
||||||
|
COMMAND(dac, "get/set DAC value") \
|
||||||
|
COMMAND(pwm, "get/set PWM for channel n (0..100%)") \
|
||||||
|
COMMAND(sendstr, "send string to other interface: sendstr = text")
|
||||||
|
|
||||||
|
|
||||||
|
// Command prototypes
|
||||||
|
#define COMMAND(name, desc) static errcodes_t cmd_ ## name(const char*, char*);
|
||||||
|
COMMAND_TABLE
|
||||||
|
#undef COMMAND
|
||||||
|
|
||||||
|
// descrtiptions for `help`
|
||||||
|
typedef struct {
|
||||||
|
const char *name;
|
||||||
|
const char *desc;
|
||||||
|
} CmdInfo;
|
||||||
|
|
||||||
|
static const CmdInfo cmdInfo[] = {
|
||||||
|
#define COMMAND(name, desc) { #name, desc },
|
||||||
|
COMMAND_TABLE
|
||||||
|
#undef COMMAND
|
||||||
|
};
|
||||||
|
|
||||||
|
// Text descriptions for error codes
|
||||||
|
static const char* errtxt[ERR_AMOUNT] = {
|
||||||
|
[ERR_OK] = "OK\n",
|
||||||
|
[ERR_BADCMD] = "BADCMD\n",
|
||||||
|
[ERR_BADPAR] = "BADPAR\n",
|
||||||
|
[ERR_BADVAL] = "BADVAL\n",
|
||||||
|
[ERR_WRONGLEN] = "WRONGLEN\n",
|
||||||
|
[ERR_CANTRUN] = "CANTRUN\n",
|
||||||
|
[ERR_BUSY] = "BUSY\n",
|
||||||
|
[ERR_OVERFLOW] = "OVERFLOW\n",
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *EQ = " = "; // equal sign for getters
|
||||||
|
|
||||||
|
// send `command = `
|
||||||
|
#define CMDEQ() do{SEND(cmd); SEND(EQ);}while(0)
|
||||||
|
// send `commandXXX = `
|
||||||
|
#define CMDEQP(x) do{SEND(cmd); SEND(u2str((uint32_t)x)); SEND(EQ);}while(0)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief splitargs - get command parameter and setter from `args`
|
||||||
|
* @param args (i) - rest of string after command (like `1 = PU OD OUT`)
|
||||||
|
* @param parno (o) - parameter number or -1 if none
|
||||||
|
* @return setter (part after `=` without leading spaces) or NULL if none
|
||||||
|
*/
|
||||||
|
static const char *splitargs(char *args, int32_t *parno){
|
||||||
|
if(!args) return NULL;
|
||||||
|
uint32_t U32;
|
||||||
|
const char *next = getnum(args, &U32);
|
||||||
|
int p = -1;
|
||||||
|
if(next != args && U32 <= MAXPARNO) p = U32;
|
||||||
|
if(parno) *parno = p;
|
||||||
|
next = strchr(next, '=');
|
||||||
|
if(next){
|
||||||
|
if(*(++next)) next = omit_spaces(next);
|
||||||
|
if(*next == 0) next = NULL;
|
||||||
|
}
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief argsvals - split `args` into `parno` and setter's value
|
||||||
|
* @param args - rest of string after command
|
||||||
|
* @param parno (o) - parameter number or -1 if none
|
||||||
|
* @param parval - integer setter's value
|
||||||
|
* @return false if no setter or it's not a number, true - got setter's num
|
||||||
|
*/
|
||||||
|
static bool argsvals(char *args, int32_t *parno, int32_t *parval){
|
||||||
|
const char *setter = splitargs(args, parno);
|
||||||
|
if(!setter) return false;
|
||||||
|
int32_t I32;
|
||||||
|
const char *next = getint(setter, &I32);
|
||||||
|
if(next != setter && parval){
|
||||||
|
*parval = I32;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/************* List of proto functions for each command *************/
|
||||||
|
|
||||||
|
static errcodes_t cmd_help(const char*, char*){
|
||||||
|
SEND(REPOURL);
|
||||||
|
for(size_t i = 0; i < sizeof(cmdInfo)/sizeof(cmdInfo[0]); ++i){
|
||||||
|
SEND(cmdInfo[i].name);
|
||||||
|
SEND(" - ");
|
||||||
|
SEND(cmdInfo[i].desc);
|
||||||
|
SEND("\n");
|
||||||
|
}
|
||||||
|
return ERR_AMOUNT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static errcodes_t cmd_time(const char* cmd, char*){
|
||||||
|
CMDEQ();
|
||||||
|
printu(Tms); N();
|
||||||
|
return ERR_AMOUNT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static errcodes_t cmd_reset(const char*, char*){
|
||||||
|
NVIC_SystemReset();
|
||||||
|
return ERR_CANTRUN; // unreacheable
|
||||||
|
}
|
||||||
|
|
||||||
|
// send acquisition time
|
||||||
|
static void imaqtime(uint8_t sensno){
|
||||||
|
uint32_t T = mlx_lastimT(sensno);
|
||||||
|
SEND(Timage); printu(sensno); SEND(EQ);
|
||||||
|
printu(T); N();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Common image command for ASCII/binary/tempmap
|
||||||
|
static errcodes_t image_cmd(char* args, int mode){
|
||||||
|
int32_t sensno = -1;
|
||||||
|
splitargs(args, &sensno);
|
||||||
|
if(sensno < 0 || sensno >= N_SENSORS) return ERR_BADPAR;
|
||||||
|
fp_t *img = mlx_getimage(sensno);
|
||||||
|
if(!img) return ERR_CANTRUN;
|
||||||
|
|
||||||
|
// Frame number
|
||||||
|
imaqtime(sensno);
|
||||||
|
|
||||||
|
switch(mode){
|
||||||
|
case 0: // tempmap
|
||||||
|
dumpIma(img);
|
||||||
|
break;
|
||||||
|
case 1: // ascii
|
||||||
|
drawIma(img);
|
||||||
|
break;
|
||||||
|
case 2: // binary
|
||||||
|
SEND("BINARY"); putb('0'+sensno); putb('=');
|
||||||
|
uint8_t *d = (uint8_t*)img;
|
||||||
|
uint32_t _2send = MLX_PIXNO * sizeof(float);
|
||||||
|
// send by portions of 256 bytes
|
||||||
|
while(_2send){
|
||||||
|
uint32_t portion = (_2send > 256) ? 256 : _2send;
|
||||||
|
if(sendbin(d, portion)){
|
||||||
|
_2send -= portion;
|
||||||
|
d += portion;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SEND("ENDIMAGE"); N();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ERR_AMOUNT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static errcodes_t cmd_ascii(const char* , char* args){
|
||||||
|
return image_cmd(args, 1);
|
||||||
|
}
|
||||||
|
static errcodes_t cmd_binary(const char* , char* args){
|
||||||
|
return image_cmd(args, 2);
|
||||||
|
}
|
||||||
|
static errcodes_t cmd_tempmap(const char* , char* args){
|
||||||
|
return image_cmd(args, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static errcodes_t cmd_acqtime(const char* , char* args){
|
||||||
|
int32_t sensno = -1;
|
||||||
|
splitargs(args, &sensno);
|
||||||
|
if(sensno < 0 || sensno >= N_SENSORS) return ERR_BADPAR;
|
||||||
|
imaqtime(sensno);
|
||||||
|
return ERR_AMOUNT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static errcodes_t cmd_listids(const char*, char*){
|
||||||
|
int N = mlx_nactive();
|
||||||
|
if(!N) return ERR_CANTRUN;
|
||||||
|
uint8_t *ids = mlx_activeids();
|
||||||
|
SEND("Found "); printu(N); SEND(" active sensors:\n");
|
||||||
|
for(int i = 0; i < N_SENSORS; ++i){
|
||||||
|
if(ids[i]){
|
||||||
|
SEND("SENSID"); printu(i); SEND(EQ); printuhex(ids[i]>>1); N();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ERR_AMOUNT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static errcodes_t cmd_bmereinit(const char*, char*){
|
||||||
|
if(bme_init()) return ERR_OK;
|
||||||
|
return ERR_CANTRUN;
|
||||||
|
}
|
||||||
|
|
||||||
|
static errcodes_t cmd_environ(const char*, char*){
|
||||||
|
bme280_t env;
|
||||||
|
if(!get_environment(&env)) return ERR_CANTRUN;
|
||||||
|
SEND("TEMPERATURE="); printfl(env.T, 2); N();
|
||||||
|
SEND("SKYTEMPERATURE="); printfl(env.Tsky, 2); N();
|
||||||
|
SEND("PRESSURE_HPA="); printfl(env.P/100.f, 2); N();
|
||||||
|
SEND("PRESSURE_MM="); printfl(env.P * 0.00750062f, 2); N();
|
||||||
|
SEND("HUMIDITY="); printfl(env.H, 2); N();
|
||||||
|
SEND("TEMP_DEW="); printfl(env.Tdew, 1); N();
|
||||||
|
SEND("T_MEASUREMENT="); printu(env.Tmeas); N();
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static errcodes_t cmd_state(const char* cmd, char*){
|
||||||
|
static const char *states[] = {
|
||||||
|
[MLX_NOTINIT] = "not init",
|
||||||
|
[MLX_WAITPARAMS] = "wait parameters DMA read",
|
||||||
|
[MLX_WAITSUBPAGE] = "wait subpage",
|
||||||
|
[MLX_READSUBPAGE] = "wait subpage DMA read",
|
||||||
|
[MLX_RELAX] = "do nothing"
|
||||||
|
};
|
||||||
|
mlx_state_t s = mlx_state();
|
||||||
|
CMDEQ(); SEND(states[s]); N();
|
||||||
|
return ERR_AMOUNT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/********** I2C commands **********/
|
||||||
|
|
||||||
|
static errcodes_t cmd_iicaddr(const char* cmd, char* args){
|
||||||
|
int32_t addr;
|
||||||
|
if(argsvals(args, NULL, &addr)){
|
||||||
|
if(addr < 0 || addr > 0x7f) return ERR_BADVAL;
|
||||||
|
I2Caddress = (uint8_t)(addr << 1);
|
||||||
|
mlx_sethwaddr(I2Caddress, addr);
|
||||||
|
return ERR_AMOUNT;
|
||||||
|
}
|
||||||
|
// getter
|
||||||
|
CMDEQ(); printuhex(I2Caddress >> 1); N();
|
||||||
|
return ERR_AMOUNT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static errcodes_t cmd_mlxcont(const char*, char*){
|
||||||
|
mlx_continue();
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static errcodes_t cmd_iicspeed(const char* cmd, char* args){
|
||||||
|
static const char *speeds[] = {"10K","100K","400K","1M","2M"};
|
||||||
|
int32_t speed;
|
||||||
|
// TODO: allow string parameter
|
||||||
|
if(argsvals(args, NULL, &speed)){
|
||||||
|
if (speed < 0 || speed >= I2C_SPEED_AMOUNT) return ERR_BADVAL;
|
||||||
|
i2c_setup((i2c_speed_t)speed);
|
||||||
|
}
|
||||||
|
// getter
|
||||||
|
CMDEQ(); SEND(speeds[i2c_curspeed]); N();
|
||||||
|
return ERR_AMOUNT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static errcodes_t cmd_mlxpause(const char*, char*){
|
||||||
|
mlx_pause();
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static errcodes_t cmd_mlxstop(const char*, char*){
|
||||||
|
mlx_stop();
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static errcodes_t cmd_adc(const char* cmd, char* args){
|
||||||
|
if(!args){ // show all values
|
||||||
|
for(uint8_t i = 0; i < NUMBER_OF_ADC_CHANNELS; ++i){
|
||||||
|
CMDEQP(i); printu(getADCval(i)); N();
|
||||||
|
}
|
||||||
|
return ERR_AMOUNT;
|
||||||
|
}
|
||||||
|
int32_t addr;
|
||||||
|
splitargs(args, &addr);
|
||||||
|
if(addr < 0 || addr >= NUMBER_OF_ADC_CHANNELS) return ERR_BADPAR;
|
||||||
|
CMDEQP(addr); printu(getADCval(static_cast<uint8_t>(addr))); N();
|
||||||
|
return ERR_AMOUNT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static errcodes_t cmd_ntc(const char* cmd, char* args){
|
||||||
|
if(!args){ // show all values
|
||||||
|
for(uint8_t i = 0; i <= ADC_AIN4; ++i){
|
||||||
|
CMDEQP(i); printfl(getNTCtemp(i), 1); N();
|
||||||
|
}
|
||||||
|
return ERR_AMOUNT;
|
||||||
|
}
|
||||||
|
int32_t addr;
|
||||||
|
splitargs(args, &addr);
|
||||||
|
if(addr < 0 || addr > ADC_AIN4) return ERR_BADPAR;
|
||||||
|
CMDEQP(addr); printfl(getNTCtemp(static_cast<uint8_t>(addr)), 1); N();
|
||||||
|
return ERR_AMOUNT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static errcodes_t cmd_cartoon(const char*, char*){
|
||||||
|
// TODO: should be getter/setter!
|
||||||
|
cartoon = !cartoon;
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static errcodes_t cmd_mlxdump(const char*, char* args){
|
||||||
|
int32_t sensno = -1;
|
||||||
|
splitargs(args, &sensno);
|
||||||
|
if (sensno < 0 || sensno >= N_SENSORS) return ERR_BADPAR;
|
||||||
|
MLX90640_params *params = mlx_getparams(sensno);
|
||||||
|
if(!params) return ERR_CANTRUN;
|
||||||
|
|
||||||
|
SEND("SENSNO="); printi(sensno); N();
|
||||||
|
SEND("kVdd="); printi(params->kVdd); N();
|
||||||
|
SEND("vdd25="); printi(params->vdd25); N();
|
||||||
|
SEND("KvPTAT="); printfl(params->KvPTAT, 4); N();
|
||||||
|
SEND("KtPTAT="); printfl(params->KtPTAT, 4); N();
|
||||||
|
SEND("vPTAT25="); printi(params->vPTAT25); N();
|
||||||
|
SEND("alphaPTAT="); printfl(params->alphaPTAT, 2); N();
|
||||||
|
SEND("gainEE="); printi(params->gainEE); N();
|
||||||
|
SEND("Pixel offset parameters:\n");
|
||||||
|
dumpIma(params->offset);
|
||||||
|
SEND("K_talpha:\n");
|
||||||
|
dumpIma(params->kta);
|
||||||
|
SEND("Kv: ");
|
||||||
|
for(int i = 0; i < 4; ++i) { printfl(params->kv[i], 2); putb(' '); }
|
||||||
|
N();
|
||||||
|
SEND("cpOffset="); printi(params->cpOffset[0]); SEND(", "); printi(params->cpOffset[1]); N();
|
||||||
|
SEND("cpKta="); printfl(params->cpKta, 2); N();
|
||||||
|
SEND("cpKv="); printfl(params->cpKv, 2); N();
|
||||||
|
SEND("tgc="); printfl(params->tgc, 2); N();
|
||||||
|
SEND("cpALpha="); printfl(params->cpAlpha[0], 2); SEND(", "); printfl(params->cpAlpha[1], 2); N();
|
||||||
|
SEND("KsTa="); printfl(params->KsTa, 2); N();
|
||||||
|
SEND("Alpha:\n");
|
||||||
|
dumpIma(params->alpha);
|
||||||
|
SEND("CT3="); printfl(params->CT[1], 2); N();
|
||||||
|
SEND("CT4="); printfl(params->CT[2], 2); N();
|
||||||
|
for(int i = 0; i < 4; ++i){
|
||||||
|
SEND("KsTo"); putb('0'+i); putb('='); printfl(params->KsTo[i], 2); N();
|
||||||
|
SEND("alphacorr"); putb('0'+i); putb('='); printfl(params->alphacorr[i], 2); N();
|
||||||
|
}
|
||||||
|
return ERR_AMOUNT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static errcodes_t cmd_mlxaddr(const char* cmd, char* args){
|
||||||
|
int32_t sensno = -1;
|
||||||
|
if(!args || !*args) { // without args: show global address
|
||||||
|
//CMDEQ(); printuhex(I2Caddress>>1); N();
|
||||||
|
//return ERR_AMOUNT;
|
||||||
|
return ERR_BADPAR;
|
||||||
|
}
|
||||||
|
const char *setter = splitargs(args, &sensno);
|
||||||
|
if(sensno < 0 || sensno >= N_SENSORS) return ERR_BADPAR;
|
||||||
|
|
||||||
|
if(setter){ // setter: set current address
|
||||||
|
uint32_t a;
|
||||||
|
const char *nxt = getnum(setter, &a);
|
||||||
|
if(nxt == setter || a > 0x7f) return ERR_BADVAL;
|
||||||
|
mlx_setaddr(sensno, (uint8_t)a);
|
||||||
|
return ERR_AMOUNT;
|
||||||
|
}else{ // getter
|
||||||
|
uint8_t a = mlx_getaddr(sensno);
|
||||||
|
CMDEQP(sensno); printuhex(a); N();
|
||||||
|
return ERR_AMOUNT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static errcodes_t cmd_readreg(const char* cmd, char* args){
|
||||||
|
int32_t reg = -1, nwords = 1;
|
||||||
|
const char *setter = splitargs(args, ®);
|
||||||
|
if(reg < 0) return ERR_BADPAR;
|
||||||
|
if(setter){ // read more than one byte
|
||||||
|
uint32_t n;
|
||||||
|
const char *nxt = getnum(setter, &n);
|
||||||
|
if (nxt == setter || n == 0 || n > I2C_BUFSIZE) return ERR_BADVAL;
|
||||||
|
nwords = (int32_t)n;
|
||||||
|
}
|
||||||
|
uint16_t *data = i2c_read_reg16(I2Caddress, (uint16_t)reg, nwords, 0);
|
||||||
|
if(!data) return ERR_CANTRUN;
|
||||||
|
if(nwords == 1){
|
||||||
|
CMDEQP(reg); printuhex(*data); N();
|
||||||
|
}else{
|
||||||
|
CMDEQP(reg); N(); hexdump16(SEND, data, nwords);
|
||||||
|
}
|
||||||
|
return ERR_AMOUNT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static errcodes_t cmd_writedata(const char*, char* args){
|
||||||
|
const char *setter = splitargs(args, NULL);
|
||||||
|
if(!setter) return ERR_BADVAL;
|
||||||
|
int N = 0;
|
||||||
|
const char *p = setter;
|
||||||
|
while (*p){
|
||||||
|
if(N >= LOCBUFFSZ) return ERR_AMOUNT;
|
||||||
|
uint32_t val;
|
||||||
|
p = getnum(p, &val);
|
||||||
|
if(p == setter) break; // not a number
|
||||||
|
locBuffer[N++] = (uint16_t)val;
|
||||||
|
p = omit_spaces(p);
|
||||||
|
if (!*p) break;
|
||||||
|
}
|
||||||
|
if(N == 0) return ERR_BADVAL;
|
||||||
|
if(!i2c_write(I2Caddress, locBuffer, N)) return ERR_CANTRUN;
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static errcodes_t cmd_iicscan(const char*, char*) {
|
||||||
|
i2c_init_scan_mode();
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static errcodes_t cmd_mcutemp(const char* cmd, char*){
|
||||||
|
CMDEQ(); printfl(getMCUtemp(), 2); N();
|
||||||
|
return ERR_AMOUNT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static errcodes_t cmd_mcuvdd(const char* cmd, char*){
|
||||||
|
CMDEQ(); printfl(getVdd(), 2); N();
|
||||||
|
return ERR_AMOUNT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static errcodes_t cmd_dac(const char* cmd, char* args){
|
||||||
|
int32_t val;
|
||||||
|
if(argsvals(args, NULL, &val)){
|
||||||
|
if(val < 0 || val > 4095) return ERR_BADVAL;
|
||||||
|
DAC1->DHR12R1 = static_cast<uint32_t>(val);
|
||||||
|
}
|
||||||
|
// getter
|
||||||
|
CMDEQ(); printu(DAC1->DHR12R1); N();
|
||||||
|
return ERR_AMOUNT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void showpwm(const char* cmd, uint8_t nch){
|
||||||
|
uint16_t ccr;
|
||||||
|
switch(nch){
|
||||||
|
case 0: ccr = TIM3->CCR1; break;
|
||||||
|
case 1: ccr = TIM3->CCR2; break;
|
||||||
|
case 2: ccr = TIM3->CCR3; break;
|
||||||
|
case 3: ccr = TIM3->CCR4; break;
|
||||||
|
default: return;
|
||||||
|
}
|
||||||
|
CMDEQP(nch); printu(ccr); N();
|
||||||
|
}
|
||||||
|
|
||||||
|
// four PWM channels: 1,2 - heaters, 3,4 - info
|
||||||
|
static errcodes_t cmd_pwm(const char* cmd, char* args){
|
||||||
|
int32_t ch = -1, val;
|
||||||
|
const char *setter = splitargs(args, &ch);
|
||||||
|
if(ch < 0 || ch > PWM_CH_MAX){ // all channels
|
||||||
|
for(uint8_t i = 0; i <= PWM_CH_MAX; ++i)
|
||||||
|
showpwm(cmd, i);
|
||||||
|
return ERR_AMOUNT;
|
||||||
|
}
|
||||||
|
if(setter){
|
||||||
|
if(!getint(setter, &val) || val < 0 || val > 100) return ERR_BADVAL;
|
||||||
|
if(!setPWM(static_cast<uint8_t>(ch), static_cast<uint32_t>(val)))
|
||||||
|
return ERR_CANTRUN;
|
||||||
|
}
|
||||||
|
// getter
|
||||||
|
showpwm(cmd, (uint8_t)ch);
|
||||||
|
return ERR_AMOUNT;
|
||||||
|
}
|
||||||
|
|
||||||
|
static errcodes_t cmd_sendstr(const char*, char* args) {
|
||||||
|
int32_t dummy;
|
||||||
|
const char *text = splitargs(args, &dummy);
|
||||||
|
if(!text || !*text) return ERR_BADVAL;
|
||||||
|
// switch to other interface
|
||||||
|
int (*other_sender)(const char*) = (SEND == usb_sender) ? usart_sender : usb_sender;
|
||||||
|
if (!other_sender) return ERR_CANTRUN;
|
||||||
|
other_sender(text);
|
||||||
|
other_sender("\n");
|
||||||
|
return ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr uint32_t hash(const char* str, uint32_t h = 0) {
|
||||||
|
return *str ? hash(str + 1, h + ((h << 7) ^ *str)) : h;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char *parse_cmd(int (*sendfun)(const char*), char *buf) {
|
||||||
|
if(!buf || !*buf || !sendfun) return NULL;
|
||||||
|
SEND = sendfun;
|
||||||
|
if(sendfun == usb_sender){
|
||||||
|
putb = usb_putb;
|
||||||
|
sendbin = usb_sendbin;
|
||||||
|
}else{
|
||||||
|
putb = usart_putb;
|
||||||
|
sendbin = usart_sendbin;
|
||||||
|
}
|
||||||
|
char command[CMD_MAXLEN+1];
|
||||||
|
int i = 0;
|
||||||
|
while(*buf > '@' && i < CMD_MAXLEN) command[i++] = *buf++;
|
||||||
|
command[i] = 0;
|
||||||
|
while(*buf && *buf <= ' ') ++buf;
|
||||||
|
char *args = buf;
|
||||||
|
#ifdef EBUG
|
||||||
|
USB_sendstr("__args='"); USB_sendstr(args); USB_sendstr("'\n");
|
||||||
|
#endif
|
||||||
|
if(!*args) args = NULL;
|
||||||
|
|
||||||
|
uint32_t h = hash(command);
|
||||||
|
errcodes_t ecode = ERR_AMOUNT;
|
||||||
|
switch (h){
|
||||||
|
#define COMMAND(name, desc) case hash(#name): ecode = cmd_##name(command, args); break;
|
||||||
|
COMMAND_TABLE
|
||||||
|
#undef COMMAND
|
||||||
|
default:
|
||||||
|
SEND("Unknown command, try 'help'\n");
|
||||||
|
}
|
||||||
|
if(ecode < ERR_AMOUNT) return errtxt[ecode];
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
putb(' ');
|
||||||
|
}
|
||||||
|
N();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define GRAY_LEVELS 16
|
||||||
|
static const char *const CHARS_16 = " .':;+*oxX#&%B$@";
|
||||||
|
void drawIma(const fp_t im[MLX_PIXNO]){
|
||||||
|
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;
|
||||||
|
SEND("RANGE="); printfl(range, 3); N();
|
||||||
|
SEND("MIN="); printfl(min_val, 3); N();
|
||||||
|
SEND("MAX="); printfl(max_val, 3); N();
|
||||||
|
if(fabsf(range) < 0.001) range = 1.0f;
|
||||||
|
iptr = im;
|
||||||
|
char string[MLX_W+2];
|
||||||
|
string[MLX_W] = '\n'; string[MLX_W+1] = 0; // end of line
|
||||||
|
for(int row = 0; row < MLX_H; ++row){
|
||||||
|
for(int col = 0; col < MLX_W; ++col){
|
||||||
|
fp_t normalized = ((*iptr++) - min_val) / range;
|
||||||
|
int idx = (int)(normalized * GRAY_LEVELS);
|
||||||
|
if(idx < 0) idx = 0;
|
||||||
|
else if(idx >= GRAY_LEVELS) idx = GRAY_LEVELS-1;
|
||||||
|
string[col] = CHARS_16[idx];
|
||||||
|
}
|
||||||
|
SEND(string);
|
||||||
|
}
|
||||||
|
N();
|
||||||
|
}
|
||||||
61
F3:F303/MLX90640-allsky/commproto.h
Normal file
61
F3:F303/MLX90640-allsky/commproto.h
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the as3935 project.
|
||||||
|
* Copyright 2026 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 "mlx90640.h"
|
||||||
|
|
||||||
|
#include "version.inc"
|
||||||
|
|
||||||
|
#ifdef EBUG
|
||||||
|
#define RLSDBG "debug"
|
||||||
|
#else
|
||||||
|
#define RLSDBG "release"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define REPOURL "https://github.com/eddyem/stm32samples/tree/master/F3:F303/MLX90640-allsky " RLSDBG " build #" BUILD_NUMBER "@" BUILD_DATE "\n"
|
||||||
|
|
||||||
|
|
||||||
|
// error codes for answer message
|
||||||
|
typedef enum{
|
||||||
|
ERR_OK, // all OK
|
||||||
|
ERR_BADCMD, // wrong command
|
||||||
|
ERR_BADPAR, // wrong parameter
|
||||||
|
ERR_BADVAL, // wrong value (for setter)
|
||||||
|
ERR_WRONGLEN, // wrong message length
|
||||||
|
ERR_CANTRUN, // can't run given command due to bad parameters or other
|
||||||
|
ERR_BUSY, // target interface busy, try later
|
||||||
|
ERR_OVERFLOW, // string was too long -> overflow
|
||||||
|
ERR_AMOUNT // amount of error codes or "send nothing"
|
||||||
|
} errcodes_t;
|
||||||
|
|
||||||
|
// maximal length of command (without trailing zero)
|
||||||
|
#define CMD_MAXLEN 15
|
||||||
|
// maximal available parameter number (for 16-bit registers is 0xffff
|
||||||
|
#define MAXPARNO 0xffff
|
||||||
|
|
||||||
|
extern const char *EQ;
|
||||||
|
const char *parse_cmd(int (*sendfun)(const char*), char *buf);
|
||||||
|
void set_senders(int (*usbs)(const char*), int (*usbb)(uint8_t), int (*usbbin)(const uint8_t*, int),
|
||||||
|
int (*usarts)(const char*), int (*usartb)(uint8_t), int (*usartbin)(const uint8_t*, int));
|
||||||
|
|
||||||
|
extern const char *const Timage;
|
||||||
|
|
||||||
|
extern uint8_t cartoon;
|
||||||
|
void dumpIma(const fp_t im[MLX_PIXNO]);
|
||||||
|
void drawIma(const fp_t im[MLX_PIXNO]);
|
||||||
@@ -51,16 +51,19 @@ TRUE_INLINE void iwdg_setup(){
|
|||||||
TRUE_INLINE void gpio_setup(){
|
TRUE_INLINE void gpio_setup(){
|
||||||
RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN; // for USART and LEDs
|
RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN; // for USART and LEDs
|
||||||
for(int i = 0; i < 10000; ++i) nop();
|
for(int i = 0; i < 10000; ++i) nop();
|
||||||
// USB - alternate function 14 @ pins PA11/PA12; SWD - AF0 @PA13/14; USB pullup - PA15
|
// USB - alternate function 14 @ pins PA11/PA12; SWD - AF0 @PA13/14
|
||||||
// PA6 - PWM for external heater (TIM3_CH1 or TIM16_CH1); PA7 - PWM propto (humidity - 50%)
|
// PA6,PA7 - PWM for external heaters (TIM3_CH1, TIM3_CH2)
|
||||||
|
// PA0..PA4 - NTC in, PA5 - DAC_OUT1 (board heater), PA6 - ADC in for DAC out
|
||||||
|
// USART pins will be setup in usart.c
|
||||||
GPIOA->AFR[0] = AFRf(2, 6) | AFRf(2, 7);
|
GPIOA->AFR[0] = AFRf(2, 6) | AFRf(2, 7);
|
||||||
GPIOA->AFR[1] = AFRf(14, 11) | AFRf(14, 12);
|
GPIOA->AFR[1] = AFRf(14, 11) | AFRf(14, 12);
|
||||||
GPIOA->MODER = MODER_AI(0) | MODER_AI(1) | MODER_AI(4) | MODER_AI(5) | MODER_AF(6) |
|
// force USB DP to low level for a while
|
||||||
MODER_AF(7) | MODER_AF(11) | MODER_AF(12) | MODER_AF(13) | MODER_AF(14) | MODER_O(15);
|
GPIOA->MODER = MODER_AI(0) | MODER_AI(1) | MODER_AI(2) | MODER_AI(3) | MODER_AI(4) | MODER_AI(5) | MODER_AF(6) |
|
||||||
// PB0 - PWM propto Text (<=20 - 0%, >=30 - 100%), PB1 - PWM propto (Text-Tsky) (<=-5 - 0%, >=+35 - 100%) PB2 - SPI_CS
|
MODER_AF(7) | MODER_AF(11) | MODER_O(12) | MODER_AF(13) | MODER_AF(14) | MODER_O(15);
|
||||||
|
// PB0 - PWM propto Text (<=20 - 0%, >=30 - 100%), PB1 - PWM propto (Text-Tsky) (<=-5 - 0%, >=+35 - 100%) PB9 - SPI_CS
|
||||||
|
// SPI and I2C will be setup in spi.c and i2c.c
|
||||||
GPIOB->AFR[0] = AFRf(2, 0) | AFRf(2, 1);
|
GPIOB->AFR[0] = AFRf(2, 0) | AFRf(2, 1);
|
||||||
GPIOB->MODER = MODER_AF(0) | MODER_AF(1) | MODER_O(2);
|
GPIOB->MODER = MODER_AF(0) | MODER_AF(1) | MODER_O(9);
|
||||||
pin_set(GPIOB, 1<<1);
|
|
||||||
SPI_CS_1();
|
SPI_CS_1();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,7 +88,7 @@ TRUE_INLINE void pwm_setup(){
|
|||||||
|
|
||||||
// change PWM value in percents; return 0 if `val` is bad or `ch` not 0..3
|
// change PWM value in percents; return 0 if `val` is bad or `ch` not 0..3
|
||||||
int setPWM(uint8_t ch, uint8_t val){
|
int setPWM(uint8_t ch, uint8_t val){
|
||||||
if(ch > 3 || val > PWM_CCR_MAX) return 0;
|
if(ch >= PWM_CH_MAX || val > PWM_CCR_MAX) return 0;
|
||||||
volatile uint32_t *CCRs = &(TIM3->CCR1);
|
volatile uint32_t *CCRs = &(TIM3->CCR1);
|
||||||
CCRs[ch] = val;
|
CCRs[ch] = val;
|
||||||
return 1;
|
return 1;
|
||||||
@@ -139,7 +142,6 @@ void bme_process(){
|
|||||||
// set PWM duty propto humidity
|
// set PWM duty propto humidity
|
||||||
float h = (Humidity - 50.f) * 2.f;
|
float h = (Humidity - 50.f) * 2.f;
|
||||||
if(h < 0.f) h = 0.f; else if(h > 100.f) h = 100.f;
|
if(h < 0.f) h = 0.f; else if(h > 100.f) h = 100.f;
|
||||||
setPWM(PWM_CH_HUMIDITY, (uint8_t)h);
|
|
||||||
environment.Tmeas = Tms;
|
environment.Tmeas = Tms;
|
||||||
// set PWM duty propto external T
|
// set PWM duty propto external T
|
||||||
float t = (Temperature + 20.f) * 2.f;
|
float t = (Temperature + 20.f) * 2.f;
|
||||||
|
|||||||
@@ -25,9 +25,9 @@
|
|||||||
#define USBPU_ON() pin_clear(USBPU_port, USBPU_pin)
|
#define USBPU_ON() pin_clear(USBPU_port, USBPU_pin)
|
||||||
#define USBPU_OFF() pin_set(USBPU_port, USBPU_pin)
|
#define USBPU_OFF() pin_set(USBPU_port, USBPU_pin)
|
||||||
|
|
||||||
// SPI_CS - PB2
|
// SPI_CS - PB9
|
||||||
#define SPI_CS_1() pin_set(GPIOB, 1<<2)
|
#define SPI_CS_1() pin_set(GPIOB, 1<<9)
|
||||||
#define SPI_CS_0() pin_clear(GPIOB, 1<<2)
|
#define SPI_CS_0() pin_clear(GPIOB, 1<<9)
|
||||||
|
|
||||||
// interval of environment measurements, ms
|
// interval of environment measurements, ms
|
||||||
#define ENV_MEAS_PERIOD (10000)
|
#define ENV_MEAS_PERIOD (10000)
|
||||||
@@ -36,14 +36,11 @@
|
|||||||
// Max PWM CCR1 value (->1)
|
// Max PWM CCR1 value (->1)
|
||||||
#define PWM_CCR_MAX (100)
|
#define PWM_CCR_MAX (100)
|
||||||
// PWM channels (start from 0 - CH1)
|
// PWM channels (start from 0 - CH1)
|
||||||
// external heater
|
|
||||||
#define PWM_CH_HEATER (0)
|
|
||||||
// propto humidity (the higher - the brighter)
|
|
||||||
#define PWM_CH_HUMIDITY (1)
|
|
||||||
// propto external T (the higher - the brighter)
|
// propto external T (the higher - the brighter)
|
||||||
#define PWM_CH_TEXT (2)
|
#define PWM_CH_TEXT (2)
|
||||||
// propto Tsky - Text (the higher - the brighter)
|
// propto Tsky - Text (the higher - the brighter)
|
||||||
#define PWM_CH_TSKY (3)
|
#define PWM_CH_TSKY (3)
|
||||||
|
#define PWM_CH_MAX (3)
|
||||||
|
|
||||||
typedef struct{
|
typedef struct{
|
||||||
float T; // temperature, degC
|
float T; // temperature, degC
|
||||||
|
|||||||
@@ -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 17.0.1, 2025-10-06T23:24:05. -->
|
<!-- Written by QtCreator 19.0.1, 2026-05-06T23:28:28. -->
|
||||||
<qtcreator>
|
<qtcreator>
|
||||||
<data>
|
<data>
|
||||||
<variable>EnvironmentId</variable>
|
<variable>EnvironmentId</variable>
|
||||||
@@ -86,6 +86,7 @@
|
|||||||
<valuelist type="QVariantList" key="ClangTools.SuppressedDiagnostics"/>
|
<valuelist type="QVariantList" key="ClangTools.SuppressedDiagnostics"/>
|
||||||
<value type="bool" key="ClangTools.UseGlobalSettings">true</value>
|
<value type="bool" key="ClangTools.UseGlobalSettings">true</value>
|
||||||
</valuemap>
|
</valuemap>
|
||||||
|
<value type="int" key="RcSync">0</value>
|
||||||
</valuemap>
|
</valuemap>
|
||||||
</data>
|
</data>
|
||||||
<data>
|
<data>
|
||||||
@@ -153,6 +154,7 @@
|
|||||||
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
|
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
|
||||||
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
|
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
|
||||||
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
|
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
|
||||||
|
<valuelist type="QVariantList" key="Analyzer.Valgrind.SuppressionFiles"/>
|
||||||
<valuelist type="QVariantList" key="CustomOutputParsers"/>
|
<valuelist type="QVariantList" key="CustomOutputParsers"/>
|
||||||
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
||||||
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
||||||
@@ -162,6 +164,7 @@
|
|||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.CustomExecutableRunConfiguration</value>
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.CustomExecutableRunConfiguration</value>
|
||||||
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey"></value>
|
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey"></value>
|
||||||
<value type="bool" key="ProjectExplorer.RunConfiguration.Customized">false</value>
|
<value type="bool" key="ProjectExplorer.RunConfiguration.Customized">false</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.RunConfiguration.UniqueId"></value>
|
||||||
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
|
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
|
||||||
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
||||||
</valuemap>
|
</valuemap>
|
||||||
@@ -185,6 +188,7 @@
|
|||||||
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
|
<value type="bool" key="Analyzer.Perf.Settings.UseGlobalSettings">true</value>
|
||||||
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
|
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
|
||||||
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
|
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
|
||||||
|
<valuelist type="QVariantList" key="Analyzer.Valgrind.SuppressionFiles"/>
|
||||||
<valuelist type="QVariantList" key="CustomOutputParsers"/>
|
<valuelist type="QVariantList" key="CustomOutputParsers"/>
|
||||||
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
||||||
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
||||||
@@ -194,6 +198,7 @@
|
|||||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.CustomExecutableRunConfiguration</value>
|
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.CustomExecutableRunConfiguration</value>
|
||||||
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey"></value>
|
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey"></value>
|
||||||
<value type="bool" key="ProjectExplorer.RunConfiguration.Customized">false</value>
|
<value type="bool" key="ProjectExplorer.RunConfiguration.Customized">false</value>
|
||||||
|
<value type="QString" key="ProjectExplorer.RunConfiguration.UniqueId"></value>
|
||||||
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
|
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
|
||||||
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
||||||
</valuemap>
|
</valuemap>
|
||||||
@@ -204,10 +209,6 @@
|
|||||||
<variable>ProjectExplorer.Project.TargetCount</variable>
|
<variable>ProjectExplorer.Project.TargetCount</variable>
|
||||||
<value type="qlonglong">1</value>
|
<value type="qlonglong">1</value>
|
||||||
</data>
|
</data>
|
||||||
<data>
|
|
||||||
<variable>ProjectExplorer.Project.Updater.FileVersion</variable>
|
|
||||||
<value type="int">22</value>
|
|
||||||
</data>
|
|
||||||
<data>
|
<data>
|
||||||
<variable>Version</variable>
|
<variable>Version</variable>
|
||||||
<value type="int">22</value>
|
<value type="int">22</value>
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ BMP280.c
|
|||||||
BMP280.h
|
BMP280.h
|
||||||
adc.c
|
adc.c
|
||||||
adc.h
|
adc.h
|
||||||
|
commproto.cpp
|
||||||
|
commproto.h
|
||||||
hardware.c
|
hardware.c
|
||||||
hardware.h
|
hardware.h
|
||||||
i2c.c
|
i2c.c
|
||||||
@@ -15,8 +17,6 @@ mlx90640.h
|
|||||||
mlx90640_regs.h
|
mlx90640_regs.h
|
||||||
mlxproc.c
|
mlxproc.c
|
||||||
mlxproc.h
|
mlxproc.h
|
||||||
proto.c
|
|
||||||
proto.h
|
|
||||||
ringbuffer.c
|
ringbuffer.c
|
||||||
ringbuffer.h
|
ringbuffer.h
|
||||||
spi.c
|
spi.c
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 344 B After Width: | Height: | Size: 354 B |
@@ -20,7 +20,7 @@
|
|||||||
#include "hardware.h"
|
#include "hardware.h"
|
||||||
#include "i2c.h"
|
#include "i2c.h"
|
||||||
#include "mlxproc.h"
|
#include "mlxproc.h"
|
||||||
#include "proto.h"
|
#include "commproto.h"
|
||||||
#include "strfunc.h"
|
#include "strfunc.h"
|
||||||
#include "usart.h"
|
#include "usart.h"
|
||||||
#include "usb_dev.h"
|
#include "usb_dev.h"
|
||||||
@@ -43,14 +43,18 @@ int main(void){
|
|||||||
StartHSI();
|
StartHSI();
|
||||||
SysTick_Config((uint32_t)48000); // 1ms
|
SysTick_Config((uint32_t)48000); // 1ms
|
||||||
}
|
}
|
||||||
USBPU_OFF();
|
USBPU_OFF(); // for development board with managed pullup resistor
|
||||||
hw_setup();
|
hw_setup();
|
||||||
adc_setup();
|
adc_setup();
|
||||||
i2c_setup(I2C_SPEED_400K);
|
i2c_setup(I2C_SPEED_400K);
|
||||||
bme_init();
|
bme_init();
|
||||||
USB_setup();
|
|
||||||
usart_setup(115200);
|
usart_setup(115200);
|
||||||
|
// setup USB DP as alternate function - for sensors' board with constant pullup resistor
|
||||||
|
GPIOA->MODER = (GPIOA->MODER & ~GPIO_MODER_MODER12) | MODER_AF(12);
|
||||||
USBPU_ON();
|
USBPU_ON();
|
||||||
|
USB_setup();
|
||||||
|
// set senders for abiliby of sending messages between interfaces
|
||||||
|
set_senders(USB_sendstr, USB_putbyte, USB_send, usart_sendstr, usart_putbyte, usart_send);
|
||||||
uint32_t ctr = Tms, Tlastima[N_SENSORS] = {0};
|
uint32_t ctr = Tms, Tlastima[N_SENSORS] = {0};
|
||||||
mlx_continue(); // init state machine
|
mlx_continue(); // init state machine
|
||||||
while(1){
|
while(1){
|
||||||
@@ -63,7 +67,7 @@ int main(void){
|
|||||||
int l = USB_receivestr(inbuff, MAXSTRLEN);
|
int l = USB_receivestr(inbuff, MAXSTRLEN);
|
||||||
if(l < 0) USB_sendstr("USBOVERFLOW\n");
|
if(l < 0) USB_sendstr("USBOVERFLOW\n");
|
||||||
else if(l){
|
else if(l){
|
||||||
const char *ans = parse_cmd(inbuff, SEND_USB);
|
const char *ans = parse_cmd(USB_sendstr, inbuff);
|
||||||
if(ans) USB_sendstr(ans);
|
if(ans) USB_sendstr(ans);
|
||||||
}
|
}
|
||||||
if(i2c_scanmode){ // send this to both
|
if(i2c_scanmode){ // send this to both
|
||||||
@@ -84,7 +88,6 @@ int main(void){
|
|||||||
if(Tnow != Tlastima[i]){
|
if(Tnow != Tlastima[i]){
|
||||||
fp_t *im = mlx_getimage(i);
|
fp_t *im = mlx_getimage(i);
|
||||||
if(im){
|
if(im){
|
||||||
chsendfun(SEND_USB);
|
|
||||||
//U(Sensno); UN(i2str(i));
|
//U(Sensno); UN(i2str(i));
|
||||||
U(Timage); USB_putbyte('0'+i); USB_putbyte('='); UN(u2str(Tnow));
|
U(Timage); USB_putbyte('0'+i); USB_putbyte('='); UN(u2str(Tnow));
|
||||||
drawIma(im);
|
drawIma(im);
|
||||||
@@ -96,7 +99,7 @@ int main(void){
|
|||||||
if(usart_ovr()) usart_sendstr("USART_OVERFLOW\n");
|
if(usart_ovr()) usart_sendstr("USART_OVERFLOW\n");
|
||||||
char *got = usart_getline(NULL);
|
char *got = usart_getline(NULL);
|
||||||
if(got){
|
if(got){
|
||||||
const char *ans = parse_cmd(got, SEND_USART);
|
const char *ans = parse_cmd(usart_sendstr, got);
|
||||||
if(ans) usart_sendstr(ans);
|
if(ans) usart_sendstr(ans);
|
||||||
}
|
}
|
||||||
bme_process();
|
bme_process();
|
||||||
|
|||||||
@@ -63,12 +63,16 @@ static int sensno = -1;
|
|||||||
mlx_state_t mlx_state(){ return MLX_state; }
|
mlx_state_t mlx_state(){ return MLX_state; }
|
||||||
// set address
|
// set address
|
||||||
int mlx_setaddr(int n, uint8_t addr){
|
int mlx_setaddr(int n, uint8_t addr){
|
||||||
if(n < 0 || n > N_SENSORS) return 0;
|
if(n < 0 || n >= N_SENSORS) return 0;
|
||||||
if(addr > 0x7f) return 0;
|
if(addr > 0x7f) return 0;
|
||||||
sens_addresses[n] = addr << 1;
|
sens_addresses[n] = addr << 1;
|
||||||
Tlastimage[n] = Tms; // refresh counter for autoreset I2C in case of error
|
Tlastimage[n] = Tms; // refresh counter for autoreset I2C in case of error
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
uint8_t mlx_getaddr(int n){
|
||||||
|
if(n < 0 || n >= N_SENSORS) return 0;
|
||||||
|
return sens_addresses[n];
|
||||||
|
}
|
||||||
// pause state machine and stop
|
// pause state machine and stop
|
||||||
void mlx_pause(){
|
void mlx_pause(){
|
||||||
MLX_oldstate = MLX_state;
|
MLX_oldstate = MLX_state;
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ typedef enum{
|
|||||||
} mlx_state_t;
|
} mlx_state_t;
|
||||||
|
|
||||||
int mlx_setaddr(int n, uint8_t addr);
|
int mlx_setaddr(int n, uint8_t addr);
|
||||||
|
uint8_t mlx_getaddr(int n);
|
||||||
mlx_state_t mlx_state();
|
mlx_state_t mlx_state();
|
||||||
int mlx_nactive();
|
int mlx_nactive();
|
||||||
uint8_t *mlx_activeids();
|
uint8_t *mlx_activeids();
|
||||||
|
|||||||
@@ -1,539 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of the ir-allsky project.
|
|
||||||
* Copyright 2025 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 <math.h>
|
|
||||||
#include <stm32f3.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "adc.h"
|
|
||||||
#include "hardware.h"
|
|
||||||
#include "i2c.h"
|
|
||||||
#include "mlxproc.h"
|
|
||||||
#include "proto.h"
|
|
||||||
#include "strfunc.h"
|
|
||||||
#include "usart.h"
|
|
||||||
#include "usb_dev.h"
|
|
||||||
#include "version.inc"
|
|
||||||
|
|
||||||
#define LOCBUFFSZ (32)
|
|
||||||
// local buffer for I2C data to send
|
|
||||||
static uint16_t locBuffer[LOCBUFFSZ];
|
|
||||||
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* const Timage = "TIMAGE";
|
|
||||||
const char* const Image = "IMAGE";
|
|
||||||
static const char *const Sensno = "SENSNO=";
|
|
||||||
|
|
||||||
static const char *const OK = "OK\n", *const ERR = "ERR\n";
|
|
||||||
const char *const helpstring =
|
|
||||||
"https://github.com/eddyem/stm32samples/tree/master/F3:F303/MLX90640multi build#" BUILD_NUMBER " @ " BUILD_DATE "\n"
|
|
||||||
" management of single IR bolometer MLX90640\n"
|
|
||||||
"dn - draw nth image in ASCII\n"
|
|
||||||
"gn - get nth image 'as is' - float array of 768x4 bytes\n"
|
|
||||||
"l - list active sensors IDs\n"
|
|
||||||
"mn - show temperature map of nth image\n"
|
|
||||||
"tn - show nth image aquisition time\n"
|
|
||||||
"B - reinit BME280\n"
|
|
||||||
"E - get environment parameters (temperature etc)\n"
|
|
||||||
"G - get MLX state\n"
|
|
||||||
"R - reset device\n"
|
|
||||||
"T - print current Tms\n"
|
|
||||||
" Debugging options:\n"
|
|
||||||
"aa - change I2C address to a (a should be non-shifted value!!!)\n"
|
|
||||||
"c - continue MLX\n"
|
|
||||||
"i0..4 - setup I2C with speed 10k, 100k, 400k, 1M or 2M (experimental!)\n"
|
|
||||||
"p - pause MLX\n"
|
|
||||||
"s - stop MLX (and start from zero @ 'c')\n"
|
|
||||||
"A - get ADC values\n"
|
|
||||||
"C - \"cartoon\" mode on/off (show each new image) - USB only!!!\n"
|
|
||||||
"Dn - dump MLX parameters for sensor number n\n"
|
|
||||||
"Ia addr [n] - set device address for interactive work or (with n) change address of n'th sensor\n"
|
|
||||||
"Ir reg n - read n words from 16-bit register\n"
|
|
||||||
"Iw words - send words (hex/dec/oct/bin) to I2C\n"
|
|
||||||
"Is - scan I2C bus\n"
|
|
||||||
"M - get MCU temperature and Vdd value\n"
|
|
||||||
"O - set output of DAC (0..4095)\n"
|
|
||||||
"Px - set PWM output (0..100%) or get current value\n"
|
|
||||||
"Us - send string 's' to other interface\n"
|
|
||||||
;
|
|
||||||
|
|
||||||
TRUE_INLINE const char *setupI2C(char *buf){
|
|
||||||
static const char * const speeds[I2C_SPEED_AMOUNT] = {
|
|
||||||
[I2C_SPEED_10K] = "10K",
|
|
||||||
[I2C_SPEED_100K] = "100K",
|
|
||||||
[I2C_SPEED_400K] = "400K",
|
|
||||||
[I2C_SPEED_1M] = "1M",
|
|
||||||
[I2C_SPEED_2M] = "2M"
|
|
||||||
};
|
|
||||||
if(buf && *buf){
|
|
||||||
buf = omit_spaces(buf);
|
|
||||||
int speed = *buf - '0';
|
|
||||||
if(speed < 0 || speed >= I2C_SPEED_AMOUNT){
|
|
||||||
return ERR;
|
|
||||||
}
|
|
||||||
i2c_setup((i2c_speed_t)speed);
|
|
||||||
}
|
|
||||||
sendfun->S("I2CSPEED="); sendfun->S(speeds[i2c_curspeed]); N();
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
TRUE_INLINE const char *chhwaddr(const char *buf){
|
|
||||||
uint32_t a;
|
|
||||||
if(buf && *buf){
|
|
||||||
const char *nxt = getnum(buf, &a);
|
|
||||||
if(nxt && nxt != buf){
|
|
||||||
if(!mlx_sethwaddr(I2Caddress, a)) return ERR;
|
|
||||||
}else{
|
|
||||||
sendfun->S("Wrong number"); N();
|
|
||||||
return ERR;
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
sendfun->S("Need address"); N();
|
|
||||||
return ERR;
|
|
||||||
}
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
// read sensor's number from `buf`; return -1 if error
|
|
||||||
static int getsensnum(const char *buf){
|
|
||||||
if(!buf || !*buf) return -1;
|
|
||||||
uint32_t num;
|
|
||||||
const char *nxt = getnum(buf, &num);
|
|
||||||
if(!nxt || nxt == buf || num >= N_SENSORS) return -1;
|
|
||||||
return (int) num;
|
|
||||||
}
|
|
||||||
|
|
||||||
TRUE_INLINE const char *chaddr(const char *buf){
|
|
||||||
uint32_t addr;
|
|
||||||
const char *nxt = getnum(buf, &addr);
|
|
||||||
if(nxt && nxt != buf){
|
|
||||||
if(addr > 0x7f) return ERR;
|
|
||||||
I2Caddress = (uint8_t) addr << 1;
|
|
||||||
int n = getsensnum(nxt);
|
|
||||||
if(n > -1) mlx_setaddr(n, addr);
|
|
||||||
}else addr = I2Caddress >> 1;
|
|
||||||
sendfun->S("I2CADDR="); sendfun->S(uhex2str(addr)); N();
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// read I2C register[s] - only blocking read! (DMA allowable just for config/image reading in main process)
|
|
||||||
static const char *rdI2C(const char *buf){
|
|
||||||
uint32_t N = 0;
|
|
||||||
const char *nxt = getnum(buf, &N);
|
|
||||||
if(!nxt || buf == nxt || N > 0xffff) return ERR;
|
|
||||||
buf = nxt;
|
|
||||||
uint16_t reg = N, *b16 = NULL;
|
|
||||||
nxt = getnum(buf, &N);
|
|
||||||
if(!nxt || buf == nxt || N == 0 || N > I2C_BUFSIZE) return ERR;
|
|
||||||
if(!(b16 = i2c_read_reg16(I2Caddress, reg, N, 0))) return ERR;
|
|
||||||
if(N == 1){
|
|
||||||
char b[5];
|
|
||||||
u16s(*b16, b);
|
|
||||||
b[4] = 0;
|
|
||||||
sendfun->S(b); N();
|
|
||||||
}else hexdump16(sendfun->S, b16, N);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// read N numbers from buf, @return 0 if wrong or none
|
|
||||||
TRUE_INLINE uint16_t readNnumbers(const char *buf){
|
|
||||||
uint32_t D;
|
|
||||||
const char *nxt;
|
|
||||||
uint16_t N = 0;
|
|
||||||
while((nxt = getnum(buf, &D)) && nxt != buf && N < LOCBUFFSZ){
|
|
||||||
buf = nxt;
|
|
||||||
locBuffer[N++] = (uint16_t) D;
|
|
||||||
}
|
|
||||||
return N;
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char *wrI2C(const char *buf){
|
|
||||||
uint16_t N = readNnumbers(buf);
|
|
||||||
if(N == 0) return ERR;
|
|
||||||
for(int i = 0; i < N; ++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;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dumpfarr(float *arr){
|
|
||||||
for(int row = 0; row < 24; ++row){
|
|
||||||
for(int col = 0; col < 32; ++col){
|
|
||||||
printfl(*arr++, 2); sendfun->P(' ');
|
|
||||||
}
|
|
||||||
N();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// dump MLX parameters
|
|
||||||
TRUE_INLINE void dumpparams(const char *buf){
|
|
||||||
int N = getsensnum(buf);
|
|
||||||
if(N < 0){ sendfun->S(ERR); return; }
|
|
||||||
MLX90640_params *params = mlx_getparams(N);
|
|
||||||
if(!params){ sendfun->S(ERR); return; }
|
|
||||||
N(); sendfun->S(Sensno); sendfun->S(i2str(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); sendfun->P(' ');
|
|
||||||
}
|
|
||||||
N();
|
|
||||||
}
|
|
||||||
sendfun->S("K_talpha:\n");
|
|
||||||
dumpfarr(params->kta);
|
|
||||||
sendfun->S("Kv: ");
|
|
||||||
for(int i = 0; i < 4; ++i){
|
|
||||||
printfl(params->kv[i], 2); sendfun->P(' ');
|
|
||||||
}
|
|
||||||
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);
|
|
||||||
sendfun->S("\nCT3="); printfl(params->CT[1], 2);
|
|
||||||
sendfun->S("\nCT4="); printfl(params->CT[2], 2);
|
|
||||||
for(int i = 0; i < 4; ++i){
|
|
||||||
sendfun->S("\nKsTo"); sendfun->P('0'+i); sendfun->P('=');
|
|
||||||
printfl(params->KsTo[i], 2);
|
|
||||||
sendfun->S("\nalphacorr"); sendfun->P('0'+i); sendfun->P('=');
|
|
||||||
printfl(params->alphacorr[i], 2);
|
|
||||||
}
|
|
||||||
N();
|
|
||||||
}
|
|
||||||
// get MLX state
|
|
||||||
TRUE_INLINE void getst(){
|
|
||||||
static const char *states[] = {
|
|
||||||
[MLX_NOTINIT] = "not init",
|
|
||||||
[MLX_WAITPARAMS] = "wait parameters DMA read",
|
|
||||||
[MLX_WAITSUBPAGE] = "wait subpage",
|
|
||||||
[MLX_READSUBPAGE] = "wait subpage DMA read",
|
|
||||||
[MLX_RELAX] = "do nothing"
|
|
||||||
};
|
|
||||||
mlx_state_t s = mlx_state();
|
|
||||||
sendfun->S("MLXSTATE=");
|
|
||||||
sendfun->S(states[s]); N();
|
|
||||||
}
|
|
||||||
|
|
||||||
// `draw`==1 - draw, ==0 - show T map, 2 - send raw float array with prefix 'TIMAGEX=y\nIMAGEX=' and postfix "ENDIMAGE\n"
|
|
||||||
static const char *drawimg(const char *buf, int draw){
|
|
||||||
int sensno = getsensnum(buf);
|
|
||||||
if(sensno > -1){
|
|
||||||
uint32_t T = mlx_lastimT(sensno);
|
|
||||||
fp_t *img = mlx_getimage(sensno);
|
|
||||||
if(img){
|
|
||||||
//sendfun->S(Sensno); sendfun->S(u2str(sensno)); N();
|
|
||||||
sendfun->S(Timage); sendfun->P('0'+sensno); sendfun->P('='); sendfun->S(u2str(T)); N();
|
|
||||||
switch(draw){
|
|
||||||
case 0:
|
|
||||||
dumpIma(img);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
drawIma(img);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
sendfun->S(Image); sendfun->P('0'+sensno); sendfun->P('=');
|
|
||||||
uint8_t *d = (uint8_t*)img;
|
|
||||||
uint32_t _2send = MLX_PIXNO * sizeof(float);
|
|
||||||
// send by portions of 256 bytes (as image is larger than ringbuffer)
|
|
||||||
while(_2send){
|
|
||||||
uint32_t portion = (_2send > 256) ? 256 : _2send;
|
|
||||||
sendfun->B(d, portion);
|
|
||||||
_2send -= portion;
|
|
||||||
d += portion;
|
|
||||||
}
|
|
||||||
sendfun->S("ENDIMAGE"); N();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ERR;
|
|
||||||
}
|
|
||||||
|
|
||||||
TRUE_INLINE void listactive(){
|
|
||||||
int N = mlx_nactive();
|
|
||||||
if(!N){ sendfun->S("No active sensors found!\n"); return; }
|
|
||||||
uint8_t *ids = mlx_activeids();
|
|
||||||
sendfun->S("Found "); sendfun->P('0'+N);
|
|
||||||
sendfun->S(" active sensors:"); N();
|
|
||||||
for(int i = 0; i < N_SENSORS; ++i)
|
|
||||||
if(ids[i]){
|
|
||||||
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){
|
|
||||||
sendfun->S(Timage); sendfun->P('0'+sensno); sendfun->P('='); sendfun->S(u2str(mlx_lastimT(sensno))); N();
|
|
||||||
}else sendfun->S(ERR);
|
|
||||||
}
|
|
||||||
|
|
||||||
TRUE_INLINE void getenv(){
|
|
||||||
bme280_t env;
|
|
||||||
if(!get_environment(&env)) sendfun->S("BADENVIRONMENT\n");
|
|
||||||
sendfun->S("TEMPERATURE="); sendfun->S(float2str(env.T, 2));
|
|
||||||
sendfun->S("\nSKYTEMPERATURE="); sendfun->S(float2str(env.Tsky, 2));
|
|
||||||
sendfun->S("\nPRESSURE_HPA="); sendfun->S(float2str(env.P/100.f, 2));
|
|
||||||
sendfun->S("\nPRESSURE_MM="); sendfun->S(float2str(env.P * 0.00750062f, 2));
|
|
||||||
sendfun->S("\nHUMIDITY="); sendfun->S(float2str(env.H, 2));
|
|
||||||
sendfun->S("\nTEMP_DEW="); sendfun->S(float2str(env.Tdew, 1));
|
|
||||||
sendfun->S("\nT_MEASUREMENT="); sendfun->S(u2str(env.Tmeas));
|
|
||||||
N();
|
|
||||||
}
|
|
||||||
|
|
||||||
TRUE_INLINE const char *DAC_chval(const char *buf){
|
|
||||||
uint32_t D;
|
|
||||||
const char *nxt = getnum(buf, &D);
|
|
||||||
if(!nxt || nxt == buf || D > 4095) return ERR;
|
|
||||||
DAC1->DHR12R1 = D;
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
TRUE_INLINE void getADC(){
|
|
||||||
sendfun->S("AIN0="); sendfun->S(u2str(getADCval(ADC_AIN0)));
|
|
||||||
sendfun->S("\nAIN1="); sendfun->S(u2str(getADCval(ADC_AIN1)));
|
|
||||||
sendfun->S("\nAIN5="); sendfun->S(u2str(getADCval(ADC_AIN5)));
|
|
||||||
N();
|
|
||||||
}
|
|
||||||
|
|
||||||
TRUE_INLINE void getMCUvals(){
|
|
||||||
sendfun->S("MCUTEMP="); sendfun->S(float2str(getMCUtemp(), 2));
|
|
||||||
sendfun->S("\nMCUVDD="); sendfun->S(float2str(getVdd(), 2));
|
|
||||||
N();
|
|
||||||
}
|
|
||||||
|
|
||||||
TRUE_INLINE const char* setpwm(const char *buf){
|
|
||||||
uint32_t D;
|
|
||||||
if(!buf || !*buf){
|
|
||||||
sendfun->S("PWM1="); sendfun->S(u2str(TIM3->CCR1));
|
|
||||||
sendfun->S("\nPWM2="); sendfun->S(u2str(TIM3->CCR2));
|
|
||||||
sendfun->S("\nPWM3="); sendfun->S(u2str(TIM3->CCR3));
|
|
||||||
sendfun->S("\nPWM4="); sendfun->S(u2str(TIM3->CCR4));
|
|
||||||
N();
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
const char *nxt = getnum(buf, &D);
|
|
||||||
if(!nxt || nxt == buf || !setPWM(PWM_CH_HEATER, D)) return ERR;
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @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':
|
|
||||||
return chhwaddr(buf);
|
|
||||||
case 'd':
|
|
||||||
return drawimg(buf, 1);
|
|
||||||
case 'g':
|
|
||||||
return drawimg(buf, 2);
|
|
||||||
case 'i':
|
|
||||||
return setupI2C(buf);
|
|
||||||
case 'm':
|
|
||||||
return drawimg(buf, 0);
|
|
||||||
case 't':
|
|
||||||
getimt(buf); return NULL;
|
|
||||||
case 'D':
|
|
||||||
dumpparams(buf);
|
|
||||||
return NULL;
|
|
||||||
break;
|
|
||||||
case 'I':
|
|
||||||
buf = omit_spaces(buf);
|
|
||||||
switch(*buf++){
|
|
||||||
case 'a':
|
|
||||||
return chaddr(buf);
|
|
||||||
case 'r':
|
|
||||||
return rdI2C(buf);
|
|
||||||
case 'w':
|
|
||||||
return wrI2C(buf);
|
|
||||||
case 's':
|
|
||||||
i2c_init_scan_mode();
|
|
||||||
return OK;
|
|
||||||
default:
|
|
||||||
return ERR;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'O':
|
|
||||||
return DAC_chval(buf);
|
|
||||||
case 'P':
|
|
||||||
return setpwm(buf);
|
|
||||||
case 'U':
|
|
||||||
if(sendto == SEND_USB) chsendfun(SEND_USART);
|
|
||||||
else chsendfun(SEND_USB);
|
|
||||||
if(sendfun->S(buf) && N()) return OK;
|
|
||||||
return ERR;
|
|
||||||
default:
|
|
||||||
return ERR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
switch(*buf){ // "short" (one letter) commands
|
|
||||||
case 'A':
|
|
||||||
getADC();
|
|
||||||
break;
|
|
||||||
case 'c':
|
|
||||||
mlx_continue(); return OK;
|
|
||||||
break;
|
|
||||||
case 'i': return setupI2C(NULL); // current settings
|
|
||||||
case 'l':
|
|
||||||
listactive();
|
|
||||||
break;
|
|
||||||
case 'p':
|
|
||||||
mlx_pause(); return OK;
|
|
||||||
break;
|
|
||||||
case 's':
|
|
||||||
mlx_stop(); return OK;
|
|
||||||
case 'B':
|
|
||||||
if(bme_init()) return OK;
|
|
||||||
return ERR;
|
|
||||||
case 'C':
|
|
||||||
if(sendto != SEND_USB) return ERR;
|
|
||||||
cartoon = !cartoon; return OK;
|
|
||||||
case 'E':
|
|
||||||
getenv();
|
|
||||||
break;
|
|
||||||
case 'G':
|
|
||||||
getst();
|
|
||||||
break;
|
|
||||||
case 'M':
|
|
||||||
getMCUvals();
|
|
||||||
break;
|
|
||||||
case 'P':
|
|
||||||
return setpwm(NULL);
|
|
||||||
case 'R':
|
|
||||||
NVIC_SystemReset();
|
|
||||||
break;
|
|
||||||
case 'T':
|
|
||||||
sendfun->S("T="); sendfun->S(u2str(Tms)); N();
|
|
||||||
break;
|
|
||||||
case '?': // help
|
|
||||||
case 'h':
|
|
||||||
case 'H':
|
|
||||||
sendfun->S(helpstring);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return ERR;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
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 *const 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();
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of the ir-allsky project.
|
|
||||||
* Copyright 2025 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
|
|
||||||
|
|
||||||
extern const char *const Timage;
|
|
||||||
|
|
||||||
#define SEND_USB (1)
|
|
||||||
#define SEND_USART (0)
|
|
||||||
|
|
||||||
extern uint8_t cartoon;
|
|
||||||
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]);
|
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
#define BUILD_NUMBER "45"
|
#define BUILD_NUMBER "65"
|
||||||
#define BUILD_DATE "2026-05-01"
|
#define BUILD_DATE "2026-05-06"
|
||||||
|
|||||||
Reference in New Issue
Block a user