test sending sensor results over lora radio. Accelerometer and temp/pressure.
Serial terminal operates at 115200.
This project provides a text-based menu over serial port.
Operating the program only requires using the arrow keys, enter key to activate a control, or entering numbers.
Two sensors provided:
LIS12DH12
accelerometer operates in a continuous sampling mode. Enable control for accelerometer enables this continuous sampling, approx every 3 seconds.
LPS22HH temperature / pressure sensor operates as single shot, where pressing the control button on terminal causes single sample to be performed.
poll rate control will enable repeated reading of pressure/temperature-sensor or photo-sensor when poll rate is greater than zero.
target must be: DISCO_L072CZ_LRWAN1
main.cpp
- Committer:
- Wayne Roberts
- Date:
- 2019-04-29
- Revision:
- 2:972a5704f152
- Parent:
- 0:e1e70da93044
File content as of revision 2:972a5704f152:
#include "mbed.h"
#include "radio.h"
#include "demo.h"
bool svc_lis2dh12;
//#define MENU_DEBUG
RawSerial pc(USBTX, USBRX);
menuState_t menuState;
typedef enum {
MSG_TYPE_PACKET = 0,
MSG_TYPE_PER,
MSG_TYPE_PINGPONG
} msgType_e;
enum {
CMD_TEMP,
CMD_PRES,
CMD_ACCEL,
CMD_PHOTOS,
CMD_NONE
};
#define MAX_MENU_ROWS 16
// [row][column]
const menu_t* menu_table[MAX_MENU_ROWS][MAX_MENU_COLUMNS];
int8_t StopMenuCols[MAX_MENU_ROWS];
//#define SCROLLING_ROWS 20
#define SCROLLING_ROWS 30
struct _cp_ {
uint8_t row;
uint8_t tableCol;
} curpos;
uint8_t entry_buf_idx;
char entry_buf[64];
msgType_e msg_type = MSG_TYPE_PACKET;
const uint8_t PingMsg[] = "PING";
const uint8_t PongMsg[] = "PONG";
const uint8_t PerMsg[] = "PER";
volatile struct _flags_ {
uint8_t ping_master : 1; // 0
uint8_t send_ping : 1; // 1
uint8_t send_pong : 1; // 2
uint8_t pingpongEnable : 1; // 3
uint8_t do_next_tx : 1; // 4
uint8_t txBusy : 1; // 5
uint8_t measure_tx : 1; // 5
} flags;
uint8_t botRow;
int regAddr = -1;
#define PHOTOS_PIN PA_0
/*
* available pins PA_0, PA_1, PA_2, PA_3, PA_4, PA_5, PA_6, PA_7, PB_0, PB_1, PC_0, PC_1, PC_2
*/
#ifdef PHOTOS_PIN
AnalogIn photos(PHOTOS_PIN);
#endif /* PHOTOS_PIN */
#define UART_RX_BUF_LEN 8
uint8_t uart_rx_buf[UART_RX_BUF_LEN];
volatile uint8_t uart_rx_buf_in;
volatile uint8_t uart_rx_buf_out;
bool accel_tx_en;
#ifdef MENU_DEBUG
char wait_uart_rx()
{
char ret;
unsigned foo = uart_rx_buf_in;
while (uart_rx_buf_in == foo) {
asm("nop");
}
ret = uart_rx_buf[uart_rx_buf_out++];
if (uart_rx_buf_out == UART_RX_BUF_LEN)
uart_rx_buf_out = 0;
return ret;
}
#endif /* MENU_DEBUG */
unsigned lfsr;
#define LFSR_INIT 0x1ff
uint8_t get_pn9_byte()
{
uint8_t ret = 0;
int xor_out;
xor_out = ((lfsr >> 5) & 0xf) ^ (lfsr & 0xf); // four bits at a time
lfsr = (lfsr >> 4) | (xor_out << 5); // four bits at a time
ret |= (lfsr >> 5) & 0x0f;
xor_out = ((lfsr >> 5) & 0xf) ^ (lfsr & 0xf); // four bits at a time
lfsr = (lfsr >> 4) | (xor_out << 5); // four bits at a time
ret |= ((lfsr >> 1) & 0xf0);
return ret;
}
void hw_reset_push()
{
Radio::hw_reset();
Radio::readChip();
menuState.mode = MENUMODE_REINIT_MENU;
}
const button_item_t hw_reset_item = { _ITEM_BUTTON, "hw_reset", hw_reset_push };
void clearIrqs_push()
{
Radio::clearIrqFlags();
}
const button_item_t clearirqs_item = { _ITEM_BUTTON, "clearIrqs", clearIrqs_push };
const dropdown_item_t pktType_item = { _ITEM_DROPDOWN, Radio::pktType_strs, Radio::pktType_strs, Radio::pktType_read, Radio::pktType_write};
unsigned msgType_read(bool fw)
{
return msg_type;
}
menuMode_e msgType_write(unsigned widx)
{
msg_type = (msgType_e)widx;
if (msg_type == MSG_TYPE_PER) {
flags.pingpongEnable = 0;
if (Radio::get_payload_length() < 7)
Radio::set_payload_length(7);
} else if (msg_type == MSG_TYPE_PINGPONG) {
if (Radio::get_payload_length() != 12)
Radio::set_payload_length(12);
} else if (msg_type == MSG_TYPE_PACKET) {
flags.pingpongEnable = 0;
}
return MENUMODE_REINIT_MENU;
}
const char* const msgType_strs[] = {
"PACKET ",
"PER ",
"PINGPONG",
NULL
};
const dropdown_item_t msgType_item = { _ITEM_DROPDOWN, msgType_strs, msgType_strs, msgType_read, msgType_write};
#define LAST_CHIP_MENU_ROW (MAX_MENU_ROWS-5)
const value_item_t tx_payload_length_item = { _ITEM_VALUE, 5, Radio::tx_payload_length_print, Radio::tx_payload_length_write};
void pn9_push()
{
uint8_t i, len = Radio::get_payload_length();
for (i = 0; i < len; i++)
Radio::radio.tx_buf[i] = get_pn9_byte();
}
const button_item_t tx_payload_pn9_item = { _ITEM_BUTTON, "PN9", pn9_push };
void regAddr_print()
{
if (regAddr != -1)
pc.printf("%x", regAddr);
}
bool regAddr_write(const char* txt)
{
sscanf(txt, "%x", ®Addr);
return false;
}
const value_item_t regAddr_item = { _ITEM_VALUE, 5, regAddr_print, regAddr_write};
void regValue_print()
{
if (regAddr != -1) {
pc.printf("%x", Radio::read_register(regAddr));
}
}
bool regValue_write(const char* txt)
{
unsigned val;
sscanf(txt, "%x", &val);
if (regAddr != -1) {
Radio::write_register(regAddr, val);
}
return false;
}
const value_item_t regValue_item = { _ITEM_VALUE, 5, regValue_print, regValue_write};
void tx_payload_print()
{
uint8_t i, len = Radio::get_payload_length();
for (i = 0; i < len; i++)
pc.printf("%02x ", Radio::radio.tx_buf[i]);
}
bool tx_payload_write(const char* txt)
{
unsigned o, i = 0, pktidx = 0;
while (i < entry_buf_idx) {
sscanf(entry_buf+i, "%02x", &o);
pc.printf("%02x ", o);
i += 2;
Radio::radio.tx_buf[pktidx++] = o;
while (entry_buf[i] == ' ' && i < entry_buf_idx)
i++;
}
log_printf("set payload len %u\r\n", pktidx);
Radio::set_payload_length(pktidx);
return true;
}
const value_item_t tx_payload_item = { _ITEM_VALUE, 80, tx_payload_print, tx_payload_write};
void txpkt_push()
{
Radio::txPkt();
}
const button_item_t tx_pkt_item = { _ITEM_BUTTON, "TXPKT", txpkt_push };
void rxpkt_push()
{
Radio::Rx();
menuState.mode = MENUMODE_REDRAW;
}
const button_item_t rx_pkt_item = { _ITEM_BUTTON, "RXPKT", rxpkt_push };
const dropdown_item_t opmode_item = { _ITEM_DROPDOWN, Radio::opmode_status_strs, Radio::opmode_select_strs, Radio::opmode_read, Radio::opmode_write };
void tx_carrier_push()
{
Radio::tx_carrier();
}
const button_item_t tx_carrier_item = { _ITEM_BUTTON, "TX_CARRIER", tx_carrier_push };
void tx_preamble_push()
{
Radio::tx_preamble();
}
const button_item_t tx_preamble_item = { _ITEM_BUTTON, "TX_PREAMBLE", tx_preamble_push };
bool accel_en_read()
{
uint8_t status;
accel_is_enabled(&status);
return status;
}
bool accel_tx_en_read()
{
uint8_t status;
accel_is_enabled(&status);
return status && accel_tx_en;
}
bool accel_en_push()
{
uint8_t status;
accel_is_enabled(&status);
accel_tx_en = false;
if (status)
accel_enable(false);
else
accel_enable(true);
accel_is_enabled(&status);
return status;
}
bool accel_tx_en_push()
{
uint8_t status;
accel_is_enabled(&status);
accel_tx_en = true;
if (status)
accel_enable(false);
else
accel_enable(true);
accel_is_enabled(&status);
return status;
}
const toggle_item_t accel_enable_item = { _ITEM_TOGGLE, "enable", NULL, accel_en_read, accel_en_push};
const toggle_item_t accel_tx_enable_item = { _ITEM_TOGGLE, "tx_enable", NULL, accel_tx_en_read, accel_tx_en_push};
const menu_t lis12dh12_menu[] = {
{ {LAST_CHIP_MENU_ROW-1, 1}, "LIS12DH12 ", &accel_enable_item, FLAG_MSGTYPE_ALL },
{ {LAST_CHIP_MENU_ROW-1, 24}, NULL, &accel_tx_enable_item, FLAG_MSGTYPE_ALL },
{ {0, 0}, NULL, NULL }
};
#ifdef PHOTOS_PIN
void photos_push()
{
uint16_t val = photos.read_u16();
log_printf("photos %u\r\n", val);
}
void photos_tx()
{
uint16_t val;
val = photos.read_u16();
log_printf("Tx photos %u\r\n", val);
Radio::radio.tx_buf[0] = CMD_PHOTOS;
Radio::set_payload_length(sizeof(uint16_t)+1);
memcpy(&Radio::radio.tx_buf[1], &val, sizeof(uint16_t));
flags.txBusy = true;
Radio::txPkt();
}
unsigned pollTickerRate;
Ticker pollTicker;
uint8_t enabledSensor = CMD_NONE;
void tx_photos_push()
{
if (pollTickerRate > 0) {
if (enabledSensor != CMD_PHOTOS)
enabledSensor = CMD_PHOTOS;
else {
enabledSensor = CMD_NONE;
}
return;
}
photos_tx();
}
const button_item_t photos_item = { _ITEM_BUTTON, "photos", photos_push };
const button_item_t tx_photos_item = { _ITEM_BUTTON, "tx_photos", tx_photos_push };
const menu_t photos_menu[] = {
{ {(LAST_CHIP_MENU_ROW-2), 1}, "PHOTOS ", &photos_item, FLAG_MSGTYPE_ALL },
{ {(LAST_CHIP_MENU_ROW-2), 24}, NULL, &tx_photos_item, FLAG_MSGTYPE_ALL },
{ {0, 0}, NULL, NULL }
};
#endif /* PHOTOS_PIN */
void temperature_push()
{
displayFloatToInt_t val;
demo_sample_temp(&val);
}
void pressure_push()
{
displayFloatToInt_t val;
demo_sample_pressure(&val);
}
void temp_tx()
{
displayFloatToInt_t val;
demo_sample_temp(&val);
Radio::set_payload_length(sizeof(displayFloatToInt_t)+1);
Radio::radio.tx_buf[0] = CMD_TEMP;
memcpy(&Radio::radio.tx_buf[1], &val, sizeof(displayFloatToInt_t));
flags.txBusy = true;
Radio::txPkt();
}
void tx_temp_push()
{
if (pollTickerRate > 0) {
if (enabledSensor != CMD_TEMP)
enabledSensor = CMD_TEMP;
else {
enabledSensor = CMD_NONE;
}
return;
}
temp_tx();
}
void pres_tx()
{
displayFloatToInt_t val;
demo_sample_pressure(&val);
Radio::set_payload_length(sizeof(displayFloatToInt_t)+1);
Radio::radio.tx_buf[0] = CMD_PRES;
memcpy(&Radio::radio.tx_buf[1], &val, sizeof(displayFloatToInt_t));
flags.txBusy = true;
Radio::txPkt();
}
void tx_pressure_push()
{
if (pollTickerRate > 0) {
if (enabledSensor != CMD_PRES)
enabledSensor = CMD_PRES;
else {
enabledSensor = CMD_NONE;
}
return;
}
pres_tx();
}
void sensorPoll()
{
if (!flags.txBusy && menuState.mode == MENUMODE_NONE)
flags.measure_tx = 1;
}
void pollRate_print()
{
pc.printf("%ums", pollTickerRate / 1000);
}
bool pollRate_write(const char* str)
{
sscanf(str, "%u", &pollTickerRate);
if (pollTickerRate > 0) {
pollTickerRate *= 1000;
pollTicker.attach_us(sensorPoll, pollTickerRate);
} else
pollTicker.detach();
log_printf("pollTickerRate %uus\r\n", pollTickerRate);
return false;
}
const button_item_t temperature_item = { _ITEM_BUTTON, "temperature", temperature_push };
const button_item_t pressure_item = { _ITEM_BUTTON, "pressure", pressure_push };
const button_item_t tx_temp_item = { _ITEM_BUTTON, "tx_temp", tx_temp_push };
const button_item_t tx_pressure_item = { _ITEM_BUTTON, "tx_pressure", tx_pressure_push };
const value_item_t pollRate_item = { _ITEM_VALUE, 8, pollRate_print, pollRate_write };
const menu_t lps22hh_menu[] = {
{ {LAST_CHIP_MENU_ROW, 1}, "LPS22HH ", &temperature_item, FLAG_MSGTYPE_ALL },
{ {LAST_CHIP_MENU_ROW, 22}, NULL, &pressure_item, FLAG_MSGTYPE_ALL },
{ {LAST_CHIP_MENU_ROW, 31}, NULL, &tx_temp_item, FLAG_MSGTYPE_ALL },
{ {LAST_CHIP_MENU_ROW, 40}, NULL, &tx_pressure_item, FLAG_MSGTYPE_ALL },
{ {LAST_CHIP_MENU_ROW, 53}, "poll rate:", &pollRate_item, FLAG_MSGTYPE_ALL },
{ {0, 0}, NULL, NULL }
};
const menu_t msg_pkt_menu[] = {
{ {LAST_CHIP_MENU_ROW+1, 1}, "tx payload length:", &tx_payload_length_item, FLAG_MSGTYPE_PKT },
{ {LAST_CHIP_MENU_ROW+1, 25}, NULL, &tx_payload_pn9_item, FLAG_MSGTYPE_PKT, &tx_payload_item },
{ {LAST_CHIP_MENU_ROW+1, 40}, "regAddr:", ®Addr_item, FLAG_MSGTYPE_PKT, ®Value_item },
{ {LAST_CHIP_MENU_ROW+1, 53}, "regValue:", ®Value_item, FLAG_MSGTYPE_PKT, },
{ {LAST_CHIP_MENU_ROW+2, 1}, NULL, &tx_payload_item, FLAG_MSGTYPE_PKT },
{ {LAST_CHIP_MENU_ROW+3, 1}, NULL, &tx_pkt_item, FLAG_MSGTYPE_PKT, &opmode_item },
{ {LAST_CHIP_MENU_ROW+3, 10}, NULL, &rx_pkt_item, FLAG_MSGTYPE_PKT },
{ {LAST_CHIP_MENU_ROW+3, 20}, NULL, &tx_carrier_item, FLAG_MSGTYPE_PKT, &opmode_item },
{ {LAST_CHIP_MENU_ROW+3, 45}, NULL, &tx_preamble_item, FLAG_MSGTYPE_PKT, &opmode_item },
{ {0, 0}, NULL, NULL }
};
unsigned tx_ipd_ms;
Timeout mbedTimeout;
unsigned MaxNumPacket;
unsigned CntPacketTx;
unsigned PacketRxSequencePrev;
unsigned CntPacketRxKO;
unsigned CntPacketRxOK;
unsigned RxTimeOutCount;
unsigned receivedCntPacket;
void do_next_tx ()
{
Radio::radio.tx_buf[0] = CntPacketTx >> 24;
Radio::radio.tx_buf[1] = CntPacketTx >> 16;
Radio::radio.tx_buf[2] = CntPacketTx >> 8;
Radio::radio.tx_buf[3] = CntPacketTx;
Radio::radio.tx_buf[4] = PerMsg[0];
Radio::radio.tx_buf[5] = PerMsg[1];
Radio::radio.tx_buf[6] = PerMsg[2];
Radio::txPkt();
}
void next_tx_callback()
{
flags.do_next_tx = 1;
}
void pertx_push()
{
CntPacketTx = 1; // PacketRxSequencePrev initialized to 0 on receiver
log_printf("do perTx\r\n");
next_tx_callback();
}
const button_item_t pertx_item = { _ITEM_BUTTON, "PERTX", pertx_push };
void tx_ipd_print()
{
pc.printf("%u", tx_ipd_ms);
}
bool tx_ipd_write(const char* valStr)
{
sscanf(valStr, "%u", &tx_ipd_ms);
return false;
}
value_item_t per_ipd_item = { _ITEM_VALUE, 4, tx_ipd_print, tx_ipd_write };
void numpkts_print()
{
pc.printf("%u", MaxNumPacket);
}
bool numpkts_write(const char* valStr)
{
sscanf(valStr, "%u", &MaxNumPacket);
return false;
}
value_item_t per_numpkts_item = { _ITEM_VALUE, 6, numpkts_print, numpkts_write };
void perrx_push()
{
PacketRxSequencePrev = 0;
CntPacketRxKO = 0;
CntPacketRxOK = 0;
RxTimeOutCount = 0;
Radio::Rx();
}
const button_item_t perrx_item = { _ITEM_BUTTON, "PERRX", perrx_push };
void per_reset_push()
{
PacketRxSequencePrev = 0;
CntPacketRxKO = 0;
CntPacketRxOK = 0;
RxTimeOutCount = 0;
}
const button_item_t per_clear_item = { _ITEM_BUTTON, "resetCount", per_reset_push };
const menu_t msg_per_menu[] = {
{ {LAST_CHIP_MENU_ROW+3, 1}, NULL, &pertx_item, FLAG_MSGTYPE_PER },
{ {LAST_CHIP_MENU_ROW+3, 12}, "TX IPD ms:", &per_ipd_item, FLAG_MSGTYPE_PER },
{ {LAST_CHIP_MENU_ROW+3, 26}, "numPkts:", &per_numpkts_item, FLAG_MSGTYPE_PER },
{ {LAST_CHIP_MENU_ROW+3, 40}, NULL, &perrx_item, FLAG_MSGTYPE_PER, &opmode_item },
{ {LAST_CHIP_MENU_ROW+3, 50}, NULL, &per_clear_item, FLAG_MSGTYPE_PER, &opmode_item },
{ {0, 0}, NULL, NULL }
};
void SendPong()
{
unsigned failCnt = CntPacketRxKO + RxTimeOutCount;
/* ping slave tx */
log_printf("ACK PKT%u\r\n", receivedCntPacket);
Radio::radio.tx_buf[ 0] = receivedCntPacket >> 24;
Radio::radio.tx_buf[ 1] = receivedCntPacket >> 16;
Radio::radio.tx_buf[ 2] = receivedCntPacket >> 8;
Radio::radio.tx_buf[ 3] = receivedCntPacket;
Radio::radio.tx_buf[ 4] = failCnt >> 24;
Radio::radio.tx_buf[ 5] = failCnt >> 16;
Radio::radio.tx_buf[ 6] = failCnt >> 8;
Radio::radio.tx_buf[ 7] = failCnt;
Radio::radio.tx_buf[ 8] = PongMsg[0];
Radio::radio.tx_buf[ 9] = PongMsg[1];
Radio::radio.tx_buf[10] = PongMsg[2];
Radio::radio.tx_buf[11] = PongMsg[3];
Radio::txPkt();
}
void SendPing()
{
/* ping master tx */
log_printf("MASTER > PING PKT%u\r\n", CntPacketTx);
Radio::radio.tx_buf[0] = CntPacketTx >> 24;
Radio::radio.tx_buf[1] = CntPacketTx >> 16;
Radio::radio.tx_buf[2] = CntPacketTx >> 8;
Radio::radio.tx_buf[3] = CntPacketTx;
Radio::radio.tx_buf[4] = PingMsg[0];
Radio::radio.tx_buf[5] = PingMsg[1];
Radio::radio.tx_buf[6] = PingMsg[2];
Radio::radio.tx_buf[7] = PingMsg[3];
Radio::txPkt();
}
void
pingpong_start_push()
{
CntPacketTx = 1;
CntPacketRxKO = 0;
CntPacketRxOK = 0;
RxTimeOutCount = 0;
receivedCntPacket = 0;
flags.send_ping = 1;
flags.ping_master = 1;
flags.pingpongEnable = 1;
log_printf("ping start\r\n");
}
const button_item_t pingpong_start_item = { _ITEM_BUTTON, "START", pingpong_start_push };
void
pingpong_stop_push ()
{
flags.pingpongEnable = 0;
}
const button_item_t pingpong_stop_item = { _ITEM_BUTTON, "STOP", pingpong_stop_push };
const menu_t msg_pingpong_menu[] = {
{ {LAST_CHIP_MENU_ROW+3, 1}, NULL, &pingpong_start_item, FLAG_MSGTYPE_PING },
{ {LAST_CHIP_MENU_ROW+3, 15}, NULL, &pingpong_stop_item, FLAG_MSGTYPE_PING },
{ {0, 0}, NULL, NULL }
};
const menu_t* get_msg_menu()
{
switch (msg_type) {
case MSG_TYPE_PACKET:
return msg_pkt_menu;
case MSG_TYPE_PER:
return msg_per_menu;
case MSG_TYPE_PINGPONG:
return msg_pingpong_menu;
}
return NULL;
}
void frf_print()
{
float MHz;
#ifdef SX127x_H
MHz = Radio::radio.get_frf_MHz();
#else
MHz = Radio::radio.getMHz();
#endif
pc.printf("%.3fMHz", MHz);
}
bool frf_write(const char* valStr)
{
float MHz;
sscanf(valStr, "%f", &MHz);
#ifdef SX127x_H
Radio::radio.set_frf_MHz(MHz);
#else
Radio::radio.setMHz(MHz);
#endif
return false;
}
const value_item_t frf_item = { _ITEM_VALUE, 14, frf_print, frf_write };
const value_item_t Radio::tx_dbm_item = { _ITEM_VALUE, 7, Radio::tx_dbm_print, Radio::tx_dbm_write };
const dropdown_item_t tx_ramp_item = { _ITEM_DROPDOWN, Radio::tx_ramp_strs, Radio::tx_ramp_strs, Radio::tx_ramp_read, Radio::tx_ramp_write };
const button_item_t chipNum_item = { _ITEM_BUTTON, Radio::chipNum_str, NULL};
void botrow_print()
{
pc.printf("%u", botRow);
}
bool botrow_write(const char* str)
{
unsigned n;
sscanf(str, "%u", &n);
botRow = n;
pc.printf("\e[%u;%ur", MAX_MENU_ROWS, botRow); // set scrolling region
return false;
}
const value_item_t bottomRow_item = { _ITEM_VALUE, 4, botrow_print, botrow_write };
const menu_t common_menu[] = {
{ {1, 1}, NULL, &hw_reset_item, FLAG_MSGTYPE_ALL },
{ {1, 15}, "packetType:", &pktType_item, FLAG_MSGTYPE_ALL },
{ {1, 37}, NULL, &msgType_item, FLAG_MSGTYPE_ALL },
{ {1, 50}, NULL, &chipNum_item, FLAG_MSGTYPE_ALL },
{ {1, 60}, "bottomRow:", &bottomRow_item, FLAG_MSGTYPE_ALL },
{ {2, 1}, NULL, &frf_item, FLAG_MSGTYPE_ALL },
{ {2, 15}, "TX dBm:", &Radio::tx_dbm_item, FLAG_MSGTYPE_ALL },
{ {2, 30}, "ramp us:", &tx_ramp_item, FLAG_MSGTYPE_ALL },
{ {2, 45}, NULL, &clearirqs_item, FLAG_MSGTYPE_ALL },
{ {2, 55}, "opmode:", &opmode_item, FLAG_MSGTYPE_ALL },
{ {0, 0}, NULL, NULL }
};
bool
is_menu_item_changable(uint8_t table_row, uint8_t table_col)
{
const menu_t* m = menu_table[table_row][table_col];
const dropdown_item_t* di = (const dropdown_item_t*)m->itemPtr;
switch (msg_type) {
case MSG_TYPE_PACKET:
if (m->flags & FLAG_MSGTYPE_PKT)
break;
else
return false;
case MSG_TYPE_PER:
if (m->flags & FLAG_MSGTYPE_PER)
break;
else
return false;
case MSG_TYPE_PINGPONG:
if (m->flags & FLAG_MSGTYPE_PING)
break;
else
return false;
}
if (di->itemType == _ITEM_DROPDOWN) {
if (di->selectable_strs == NULL || di->selectable_strs[0] == NULL) {
log_printf("NULLstrs%u,%u\r\n", table_row, table_col);
return false;
}
} else if (di->itemType == _ITEM_VALUE) {
const value_item_t* vi = (const value_item_t*)m->itemPtr;
if (vi->write == NULL)
return false;
} else if (di->itemType == _ITEM_BUTTON) {
const button_item_t* bi = (const button_item_t*)m->itemPtr;
if (bi->push == NULL)
return false;
} else if (di->itemType == _ITEM_TOGGLE) {
const toggle_item_t * ti = (const toggle_item_t *)m->itemPtr;
if (ti->push == NULL)
return false;
}
return true;
} // ..is_menu_item_changable()
void read_menu_item(const menu_t* m, bool selected)
{
uint8_t valCol;
const dropdown_item_t* di = (const dropdown_item_t*)m->itemPtr;
switch (msg_type) {
case MSG_TYPE_PACKET:
if (m->flags & FLAG_MSGTYPE_PKT)
break;
else
return;
case MSG_TYPE_PER:
if (m->flags & FLAG_MSGTYPE_PER)
break;
else
return;
case MSG_TYPE_PINGPONG:
if (m->flags & FLAG_MSGTYPE_PING)
break;
else
return;
}
pc.printf("\e[%u;%uf", m->pos.row, m->pos.col); // set (force) cursor to row;column
valCol = m->pos.col;
if (m->label) {
pc.printf(m->label);
valCol += strlen(m->label);
}
if (di->itemType == _ITEM_DROPDOWN) {
if (di->read && di->printed_strs) {
uint8_t ridx = di->read(false);
if (selected)
pc.printf("\e[7m");
pc.printf(di->printed_strs[ridx]);
if (selected)
pc.printf("\e[0m");
} else if (di->printed_strs) {
pc.printf(di->printed_strs[0]);
}
} else if (di->itemType == _ITEM_VALUE) {
const value_item_t* vi = (const value_item_t*)m->itemPtr;
if (vi->print) {
for (unsigned n = 0; n < vi->width; n++)
pc.putc(' ');
pc.printf("\e[%u;%uf", m->pos.row, valCol); // set (force) cursor to row;column
if (selected)
pc.printf("\e[7m");
vi->print();
if (selected)
pc.printf("\e[0m");
}
} else if (di->itemType == _ITEM_BUTTON) {
const button_item_t* bi = (const button_item_t*)m->itemPtr;
if (bi->label) {
if (selected)
pc.printf("\e[7m%s\e[0m", bi->label);
else
pc.printf("%s", bi->label);
}
} else if (di->itemType == _ITEM_TOGGLE) {
const toggle_item_t* ti = (const toggle_item_t *)m->itemPtr;
bool on = ti->read();
if (ti->label1) {
const char* const cptr = on ? ti->label1 : ti->label0;
if (selected)
pc.printf("\e[7m%s\e[0m", cptr);
else
pc.printf("%s", cptr);
} else {
if (on)
pc.printf("\e[1m");
if (selected)
pc.printf("\e[7m");
pc.printf("%s", ti->label0);
if (selected || on)
pc.printf("\e[0m");
}
}
} // ..read_menu_item()
void draw_menu()
{
unsigned table_row;
for (table_row = 0; table_row < MAX_MENU_ROWS; table_row++) {
int table_col;
for (table_col = 0; table_col < StopMenuCols[table_row]; table_col++) {
read_menu_item(menu_table[table_row][table_col], false);
} // ..table column iterator
} // ..table row iterator
read_menu_item(menu_table[curpos.row][curpos.tableCol], true);
} // ..draw_menu()
typedef struct {
int row;
int col;
} tablexy_t;
void
menu_init_(const menu_t* in, tablexy_t* tc)
{
unsigned n;
for (n = 0; in[n].pos.row > 0; n++) {
const menu_t* m = &in[n];
if (tc->row != m->pos.row - 1) {
tc->row = m->pos.row - 1;
tc->col = 0;
} else
tc->col++;
menu_table[tc->row][tc->col] = m;
#ifdef MENU_DEBUG
pc.printf("table:%u,%u ", tc->row, tc->col);
pc.printf(" %d<%d? ", StopMenuCols[tc->row], tc->col);
#endif /* MENU_DEBUG */
if (StopMenuCols[tc->row] < tc->col)
StopMenuCols[tc->row] = tc->col;
#ifdef MENU_DEBUG
pc.printf("{%u %u}", tc->row, tc->col);
pc.printf("in:%p[%u] screen:%u,%u ", in, n, m->pos.row, m->pos.col);
//pc.printf(" loc:%p ", &in[n].itemPtr);
if (in[n].itemPtr) {
const dropdown_item_t* di = (const dropdown_item_t*)m->itemPtr;
pc.printf(" itemPtr:%p type:%02x ", di, di->itemType);
}
pc.printf("stopMenuCols[%u]: %d ", tc->row, StopMenuCols[tc->row]);
if (m->label)
pc.printf("label:%s", m->label);
else
pc.printf("noLabel");
pc.printf("\r\n");
#endif /* MENU_DEBUG */
}
#ifdef MENU_DEBUG
pc.printf("hit key:");
wait_uart_rx(); //pc.getc();
#endif /* MENU_DEBUG */
}
void navigate_dropdown(uint8_t ch)
{
unsigned n;
const menu_t* m = menuState.sm;
const dropdown_item_t* di = (const dropdown_item_t*)m->itemPtr;
switch (ch) {
case 'A': // cursor UP
if (menuState.sel_idx > 0) {
menuState.sel_idx--;
}
break;
case 'B': // cursor DOWN
if (di->selectable_strs[menuState.sel_idx+1] != NULL)
menuState.sel_idx++;
break;
} // ..switch (ch)
for (n = 0; di->selectable_strs[n] != NULL; n++) {
pc.printf("\e[%u;%uf", m->pos.row+n, menuState.dropdown_col);
if (n == menuState.sel_idx)
pc.printf("\e[7m");
pc.printf(di->selectable_strs[n]);
if (n == menuState.sel_idx)
pc.printf("\e[0m");
}
pc.printf("\e[%u;%uf", m->pos.row + menuState.sel_idx, menuState.dropdown_col + strlen(di->selectable_strs[menuState.sel_idx]));
}
bool is_item_selectable(const menu_t* m)
{
const dropdown_item_t* di = (const dropdown_item_t*)m->itemPtr;
if (di->itemType == _ITEM_BUTTON) {
const button_item_t* bi = (const button_item_t*)m->itemPtr;
if (bi->push == NULL)
return false;
} else if (di->itemType == _ITEM_TOGGLE) {
const toggle_item_t* ti = (const toggle_item_t*)m->itemPtr;
if (ti->push == NULL)
return false;
}
return true;
}
void navigate_menu(uint8_t ch)
{
read_menu_item(menu_table[curpos.row][curpos.tableCol], false);
switch (ch) {
case 'A': // cursor UP
if (curpos.row == 0)
break;
{ // find previous row up with column
int8_t row;
for (row = curpos.row - 1; row >= 0; row--) {
if (StopMenuCols[row] > -1) {
curpos.row = row;
break;
}
}
if (row == 0 && StopMenuCols[0] < 0)
break; // nothing found
}
if (curpos.tableCol >= StopMenuCols[curpos.row]) {
curpos.tableCol = StopMenuCols[curpos.row]-1;
}
break;
case 'B': // cursor DOWN
if (curpos.row >= MAX_MENU_ROWS)
break;
{ // find next row down with column
uint8_t row;
for (row = curpos.row + 1; row < MAX_MENU_ROWS; row++) {
if (StopMenuCols[row] != -1) {
curpos.row = row;
break;
}
}
if (row == MAX_MENU_ROWS-1 && StopMenuCols[row] == -1)
break; // nothing found
}
if (curpos.tableCol >= StopMenuCols[curpos.row]) {
curpos.tableCol = StopMenuCols[curpos.row]-1;
}
break;
case 'C': // cursor LEFT
if (curpos.tableCol >= StopMenuCols[curpos.row]-1)
break;
{ // find next row left with editable
uint8_t tcol;
for (tcol = curpos.tableCol + 1; tcol < StopMenuCols[curpos.row]; tcol++) {
if (is_menu_item_changable(curpos.row, tcol)) {
curpos.tableCol = tcol;
break;
}
}
}
break;
case 'D': // cursor RIGHT
if (curpos.tableCol == 0)
break;
{
int8_t tcol;
for (tcol = curpos.tableCol - 1; tcol >= 0; tcol--) {
if (is_menu_item_changable(curpos.row, tcol)) {
curpos.tableCol = tcol;
break;
}
}
}
break;
default:
//pc.printf("unhancled-csi:%02x\eE", ch);
break;
} // ..switch (ch)
if (!is_item_selectable(menu_table[curpos.row][curpos.tableCol])) {
int c;
for (c = 0; c < StopMenuCols[curpos.row]; c++) {
if (is_item_selectable(menu_table[curpos.row][c])) {
curpos.tableCol = c;
break;
}
}
if (c == StopMenuCols[curpos.row])
return;
}
#ifdef MENU_DEBUG
log_printf("table:%u,%u screen:%u,%u \r\n", curpos.row, curpos.tableCol,
menu_table[curpos.row][curpos.tableCol]->pos.row,
menu_table[curpos.row][curpos.tableCol]->pos.col
);
#endif /* MENU_DEBUG */
read_menu_item(menu_table[curpos.row][curpos.tableCol], true);
} // ..navigate_menu
void commit_menu_item_change()
{
const menu_t* m = menu_table[curpos.row][curpos.tableCol];
const dropdown_item_t* di = (const dropdown_item_t*)m->itemPtr;
if (di->itemType == _ITEM_DROPDOWN) {
menuState.mode = di->write(menuState.sel_idx);
pc.printf("\e[%u;%uf", m->pos.row, m->pos.col-2);
} else if (di->itemType == _ITEM_VALUE) {
const value_item_t* vi = (const value_item_t*)m->itemPtr;
/* commit value entry */
if (vi->write) {
if (vi->write(entry_buf))
menuState.mode = MENUMODE_REDRAW;
else
menuState.mode = MENUMODE_NONE;
} else
menuState.mode = MENUMODE_NONE;
if (menuState.mode == MENUMODE_NONE) {
read_menu_item(menu_table[curpos.row][curpos.tableCol], true);
}
}
} // ..commit_menu_item_change()
void refresh_item_in_table(const void* item)
{
unsigned table_row;
if (item == NULL)
return;
for (table_row = 0; table_row < MAX_MENU_ROWS; table_row++) {
int table_col;
for (table_col = 0; table_col < StopMenuCols[table_row]; table_col++) {
//log_printf("%u %u %p\r\n", table_row, table_col, menu_table[table_row][table_col]->itemPtr);
if (item == menu_table[table_row][table_col]->itemPtr) {
read_menu_item(menu_table[table_row][table_col], false);
return;
}
}
}
}
void
start_value_entry(const menu_t* m)
{
const value_item_t* vi = (const value_item_t*)m->itemPtr;
uint8_t col = m->pos.col;
if (m->label)
col += strlen(m->label);
pc.printf("\e[%u;%uf", m->pos.row, col);
for (unsigned i = 0; i < vi->width; i++)
pc.putc(' '); // clear displayed value for user entry
pc.printf("\e[%u;%uf", m->pos.row, col);
menuState.mode = MENUMODE_ENTRY;
entry_buf_idx = 0;
}
void start_menu_item_change()
{
const menu_t* m = menu_table[curpos.row][curpos.tableCol];
const dropdown_item_t* di = (const dropdown_item_t*)m->itemPtr;
bool checkRefresh = false;
if (di->itemType == _ITEM_DROPDOWN && di->selectable_strs) {
menuState.dropdown_col = m->pos.col;
unsigned n, sidx = 0;
/* start dropdown */
if (di->read)
sidx = di->read(true);
if (m->label)
menuState.dropdown_col += strlen(m->label);
for (n = 0; di->selectable_strs[n] != NULL; n++) {
uint8_t col = menuState.dropdown_col;
bool leftPad = false;
if (col > 3 && n > 0) { // dropdown left side padding
col -= 2;
leftPad = true;
}
pc.printf("\e[%u;%uf", m->pos.row+n, col);
if (leftPad ) {
pc.putc(' ');
pc.putc(' ');
}
if (n == sidx)
pc.printf("\e[7m");
pc.printf(di->selectable_strs[n]);
if (n == sidx)
pc.printf("\e[0m");
pc.putc(' '); // right side padding
pc.putc(' ');
}
pc.printf("\e[%u;%uf", m->pos.row, menuState.dropdown_col-2);
menuState.mode = MENUMODE_DROPDOWN;
menuState.sel_idx = sidx;
menuState.sm = m;
} else if (di->itemType == _ITEM_VALUE) {
/* start value entry */
start_value_entry(m);
} else if (di->itemType == _ITEM_BUTTON) {
const button_item_t* bi = (const button_item_t*)m->itemPtr;
if (bi->push) {
bi->push();
checkRefresh = true;
}
} else if (di->itemType == _ITEM_TOGGLE) {
const toggle_item_t* ti = (const toggle_item_t*)m->itemPtr;
if (ti->push) {
bool on = ti->push();
uint8_t col = m->pos.col;
if (m->label)
col += strlen(m->label);
pc.printf("\e[%u;%uf", m->pos.row, col);
if (ti->label1) {
pc.printf("\e[7m%s\e[0m", on ? ti->label1 : ti->label0);
} else {
if (on)
pc.printf("\e[1;7m%s\e[0m", ti->label0);
else
pc.printf("\e[7m%s\e[0m", ti->label0);
}
checkRefresh = true;
}
}
if (checkRefresh) {
if (m->refreshReadItem) {
refresh_item_in_table(m->refreshReadItem); // read associated
read_menu_item(m, true); // restore cursor
}
}
} // ..start_menu_item_change()
void full_menu_init()
{
unsigned n;
const menu_t *m;
tablexy_t txy;
txy.row = INT_MAX;
txy.col = 0;
for (n = 0; n < MAX_MENU_ROWS; n++) {
StopMenuCols[n] = -1;
}
menu_init_(common_menu, &txy);
menu_init_(Radio::common_menu, &txy);
m = Radio::get_modem_menu();
if (m == NULL) {
log_printf("NULL-modemMenu\r\n");
for (;;) asm("nop");
}
#ifdef MENU_DEBUG
pc.printf("modemmenuInit\r\n");
#endif
menu_init_(m, &txy);
m = Radio::get_modem_sub_menu();
if (m) {
#ifdef MENU_DEBUG
pc.printf("modemsubmenuInit\r\n");
#endif
menu_init_(m, &txy);
}
#ifdef MENU_DEBUG
else
pc.printf("no-modemsubmenu\r\n");
#endif
#ifdef PHOTOS_PIN
menu_init_(photos_menu, &txy);
#endif /* PHOTOS_PIN */
menu_init_(lis12dh12_menu, &txy); // accel
menu_init_(lps22hh_menu, &txy); // temp, pressure
m = get_msg_menu();
if (m == NULL) {
log_printf("NULL-msgMenu %d\r\n", msg_type);
for (;;) asm("nop");
}
menu_init_(m, &txy);
for (n = 0; n < MAX_MENU_ROWS; n++) {
if (StopMenuCols[n] != -1)
StopMenuCols[n]++;
}
}
bool ishexchar(char ch)
{
if (((ch >= 'a' && ch <= 'f') || (ch >= 'A' && ch <= 'F')) || (ch >= '0' && ch <= '9'))
return true;
else
return false;
}
enum _urx_ {
URX_STATE_NONE = 0,
URX_STATE_ESCAPE,
URX_STATE_CSI,
} uart_rx_state;
Timeout uartRxTimeout;
void uart_rx_timeout()
{
/* escape by itself: abort change on item */
menuState.mode = MENUMODE_REDRAW;
uart_rx_state = URX_STATE_NONE;
}
void serial_callback(char ch)
{
switch (uart_rx_state) {
case URX_STATE_NONE:
if (ch == 0x1b) {
if (menuState.mode == MENUMODE_ENTRY) {
/* abort entry mode */
menuState.mode = MENUMODE_NONE;
read_menu_item(menu_table[curpos.row][curpos.tableCol], true);
} else {
uart_rx_state = URX_STATE_ESCAPE;
if (menuState.mode != MENUMODE_NONE) {
/* is this escape by itself, user wants to abort? */
uartRxTimeout.attach(uart_rx_timeout, 0.03);
}
}
} else if (ch == 2) { // ctrl-B
log_printf("--------------\r\n");
} else if (ch == '\r') {
if (menuState.mode == MENUMODE_NONE) {
start_menu_item_change();
} else {
entry_buf[entry_buf_idx] = 0;
commit_menu_item_change();
}
} else if (menuState.mode == MENUMODE_ENTRY) {
if (ch == 8) {
if (entry_buf_idx > 0) {
pc.putc(8);
pc.putc(' ');
pc.putc(8);
entry_buf_idx--;
}
} else if (ch == 3) { // ctrl-C
menuState.mode = MENUMODE_NONE;
} else if (entry_buf_idx < sizeof(entry_buf)) {
entry_buf[entry_buf_idx++] = ch;
pc.putc(ch);
}
} else if (menuState.mode == MENUMODE_NONE) {
if (ishexchar(ch) || ch == '-') { // characters which start entry
const value_item_t* vi = (const value_item_t*)menu_table[curpos.row][curpos.tableCol]->itemPtr;
if (vi->itemType == _ITEM_VALUE) {
start_value_entry(menu_table[curpos.row][curpos.tableCol]);
entry_buf[entry_buf_idx++] = ch;
pc.putc(ch);
}
} else if (ch == 'r') {
menuState.mode = MENUMODE_REDRAW;
} else if (ch == '.') {
Radio::test();
}
}
break;
case URX_STATE_ESCAPE:
uartRxTimeout.detach();
if (ch == '[')
uart_rx_state = URX_STATE_CSI;
else {
#ifdef MENU_DEBUG
log_printf("unhancled-esc:%02x\r\n", ch);
#endif /* MENU_DEBUG */
uart_rx_state = URX_STATE_NONE;
}
break;
case URX_STATE_CSI:
if (menuState.mode == MENUMODE_NONE)
navigate_menu(ch);
else if (menuState.mode == MENUMODE_DROPDOWN)
navigate_dropdown(ch);
uart_rx_state = URX_STATE_NONE;
//pc.printf("\e[18;1f"); // set (force) cursor to row;column
break;
} // ..switch (uart_rx_state)
}
void ev_uart_rx()
{
log_printf("ev_uart_rx %u %u\r\n", uart_rx_buf_in, uart_rx_buf_out);
while (uart_rx_buf_in != uart_rx_buf_out) {
log_printf("X ev_uart_rx %u %u\r\n", uart_rx_buf_in, uart_rx_buf_out);
serial_callback(uart_rx_buf[uart_rx_buf_out++]);
if (uart_rx_buf_out == UART_RX_BUF_LEN)
uart_rx_buf_out = 0;
}
}
//volatile unsigned rxCnt = 0;
void rx_isr()
{
//rxCnt++;
uart_rx_buf[uart_rx_buf_in++] = pc.getc();
if (uart_rx_buf_in == UART_RX_BUF_LEN)
uart_rx_buf_in = 0;
//queue.call(ev_uart_rx);
}
void txDone()
{
if (msg_type == MSG_TYPE_PER) {
log_printf("CntPacketTx%u, max:%u ipd%u\r\n", CntPacketTx, MaxNumPacket, tx_ipd_ms);
if (++CntPacketTx <= MaxNumPacket)
mbedTimeout.attach_us(next_tx_callback, tx_ipd_ms * 1000);
} else if (msg_type == MSG_TYPE_PINGPONG) {
if (flags.ping_master) {
++CntPacketTx;
}
Radio::Rx();
}
flags.txBusy = false;
}
static void
printRxPkt(uint8_t size)
{
char str[80];
char *ptr, *endPtr;
unsigned n = 0;
endPtr = str + sizeof(str);
ptr = str;
while (ptr < endPtr) {
sprintf(ptr, "%02x ", Radio::radio.rx_buf[n]);
ptr += 3;
if (++n >= size)
break;
}
log_printf("%s\r\n", str);
}
void rxDone(uint8_t size, float rssi, float snr)
{
log_printf("rxDone %u, %.1fdBm %.1fdB\r\n", size, rssi, snr);
if (msg_type == MSG_TYPE_PACKET) {
switch (Radio::radio.rx_buf[0]) {
displayFloatToInt_t val;
case CMD_TEMP:
memcpy(&val, &Radio::radio.rx_buf[1], sizeof(displayFloatToInt_t));
log_printf("TEMP: %c%d.%02d\r\n", ((val.sign) ? '-' : '+'),
(int)val.out_int, (int)val.out_dec);
break;
case CMD_PRES:
memcpy(&val, &Radio::radio.rx_buf[1], sizeof(displayFloatToInt_t));
log_printf("PRESS: %c%d.%02d\r\n", ((val.sign) ? '-' : '+'),
(int)val.out_int, (int)val.out_dec);
break;
case CMD_ACCEL:
SensorAxes_t acc;
memcpy(&acc, &Radio::radio.rx_buf[1], sizeof(SensorAxes_t));
log_printf("ACC %5ld %5ld %5ld\r\n", acc.AXIS_X, acc.AXIS_Y, acc.AXIS_Z);
break;
case CMD_PHOTOS:
uint16_t pv;
memcpy(&pv, &Radio::radio.rx_buf[1], sizeof(uint16_t));
log_printf("photos: %u\r\n", pv);
break;
default:
printRxPkt(size);
break;
}
} else if (msg_type == MSG_TYPE_PER) {
if (memcmp(Radio::radio.rx_buf+4, PerMsg, 3) == 0) {
unsigned i, PacketRxSequence = Radio::radio.rx_buf[0];
PacketRxSequence <<= 8;
PacketRxSequence += Radio::radio.rx_buf[1];
PacketRxSequence <<= 8;
PacketRxSequence += Radio::radio.rx_buf[2];
PacketRxSequence <<= 8;
PacketRxSequence += Radio::radio.rx_buf[3];
CntPacketRxOK++;
if (PacketRxSequence <= PacketRxSequencePrev || PacketRxSequencePrev == 0)
i = 0; // sequence reset to resync, dont count missed packets this time
else
i = PacketRxSequence - PacketRxSequencePrev - 1;
CntPacketRxKO += i;
RxTimeOutCount = 0;
log_printf("PER rx%u ok%u ko%u\r\n", PacketRxSequence , CntPacketRxOK, CntPacketRxKO);
PacketRxSequencePrev = PacketRxSequence;
} // ..if PerMsg
else {
log_printf("per?\r\n");
printRxPkt(size);
}
} else if (msg_type == MSG_TYPE_PINGPONG) {
if (memcmp(Radio::radio.rx_buf+4, PingMsg, 4) == 0) {
/* ping slave rx */
Radio::setFS();
receivedCntPacket = Radio::radio.rx_buf[0];
receivedCntPacket <<= 8;
receivedCntPacket += Radio::radio.rx_buf[1];
receivedCntPacket <<= 8;
receivedCntPacket += Radio::radio.rx_buf[2];
receivedCntPacket <<= 8;
receivedCntPacket += Radio::radio.rx_buf[3];
log_printf("%u rxPing->txPong\r\n", receivedCntPacket);
flags.ping_master = 0;
flags.send_pong = 1;
} else if (memcmp(Radio::radio.rx_buf+8, PongMsg, 4) == 0) {
unsigned cnt;
/* ping master rx */
Radio::setFS();
cnt = Radio::radio.rx_buf[0];
cnt <<= 8;
cnt += Radio::radio.rx_buf[1];
cnt <<= 8;
cnt += Radio::radio.rx_buf[2];
cnt <<= 8;
cnt += Radio::radio.rx_buf[3];
log_printf("%u rxPong->txPing\r\n", cnt);
flags.send_ping = 1;
} else {
log_printf("pingpong?\r\n");
printRxPkt(size);
}
} else {
/*for (unsigned n = 0; n < size; n++)
log_printf("%02x\r\n", Radio::radio.rx_buf[n]);*/
log_printf("msg_type %u\r\n", msg_type);
}
}
const RadioEvents_t rev = {
txDone,
rxDone
};
static DrvStatusTypeDef LIS2DH12_Read_Single_FIFO_Data(uint16_t sampleIndex, SensorAxes_t* acceleration)
{
//SensorAxes_t acceleration;
/* Read single FIFO data (acceleration in 3 axes) */
if (lis2dh12_get_axes(acceleration) == COMPONENT_ERROR)
{
return COMPONENT_ERROR;
}
if (sampleIndex < SAMPLE_LIST_MAX)
{
log_printf("[DATA %02d] %5ld %5ld %5ld\r\n", sampleIndex + 1, acceleration->AXIS_X,
acceleration->AXIS_Y,
acceleration->AXIS_Z);
}
return COMPONENT_OK;
}
void uart_rx_service()
{
while (uart_rx_buf_in != uart_rx_buf_out) {
serial_callback(uart_rx_buf[uart_rx_buf_out++]);
if (uart_rx_buf_out == UART_RX_BUF_LEN)
uart_rx_buf_out = 0;
}
}
static DrvStatusTypeDef LIS2DH12_Read_All_FIFO_Data(void)
{
uint16_t samplesToRead = accel_get_num_samples();
SensorAxes_t acc;
/* 'samplesToRead' actually contains number of words in FIFO but each FIFO sample (data set) consists of 3 words
so the 'samplesToRead' has to be divided by 3 */
samplesToRead /= 3;
log_printf("\r\n%d samples in FIFO.\r\n\r\nStarted downloading data from FIFO ...\r\n", samplesToRead);
log_printf("\r\n[DATA ##] ACC_X ACC_Y ACC_Z [mg]\r\n");
for (int i = 0; i < samplesToRead; i++)
{
uart_rx_service();
if (LIS2DH12_Read_Single_FIFO_Data(i, &acc) == COMPONENT_ERROR)
{
return COMPONENT_ERROR;
} else {
}
}
if (accel_tx_en) {
Radio::radio.tx_buf[0] = CMD_ACCEL;
Radio::set_payload_length(sizeof(SensorAxes_t)+1);
memcpy(&Radio::radio.tx_buf[1], &acc, sizeof(SensorAxes_t));
Radio::txPkt();
}
if (samplesToRead > SAMPLE_LIST_MAX)
{
log_printf("\r\nSample list limited to: %d\r\n", SAMPLE_LIST_MAX);
}
return COMPONENT_OK;
}
int main()
{
lfsr = LFSR_INIT;
msg_type = MSG_TYPE_PACKET;
uart_rx_state = URX_STATE_NONE;
pc.attach(rx_isr);
Radio::boardInit(&rev);
{
unsigned n;
for (n = 0; n < MAX_MENU_ROWS; n++)
StopMenuCols[n] = -1;
}
botRow = MAX_MENU_ROWS + SCROLLING_ROWS;
pc.baud(115200);
pc.printf("\e[7h"); // enable line wrapping
pc.printf("\e[%u;%ur", MAX_MENU_ROWS, botRow); // set scrolling region
pc.printf("\e[2J"); // erase entire screen
full_menu_init();
//wait_uart_rx(); //pc.getc();
pc.printf("\e[2J"); // erase entire screen
menuState.mode = MENUMODE_NONE;
draw_menu();
curpos.row = 0;
curpos.tableCol = 0;
tx_ipd_ms = 100;
if (demo_start()) {
log_printf("demo_start-Failed\r\n");
for (;;) { asm("nop"); }
} else
log_printf("demo_start-OK\r\n");
svc_lis2dh12 = true;
for (;;) {
int ret;
uart_rx_service();
if (flags.send_ping) {
if (flags.pingpongEnable)
SendPing();
flags.send_ping = 0;
}
if (flags.send_pong) {
if (flags.pingpongEnable)
SendPong();
flags.send_pong = 0;
}
if (flags.do_next_tx) {
do_next_tx();
flags.do_next_tx = 0;
}
if (menuState.mode == MENUMODE_REINIT_MENU) {
full_menu_init();
menuState.mode = MENUMODE_REDRAW;
}
if (menuState.mode == MENUMODE_REDRAW) {
// erase entire screen, some dropdowns extend to scrolling area
pc.printf("\e[%u;%ur", MAX_MENU_ROWS, botRow); // set scrolling region, if terminal started after
pc.printf("\e[2J");
//pc.printf("\e[%u;1f\e[1J", MAX_MENU_ROWS); // erase menu area
menuState.mode = MENUMODE_NONE;
draw_menu();
}
if (Radio::service(menuState.mode == MENUMODE_NONE ? LAST_CHIP_MENU_ROW : -1)) {
read_menu_item(menu_table[curpos.row][curpos.tableCol], true);
}
if (svc_lis2dh12) {
ret = lis2dh_mainloop();
switch (ret) {
case LIS2DH_FAIL_STATE:
log_printf("lis2dh-stateFail\r\n");
break;
case LIS2DH_FAIL:
log_printf("lis2dh-Fail\r\n");
break;
case LIS2DH_BSP_FAIL:
log_printf("lis2dh bsp-fail\r\n");
wait(0.05);
break;
case LIS2DH_MAIN_SLEEP:
lis2dh_set_fifo_mode();
log_printf("lis2dh fifo-mode-sleep\r\n");
svc_lis2dh12 = false;
break;
case LIS2DH_MAIN_READ_FIFO:
if (LIS2DH12_Read_All_FIFO_Data() == COMPONENT_ERROR)
{
return LIS2DH_FAIL;
}
/* Reset FIFO by setting FIFO mode to Bypass */
if (lis2dh_set_fifo_bypass() < 0) {
log_printf("fifo-bypass-fail\r\n");
}
break;
default:
break;
}
} // ..if (svc_lis2dh12)
else {
}
if (flags.measure_tx) {
switch (enabledSensor) {
case CMD_PHOTOS:
photos_tx();
break;
case CMD_PRES:
pres_tx();
break;
case CMD_TEMP:
temp_tx();
break;
}
flags.measure_tx = 0;
}
} // ..for (;;)
}
void lis2dh_int1()
{
log_printf("\r\nReceived FIFO Threshold Interrupt on INT1 pin ...\r\n"
"\r\nNucleo processor is waking up ...\r\n"
);
svc_lis2dh12 = true;
}
char strbuf[255];
void c_log_printf(const char* format, ...)
{
va_list arglist;
// put cursor at last scrolling-area line
pc.printf("\e[%u;1f", botRow);
va_start(arglist, format);
vsnprintf(strbuf, sizeof(strbuf), format, arglist);
va_end(arglist);
pc.printf(strbuf);
}
void log_printf(const char* format, ...)
{
va_list arglist;
// put cursor at last scrolling-area line
pc.printf("\e[%u;1f", botRow);
va_start(arglist, format);
vsnprintf(strbuf, sizeof(strbuf), format, arglist);
va_end(arglist);
pc.printf(strbuf);
}