mirror of
https://github.com/adrcs/ip400.git
synced 2025-04-18 18:13:44 +03:00
840 lines
20 KiB
C
840 lines
20 KiB
C
/*---------------------------------------------------------------------------
|
|
Project: WL33_NUCLEO_UART
|
|
|
|
File Name: menu.c
|
|
|
|
Author: MartinA
|
|
|
|
Description: Menu handler
|
|
|
|
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 2 of the License, or
|
|
(at your option) any later version, provided this copyright notice
|
|
is included.
|
|
|
|
Copyright (c) Alberta Digital Radio Communications Society
|
|
All rights reserved.
|
|
|
|
Revision History:
|
|
|
|
---------------------------------------------------------------------------*/
|
|
#include <string.h>
|
|
#include <malloc.h>
|
|
|
|
#include "types.h"
|
|
#include "usart.h"
|
|
#include "streambuffer.h"
|
|
#include "setup.h"
|
|
#include "tasks.h"
|
|
#include "utils.h"
|
|
#include "tod.h"
|
|
#include "config.h"
|
|
|
|
// menu state
|
|
uint8_t menuState; // menu state
|
|
enum {
|
|
MENU_OFF, // off
|
|
MENU_SHOWING, // showing the menu
|
|
MENU_SELECTING, // getting a selection
|
|
MENU_SELECTED, // item has been selected
|
|
MENU_PAUSED // pausing a while...
|
|
};
|
|
|
|
// key entry state
|
|
uint8_t entryState; // state of keyboard entry
|
|
enum {
|
|
NO_ENTRY=0, // no entry yet..
|
|
ENTERING, // entering a value
|
|
VALIDATING, // validating the entry
|
|
};
|
|
|
|
// menu items
|
|
#define NO_ITEM -1 // no item selected
|
|
#define __MEM_DEBUG 1 // memory debug
|
|
|
|
// DEC VT100 Escape sequences
|
|
#define ASCII_TAB 0x09
|
|
#define ASCII_RET 0x0D
|
|
#define ASCII_ESC 0x1B // escape char
|
|
#define DEC_LEADIN '[' // lead-in character
|
|
#define MAX_SEQ 6 // max sequence length
|
|
|
|
// control codes..
|
|
enum {
|
|
CONTROL_CLEAR=0, // clear screen
|
|
CONTROL_HOME, // cursor home
|
|
CONTROL_DOUBLE_TOP, // double wide and height (top)
|
|
CONTROL_DOUBLE_BOTTOM, // double wide and height (bottom)
|
|
CONTROL_SINGLE, // single wide and height
|
|
NCONTROL_CODES // number of conrol codes
|
|
};
|
|
|
|
struct controlCodes_t {
|
|
char sequence[MAX_SEQ]; // sequence
|
|
uint8_t len; // length
|
|
} controlCodes[NCONTROL_CODES] = {
|
|
{{ASCII_ESC, DEC_LEADIN, '2', 'J'}, 4},
|
|
{{ASCII_ESC, DEC_LEADIN, 'H'}, 3},
|
|
{{ASCII_ESC, '#', '3'}, 3},
|
|
{{ASCII_ESC, '#', '4'}, 3},
|
|
{{ASCII_ESC, '#', '5'}, 3},
|
|
};
|
|
|
|
// strings common to all menu types
|
|
char *whatItem = "??Try again->";
|
|
char *menuSpacer = "\r\n\n";
|
|
char *pauseString = "Hit enter to continue->";
|
|
char *selectItem = "Select an item->";
|
|
|
|
static char menu[100]; // Buffer for file items
|
|
int sel_item = 0; // selected item
|
|
uint8_t activeMenu; // active menu
|
|
|
|
// forward refs in this module
|
|
void printMenu(void); // print the menu
|
|
int getMenuItem(void); // get a menu item
|
|
void sendControlCode(uint8_t code);
|
|
BOOL pause(void);
|
|
void Print_Frame_stats(FRAME_STATS *stats);
|
|
void Print_Memory_Stats(void);
|
|
void Print_Radio_errors(uint32_t errs);
|
|
void Print_FSM_state(uint8_t state);
|
|
uint8_t getEntry(int activeMenu, int item);
|
|
uint8_t getKeyEntry(void);
|
|
|
|
// list of menus
|
|
enum {
|
|
MAIN_MENU=0, // main menu
|
|
RADIO_MENU, // radio params menu
|
|
STATION_MENU, // Station params menu
|
|
N_MENUS // number of menus
|
|
};
|
|
|
|
// menu return functions
|
|
enum {
|
|
RET_MORE=0, // more to do
|
|
RET_DONE, // done
|
|
RET_PAUSE // pause before leaving
|
|
};
|
|
|
|
/*
|
|
* The first part of this code contains the menus and processing routines
|
|
* handle the various menu options
|
|
* return TRUE if done, else FALSE
|
|
*/
|
|
uint8_t printAllSetup(void)
|
|
{
|
|
TIMEOFDAY tod;
|
|
getTOD(&tod);
|
|
|
|
USART_Print_string("Current firmware is at %d.%d\r\n",def_params.params.FirmwareVerMajor,
|
|
def_params.params.FirmwareVerMinor);
|
|
USART_Print_string("System time is %02d:%02d:%02d\r\n\n", tod.Hours, tod.Minutes, tod.Seconds);
|
|
|
|
printStationSetup();
|
|
printRadioSetup();
|
|
return RET_PAUSE;
|
|
}
|
|
//
|
|
uint8_t printStnSetup(void)
|
|
{
|
|
printStationSetup();
|
|
return RET_PAUSE;
|
|
}
|
|
//
|
|
uint8_t printRadSetup(void)
|
|
{
|
|
printRadioSetup();
|
|
return RET_PAUSE;
|
|
}
|
|
// list mesh status
|
|
uint8_t listMesh(void)
|
|
{
|
|
Mesh_ListStatus();
|
|
return RET_PAUSE;
|
|
}
|
|
|
|
// enter chat mode
|
|
uint8_t chatMode(void)
|
|
{
|
|
if(Chat_Task_exec())
|
|
return RET_PAUSE;
|
|
return RET_MORE;
|
|
}
|
|
|
|
// dump the rx stats
|
|
uint8_t showstats(void)
|
|
{
|
|
Print_Frame_stats(GetFrameStats());
|
|
Print_Radio_errors(GetRadioStatus());
|
|
Print_FSM_state(GetFSMState());
|
|
return RET_PAUSE;
|
|
}
|
|
|
|
// set the radio entry mode
|
|
uint8_t setRadio(void)
|
|
{
|
|
activeMenu = RADIO_MENU;
|
|
menuState = MENU_OFF;
|
|
return RET_DONE;
|
|
}
|
|
|
|
// set the station entry mode
|
|
uint8_t setStation(void)
|
|
{
|
|
activeMenu = STATION_MENU;
|
|
menuState = MENU_OFF;
|
|
return RET_DONE;
|
|
}
|
|
// enter chat mode
|
|
uint8_t ledTest(void)
|
|
{
|
|
if(LedTest())
|
|
return RET_PAUSE;
|
|
return RET_MORE;
|
|
}
|
|
// write the flash memory
|
|
uint8_t writeSetup(void)
|
|
{
|
|
if(!UpdateSetup()) {
|
|
USART_Print_string("Error in writing flash: setup may be corrupt\r\n");
|
|
} else {
|
|
USART_Print_string("Flash written successfully\r\n");
|
|
}
|
|
menuState = MENU_OFF;
|
|
return RET_PAUSE;
|
|
}
|
|
// exit the current menu
|
|
uint8_t exitMenu(void)
|
|
{
|
|
activeMenu = MAIN_MENU;
|
|
menuState = MENU_OFF;
|
|
return RET_DONE;
|
|
}
|
|
// set a parameter value
|
|
uint8_t setParam(void)
|
|
{
|
|
return(getEntry(activeMenu, sel_item));
|
|
}
|
|
/*
|
|
* These are conditional
|
|
*/
|
|
#if __ENABLE_GPS
|
|
uint8_t gpsEcho(void)
|
|
{
|
|
GPSEcho();
|
|
return(getKeyEntry());
|
|
}
|
|
#endif
|
|
#if __MEM_DEBUG
|
|
// memory statistics
|
|
uint8_t memStats(void)
|
|
{
|
|
Print_Memory_Stats();
|
|
return RET_PAUSE;
|
|
}
|
|
#endif
|
|
|
|
|
|
/*
|
|
* main menu definition
|
|
* 1) define the number of line items
|
|
* 2) create menuitms struct
|
|
* 3) add to menucontents struct
|
|
*/
|
|
struct menuItems_t {
|
|
char *menuLine; // text of menu line
|
|
char selChar; // character to select it
|
|
uint8_t (*func)(void); // processing function
|
|
};
|
|
|
|
// main menu
|
|
#if __ENABLE_GPS
|
|
#define N_GPS 1 // additional menu item for GPS
|
|
#else
|
|
#define N_GPS 0
|
|
#endif
|
|
|
|
#if __MEM_DEBUG
|
|
#define N_MEM 1 // additional menu item for memory
|
|
#else
|
|
#define N_MEM 0
|
|
#endif
|
|
|
|
#define N_MAINMENU (11+N_GPS+N_MEM) // additional menu item for GPS
|
|
|
|
struct menuItems_t mainMenu[N_MAINMENU] = {
|
|
{ "List setup parameters\r\n", 'A', printAllSetup },
|
|
{ "Mesh Status\r\n", 'B', listMesh },
|
|
{ "Chat Mode\r\n", 'C', chatMode },
|
|
{ "Dump Frame stats\r\n", 'D', showstats },
|
|
#if __ENABLE_GPS
|
|
{ "GPS Echo mode\r\n", 'G', gpsEcho },
|
|
#endif
|
|
{ "LED test\r\n", 'L', ledTest },
|
|
#if __MEM_DEBUG
|
|
{ "Memory Status\r\n", 'M', memStats },
|
|
#endif
|
|
{ "Set Radio Parameters\r\n", 'R', setRadio },
|
|
{ "Set Station Parameters\r\n", 'S', setStation },
|
|
{ "Set clock (HH:MM)\r\n\n", 'T', setParam },
|
|
{ "Write Setup Values\r\n", 'W', writeSetup },
|
|
{ "Exit\r\n\n", 'X', exitMenu }
|
|
};
|
|
|
|
// radio menu
|
|
#define N_RADIOMENU 8
|
|
struct menuItems_t radioMenu[N_RADIOMENU] = {
|
|
{ "RF Frequency\r\n", 'A', setParam },
|
|
{ "Data Rate\r\n", 'B', setParam },
|
|
{ "Peak Deviation\r\n", 'C', setParam },
|
|
{ "Channel Filter BW\r\n", 'D', setParam },
|
|
{ "Output Power (dBm)\r\n", 'E', setParam },
|
|
{ "Rx Squelch (dBm)\r\n\n", 'F', setParam },
|
|
{ "List Settings\r\n", 'L', printRadSetup },
|
|
{ "Return to main menu\r\n\n", 'X', exitMenu }
|
|
};
|
|
|
|
// these need to correspond to the items above
|
|
|
|
// station menu
|
|
#define N_STATIONMENU 8
|
|
struct menuItems_t stationMenu[N_STATIONMENU] = {
|
|
{ "Callsign\r\n", 'A', setParam },
|
|
{ "Latitude\r\n", 'B', setParam },
|
|
{ "Longitude\r\n", 'C', setParam },
|
|
{ "Grid Square\r\n", 'D', setParam },
|
|
{ "Repeat Default\r\n", 'E', setParam },
|
|
{ "Beacon Interval\r\n\n", 'F', setParam },
|
|
{ "List Settings\r\n", 'L', printStnSetup },
|
|
{ "Return to main menu\r\n\n", 'X', exitMenu }
|
|
};
|
|
|
|
// menu contents
|
|
struct menuContents_t {
|
|
char *title; // title of the menu
|
|
int nMenuLines; // number of lines
|
|
struct menuItems_t *menus; // menu items
|
|
} menuContents[N_MENUS] = {
|
|
#if _BOARD_TYPE==NUCLEO_BOARD
|
|
{ " IP400 Nucleo Main menu\r\n", N_MAINMENU, mainMenu },
|
|
#else
|
|
{ " IP400 Pi menu\r\n", N_MAINMENU, mainMenu },
|
|
#endif
|
|
{ " Radio setup menu\r\n", N_RADIOMENU, radioMenu },
|
|
{ " Station Setup menu\r\n", N_STATIONMENU, stationMenu }
|
|
};
|
|
|
|
// menu (main) task
|
|
void Menu_Task_Init(void)
|
|
{
|
|
// start off with the menu showing
|
|
activeMenu = MAIN_MENU;
|
|
menuState = MENU_SHOWING;
|
|
entryState = NO_ENTRY;
|
|
}
|
|
|
|
// send a control code
|
|
void sendControlCode(uint8_t code)
|
|
{
|
|
USART_Send_String(controlCodes[code].sequence, controlCodes[code].len);
|
|
}
|
|
|
|
// send a control code
|
|
void sendTextString(char *string)
|
|
{
|
|
strcpy(menu, string);
|
|
USART_Send_String(menu, strlen(string));
|
|
}
|
|
|
|
// process our time slot
|
|
void Menu_Task_Exec(void)
|
|
{
|
|
int nBytesinBuff = 0;
|
|
char c;
|
|
struct menuItems_t *m;
|
|
|
|
switch(menuState) {
|
|
|
|
// if there is a return in the console buffer,
|
|
// bring up the menu
|
|
case MENU_OFF:
|
|
if((nBytesinBuff=databuffer_bytesInBuffer()) == 0)
|
|
return;
|
|
for(int i=0;i<nBytesinBuff;i++)
|
|
if((c=databuffer_get(0)) == ASCII_RET)
|
|
menuState = MENU_SHOWING;
|
|
return;
|
|
|
|
case MENU_SHOWING:
|
|
printMenu();
|
|
menuState = MENU_SELECTING;
|
|
return;
|
|
|
|
case MENU_SELECTING:
|
|
if((sel_item=getMenuItem()) == NO_ITEM)
|
|
return;
|
|
menuState = MENU_SELECTED;
|
|
break;
|
|
|
|
case MENU_SELECTED:
|
|
m=menuContents[activeMenu].menus;
|
|
m += sel_item;
|
|
switch((*m->func)()) {
|
|
|
|
case RET_MORE:
|
|
break;
|
|
|
|
case RET_PAUSE:
|
|
sendTextString(pauseString);
|
|
menuState = MENU_PAUSED;
|
|
break;
|
|
|
|
case RET_DONE:
|
|
menuState = MENU_SHOWING;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case MENU_PAUSED:
|
|
if(pause())
|
|
menuState = MENU_SHOWING;
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
// print the main menu
|
|
void printMenu(void)
|
|
{
|
|
struct menuItems_t *m;
|
|
|
|
// title
|
|
sendControlCode(CONTROL_CLEAR);
|
|
sendControlCode(CONTROL_HOME);
|
|
|
|
#if _BOARD_TYPE==NUCLEO_BOARD
|
|
// only use double wide mode with Nucleo
|
|
sendControlCode(CONTROL_DOUBLE_TOP);
|
|
sendTextString(menuContents[activeMenu].title);
|
|
sendControlCode(CONTROL_DOUBLE_BOTTOM);
|
|
sendTextString(menuContents[activeMenu].title);
|
|
sendControlCode(CONTROL_SINGLE);
|
|
sendTextString(menuSpacer);
|
|
#else
|
|
sendTextString(menuContents[activeMenu].title);
|
|
sendTextString(menuSpacer);
|
|
#endif
|
|
|
|
// lines
|
|
int nMenuLines = menuContents[activeMenu].nMenuLines;
|
|
for(int i=0;i<nMenuLines;i++) {
|
|
m=menuContents[activeMenu].menus;
|
|
m += i;
|
|
menu[0] = m->selChar;
|
|
strcpy(&menu[1], ") ");
|
|
strcat(menu, m->menuLine);
|
|
USART_Send_String(menu, strlen(menu));
|
|
}
|
|
|
|
// selection
|
|
sendTextString(selectItem);
|
|
}
|
|
|
|
// get a menu item and dispatch the correct processing routine
|
|
int getMenuItem(void)
|
|
{
|
|
int nBytesinBuff =0;
|
|
struct menuItems_t *m;
|
|
char c;
|
|
|
|
if((nBytesinBuff=databuffer_bytesInBuffer()) == 0)
|
|
return NO_ITEM;
|
|
|
|
for(int i=0;i<nBytesinBuff;i++) {
|
|
if((c=databuffer_get(0)) != BUFFER_NO_DATA) {
|
|
|
|
// translate and echo
|
|
c = islower(c) ? toupper(c) : c;
|
|
USART_Send_Char(c);
|
|
|
|
// find the correct processing routine
|
|
int nMenuLines = menuContents[activeMenu].nMenuLines;
|
|
for(int j=0;j<nMenuLines;j++) {
|
|
m=menuContents[activeMenu].menus;
|
|
m += j;
|
|
if(m->selChar == c) {
|
|
sendTextString(menuSpacer);
|
|
return j;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
sendTextString(whatItem);
|
|
return NO_ITEM;
|
|
}
|
|
|
|
BOOL pause(void)
|
|
{
|
|
if(databuffer_bytesInBuffer() == 0)
|
|
return FALSE;
|
|
|
|
if(databuffer_get(0) == ASCII_RET)
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
/*
|
|
* This part pertains to getting an entry and validating it..
|
|
*/
|
|
|
|
// keys in entry mode
|
|
#define KEY_EOL 0x0D // carriage return
|
|
#define KEY_ESC 0x1B // escape key
|
|
#define KEY_DEL 0x7F // delete key
|
|
#define KEY_BKSP 0x08 // backspace key
|
|
|
|
#define MAX_ENTRY 40 // max entry chars
|
|
|
|
BOOL delMode = FALSE;
|
|
int pos = 0;
|
|
char keyBuffer[MAX_ENTRY];
|
|
|
|
// forward refs
|
|
uint8_t validateEntry(int activeMenu, int item, char *keyBuffer);
|
|
|
|
/*
|
|
* Get a key entry: basically stolen from chat.c
|
|
*/
|
|
uint8_t getKeyEntry(void)
|
|
{
|
|
|
|
char c;
|
|
int nBytesinBuff;
|
|
|
|
if((nBytesinBuff=databuffer_bytesInBuffer()) == 0)
|
|
return RET_MORE;
|
|
|
|
for(int i=0;i<nBytesinBuff;i++) {
|
|
|
|
c=databuffer_get(0);
|
|
|
|
if(delMode) {
|
|
if((c != KEY_DEL) && (c != KEY_BKSP)) {
|
|
USART_Print_string("\\%c", c);
|
|
if(pos < MAX_ENTRY)
|
|
keyBuffer[pos++] = c;
|
|
delMode = FALSE;
|
|
} else {
|
|
if(pos > 0) {
|
|
USART_Print_string("%c", keyBuffer[--pos]);
|
|
} else {
|
|
USART_Print_string("\\\r\n");
|
|
delMode = FALSE;
|
|
}
|
|
}
|
|
continue;
|
|
} else {
|
|
// processing a key
|
|
|
|
switch (c) {
|
|
|
|
// EOL key: sent the packet
|
|
case KEY_EOL:
|
|
USART_Print_string("\r\n");
|
|
keyBuffer[pos++] = '\0';
|
|
return RET_DONE;
|
|
break;
|
|
|
|
// escape key: abort the entry
|
|
case KEY_ESC:
|
|
return RET_PAUSE;
|
|
break;
|
|
|
|
case KEY_DEL:
|
|
case KEY_BKSP:
|
|
USART_Print_string("\\%c", keyBuffer[--pos]);
|
|
delMode = TRUE;
|
|
break;
|
|
|
|
default:
|
|
USART_Send_Char(c);
|
|
if(pos < MAX_ENTRY)
|
|
keyBuffer[pos++] = c;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return RET_MORE;
|
|
}
|
|
|
|
/*
|
|
* Get an entry and validate it
|
|
*/
|
|
uint8_t getEntry(int activeMenu, int item)
|
|
{
|
|
struct menuItems_t *m;
|
|
|
|
switch(entryState) {
|
|
|
|
case NO_ENTRY:
|
|
delMode = FALSE;
|
|
pos = 0;
|
|
entryState = ENTERING;
|
|
m=menuContents[activeMenu].menus;
|
|
m += item;
|
|
USART_Print_string("%s->", m->menuLine);
|
|
return RET_MORE;
|
|
|
|
case ENTERING:
|
|
int keyStat = getKeyEntry();
|
|
if(keyStat == RET_DONE) {
|
|
entryState = VALIDATING;
|
|
return RET_MORE;
|
|
}
|
|
return keyStat;
|
|
|
|
case VALIDATING:
|
|
entryState = NO_ENTRY;
|
|
return validateEntry(activeMenu, item, keyBuffer);
|
|
}
|
|
|
|
return RET_MORE;
|
|
}
|
|
|
|
// data types we are updating
|
|
enum {
|
|
uint8_type, // uint8 field
|
|
int16_type, // int16 field
|
|
uint32_type, // uint32 field
|
|
float_type, // floating point
|
|
char_type, // character type
|
|
field_type // field type
|
|
};
|
|
|
|
// struct to hold validation values
|
|
typedef struct field_validator_t {
|
|
int MinVal; // minimum value
|
|
int MaxVal; // maximum value
|
|
void *setupVal; // pointer to setup value
|
|
int type; // type of entry
|
|
uint32_t scalar; // scalar to convert to decimal
|
|
} FIELD_VALIDATOR;
|
|
|
|
// validators for radio mmenu
|
|
FIELD_VALIDATOR radioValidators[] = {
|
|
{ MIN_FREQ, 450000000, &setup_memory.params.radio_setup.lFrequencyBase, uint32_type, 1000000 },
|
|
{ 9600, 600000, &setup_memory.params.radio_setup.lDatarate, uint32_type, 1000 },
|
|
{ 12500, 150000, &setup_memory.params.radio_setup.lFreqDev, uint32_type, 1000 },
|
|
{ 2600, 1600000, &setup_memory.params.radio_setup.lBandwidth, uint32_type, 1000 },
|
|
{ 0, 20, &setup_memory.params.radio_setup.outputPower, uint8_type, 1 },
|
|
{ -115, 0, &setup_memory.params.radio_setup.rxSquelch, int16_type, 1 },
|
|
};
|
|
|
|
FIELD_VALIDATOR stationValidators[] = {
|
|
{ 4, 6, &setup_memory.params.setup_data.stnCall, char_type, 0 },
|
|
{ 2, 14, &setup_memory.params.setup_data.latitude, char_type, 0 },
|
|
{ 2, 14, &setup_memory.params.setup_data.longitude, char_type, 0 },
|
|
{ 6, 6, &setup_memory.params.setup_data.gridSq, char_type, 0 },
|
|
{ 0, 0x8, &setup_memory.params.setup_data.flags, field_type, 0 },
|
|
{ 1, 100, &setup_memory.params.setup_data.beaconInt, int16_type, 0 }
|
|
};
|
|
|
|
uint8_t validateEntry(int activeMenu, int item, char *keyBuffer)
|
|
{
|
|
|
|
int newValue, min, max;
|
|
|
|
//NB: the cases here must jive with the menu items
|
|
switch(activeMenu) {
|
|
|
|
case MAIN_MENU: // the only menu item here is the clock
|
|
setTOD(keyBuffer);
|
|
break;
|
|
|
|
case RADIO_MENU:
|
|
// convert a floating point entry to the required decimal
|
|
if(isfloat(keyBuffer))
|
|
newValue = (int)(ascii2double(keyBuffer)*radioValidators[item].scalar);
|
|
else newValue = ascii2Dec(keyBuffer);
|
|
max = radioValidators[item].MaxVal;
|
|
min = radioValidators[item].MinVal;
|
|
if((newValue<min) || (newValue>max)) {
|
|
USART_Print_string("Must be in the range of %d to %d\r\n", min, max);
|
|
return RET_PAUSE;
|
|
}
|
|
switch(radioValidators[item].type){
|
|
|
|
case uint8_type:
|
|
uint8_t *v8 = (uint8_t *)radioValidators[item].setupVal;
|
|
*v8 = (uint8_t)newValue;
|
|
break;
|
|
|
|
case int16_type:
|
|
int16_t *v16 = (int16_t *)radioValidators[item].setupVal;
|
|
*v16 = (int16_t)newValue;
|
|
break;
|
|
|
|
case uint32_type:
|
|
uint32_t *v32 = (uint32_t *)radioValidators[item].setupVal;
|
|
*v32 = (uint32_t)newValue;
|
|
break;
|
|
}
|
|
|
|
break;
|
|
|
|
case STATION_MENU:
|
|
switch(stationValidators[item].type){
|
|
|
|
case int16_type:
|
|
newValue = ascii2Dec(keyBuffer);
|
|
max = stationValidators[item].MaxVal;
|
|
min = stationValidators[item].MinVal;
|
|
if((newValue<min) || (newValue>max)) {
|
|
USART_Print_string("Must be in the range of %d to %d\r\n", min, max);
|
|
return RET_PAUSE;
|
|
}
|
|
uint16_t *v8 = (uint16_t *)stationValidators[item].setupVal;
|
|
*v8 = (uint16_t)newValue;
|
|
break;
|
|
|
|
case char_type:
|
|
size_t len = strlen(keyBuffer);
|
|
max = stationValidators[item].MaxVal;
|
|
min = stationValidators[item].MinVal;
|
|
if((len<min) || (len>max)) {
|
|
USART_Print_string("String must be %d to %d in length\r\n", min, max);
|
|
return RET_PAUSE;
|
|
}
|
|
strcpy((char *)stationValidators[item].setupVal, keyBuffer);
|
|
break;
|
|
|
|
case field_type:
|
|
uint8_t val = keyBuffer[0] == 'T' ? 1 : 0;
|
|
uint8_t *f8= (uint8_t *)stationValidators[item].setupVal;
|
|
if(val)
|
|
*f8 |= (uint8_t)stationValidators[item].MinVal;
|
|
else
|
|
*f8 &= (uint8_t)stationValidators[item].MinVal;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
}
|
|
|
|
// falls to here when done...
|
|
return RET_DONE;
|
|
}
|
|
|
|
|
|
/*
|
|
* Print the frame stats
|
|
*/
|
|
void Print_Frame_stats(FRAME_STATS *stats)
|
|
{
|
|
USART_Print_string("Frame Statistics\r\n\n");
|
|
|
|
USART_Print_string("Transmitted frames->%d\r\n", stats->TxFrameCnt);
|
|
USART_Print_string("CRC Errors->%d\r\n", stats->CRCErrors);
|
|
USART_Print_string("Rx Timeouts->%d\r\n", stats->TimeOuts);
|
|
USART_Print_string("Frames with good CRC->%d\r\n", stats->RxFrameCnt);
|
|
USART_Print_string("Beacon frames->%d\r\n", stats->nBeacons);
|
|
USART_Print_string("Repeated frames->%d\r\n", stats->nRepeated);
|
|
|
|
USART_Print_string("Processed Frames->%d\r\n", stats->RxFrameCnt);
|
|
USART_Print_string("Dropped frames->%d\r\n", stats->dropped);
|
|
USART_Print_string("Duplicate frames->%d\r\n", stats->duplicates);
|
|
USART_Print_string("Repeated frames->%d\r\n", stats->duplicates);
|
|
|
|
|
|
}
|
|
/*
|
|
* Print the radio error stats
|
|
*/
|
|
struct radio_errs_t {
|
|
uint32_t mask;
|
|
char *errmsg;
|
|
} radio_errs[N_RADIO_ERRS] = {
|
|
{ SEQ_COMPLETE_ERR, "Sequencer Error" },
|
|
{ SEQ_ACT_TIMEOUT, "Sequencer action timeout" },
|
|
{ PLL_CALAMP_ERR, "VCO Amplitude calibration error" },
|
|
{ PLL_CALFREQ_ERR, "VCO Frequency calibration error" },
|
|
{ PLL_UNLOCK_ERR, "PLL Unlocked" },
|
|
{ PLL_LOCK_FAIL, "PLL Lock failure" },
|
|
{ DBM_FIFO_ERR, "Data buffer FIFO error" }
|
|
};
|
|
//
|
|
void Print_Radio_errors(uint32_t errs)
|
|
{
|
|
if(errs == 0){
|
|
USART_Print_string("No radio errors\r\n");
|
|
return;
|
|
}
|
|
for(int i=0;i<N_RADIO_ERRS;i++)
|
|
if(errs & radio_errs[i].mask)
|
|
USART_Print_string("%s\r\n", radio_errs[i].errmsg);
|
|
}
|
|
/*
|
|
* Print the FSM state
|
|
*/
|
|
char *fsm_states[FSM_N_FSM_STATES] = {
|
|
"Idle",
|
|
"Enable RF registers",
|
|
"Wait for active 2",
|
|
"Active 2",
|
|
"Enable current",
|
|
"Synth setup",
|
|
"VCO calibration",
|
|
"Lock Rx and Rx",
|
|
"Llock on Rx",
|
|
"Enable PA",
|
|
"Transmit",
|
|
"Analog power down",
|
|
"End transmit",
|
|
"lock on Rx",
|
|
"Enable Rx",
|
|
"Enable LNA",
|
|
"Recieve",
|
|
"End rx",
|
|
"Synth power down"
|
|
};
|
|
void Print_FSM_state(uint8_t state)
|
|
{
|
|
if(state > FSM_N_FSM_STATES) {
|
|
USART_Print_string("\r\n?Unknown FSM state\r\n");
|
|
return;
|
|
}
|
|
USART_Print_string("\r\nRadio FSM State: %d: %s\r\n", state, fsm_states[state]);
|
|
}
|
|
|
|
#if __MEM_DEBUG
|
|
/*
|
|
* dump memory statistics
|
|
* uses the mallinfo structure
|
|
*/
|
|
void Print_Memory_Stats(void)
|
|
{
|
|
|
|
struct mallinfo memStats;
|
|
|
|
memStats = mallinfo();
|
|
|
|
USART_Print_string("Memory Statistics\r\n\n");
|
|
|
|
USART_Print_string("Total non-mapped bytes (arena)->%ld\r\n", memStats.arena);
|
|
USART_Print_string("Chunks not in use->%ld\r\n", memStats.ordblks);
|
|
USART_Print_string("Free fast bin blocks->%ld\r\n", memStats.smblks);
|
|
USART_Print_string("Mapped Regions->%ld\r\n", memStats.hblks);
|
|
USART_Print_string("Bytes in mapped regions->%ld\r\n\n", memStats.hblkhd);
|
|
|
|
USART_Print_string("Free bytes in fast bins->%ld\r\n", memStats.fsmblks);
|
|
USART_Print_string("Total Allocated Space->%ld\r\n", memStats.uordblks);
|
|
USART_Print_string("Total Space not in use->%ld\r\n", memStats.fordblks);
|
|
USART_Print_string("Topmost releasable block->%ld\r\n", memStats.keepcost);
|
|
|
|
}
|
|
#endif
|