changeset 51:cb184206344d

Rejig command parsing and assume the compiler isn't dumb (eg it can reuse stack variables).
author darius@Inchoate
date Wed, 29 Oct 2008 16:09:55 +1030
parents a13e0ccc1d2d
children 3217e93b28a3
files tempctrl.c testavr.c
diffstat 2 files changed, 276 insertions(+), 261 deletions(-) [+]
line wrap: on
line diff
--- a/tempctrl.c	Wed Oct 29 16:06:42 2008 +1030
+++ b/tempctrl.c	Wed Oct 29 16:09:55 2008 +1030
@@ -29,6 +29,7 @@
 #include <stdio.h>
 #include <stdint.h>
 #include <stdlib.h>
+#include <string.h>
 #include <avr/interrupt.h>
 #include <avr/pgmspace.h>
 #include <avr/eeprom.h>
@@ -418,93 +419,113 @@
 tempctrl_cmd(char *buf) {
     char	cmd[6];
     int16_t	data;
-    int		i;
-
-    i = sscanf_P(buf, PSTR("tc %5s %d"), cmd, &data);
-
-    if (i == 1) {
-	if (!strcasecmp_P(cmd, PSTR("help"))) {
-	    printf_P(PSTR(
-			 "tc help	  This help\r\n"
-			 "tc save	  Save settings to EEPROM\r\n"
-			 "tc load	  Load or default settings from EEPROM\r\n"
-			 "tc dflt	  Load defaults from flash\r\n"
-			 "tc list	  List current settings\r\n"
-			 "tc mode [achin] Change control mode, must be one of\r\n"
-			 "                 a	Auto\r\n"
-			 "		   c	Always cool\r\n"
-			 "                 h	Always heat\r\n"
-			 " 		   i	Always idle\r\n"
-			 "		   n	Like idle but don't log anything\r\n"
-			 "\r\n"
-			 "tc X Y	  Set X to Y where X is one of\r\n"
-			 "   		   targ	Target temperature\r\n"
-			 "   		   hys	Hysteresis range\r\n"
-			 "		   mhov	Minimum heat overshoot\r\n"
-			 "		   mcov	Minimum cool overshoot\r\n"
-			 "		   mcon	Minimum cool on time\r\n"
-			 "		   mcoff	Minimum cool off time\r\n"
-			 "		   mhin	Minimum heat on time\r\n"
-			 "		   mhoff	Minimum heat off time\r\n"
-			 "		  Times are in seconds\r\n"
-			 "		  Temperatures are in hundredths of degrees Celcius\r\n"
-			 ));
-	    return;
-	}
+    uint8_t 	ROM[8];
+    
+    if (sscanf_P(buf, PSTR("tc %5s"), cmd, &data) == 0) {
+	printf_P(PSTR("Unable to parse tc subcommand\r\n"));
+	return;
+    }
+	
+    if (!strcasecmp_P(cmd, PSTR("help"))) {
+	printf_P(PSTR(
+		     "tc help         This help\r\n"
+		     "tc save         Save settings to EEPROM\r\n"
+		     "tc load         Load or default settings from EEPROM\r\n"
+		     "tc dflt         Load defaults from flash\r\n"
+		     "tc list         List current settings\r\n"
+		     "tc mode [achin] Change control mode, must be one of\r\n"
+		     "                 a    Auto\r\n"
+		     "                 c    Always cool\r\n"
+		     "                 h    Always heat\r\n"
+		     "                 i    Always idle\r\n"
+		     "                 n    Like idle but don't log anything\r\n"
+		     "tc X Y          Set X to Y where X is one of\r\n"
+		     "                 targ Target temperature\r\n"
+		     "                 hys  Hysteresis range\r\n"
+		     "                 mhov Minimum heat overshoot\r\n"
+		     "                 mcov Minimum cool overshoot\r\n"
+		     "                 mcon Minimum cool on time\r\n"
+		     "                 mcoff        Minimum cool off time\r\n"
+		     "                 mhin Minimum heat on time\r\n"
+		     "                 mhoff        Minimum heat off time\r\n"
+		     "tc A B          Set temperature sensor ID\r\n"
+		     "                 Where A is ferm, frg or amb\r\n"
+		     "                 and B is of the form xx:xx:xx:xx:xx:xx:xx:xx\r\n"
+		     "\r\n"
+		     "                Times are in seconds\r\n"
+		     "                Temperatures are in hundredths of degrees Celcius\r\n"
+		     ));
+	return;
+    }
 	
-	if (!strcasecmp_P(cmd, PSTR("save"))) {
-	    tempctrl_write_settings();
-	    return;
-	}
-	if (!strcasecmp_P(cmd, PSTR("load"))) {
-	    tempctrl_load_or_init_settings();
-	    return;
+    if (!strcasecmp_P(cmd, PSTR("save"))) {
+	tempctrl_write_settings();
+	return;
+    }
+    if (!strcasecmp_P(cmd, PSTR("load"))) {
+	tempctrl_load_or_init_settings();
+	return;
+    }
+    if (!strcasecmp_P(cmd, PSTR("dflt"))) {
+	tempctrl_default_settings();
+	return;
+    }
+    if (!strcasecmp_P(cmd, PSTR("list"))) {
+	printf_P(PSTR("Fermenter ROM ID %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\r\n"
+		      "Fridge ROM ID    %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\r\n"
+		      "Ambient ROM ID   %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\r\n"
+		      "Mode - %c, Target - %d, Hystersis - %d\r\n"
+		      "Min heat overshoot - %d, Min cool overshoot - %d\r\n"
+		      "Min cool on time - %d, Min cool off time - %d\r\n"
+		      "Min heat on time - %d, Min heat off time - %d\r\n"),
+		 settings.fermenter_ROM[0], settings.fermenter_ROM[1], settings.fermenter_ROM[2], settings.fermenter_ROM[3], 
+		 settings.fermenter_ROM[4], settings.fermenter_ROM[5], settings.fermenter_ROM[6], settings.fermenter_ROM[7], 
+		 settings.fridge_ROM[0], settings.fridge_ROM[1], settings.fridge_ROM[2], settings.fridge_ROM[3], 
+		 settings.fridge_ROM[4], settings.fridge_ROM[5], settings.fridge_ROM[6], settings.fridge_ROM[7], 
+		 settings.ambient_ROM[0], settings.ambient_ROM[1], settings.ambient_ROM[2], settings.ambient_ROM[3], 
+		 settings.ambient_ROM[4], settings.ambient_ROM[5], settings.ambient_ROM[6], settings.ambient_ROM[7], 
+		 settings.mode, settings.target_temp, settings.hysteresis,
+		 settings.minheatovershoot, settings.mincoolovershoot,
+		 settings.mincoolontime, settings.minheatontime,
+		 settings.minheatontime, settings.minheatofftime);
+	return;
+    }
+    if (!strcasecmp_P(cmd, PSTR("mode"))) {
+	switch (buf[8]) {
+	    case TC_MODE_AUTO:
+	    case TC_MODE_HEAT:
+	    case TC_MODE_COOL:
+	    case TC_MODE_IDLE:
+	    case TC_MODE_NOTHING:
+		settings.mode = buf[8];
+		break;
+		    
+	    default:
+		printf_P(PSTR("Unknown mode character '%c'\r\n"), buf[8]);
+		break;
 	}
-	if (!strcasecmp_P(cmd, PSTR("dflt"))) {
-	    tempctrl_default_settings();
-	    return;
+	return;
+    }
+    if (!strcasecmp_P(cmd, PSTR("ferm")) ||
+	!strcasecmp_P(cmd, PSTR("frg")) ||
+	!strcasecmp_P(cmd, PSTR("amb"))) {
+
+	if (sscanf_P((char *)cmd, PSTR("tc %5s %hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx"), cmd,
+		     &ROM[0], &ROM[1], &ROM[2], &ROM[3],
+		     &ROM[4], &ROM[5], &ROM[6], &ROM[7]) != 9) {
+	    printf_P(PSTR("Unable to parse ROM ID\r\n"));
+	} else {
+	    if (!strcasecmp_P(cmd, PSTR("ferm")))
+		memcpy(settings.fermenter_ROM, ROM, sizeof(ROM));
+	    if (!strcasecmp_P(cmd, PSTR("frg")))
+		memcpy(settings.fridge_ROM, ROM, sizeof(ROM));
+	    if (!strcasecmp_P(cmd, PSTR("amb")))
+		memcpy(settings.ambient_ROM, ROM, sizeof(ROM));
 	}
-	if (!strcasecmp_P(cmd, PSTR("list"))) {
-	    printf_P(PSTR("Fermenter ROM ID %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\r\n"
-			  "Fridge ROM ID    %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\r\n"
-			  "Ambient ROM ID   %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\r\n"
-			  "Mode - %c, Target - %d, Hystersis - %d\r\n"
-			  "Min heat overshoot - %d, Min cool overshoot - %d\r\n"
-			  "Min cool on time - %d, Min cool off time - %d\r\n"
-			  "Min heat on time - %d, Min heat off time - %d\r\n"),
-		     settings.fermenter_ROM[0], settings.fermenter_ROM[1], settings.fermenter_ROM[2], settings.fermenter_ROM[3], 
-		     settings.fermenter_ROM[4], settings.fermenter_ROM[5], settings.fermenter_ROM[6], settings.fermenter_ROM[7], 
-		     settings.fridge_ROM[0], settings.fridge_ROM[1], settings.fridge_ROM[2], settings.fridge_ROM[3], 
-		     settings.fridge_ROM[4], settings.fridge_ROM[5], settings.fridge_ROM[6], settings.fridge_ROM[7], 
-		     settings.ambient_ROM[0], settings.ambient_ROM[1], settings.ambient_ROM[2], settings.ambient_ROM[3], 
-		     settings.ambient_ROM[4], settings.ambient_ROM[5], settings.ambient_ROM[6], settings.ambient_ROM[7], 
-		     settings.mode, settings.target_temp, settings.hysteresis,
-		     settings.minheatovershoot, settings.mincoolovershoot,
-		     settings.mincoolontime, settings.minheatontime,
-		     settings.minheatontime, settings.minheatofftime);
-	    return;
-	}
-	if (!strcasecmp_P(cmd, PSTR("mode"))) {
-	    switch (buf[8]) {
-		case TC_MODE_AUTO:
-		case TC_MODE_HEAT:
-		case TC_MODE_COOL:
-		case TC_MODE_IDLE:
-		case TC_MODE_NOTHING:
-		    settings.mode = buf[8];
-		    break;
-		    
-		default:
-		    printf_P(PSTR("Unknown mode character '%c'\r\n"), buf[8]);
-		    break;
-	    }
-	    return;
-	}
-	
     }
     
-    if (i != 2) {
-	printf_P(PSTR("Unable to parse command\r\n"));
+    if (sscanf_P(buf, PSTR("tc %5s %d"), cmd, &data) != 2) {
+	printf_P(PSTR("Unable to parse tc subcommand & value\r\n"));
 	return;
     }
 
--- a/testavr.c	Wed Oct 29 16:06:42 2008 +1030
+++ b/testavr.c	Wed Oct 29 16:09:55 2008 +1030
@@ -170,62 +170,63 @@
     if (cmd.len == 0)
 	return;
 	     
-    if (cmd.buf[0] == '?') {
+    if (!strcasecmp_P((char *)cmd.buf, PSTR("?")) ||
+	!strcasecmp_P((char *)cmd.buf, PSTR("help"))) {
         printf_P(PSTR("rs               Reset and check for presence\r\n"
 		      "sr               Search the bus for ROMs\r\n"
 		      "re               Read a bit\r\n"
 		      "rb               Read a byte\r\n"
-		      "wr  bit          Write a bit\r\n"
-		      "wb  byte         Write a byte (hex)\r\n"
-		      "wc  cmd [ROMID]  Write command\r\n"
-		      "te  ROMID        Read the temperature from a DS1820\r\n"
-		      "in  port         Read from a port\r\n"
-		      "out port val     Write to a port\r\n"
-		      "ddr port [val]   Read/write DDR for a port\r\n"
-		      "tc ...		Temperature control related (tc help for more)\r\n"));
+		      "wr bit           Write a bit\r\n"
+		      "wb byte          Write a byte (hex)\r\n"
+		      "wc cmd [ROMID]   Write command\r\n"
+		      "te ROMID         Read the temperature from a DS1820\r\n"
+		      "in port          Read from a port\r\n"
+		      "ou port val      Write to a port (val in hex)\r\n"
+		      "dd port [val]    Read/write DDR for a port (val in hex)\r\n"
+		      "rt ROMID	        Read DS2502 status page\r\n"
+		      "we ROMID adr val Write data into a DS2502 PROM (adr & val in hex)\r\n"
+		      "rr ROMID         Read DS2502 PROM\r\n"
+		      "zz		Reset MCU\r\n"
+#ifdef WITHUSB
+		      "us               Generate USB data\r\n"
+#endif
+		      "tc ...           Temperature control related (tc help for more)\r\n"));
 	
 	return;
-    }
-	
-    i = strlen((char *)cmd.buf);
-    if (cmd.len < 2)
-	goto badcmd;
-	
-    if (cmd.buf[0] == 'r' && cmd.buf[1] == 's') {
+    } else if (!strncasecmp_P((char *)cmd.buf, PSTR("zz"), 2)) {
+	cli();
+	wdt_enable(WDTO_15MS);
+	for (;;)
+	    ;
+    } else if (!strncasecmp_P((char *)cmd.buf, PSTR("rs"), 2)) {
 	printf_P(PSTR("Resetting... "));
 	    
 	if (OWTouchReset() == 1)
 	    printf_P(PSTR("No presence pulse found\r\n"));
 	else
 	    printf_P(PSTR("Presence pulse found\r\n"));
-    } else if (cmd.buf[0] == 'r' && cmd.buf[1] == 'e') {
+    } else if (!strncasecmp_P((char *)cmd.buf, PSTR("re"), 2)) {
 	if (OWReadBit())
 	    printf_P(PSTR("Read a 1\r\n"));
 	else
 	    printf_P(PSTR("Read a 0\r\n"));
-    } else if (cmd.buf[0] == 'r' && cmd.buf[1] == 'b') {
+    } else if (!strncasecmp_P((char *)cmd.buf, PSTR("rb"), 2)) {
 	printf_P(PSTR("Read a 0x%02x\r\n"), OWReadByte());
-    } else if (cmd.buf[0] == 'w' && cmd.buf[1] == 'r') {
+    } else if (!strncasecmp_P((char *)cmd.buf, PSTR("wr"), 2)) {
 	arg = strtol((char *)cmd.buf + 3, (char **)NULL, 10);
 	OWWriteBit(arg);
 	printf_P(PSTR("Wrote a %c\r\n"), arg ? '1' : '0');
-    } else if (cmd.buf[0] == 'w' && cmd.buf[1] == 'b') {
+    } else if (!strncasecmp_P((char *)cmd.buf, PSTR("wb"), 2)) {
 	arg = (int)strtol((char *)cmd.buf + 3, (char **)NULL, 16); 
 	OWWriteByte(arg);
-    } else if (cmd.buf[0] == 'r' && cmd.buf[1] == 't') {
-	if (cmd.len < 26) {
+    } else if (!strncasecmp_P((char *)cmd.buf, PSTR("rt"), 2)) {
+	if (sscanf_P((char *)cmd.buf, PSTR("rt %hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx"), 
+		     &ROM[0], &ROM[1], &ROM[2], &ROM[3],
+		     &ROM[4], &ROM[5], &ROM[6], &ROM[7]) != 8) {
 	    printf_P(PSTR("Unable to parse ROM ID\r\n"));
 	    return;
 	}
-
-	if (OWTouchReset() != 0) {
-	    printf_P(PSTR("No presence\r\n"));
-	    return;
-	}
-
-	for (i = 0; i < 8; i++)
-	    ROM[i] = (int)strtol((char *)cmd.buf + 3 * (i + 1), (char **)NULL, 16);
-
+	
 	if (ROM[0] != OW_FAMILY_ROM) {
 	    printf_P(PSTR("ROM specified isn't a DS2502\r\n"));
 	    return;
@@ -263,40 +264,36 @@
 	    printf_P(PSTR("CRC mismatch on data\r\n"));
 	    return;
 	}
-    } else if (cmd.buf[0] == 'w' && cmd.buf[1] == 'e') {
-	if (cmd.len < 26) {
+    } else if (!strncasecmp_P((char *)cmd.buf, PSTR("we"), 2)) {
+	uint8_t	adr, data;
+	
+	if (sscanf_P((char *)cmd.buf, PSTR("we %hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx %hhx %hhx"),
+		     &ROM[0], &ROM[1], &ROM[2], &ROM[3],
+		     &ROM[4], &ROM[5], &ROM[6], &ROM[7],
+		     &adr, &data) != 10) {
 	    printf_P(PSTR("Unable to parse ROM ID\r\n"));
 	    return;
 	}
 
-	for (i = 0; i < 8; i++)
-	    ROM[i] = (int)strtol((char *)cmd.buf + 3 * (i + 1), (char **)NULL, 16);
-
 	if (ROM[0] != OW_FAMILY_ROM) {
-	    printf_P(PSTR("ROM specified isn't a ROM\r\n"));
+	    printf_P(PSTR("ID specified isn't a ROM\r\n"));
 	    return;
 	}
 
-	buf[0] = (int)strtol((char *)cmd.buf + 27, (char **)NULL, 16);	/* Address */
-	buf[1] = (int)strtol((char *)cmd.buf + 30, (char **)NULL, 16);	/* Data .. */
-	buf[2] = (int)strtol((char *)cmd.buf + 33, (char **)NULL, 16);
-	
 	if (OWTouchReset() != 0) {
 	    printf_P(PSTR("No presence\r\n"));
 	    return;
 	}
 
-	i = OWProgROM(ROM, buf[0], 2, &buf[1], 0, 0);
-	printf_P(PSTR("OWProgROM returned %d\r\n"), i);
-    } else if (cmd.buf[0] == 'r' && cmd.buf[1] == 'r') {
-	if (cmd.len < 26) {
+	printf_P(PSTR("OWProgROM returned %S\r\n"), OWProgROM_Status[OWProgROM(ROM, buf[0], 2, &buf[1], 0, 0)]);
+    } else if (!strncasecmp_P((char *)cmd.buf, PSTR("rr"), 2)) {
+	if (sscanf_P((char *)cmd.buf, PSTR("rr %hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx"),
+		     &ROM[0], &ROM[1], &ROM[2], &ROM[3],
+		     &ROM[4], &ROM[5], &ROM[6], &ROM[7]) != 8) {
 	    printf_P(PSTR("Unable to parse ROM ID\r\n"));
 	    return;
 	}
 
-	for (i = 0; i < 8; i++)
-	    ROM[i] = (int)strtol((char *)cmd.buf + 3 * (i + 1), (char **)NULL, 16);
-
 	if (ROM[0] != OW_FAMILY_ROM) {
 	    printf_P(PSTR("ROM specified isn't a ROM\r\n"));
 	    return;
@@ -336,96 +333,50 @@
 	    return;
 	}
 	
-    } else if (cmd.buf[0] == 'w' && cmd.buf[1] == 'c') {
-	if (cmd.len < 5) {
-	    printf_P(PSTR("No arguments\r\n"));
+    } else if (!strncasecmp_P((char *)cmd.buf, PSTR("wc"), 2)) {
+	uint8_t c;
+	
+	i = sscanf_P((char *)cmd.buf, PSTR("wc %hhx %hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx"),
+		     &ROM[0], &ROM[1], &ROM[2], &ROM[3],
+		     &ROM[4], &ROM[5], &ROM[6], &ROM[7],
+		     &c);
+	
+	if (i != 1 && i != 9) {
+	    printf_P(PSTR("Incorrect usage\r\n"));
 	    return;
 	}
 	    
-	arg = (int)strtol((char *)cmd.buf + 3, (char **)NULL, 16);
-	if (arg == 0) {
-	    printf_P(PSTR("Unparseable command\r\n"));
-	    return;
-	}
-
-	if (i == 5) {
-	    OWSendCmd(NULL, arg);
+	if (i == 1) {
+	    OWSendCmd(i == 1 ? NULL : ROM, c);
 	    return;
 	}
-	    
-	if (i < 29) {
-	    printf_P(PSTR("Can't parse ROM ID\r\n"));
-	    return;
-	}
-	for (i = 0; i < 8; i++)
-	    ROM[i] = (int)strtol((char *)cmd.buf + 6 + (3 * i), (char **)NULL, 16);
-
-	OWSendCmd(ROM, arg);
-    } else if (cmd.buf[0] == 't' && cmd.buf[1] == 'e') {
-	if (cmd.len < 26) {
+    } else if (!strncasecmp_P((char *)cmd.buf, PSTR("te"), 2)) {
+	if (sscanf_P((char *)cmd.buf, PSTR("te %hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx"), 
+		     &ROM[0], &ROM[1], &ROM[2], &ROM[3],
+		     &ROM[4], &ROM[5], &ROM[6], &ROM[7]) != 8) {
 	    printf_P(PSTR("Unable to parse ROM ID\r\n"));
 	    return;
 	}
 
-	for (i = 0; i < 8; i++)
-	    ROM[i] = (int)strtol((char *)cmd.buf + 3 * (i + 1), (char **)NULL, 16);
+	t = OWGetTemp(ROM);
+	switch (t) {
+	    case OW_TEMP_WRONG_FAM:
+		printf_P(PSTR("ROM specified isn't a temperature sensor\r\n"));
+		break;
 
-	if (ROM[0] != OW_FAMILY_TEMP) {
-	    printf_P(PSTR("ROM specified isn't a temperature sensor\r\n"));
-	    return;
-	}
-	    
-	OWSendCmd(ROM, OW_CONVERTT_CMD);
-	i = 0;
-	/* Wait for the conversion */
-	while (OWReadBit() == 0)
-	    i = 1;
-
+	    case OW_TEMP_CRC_ERR:
+		printf_P(PSTR("CRC mismatch\r\n"));
+		break;
 
-	OWSendCmd(ROM, OW_RD_SCR_CMD);
-	crc = 0;
-	for (i = 0; i < 9; i++) {
-	    buf[i] = OWReadByte();
-	    if (i < 8)
-		OWCRC(buf[i], &crc);
-	}
-	    
-	if (crc != buf[8]) {
-	    printf_P(PSTR("CRC mismatch\r\n"));
-	    return;
+	    case OW_TEMP_NO_ROM:
+		printf_P(PSTR("No ROM found\r\n"));
+		break;
+
+	    default:
+		printf_P(PSTR("%d.%02d\r\n"), GETWHOLE(t), GETFRAC(t));
+		break;
 	}
-	    
-	/* 0	Temperature LSB
-	 * 1	Temperature MSB
-	 * 2	Th
-	 * 3	Tl
-	 * 4	Reserved
-	 * 5	Reserved
-	 * 6	Count Remain
-	 * 7	Count per C
-	 * 8	CRC
-	 */
-#if 0
-	for (i = 0; i < 9; i++)
-	    printf_P(PSTR("%d\r\n"), buf[i]);
-#endif
-	temp = buf[0];
-	if (buf[1] & 0x80)
-	    temp -= 256;
-	temp >>= 1;
-
-	tfrac = buf[7] - buf[6];
-	tfrac *= (uint16_t)100;
-	tfrac /= buf[7];
-	tfrac += 75;
-	if (tfrac < 100) {
-	    temp--;
-	} else {
-	    tfrac -= 100;
-	}
-	    
-	printf_P(PSTR("%d.%02d\r\n"), temp, tfrac);
-    } else if (cmd.buf[0] == 's' && cmd.buf[1] == 'r') {
+    } else if (!strncasecmp_P((char *)cmd.buf, PSTR("sr"), 2)) {
 	memset(ROM, 0, 8);
 
 	i = OWFirst(ROM, 1, 0);
@@ -460,86 +411,129 @@
 
 	    i = OWNext(ROM, 1, 0);
 	} while (1);
-    } else if (cmd.buf[0] == 'i' && cmd.buf[1] == 'n') {
+    } else if (!strncasecmp_P((char *)cmd.buf, PSTR("in"), 2)) {
+	uint8_t inp;
+	    
 	switch (tolower(cmd.buf[3])) {
 	    case 'a':
-		crc = PINA;
+		inp = PINA;
 		break;
 		
 	    case 'b':
-		crc = PINB;
+		inp = PINB;
 		break;
 		
 	    case 'c':
-		crc = PINC;
+		inp = PINC;
 		break;
 		
 	    case 'd':
-		crc = PIND;
+		inp = PIND;
+		break;
+		
+	    default:
+		printf_P(PSTR("Unknown port\r\n"));
+		return;
+	}
+	printf_P(PSTR("0x%02x\r\n"), inp);
+    } else if (!strncasecmp_P((char *)cmd.buf, PSTR("ou"), 2)) {
+	char port;
+	int val;
+	
+	if (sscanf_P((char *)cmd.buf, PSTR("ou %c %x"), &port, &val) != 2) {
+	    printf_P(PSTR("Unable to parse ou arguments\r\n"));
+	    return;
+	}
+	
+	switch (port) {
+	    case 'a':
+		PORTA = val & 0xff;
+		break;
+		
+	    case 'b':
+		PORTB = val & 0xff;
+		break;
+		
+	    case 'c':
+		PORTC = val & 0xff;
+		break;
+		
+	    case 'd':
+		PORTD = val & 0xff;
 		break;
 		
 	    default:
 		printf_P(PSTR("Unknown port\r\n"));
 		return;
 	}
-	printf_P(PSTR("0x%02x\r\n"), crc);
-    } else if (cmd.buf[0] == 'o' && cmd.buf[1] == 'u') {
-	crc = strtol((char *)cmd.buf + 8, (char **)NULL, 16);
-	switch (tolower(cmd.buf[4])) {
-	    case 'a':
-		PORTA = crc;
-		break;
-		
-	    case 'b':
-		PORTB = crc;
-		break;
-		
-	    case 'c':
-		PORTC = crc;
-		break;
-		
-	    case 'd':
-		PORTD = crc;
-		break;
-		
-	    default:
-		printf_P(PSTR("Unknown port\r\n"));
-		return;
+	printf_P(PSTR("PORT%c <= 0x%02x\r\n"), toupper(port), val);
+    } else if (!strncasecmp_P((char *)cmd.buf, PSTR("dd"), 2)) {
+	char port;
+	uint8_t val;
+	int num;
+	
+	num = sscanf_P((char *)cmd.buf, PSTR("dd %c %x"), &port, &val);
+	
+	if (num != 2 && num != 3) {
+	    printf_P(PSTR("Unable to parse dd arguments\r\n"));
+	    return;
 	}
-	printf_P(PSTR("PORT%c <= 0x%02x\r\n"), toupper(cmd.buf[4]), crc);
-    } else if (cmd.buf[0] == 'd' && cmd.buf[1] == 'd') {
-	crc = strtol((char *)cmd.buf + 8, (char **)NULL, 16);
-	switch (tolower(cmd.buf[4])) {
-	    case 'a':
-		DDRA = crc;
-		break;
-		
-	    case 'b':
-		DDRB = crc;
-		break;
+	
+	if (num == 2) {
+	    switch (port) {
+		case 'a':
+		    val = DDRA;
+		    break;
+
+		case 'b':
+		    val = DDRB;
+		    break;
+
+		case 'c':
+		    val = DDRC;
+		    break;
+
+		case 'd':
+		    val = DDRD;
+		    break;
 		
-	    case 'c':
-		DDRC = crc;
-		break;
+		default:
+		    printf_P(PSTR("Unknown port\r\n"));
+		    return;
+	    }
+	    printf_P(PSTR("DDR%c => 0x%02x\r\n"), toupper(port), val);
+	} else {
+	    switch (port) {
+		case 'a':
+		    DDRA = val & 0xff;
+		    break;
+		
+		case 'b':
+		    DDRB = val & 0xff;
+		    break;
 		
-	    case 'd':
-		DDRD = crc;
-		break;
+		case 'c':
+		    DDRC = val & 0xff;
+		    break;
+		
+		case 'd':
+		    DDRD = val & 0xff;
+		    break;
 		
-	    default:
-		printf_P(PSTR("Unknown port\r\n"));
-		return;
+		default:
+		    printf_P(PSTR("Unknown port\r\n"));
+		    return;
+	    }
+	    printf_P(PSTR("DDR%c <= 0x%02x\r\n"), toupper(port), val);
 	}
-	printf_P(PSTR("0x%02x\r\n"), crc);
-    } else if (cmd.buf[0] == 't' && cmd.buf[1] == 'c') {
+    } else if (!strncasecmp_P((char *)cmd.buf, PSTR("tc"), 2)) {
 	tempctrl_cmd((char *)cmd.buf);
 #ifdef WITHUSB
-    } else if (cmd.buf[0] == 'u' && cmd.buf[1] == 's') {
+    } else if (!strncasecmp_P((char *)cmd.buf, PSTR("us"), 2)) {
 	usb_gendata();
 #endif
     } else {
-      badcmd:
-	printf_P(PSTR("Unknown command, ? for a list\r\n"));
+	printf_P(PSTR("Unknown command, help for a list\r\n"));
     }
 }