// config.c #include "global.h" #include "ctboard.h" #include "serial.h" #include "config.h" #include "loop.h" #include "command.h" #include "rprintf.h" #include #include // current menu entry: #define MENU_OFF 0 #define MENU_BAUD 1 #define MENU_ECHO 2 #define MENU_RXLE 3 #define MENU_TXLE 4 #define MENU_EEPROM 5 #define MENU_NUM 6 // ----- prototypes ----- static void saveConfigToEEPROM(void); static byte loadConfigFromEEPROM(void); static void changeMenu(byte up); // ----- local vars ----- static byte menuMode = MENU_OFF; // current pos in sniff sequence static byte linkSeqPos = 0; // do we need a hardware update static byte needHWUp = 0; // currently in link mode static byte linked = 0; // map calibration: lower and upper sample value static u16 adcL=0,mapL=0,adcU=10,mapU=10; // ----- CONFIG BYTES ----- #define MAX_LINK_START_CMD 8 typedef struct { u16 adcMin[2],adcMax[2]; u16 mapMin[2],mapMax[2]; byte baudRate; byte startLinked; byte sniff; byte source; byte rxLineEnd; byte txLineEnd; byte echo; byte linkStartLen; byte linkStartCmd[MAX_LINK_START_CMD]; byte checkSum; } config_t; config_t config = { .adcMin = { 0,0 }, .adcMax = { 0x3ff,0x3ff }, .mapMin = { 0,0 }, .mapMax = { 100,100 }, .baudRate = BAUD_RATE_9600, .startLinked = 0, .sniff = 1, .source = MPLEX_SRC_XPT, .rxLineEnd = LINE_END_CR, .txLineEnd = LINE_END_CRLF, .echo = 1, .linkStartLen = 2, .linkStartCmd = {'l','c'} }; // eeprom config config_t configEEPROM __attribute__ ((section (".eeprom"))); // ---------- remap ADC value ---------- u16 remapADC(byte port,u16 value) { u16 adcRange = config.adcMax[port] - config.adcMin[port]; u16 realRange = config.mapMax[port] - config.mapMin[port]; if(valueconfig.adcMax[port]) return config.mapMax[port]; value -= config.adcMin[port]; u32 vl = (u32)value; u32 ar = (u32)adcRange; u32 rr = (u32)realRange; u32 rs = vl * rr / ar; u16 r = (u16)rs; r += config.mapMin[port]; return r; } // ----- calibMapping ----- // setup the adc and map range for an ADC port // a linear monotonous mapping from adc to map // given are the two samples (adcL,mapL) and (adcU,mapU) // with adcL < adcU and mapL < mapU #define ADC_MAX 0x03ff #define MAP_MAX 0xffff byte calibMapping(byte port) { // check parameters if((adcL>=adcU)||(mapL>=mapU)) return EXEC_ERROR; u16 adcDelta = adcU - adcL; u16 mapDelta = mapU - mapL; u32 md = (u32)mapDelta; u32 ad = (u32)adcDelta; u32 ml = (u32)mapL; u32 al = (u32)adcL; // ----- determine ADC range ----- u32 A = al * md; u32 B = ad * ml; u32 pos; // MIN: origin if(A == B) { config.mapMin[port] = 0; config.adcMin[port] = 0; } // MIN: limit ADC range else if(A > B) { pos = B / md; config.mapMin[port] = 0; config.adcMin[port] = (u16)pos; } //MIN: limit MAP range else { pos = A / ad; config.mapMin[port] = ml - (u16)pos; config.adcMin[port] = 0; } A = (MAP_MAX - ml) * ad; B = (ADC_MAX - al) * md; // MAX: both max if(A == B) { config.mapMax[port] = MAP_MAX; config.adcMax[port] = ADC_MAX; } // MAX: limit MAP range else if(A > B) { pos = B / ad; config.mapMax[port] = ml + (u16)pos; config.adcMax[port] = ADC_MAX; } // MAX: limit ADC range else { pos = A / md; config.mapMax[port] = MAP_MAX; config.adcMax[port] = al + (u16)pos; } return EXEC_OK; } // ---------- HW Update & Init ---------- byte needHWUpdate(void) { return needHWUp; } void doHWUpdate(void) { needHWUp = 0; setMplex(linked,config.source); setBaud(config.baudRate); ct_beep(1); } void initConfig() { // load fails... beep and save default if(!loadConfigFromEEPROM()) { ct_beep(3); saveConfigToEEPROM(); } linked = config.startLinked; doHWUpdate(); } static void linkStart(void) { needHWUp = 1; linked = 1; } static void linkEnd(void) { needHWUp = 1; linked = 0; } byte isLinked(void) { return linked; } // ----- check link stard cmd ----- void checkLinkStartCmd(byte b) { byte found = 0; byte retry = 0; // CRLF mode: start sequence finally found? if(linkSeqPos == config.linkStartLen+1) { if(b == '\n') found = 1; else retry = 1; } // CR, LF mode: check for final char else if(linkSeqPos == config.linkStartLen) { // check for LF,CR,CRLF if(config.rxLineEnd==LINE_END_LF) { if(b == '\n') found = 1; else retry = 1; } else if(config.rxLineEnd==LINE_END_CR) { // CR/CRLF if(b == '\r') found = 1; else retry = 1; } else { // CRLF if(b == '\r') linkSeqPos++; else retry = 1; } } // still in start sequence? else if(b == config.linkStartCmd[linkSeqPos]) linkSeqPos++; else retry = 1; // restart search if(retry) { linkSeqPos = 0; if(b == config.linkStartCmd[0]) linkSeqPos++; } // found sequence start -> enter link mode if(found) linkStart(); } byte cmdExit(void) { linkEnd(); return EXEC_QUIT; } // ---------- key handling --------- void handleMenuKeys(byte keys) { // RED: next menu item if(keys & CT_LED_RED) { menuMode++; if(menuMode==MENU_NUM) menuMode=1; } // ORANGE: dec value if(keys & CT_LED_ORANGE) { changeMenu(0); } // YELLOW: inc value if(keys & CT_LED_YELLOW) { changeMenu(1); } // GREEN: leave menu if(keys & CT_LED_GREEN) { menuMode = 0; } } void handleNormalKeys(byte keys) { // RED: enter menu if(keys & CT_LED_RED) { menuMode = 1; } // ORANGE: toggle source if(keys & CT_LED_ORANGE) { if(config.source == MPLEX_SRC_XPT) config.source = MPLEX_SRC_COM; else config.source = MPLEX_SRC_XPT; needHWUp = 1; } // YELLOW: toggle pass/sniff if(keys & CT_LED_YELLOW) { config.sniff = 1-config.sniff; } // GREEN: enter link mode if(keys & CT_LED_GREEN) { linkStart(); } } static void handleLinkKeys(byte keys) { // RED: key command if(keys & CT_LED_RED) { keyCommand(0); } // ORANGE: key command if(keys & CT_LED_ORANGE) { keyCommand(1); } // YELLOW: key command if(keys & CT_LED_YELLOW) { keyCommand(2); } // GREEN: leave link mode if(keys & CT_LED_GREEN) { linkEnd(); } } void handleKeys(byte keys) { if(menuMode!=MENU_OFF) return handleMenuKeys(keys); else if(linked) return handleLinkKeys(keys); else return handleNormalKeys(keys); } // ---------- status ---------- static void showStatusOnLCD(void) { byte *str; ct_lcd_clear(); // current connection src if(config.source==MPLEX_SRC_XPT) rprintfStr("XPort "); else rprintfStr("RS232 "); // current connection mode if(linked) rprintfStr("LINK "); else if(config.sniff) rprintfStr("snif "); else rprintfStr("pass "); // baud baud rate switch(config.baudRate) { case BAUD_RATE_9600: str = " 9.6"; break; case BAUD_RATE_19200: str = " 19.2"; break; case BAUD_RATE_38400: str = " 38.4"; break; case BAUD_RATE_57600: str = " 57.6"; break; case BAUD_RATE_115200:str = "115.2"; break; default: str = "?"; break; } rprintfStr(str); } static void showStatusOnLEDs(void) { // RED/ORANGE: connection src if(config.source == MPLEX_SRC_COM) { ct_led_on (CT_LED_RED); ct_led_off(CT_LED_ORANGE); } else { ct_led_off(CT_LED_RED); ct_led_on (CT_LED_ORANGE); } // YELLOW: green led is sniff mode LED if(config.sniff) ct_led_on (CT_LED_YELLOW); else ct_led_off(CT_LED_YELLOW); // GREEN: connection mode if(linked) ct_led_on (CT_LED_GREEN); else ct_led_off(CT_LED_GREEN); } void showStatus(void) { if((menuMode==MENU_OFF)&&(!linked)) showStatusOnLEDs(); showStatusOnLCD(); } // ---------- menu control ---------- byte isMenuOpen(void) { return menuMode != MENU_OFF; } static void showOnOffOnLCD(byte value) { if(value) rprintfStr("on"); else rprintfStr("off"); } static void showLineEndOnLCD(byte value) { if(value==LINE_END_LF) rprintfStr("LF"); else if(value==LINE_END_CR) rprintfStr("CR"); else rprintfStr("CRLF"); } static void showMenuOnLCD(void) { ct_lcd_pos(0,1); rprintfChar('@'); switch(menuMode) { default: break; case MENU_BAUD: rprintfStr("baud rate"); break; case MENU_ECHO: rprintfStr("echo char: "); showOnOffOnLCD(config.echo); break; case MENU_RXLE: rprintfStr("rx eol: "); showLineEndOnLCD(config.rxLineEnd); break; case MENU_TXLE: rprintfStr("tx eol: "); showLineEndOnLCD(config.txLineEnd); break; case MENU_EEPROM: rprintfStr("save/load"); break; } } static void showOnOffOnLEDs(byte value) { ct_led_off(CT_LED_ALL); if(value) ct_led_on(CT_LED_GREEN); else ct_led_on(CT_LED_RED); } static void showValueOnLEDs(byte value) { ct_led_off(CT_LED_ALL); if(value==0) ct_led_on(CT_LED_RED); else if(value==1) ct_led_on(CT_LED_ORANGE); else if(value==2) ct_led_on(CT_LED_YELLOW); else ct_led_on(CT_LED_GREEN); } static void showMenuOnLEDs(void) { switch(menuMode) { default: break; case MENU_BAUD: ct_led_bits(config.baudRate+1); break; case MENU_ECHO: showOnOffOnLEDs(config.echo); break; case MENU_RXLE: showValueOnLEDs(config.rxLineEnd); break; case MENU_TXLE: showValueOnLEDs(config.txLineEnd); break; case MENU_EEPROM: ct_led_off(CT_LED_ALL); break; } } void showMenu(void) { showMenuOnLCD(); showMenuOnLEDs(); } static void changeMenu(byte up) { switch(menuMode) { default: break; case MENU_BAUD: if(up) { if(config.baudRate0) config.baudRate--; } needHWUp = 1; break; case MENU_ECHO: config.echo = up; break; case MENU_RXLE: if(up) { if(config.rxLineEnd0) config.rxLineEnd--; } break; case MENU_TXLE: if(up) { if(config.txLineEnd0) config.txLineEnd--; } break; case MENU_EEPROM: if(up) { if(!loadConfigFromEEPROM()) ct_beep(3); else ct_beep(1); } else { saveConfigToEEPROM(); ct_beep(1); } break; } } // ---------- command ---------- byte cmdConfig(byte *cmd) { byte port; u16 value,value2; switch(cmd[0]) { // load/save case 'S': // cs - save config to EEPROM saveConfigToEEPROM(); break; case 'L': // cl - load config from EEPROM if(!loadConfigFromEEPROM()) return EXEC_ERROR; break; // settings case 'e': // ce0 ce1 - set echo mode, ce - print echo mode if(cmd[1]=='0') config.echo = 0; else if(cmd[1]=='1') config.echo = 1; else if(cmd[1]!=0) return EXEC_ERROR; rprintfChar('0'+config.echo); return EXEC_OK | EXEC_RESULT; case 'r': // rx eol: 0=LF 1=CR 2=CR+LF if(parseNibble(cmd[1],&port)) { if(port>LINE_END_LAST) return EXEC_ERROR; config.rxLineEnd = port; } rprintfu04(config.rxLineEnd); return EXEC_OK | EXEC_RESULT; case 't': // tx eol: 0=LF 1=CR 2=CR+LF if(parseNibble(cmd[1],&port)) { if(port>LINE_END_LAST) return EXEC_ERROR; config.txLineEnd = port; } rprintfu04(config.txLineEnd); return EXEC_OK | EXEC_RESULT; case 'b': // set baud rate if(parseNibble(cmd[1],&port)) { if(port>BAUD_RATE_LAST) return EXEC_ERROR; config.baudRate = port; } rprintfu04(config.baudRate); return EXEC_OK | EXEC_RESULT; case 'k': // set key word if(cmd[1]!=0) { cmd++; byte len = 0; while(cmd[len]!=0) { config.linkStartCmd[len] = cmd[len]; len++; } config.linkStartLen = len; } rprintfStrLen(config.linkStartCmd,0,config.linkStartLen); return EXEC_OK | EXEC_RESULT; case 's': // set link source: 0=COM 1=LAN if(parseNibble(cmd[1],&port)) { if(port>1) return EXEC_ERROR; config.source = port; } rprintfu04(config.source); return EXEC_OK | EXEC_RESULT; case 'l': // set link state: 1=link 0=sniff/pass-through if(parseNibble(cmd[1],&port)) { if(port>1) return EXEC_ERROR; config.startLinked = port; } rprintfu04(config.startLinked); return EXEC_OK | EXEC_RESULT; case 'i': // set sniff mode: 1=sniff 0=pass-through if(parseNibble(cmd[1],&port)) { if(port>1) return EXEC_ERROR; config.sniff = port; } rprintfu04(config.sniff); return EXEC_OK | EXEC_RESULT; case 'm': // real range mapping if(cmd[1]=='r') { if(cmd[2]=='l') { // lower sample value = adcL; value2 = mapL; } else if(cmd[2]=='u') { // upper sample value = adcU; value2 = mapU; } else { if(!parseNibble(cmd[2],&port)) return EXEC_ERROR; if(port>1) return EXEC_ERROR; if(cmd[3]=='a') { // get adc range value = config.adcMin[port]; value2 = config.adcMax[port]; } else if(cmd[3]=='m') { // get map range value = config.mapMin[port]; value2 = config.mapMax[port]; } else return EXEC_ERROR; } } else if(cmd[1]=='w') { byte pos = 4; if((cmd[2]=='l')||(cmd[2]=='u')) pos = 3; if(!parseWord(&cmd[pos],&value)) return EXEC_ERROR; if(!parseWord(&cmd[pos+5],&value2)) return EXEC_ERROR; if(cmd[2]=='l') { // lower sample adcL = value; mapL = value2; } else if(cmd[2]=='u') { // upper sample adcU = value; mapU = value2; } else { if(!parseNibble(cmd[2],&port)) return EXEC_ERROR; if(port>1) return EXEC_ERROR; if(cmd[3]=='a') { // set adc range config.adcMin[port] = value; config.adcMax[port] = value2; } else if(cmd[3]=='m') { // set map range config.mapMin[port] = value; config.mapMax[port] = value2; } else return EXEC_ERROR; } } else if(cmd[1]=='c') { // calibrate with lower and upper sample if(!parseNibble(cmd[2],&port)) return EXEC_ERROR; if(port>1) return EXEC_ERROR; return calibMapping(port); } else return EXEC_ERROR; rprintfu16(value); rprintfChar(' '); rprintfu16(value2); return EXEC_OK | EXEC_RESULT; default: return EXEC_ERROR; } return EXEC_OK; } // ---------- query config ---------- byte isStartLinked(void) { return config.startLinked; } byte isSniff(void) { return config.sniff; } byte doEcho(void) { return config.echo; } void sendEOL(void) { sendLineEnd(config.txLineEnd); } void sendLineEOL(const byte *line) { sendLine(config.txLineEnd,line); } byte isEOL(byte b) { if(b=='\r') { if(config.rxLineEnd==LINE_END_CR) return 1; else if(config.rxLineEnd==LINE_END_CRLF) return 2; else return 0; } else if(b=='\n') { if(config.rxLineEnd!=LINE_END_CR) return 1; else return 0; } else return 0; } // ---------- eeprom ---------- void saveConfigToEEPROM(void) { // calc check sum config.checkSum = 0; byte *adr = (byte *)&config; byte sum = 0; for(byte i=0;i