<commit_before>/*
 * V2X_menu.c
 *
 * Created: 2/23/2016 9:00:14 AM
 *  Author: jbanks2
 */ 

#include "V2X.h"
#include "ctype.h"

char CMD_buffer [30] = "\0";
uint8_t sample[6] = {0,0,0,0,0,0};

void menu_add_to_command(char value) {
	if (value == 8 || value == 0x7f) {//if backspace or delete
		int leng = strlen(CMD_buffer); //get buffer sting length
		if (leng > 0) {	//if length not 0
			CMD_buffer[leng-1] = '\0';	//null out the last char
		}
	} else if (value > 0x20 && value < 0x7E ) {		//if in ascii set
		strcat(CMD_buffer, &value);					//store to buffer
	}
}

void menu_main(void) {
	for(int i = 0; i < 4; i++){
		CMD_buffer[i] = tolower(CMD_buffer[i]);
	}
	if (CMD_buffer[0] == 'v' && CMD_buffer[1] == 'x') {
		switch(CMD_buffer[2]) {
			case 'i': //information
				usb_tx_string_P(PSTR("Vehicle to Everything (V2X) RVI Node 2016\rOpen source hardware and software\rHW Rev1.2 \rSW Rev0.1\r"));
				break;
			case 'j': //Jaguar
				usb_tx_string_P(PSTR("\r\r   ,ggp@@@@mgg,,\r,$Q$(`S@@$;g$$$$$@$@@gg,\r;gP'$@gg)$$@@$@@@$(L$$||$$@g,\r  `g$P`  ``*%@@@P`)Eg|||lLLL||$Bgg,\r    `       ,gg$$@gg,`$..``$Z$$$$$EB$$@g,\r         @P`pgg$$$||`)gggg;,,     |$$$|$$$@g,\r         9w&    '*^^` ``*P#9BB00000$$$@|`$$$g|Sg,\r                                    *$@@L ```T$W~)%g,\r                                      *%@gg,,,,,    5/Sw,     ,\r                                          ```` ` `9g `9g,``*^|'\r                                                    `#g,`)h\r\r   Developed at Jaguar Land Rover OSCT. Portland OR 2016\r"));
				break;
			case 'q':
				menu_status();
				break;
			case 'r':  //reset
				reset_trigger_SYSTEM();
				break;
			case 'a':  //accel
				menu_accel();
				break;
			case 'c':  //CAN interface
				menu_can();
				break;
			case 's':  //start all modules
				GSM_modem_init();
				CAN_elm_init();
				ACL_set_sample_on();
				break;
			case 'm':  //modem
				menu_modem();
				break;
			case 'p':  //power
				menu_power();
				break;
			case 't':  //timer functions
				menu_timer();
				break;
			case '?':  //timer functions
			default:
				usb_tx_string_P(PSTR("*** Main Menu ***\rI: Device information\rA: Accelerometer menu(ACL)\rC: ELM327 menu(CAN)\rM: SIM Modem menu(GSM)\rP: Power menu\rT: Timer menu\rQ: Query system status\rS: Start System\rR: Reboot\r"));
				break;
			}
	}else{
			usb_tx_string_P(PSTR("All commands start VX\r"));
	}
	clear_buffer(CMD_buffer);	//clear the buffer for next command	
	menu_send_n_st();
}

void menu_accel (void) {
	int speed, data16;
	switch (CMD_buffer[3]) {
	case 'd':  //disable
		ACL_set_sample_off();
		usb_tx_string_P(PSTR("Accelerometer is off\r"));
		break;
	case 'e':  //enable
		ACL_set_sample_on();
		usb_tx_string_P(PSTR("Accelerometer has been started\r"));
		break;
	case 'i':
		usb_tx_string_P(PSTR("V2X uses the ADXL345 accelerometer from Analog Devices\r"));
		break;
	case 'q':
		menu_accel_status();
		break;
	case 'r':  //restart
		ACL_set_sample_off();
		ACL_take_sample(sample); //pushes "off" command
		ACL_init(); //
		ACL_set_sample_on();
		ACL_take_sample(sample); //pushes init
		usb_tx_string_P(PSTR("Accelerometer has been restarted\r"));
		break;
	case 's':  //sample rate
 		speed = atoi(CMD_buffer+4);
		if (speed > 3199) {
			ACL_set_rate(ACL_RATE_3200);	
			usb_tx_string_P(PSTR("Set to 3200Hz\r"));
		}else if (speed > 1599) {
			ACL_set_rate(ACL_RATE_1600);
			usb_tx_string_P(PSTR("Set to 1600Hz\r"));
		}else if (speed > 799) {
			ACL_set_rate(ACL_RATE_800);
			usb_tx_string_P(PSTR("Set to 800Hz\r"));
		}else if (speed > 399) {
			ACL_set_rate(ACL_RATE_400);
			usb_tx_string_P(PSTR("Set to 400Hz\r"));
		}else if (speed > 199) {
			ACL_set_rate(ACL_RATE_200);
			usb_tx_string_P(PSTR("Set to 200Hz\r"));
		}else if (speed > 99) {
			ACL_set_rate(ACL_RATE_100);
			usb_tx_string_P(PSTR("Set to 100Hz\r"));
		}else if (speed > 49) {
			ACL_set_rate(ACL_RATE_50);
			usb_tx_string_P(PSTR("Set to 50Hz\r"));
		}else if (speed > 24) {
			ACL_set_rate(ACL_RATE_25);
			usb_tx_string_P(PSTR("Set to 25Hz\r"));
		}else if (speed > 11) {
			ACL_set_rate(ACL_RATE_12);
			usb_tx_string_P(PSTR("Set to 12Hz\r"));
		}else if (speed > 5) {
			ACL_set_rate(ACL_RATE_6);
			usb_tx_string_P(PSTR("Set to 6Hz\r"));
		}else if (speed > 2) {
			ACL_set_rate(ACL_RATE_3);
			usb_tx_string_P(PSTR("Set to 3Hz\r"));
		}else if (speed > 0) {
			ACL_set_rate(ACL_RATE_1);
			usb_tx_string_P(PSTR("Set to 1Hz\r"));
 		}else {	
			usb_tx_string_P(PSTR("ERROR: Out of range, try again.\r"));	
		}
		break;
	case 'w':
		speed = atoi(CMD_buffer+4);
		if (speed > 16) {speed = 0;}
		if (speed > 8) {
			ACL_set_range(ACL_16G_RANGE);
			usb_tx_string_P(PSTR("+/-16G Range\r"));
		}else if (speed > 4) {
			ACL_set_range(ACL_8G_RANGE);
			usb_tx_string_P(PSTR("+/-8G Range\r"));
		}else if (speed > 2) {
			ACL_set_range(ACL_4G_RANGE);
			usb_tx_string_P(PSTR("+/-4G Range\r"));
		}else if (speed > 0) {
			ACL_set_range(ACL_2G_RANGE);
			usb_tx_string_P(PSTR("+/-2G Range\r"));
		}else {menu_send_out_of_range();}
		break;
		
	case 'x':
	case 'y':
	case 'z':
		data16 = atoi(CMD_buffer+4);  //convert input chars to int
		if (data16 == 0){ //conversion resulted in 0
			if (CMD_buffer[4] != '0'){ //check if it is really a '0' of an invalad conversion
				menu_send_out_of_range(); //invalid result
				break; //exit offset menu
			}
		}
		if (data16 < -127 || data16 > 127) {  //must be 16 to detect out of range
			menu_send_out_of_range();
		} else {
			uint8_t data8 = (uint8_t)data16;  //reduce to 8 bits of data
			switch (CMD_buffer[3]) {
				case 'x':
					usb_tx_string_P(PSTR("X"));
					ACL_set_offset(ACL_X_OFFSET, data8);
					break;
				case 'y':
					usb_tx_string_P(PSTR("Y"));
					ACL_set_offset(ACL_Y_OFFSET, data8);
					break;
				case 'z':
					usb_tx_string_P(PSTR("Z"));
					ACL_set_offset(ACL_Z_OFFSET, data8);
					break;
				default:
					menu_send_q();
					break;
			}
			usb_tx_string_P(PSTR(" Offset: "));
			menu_print_int(data16);
			menu_send_n();
		}
		break;
	case 'g':
		if (ACL_sampling()){
			if (usb_cdc_is_active(USB_ACL)) {
				ACL_get_last_sample(sample);
			} else {
				ACL_take_sample(sample);
			}
			ACL_data_to_string(sample, CMD_buffer); 
			for (int i = 0; i < strlen(CMD_buffer); i++)
				{usb_cdc_send_byte(USB_CMD, CMD_buffer[i]);}
		} else {
			usb_tx_string_P(PSTR("ERROR: Not currently sampling, use VXAE\r"));}
		
		break;
	case 'f':
		if (CMD_buffer[4] == '0') {
			ACL_set_full_resolution(0);
			usb_tx_string_P(PSTR("10bit resolution, scale changes with 'G' range\r"));
		}
		else if (CMD_buffer[4] == '1') {
			ACL_set_full_resolution(1);
			usb_tx_string_P(PSTR("Full resolution, 4mg/bit\r"));
		}
		else {menu_send_q();}
		break;
	case '?':  
	default:
		usb_tx_string_P(PSTR("*** Accelerometer Menu ***\rE: Enable\rD: Disable\rR: Restart\rI: Subsystem Information\rQ: Query status\rG: Get last Sample\rSn: Set sample rate in HZ (1, 3, 6, 12, 25, 50, 100, 200, 400, 800)\rWn: Set \"G\" Range (2, 4, 8, 16)\rF: Full range (1: full 0: 10bit)\rXn: Set X offset (+/-127)\rYn: Set Y offset\rZn: Set Z offset\r"));
		break;
	}
}

void menu_modem (void) {
	int i; 
	switch (CMD_buffer[3]) {
	case 'd':  
		PWR_gsm_stop(); //disable
		usb_tx_string_P(PSTR("GSM is off\r"));
		break;
	case 'e':  //enable modem
		usb_tx_string_P(PSTR("GSM Start pending"));
		GSM_modem_init();
		break;
	case 'r':  //reset
		reset_trigger_GSM();
		usb_tx_string_P(PSTR("GSM restarting\r"));
		break;
	case 'q':
		menu_modem_status();
		break;
	case 'i':
		usb_tx_string_P(PSTR("V2X uses the SIM5320A 3G GSM modem + GPS receiver by SIMCOM\r"));
		break;
	case 'x':
		strcat_P(CMD_buffer, PSTR("\r\n"));  //put these char at the end of the string
		GSM_add_string_to_buffer(BUFFER_OUT, &CMD_buffer[4]); //send it on to the modem
		GSM_mark_for_processing(BUFFER_OUT); //initiate send
 		break;
	case '?':
	default:
		usb_tx_string_P(PSTR("*** Modem Menu ***\rE: Enable\rD: Disable\rR: Restart\rI: Subsystem Information\rQ: Query status\rX: AT Command Pass through\r"));
		break;
	}
}

void menu_can (void) {
	int i;
	char buffer[EE_CAN_ARRAY_SIZE+1];
	switch (CMD_buffer[3]) {
	case 'd':  //disable;
		usb_tx_string_P(PSTR("CAN is off\r"));
		PWR_can_stop();
		PWR_is_5_needed();
		break;
	case 'e':  //enable
		usb_tx_string_P(PSTR("CAN Starting\r"));
		CAN_elm_init();
		break;
	case 'r':  //reset
		usb_tx_string_P(PSTR("CAN restarting\r"));
		reset_trigger_CAN();
		break;
	case 'q': //query
		menu_can_status();
		break;
	case 'i': //info
		usb_tx_string_P(PSTR("V2X uses the STN1110 CANbus interface from Scantool\r"));
		usb_tx_string_P(PSTR("The STN1110 is compliant with the ELM327 V1.3\r"));
		break;
	case 'x': //pass command
		strcat_P(CMD_buffer, PSTR("\r"));
		
		CAN_add_string_to_buffer(BUFFER_OUT, CMD_buffer+4);
		CAN_mark_for_processing(BUFFER_OUT);
		CAN_start_snoop();
		break;
	case 's':  //save string to eeprom
		//strcat_P(CMD_buffer, PSTR("\r"));
		eeprom_store_CAN_string(CMD_buffer+4);
		break;
	case 'a': //load string and parse from eeprom
// 		eeprom_read_CAN_string(buffer);
// 		usb_cdc_send_string(USB_CMD, buffer);
// 		menu_send_n();
// 		//CAN_can_start();
// 		CAN_find_message(buffer,0);
		CAN_EE_start();
		break;
	case '?':
	default:
		usb_tx_string_P(PSTR("*** CANbus Menu ***\rE: Enable\rD: Disable\rR: Restart\rI: Subsystem Information\rQ: Query status\r"));
		break;
	}
}

void menu_power (void) {
	switch (CMD_buffer[3]) {
	case 'd':  //disable power
		switch (CMD_buffer[4]) {
		case '3':  //3v
			menu_send_ok();
			usb_tx_string_P(PSTR("Shutting down V2X in 30 seconds\r"));
			delay_s(30);
			PWR_turn_off((1<<ENABLE_3V3));
			PWR_push();
			break;
		case '4':  //4v
			PWR_turn_off((1<<ENABLE_4V1)|(1<<ENABLE_SIM_RESET));
			PWR_push();
			menu_send_ok();
			break;
		case '5':  //5v
			PWR_turn_off((1<<ENABLE_5V0)|(1<<ENABLE_5V0B)|(1<<ENABLE_CAN_RESET));
			PWR_push();<commit_msg>added menu defs and func for EE commands<commit_after>/*
 * V2X_menu.c
 *
 * Created: 2/23/2016 9:00:14 AM
 *  Author: jbanks2
 */ 

#include "V2X.h"
#include "ctype.h"

char CMD_buffer [30] = "\0";
uint8_t sample[6] = {0,0,0,0,0,0};

void menu_add_to_command(char value) {
	if (value == 8 || value == 0x7f) {//if backspace or delete
		int leng = strlen(CMD_buffer); //get buffer sting length
		if (leng > 0) {	//if length not 0
			CMD_buffer[leng-1] = '\0';	//null out the last char
		}
	} else if (value > 0x20 && value < 0x7E ) {		//if in ascii set
		strcat(CMD_buffer, &value);					//store to buffer
	}
}

void menu_main(void) {
	for(int i = 0; i < 4; i++){
		CMD_buffer[i] = tolower(CMD_buffer[i]);
	}
	if (CMD_buffer[0] == 'v' && CMD_buffer[1] == 'x') {
		switch(CMD_buffer[2]) {
			case 'i': //information
				usb_tx_string_P(PSTR("Vehicle to Everything (V2X) RVI Node 2016\rOpen source hardware and software\rHW Rev1.2 \rSW Rev0.1\r"));
				break;
			case 'j': //Jaguar
				usb_tx_string_P(PSTR("\r\r   ,ggp@@@@mgg,,\r,$Q$(`S@@$;g$$$$$@$@@gg,\r;gP'$@gg)$$@@$@@@$(L$$||$$@g,\r  `g$P`  ``*%@@@P`)Eg|||lLLL||$Bgg,\r    `       ,gg$$@gg,`$..``$Z$$$$$EB$$@g,\r         @P`pgg$$$||`)gggg;,,     |$$$|$$$@g,\r         9w&    '*^^` ``*P#9BB00000$$$@|`$$$g|Sg,\r                                    *$@@L ```T$W~)%g,\r                                      *%@gg,,,,,    5/Sw,     ,\r                                          ```` ` `9g `9g,``*^|'\r                                                    `#g,`)h\r\r   Developed at Jaguar Land Rover OSCT. Portland OR 2016\r"));
				break;
			case 'q':
				menu_status();
				break;
			case 'r':  //reset
				reset_trigger_SYSTEM();
				break;
			case 'a':  //accel
				menu_accel();
				break;
			case 'c':  //CAN interface
				menu_can();
				break;
			case 's':  //start all modules
				GSM_modem_init();
				CAN_elm_init();
				ACL_set_sample_on();
				break;
			case 'm':  //modem
				menu_modem();
				break;
			case 'p':  //power
				menu_power();
				break;
			case 't':  //timer functions
				menu_timer();
				break;
			case '?':  //timer functions
			default:
				usb_tx_string_P(PSTR("*** Main Menu ***\rI: Device information\rA: Accelerometer menu(ACL)\rC: ELM327 menu(CAN)\rM: SIM Modem menu(GSM)\rP: Power menu\rT: Timer menu\rQ: Query system status\rS: Start System\rR: Reboot\r"));
				break;
			}
	}else{
			usb_tx_string_P(PSTR("All commands start VX\r"));
	}
	clear_buffer(CMD_buffer);	//clear the buffer for next command	
	menu_send_n_st();
}

void menu_accel (void) {
	int speed, data16;
	switch (CMD_buffer[3]) {
	case 'd':  //disable
		ACL_set_sample_off();
		usb_tx_string_P(PSTR("Accelerometer is off\r"));
		break;
	case 'e':  //enable
		ACL_set_sample_on();
		usb_tx_string_P(PSTR("Accelerometer has been started\r"));
		break;
	case 'i':
		usb_tx_string_P(PSTR("V2X uses the ADXL345 accelerometer from Analog Devices\r"));
		break;
	case 'q':
		menu_accel_status();
		break;
	case 'r':  //restart
		ACL_set_sample_off();
		ACL_take_sample(sample); //pushes "off" command
		ACL_init(); //
		ACL_set_sample_on();
		ACL_take_sample(sample); //pushes init
		usb_tx_string_P(PSTR("Accelerometer has been restarted\r"));
		break;
	case 's':  //sample rate
 		speed = atoi(CMD_buffer+4);
		if (speed > 3199) {
			ACL_set_rate(ACL_RATE_3200);	
			usb_tx_string_P(PSTR("Set to 3200Hz\r"));
		}else if (speed > 1599) {
			ACL_set_rate(ACL_RATE_1600);
			usb_tx_string_P(PSTR("Set to 1600Hz\r"));
		}else if (speed > 799) {
			ACL_set_rate(ACL_RATE_800);
			usb_tx_string_P(PSTR("Set to 800Hz\r"));
		}else if (speed > 399) {
			ACL_set_rate(ACL_RATE_400);
			usb_tx_string_P(PSTR("Set to 400Hz\r"));
		}else if (speed > 199) {
			ACL_set_rate(ACL_RATE_200);
			usb_tx_string_P(PSTR("Set to 200Hz\r"));
		}else if (speed > 99) {
			ACL_set_rate(ACL_RATE_100);
			usb_tx_string_P(PSTR("Set to 100Hz\r"));
		}else if (speed > 49) {
			ACL_set_rate(ACL_RATE_50);
			usb_tx_string_P(PSTR("Set to 50Hz\r"));
		}else if (speed > 24) {
			ACL_set_rate(ACL_RATE_25);
			usb_tx_string_P(PSTR("Set to 25Hz\r"));
		}else if (speed > 11) {
			ACL_set_rate(ACL_RATE_12);
			usb_tx_string_P(PSTR("Set to 12Hz\r"));
		}else if (speed > 5) {
			ACL_set_rate(ACL_RATE_6);
			usb_tx_string_P(PSTR("Set to 6Hz\r"));
		}else if (speed > 2) {
			ACL_set_rate(ACL_RATE_3);
			usb_tx_string_P(PSTR("Set to 3Hz\r"));
		}else if (speed > 0) {
			ACL_set_rate(ACL_RATE_1);
			usb_tx_string_P(PSTR("Set to 1Hz\r"));
 		}else {	
			usb_tx_string_P(PSTR("ERROR: Out of range, try again.\r"));	
		}
		break;
	case 'w':
		speed = atoi(CMD_buffer+4);
		if (speed > 16) {speed = 0;}
		if (speed > 8) {
			ACL_set_range(ACL_16G_RANGE);
			usb_tx_string_P(PSTR("+/-16G Range\r"));
		}else if (speed > 4) {
			ACL_set_range(ACL_8G_RANGE);
			usb_tx_string_P(PSTR("+/-8G Range\r"));
		}else if (speed > 2) {
			ACL_set_range(ACL_4G_RANGE);
			usb_tx_string_P(PSTR("+/-4G Range\r"));
		}else if (speed > 0) {
			ACL_set_range(ACL_2G_RANGE);
			usb_tx_string_P(PSTR("+/-2G Range\r"));
		}else {menu_send_out_of_range();}
		break;
		
	case 'x':
	case 'y':
	case 'z':
		data16 = atoi(CMD_buffer+4);  //convert input chars to int
		if (data16 == 0){ //conversion resulted in 0
			if (CMD_buffer[4] != '0'){ //check if it is really a '0' of an invalad conversion
				menu_send_out_of_range(); //invalid result
				break; //exit offset menu
			}
		}
		if (data16 < -127 || data16 > 127) {  //must be 16 to detect out of range
			menu_send_out_of_range();
		} else {
			uint8_t data8 = (uint8_t)data16;  //reduce to 8 bits of data
			switch (CMD_buffer[3]) {
				case 'x':
					usb_tx_string_P(PSTR("X"));
					ACL_set_offset(ACL_X_OFFSET, data8);
					break;
				case 'y':
					usb_tx_string_P(PSTR("Y"));
					ACL_set_offset(ACL_Y_OFFSET, data8);
					break;
				case 'z':
					usb_tx_string_P(PSTR("Z"));
					ACL_set_offset(ACL_Z_OFFSET, data8);
					break;
				default:
					menu_send_q();
					break;
			}
			usb_tx_string_P(PSTR(" Offset: "));
			menu_print_int(data16);
			menu_send_n();
		}
		break;
	case 'g':
		if (ACL_sampling()){
			if (usb_cdc_is_active(USB_ACL)) {
				ACL_get_last_sample(sample);
			} else {
				ACL_take_sample(sample);
			}
			ACL_data_to_string(sample, CMD_buffer); 
			for (int i = 0; i < strlen(CMD_buffer); i++)
				{usb_cdc_send_byte(USB_CMD, CMD_buffer[i]);}
		} else {
			usb_tx_string_P(PSTR("ERROR: Not currently sampling, use VXAE\r"));}
		
		break;
	case 'f':
		if (CMD_buffer[4] == '0') {
			ACL_set_full_resolution(0);
			usb_tx_string_P(PSTR("10bit resolution, scale changes with 'G' range\r"));
		}
		else if (CMD_buffer[4] == '1') {
			ACL_set_full_resolution(1);
			usb_tx_string_P(PSTR("Full resolution, 4mg/bit\r"));
		}
		else {menu_send_q();}
		break;
	case '?':  
	default:
		usb_tx_string_P(PSTR("*** Accelerometer Menu ***\rE: Enable\rD: Disable\rR: Restart\rI: Subsystem Information\rQ: Query status\rG: Get last Sample\rSn: Set sample rate in HZ (1, 3, 6, 12, 25, 50, 100, 200, 400, 800)\rWn: Set \"G\" Range (2, 4, 8, 16)\rF: Full range (1: full 0: 10bit)\rXn: Set X offset (+/-127)\rYn: Set Y offset\rZn: Set Z offset\r"));
		break;
	}
}

void menu_modem (void) {
	int i; 
	switch (CMD_buffer[3]) {
	case 'd':  
		PWR_gsm_stop(); //disable
		usb_tx_string_P(PSTR("GSM is off\r"));
		break;
	case 'e':  //enable modem
		usb_tx_string_P(PSTR("GSM Start pending"));
		GSM_modem_init();
		break;
	case 'r':  //reset
		reset_trigger_GSM();
		usb_tx_string_P(PSTR("GSM restarting\r"));
		break;
	case 'q':
		menu_modem_status();
		break;
	case 'i':
		usb_tx_string_P(PSTR("V2X uses the SIM5320A 3G GSM modem + GPS receiver by SIMCOM\r"));
		break;
	case 'x':
		strcat_P(CMD_buffer, PSTR("\r\n"));  //put these char at the end of the string
		GSM_add_string_to_buffer(BUFFER_OUT, &CMD_buffer[4]); //send it on to the modem
		GSM_mark_for_processing(BUFFER_OUT); //initiate send
 		break;
	case '?':
	default:
		usb_tx_string_P(PSTR("*** Modem Menu ***\rE: Enable\rD: Disable\rR: Restart\rI: Subsystem Information\rQ: Query status\rX: AT Command Pass through\r"));
		break;
	}
}

void menu_can (void) {
	int i;
	char buffer[EE_CAN_ARRAY_SIZE+1];
	switch (CMD_buffer[3]) {
	case 'd':  //disable;
		usb_tx_string_P(PSTR("CAN is off\r"));
		PWR_can_stop();
		PWR_is_5_needed();
		break;
	case 'e':  //enable
		usb_tx_string_P(PSTR("CAN Starting\r"));
		CAN_elm_init();
		break;
	case 'r':  //reset
		usb_tx_string_P(PSTR("CAN restarting\r"));
		reset_trigger_CAN();
		break;
	case 'q': //query
		menu_can_status();
		break;
	case 'i': //info
		usb_tx_string_P(PSTR("V2X uses the STN1110 CANbus interface from Scantool\r"));
		usb_tx_string_P(PSTR("The STN1110 is compliant with the ELM327 V1.3\r"));
		break;
	case 'x': //pass command
		strcat_P(CMD_buffer, PSTR("\r"));
		
		CAN_add_string_to_buffer(BUFFER_OUT, CMD_buffer+4);
		CAN_mark_for_processing(BUFFER_OUT);
		CAN_start_snoop();
		break;
	case 's':  //save string to eeprom
		//strcat_P(CMD_buffer, PSTR("\r"));
		eeprom_store_CAN_string(CMD_buffer+4);
		break;
	case 'w': //what is stored in EE?
 		eeprom_read_CAN_string(buffer);
 		usb_cdc_send_string(USB_CMD, buffer);
		break;
	case 'a': //load string and parse from eeprom
		CAN_EE_start();
		break;
	case '?':
	default:
		usb_tx_string_P(PSTR("*** CANbus Menu ***\rE: Enable\rD: Disable\rR: Restart\rS: Store config string to EE\rA: Execute commands stored in EE\rW: Display stored EE commandsI: Subsystem Information\rQ: Query status\r"));
		break;
	}
}

void menu_power (void) {
	switch (CMD_buffer[3]) {
	case 'd':  //disable power
		switch (CMD_buffer[4]) {
		case '3':  //3v
			menu_send_ok();
			usb_tx_string_P(PSTR("Shutting down V2X in 30 seconds\r"));
			delay_s(30);
			PWR_turn_off((1<<ENABLE_3V3));
			PWR_push();
			break;
		case '4':  //4v
			PWR_turn_off((1<<ENABLE_4V1)|(1<<ENABLE_SIM_RESET));
			PWR_push();
			menu_send_ok();
			break;
		case '5':  //5v
			PWR_turn_off((1<<ENABLE_5V0)|(1<<ENABLE_5V0B)|(1<<ENABLE_CAN_RESET));
			PWR_push();
{'fraction_non_alphanumeric': 0.17207775814188336, 'fraction_numerical': 0.03155768745266347, 'mean_word_length': 3.4358342665173573, 'pattern_counts': {'":': 0, '<': 35, '<?xml version=': 0, '>': 43, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 14, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5807600', 'n_tokens_mistral': 9689, 'n_tokens_neox': 8389, 'n_words': 1745}