Hex Strings (Async) to/from Serial Port

Hello there,

After RTFM and TATFSP (Trying All The ______ Sample Programs), I still have one problem to getting my product to work through a RCM4300:

Reading serial data.

The product requires Hex communication 9600 baud to/from a power line modem. Initialization is in Hex (0x02), so I can’t get away with just ASCII… I’ve tried.

Starting using Docklight, I plugged the modem into the COM port and sent the correct Hex. Docklight controls the power line modem perfectly.

Then I plug Docklight through Port D on the RCM4300. From the RCM4300 can send Hex to Docklight, but I get garbage back on the return trip. Thankfully, Plugging the modem directly gets me the exact same garbage back on RCM4300 Port D with the same program.

I have two flavors of similar programs, one to check for modem ready and the other just sending the whole command.

  1. Checks for modem ready, then sends string:
#class auto
#define TCPCONFIG      0
#define SERPORT		D
#define DINBUFSIZE 	15
#define DOUTBUFSIZE 	15
#define CH_ESCAPE		27
#define serXopen		CONCAT(ser, CONCAT(SERPORT, open))
#define serXclose		CONCAT(ser, CONCAT(SERPORT, close))
#define myserport		CONCAT(SER_PORT_, SERPORT)
#define SXSR			CONCAT(S, CONCAT(SERPORT, SR))
#define INBUFSIZE		CONCAT(SERPORT, INBUFSIZE)
#define OUTBUFSIZE	        CONCAT(SERPORT, OUTBUFSIZE)
#define BAUDRATE		9600L
#define RS232_NOCHARASSYINBRK

//#memmap xmem // for later

#use RCM43xx.LIB

#if RAM_COMPILE
#error "This program is not intended to run in \"Code and BIOS in RAM\" compile mode."
#error "The User block's calibration constants are by default not accessible in this compile mode."
#endif

void main(void) {
   auto int pos, d;
   auto char p, s, c;
   auto char rx_data[10];
   const static char t[] = {0x63,0x46,0x4C,0x47,0x41};
   s = ' '; //s allows for user quit of program

   serXopen(BAUDRATE);  //set baud rates for the serial ports to be used
   serXwrFlush(myserport);    //clear Rx and Tx data buffers
   serXrdFlush(myserport);
   printf("
STDIO to Modem Test, ESC to exit.
");

   while (s != CH_ESCAPE) {    // Exit on Escape
      if (s == ' ') { //initial condition
         printf("
Initializing.
data:
");
         d = serXputc(myserport, 0x02);
         printf("TX: %d %x
", d, 0x02);
         p = serXgetc(myserport);
         printf("RX: p = %x
", p);
         if (p == 0x06) {
            p = serXgetc(myserport);
            if (p == 0x0D) {
               printf("
Fired Up!
");
               serXwrite(myserport, t, sizeof(t));
               pos = 0;
               serXread(myserport, rx_data, 10, 15);
               while (pos < 12) {
                  printf("hex %x
", rx_data[pos]);
               } //while
            } //if
         } //if
         else if (p == 0x15) {
            printf("
Sorry didn't work
");
         } //else if
         s = 'Z';
      } //if
      else {
         s = getchar();
      } //else
   } //while

   printf("
Done
");

   // allow transmission to complete before closing
   while (serXwrFree(myserport) != OUTBUFSIZE);
   // close serial port
   serXclose();
} //main

  1. Sending the full string all at once, then reading all at once:
//all # defines, uses, and ifs from program 1
void main(void)
{
	auto int pos, d;
	auto char p, s, c;
        const static char t[] = {0x02,0x63,0x46,0x4C,0x47,0x41};
        char rx_data[12];
        s = ' ';

  	serXopen(BAUDRATE);	//set baud rates for the serial ports to be used
  	serXwrFlush(myserport);		//clear Rx and Tx data buffers
  	serXrdFlush(myserport);
  	printf("
STDIO to Modem Test, ESC to exit.
");
	while (s != CH_ESCAPE) {	// Exit on Escape
  	    if (s == ' ') {
               printf("
Initializing.
data:
");
	       serXwrite(myserport, t, sizeof(t));
               pos = 0;
               serXread(myserport, rx_data, 12, 15);
  	       while (pos < 12) {
	           printf("hex %x
", rx_data[pos]);
		   if ((rx_data[pos] == 0x06) && (rx_data[pos+1] == 0x0D)) {
        	       printf("
Fired Up!
");
     		   } //if
		   else if (rx_data[pos] == 0x15) {
      	 	       printf("
Sorry didn't work
");
     		   } //else if
                   pos=pos+1;
	        } //while
	  	s = 'Z';
            } //if
            else {
                s = getchar();
            } //if
  	} //while
  	printf("
Done
");

  	// allow transmission to complete before closing
  	while (serXwrFree(myserport) != OUTBUFSIZE);
  	serXclose(); // close serial port
} //main

Now, neither one of these work, and I’d assume program 2 would work better. However, I’m expecting:

06 0D 58 46 4C 31 0D 58 46 47 31 0D

I’m getting:

data:
e9
0
fb
df
a
8
eb
6f
1
0
4
78

… and the same thing comes from the modem if I feed it the correct code. The difference is, the modem doesn’t complete its command (turn off) from the Rabbit, but it does complete commands from Docklight.

This sure seems like a simple n00b mistake. Any pointers?

Sorry, I figured it out… the n00b mistake was that I wasn’t thinking asynchronously, and that the full received string wouldn’t come in all at once.

So, for those who see this, do getchar() in a continous loop, character-match on the receive buffer for the received signal, then break out when done.

Edit: This code works with STDIO to send/receive modem commands. Note for every transmit, there is a receive, and for every receive, there is a transmit.

/********************************************************************
   stdioModemCommander.c
 	pm1759, 2008

	This program is used with RCM4300 series controllers with
	prototyping boards.

	Description
	===========
	This program demonstrates controlling port outputs with X10 communication
	from STDIO by menu driven functions.

	I/O control			On proto-board
	--------------		----------------------
	See Defines			Serial Port D

	Instructions
	============
	1. Compile and run this program.  Start a HEX-driven terminal software device
      like Docklight, or find an RS232-compatible power line modem.

	2. The program will prompt you for to send or receive an X10 command if the
      modem is ready.  Build commands using X10 HEX protocol.

	3. You'll be prompted to select an ON or OFF state.  Verify the system works
      with an X10 lamp or appliance module.  See that the devices turn on and
      off.
*********************************************************************/
#class auto
#define TCPCONFIG		0

/////
// configure your serial port connection here
//	presently configured serial port D
///
#define SERPORT      D
#define DINBUFSIZE 	15
#define DOUTBUFSIZE 	15
#define CH_ESCAPE		27
#define serXopen     CONCAT(ser, CONCAT(SERPORT, open))
#define serXclose    CONCAT(ser, CONCAT(SERPORT, close))
#define myserport    CONCAT(SER_PORT_, SERPORT)
#define SXSR         CONCAT(S, CONCAT(SERPORT, SR))
#define INBUFSIZE    CONCAT(SERPORT, INBUFSIZE)
#define OUTBUFSIZE   CONCAT(SERPORT, OUTBUFSIZE)
// Note:  Hyperterminal, or other end, must use this baud rate
#define BAUDRATE     9600L

/* These are the X10 format codes possible sent through the Powerlinc II Modem.
   Not all will be used right away, but if expansion happens all can be used.
 */
#define startcommand 0x02
#define ack 0x06
#define nak 0x15
#define creturn 0x0D
#define sendx10 0x63
#define send1 0x41
#define send2 0x42
#define send3 0x43
#define send4 0x44
#define send5 0x45
#define send6 0x46
#define send7 0x47
#define send8 0x48
#define send9 0x49
#define send10 0x4A
#define send11 0x4B
#define send12 0x4C
#define send13 0x4D
#define send14 0x4E
#define send15 0x4F
#define x10rcvd 0x58
#define sent1 0x31
#define sent2 0x32
#define sent3 0x33
#define sent4 0x34
#define sent5 0x35
#define sent6 0x36
#define sent7 0x37
#define sent8 0x38
#define sent9 0x39
#define sent10 0x3A
#define sent11 0x3B
#define sent12 0x3C
#define sent13 0x3D
#define sent14 0x3E
#define sent15 0x3F
#define x_A 0x46
#define x_B 0x4E
#define x_C 0x42
#define x_D 0x4A
#define x_E 0x41
#define x_F 0x49
#define x_G 0x45
#define x_H 0x4D
#define x_I 0x47
#define x_J 0x4F
#define x_K 0x43
#define x_L 0x4B
#define x_M 0x40
#define x_N 0x48
#define x_O 0x44
#define x_P 0x4C
#define x_1 0x4C
#define x_2 0x5C
#define x_3 0x44
#define x_4 0x54
#define x_5 0x42
#define x_6 0x52
#define x_7 0x4A
#define x_8 0x5A
#define x_9 0x4E
#define x_10 0x5E
#define x_11 0x46
#define x_12 0x56
#define x_13 0x40
#define x_14 0x50
#define x_15 0x48
#define x_16 0x58
#define x_alloff 0x41
#define x_lightson 0x43
#define x_on 0x45
#define x_off 0x47
#define x_bright 0x4B
#define x_lightsoff 0x4D
#define x_extendcode 0x4F
#define x_hail 0x51
#define x_predimhi 0x57
#define x_predimlo 0x55
#define x_extenddata 0x59
#define x_statuson 0x5B
#define x_statusoff 0x5D
#define x_statusreq 0x5F

// RCM43xx boards have no pull-up on serial Rx lines, and we assume in this
// sample the possibility of disconnected or non-driven Rx line.  This sample
// has no need of asynchronous line break recognition.  By defining the
// following macro we choose the default of disabled character assembly during
// line break condition.  This prevents possible spurious line break interrupts.
/**************************************************************/
#define RS232_NOCHARASSYINBRK

//#define FILEBUFSIZE	4096	//4K max file size
//#define TERMINATOR	'
'

//#memmap xmem

#use RCM43xx.LIB

#if RAM_COMPILE
#error "This sample is not intended to run in \"Code and BIOS in RAM\" compile mode."
#error "The User block's calibration constants are by default not accessible in this compile mode."
#endif

void encode(int room, int device, int cmd, int txrx);
int* rx(void);
int* decode(char *cmdrcvd, int txrx);
void main(void) {
	auto int r, d, s, tr;
	auto char c;
   char *getter;
   int *rcvdcmd;
   c = ' ';
   tr = 1; //initially set to transmit a command

   serXopen(BAUDRATE);	//set baud rates for the serial ports to be used
  	serXwrFlush(myserport);		//clear Rx and Tx data buffers
  	serXrdFlush(myserport);
   printf("
----------Menu----------
");
   printf("
1 to send Modem Command
2 to listen for Commands
ESC to exit.
");
   c = getchar();
   while (c != CH_ESCAPE) {	// Exit on Escape
  		while (c == '1') {  //transmit setup
         if (tr == 1) {
            printf("
Rooms 1-16, select then return.
Choice: ");
            r = _n_atoi(gets(getter));
            while (r < 1 || r > 16) {
               printf("
Nope, wrong character. (CAPS!)  Try again: ");
               r = _n_atoi(gets(getter));
            } //while
            printf("
Devices 1-16, select then return.
Choice: ");
            d = _n_atoi(gets(getter));
            while (d < 1 || d > 16) {
               printf("
Nope, wrong number.  Try again: ");
               d = _n_atoi(gets(getter));
            } //while
            printf("
1 to turn r%d d%d On
2 to turn r%d d%d Off
Then return.
Choice: ",r,d,r,d);
            s = _n_atoi(gets(getter));
            while (s < 1 || s > 2) {
               printf("Nope, wrong character.  Try again: ");
               s = _n_atoi(gets(getter));
            } //while
            encode(r,d,s,tr);
            c = '2'; //set 2 to handle receive
         } //if
         else if (tr == 0) {
            printf("
%d Means acknowledging Room %d Device %d is in State %d.
",rcvdcmd[3],rcvdcmd[0],rcvdcmd[1],rcvdcmd[2]);
            encode(rcvdcmd[0],rcvdcmd[1],rcvdcmd[2],rcvdcmd[3]);
            c = 'M';
         } //end else if
      } //while
      while(c == '2') {
         rcvdcmd = rx();
         if (rcvdcmd[3] == 0) {
            printf("
Receiving a command...
");
            tr = 0;
            c = '1';
         } //if
         else if (rcvdcmd[3] == 1) {
            tr = 1;
            c = 'M';
         }
      } //while
      while(c == 'M') {
         printf("
Continue? 1 to Send, 2 to Receive, ESC to quit
");
         c = getchar();
         if(c == '1'){
            tr = 1;
         }
         else {
            tr = 0;
         }
      } //end while
  	} //while
  	printf("
Done
");

  	// allow transmission to complete before closing
  	while (serXwrFree(myserport) != OUTBUFSIZE);
  	serXclose(); // close serial port
} //main

void encode (int r, int d, int s, int txrx) {
   char command[6];
   char cmdsent[12];

   switch (r) {
      case 1:
         command[2] = x_A;
         break;
      case 2:
         command[2] = x_B;
         break;
      case 3:
         command[2] = x_C;
         break;
      case 4:
         command[2] = x_D;
         break;
      case 5:
         command[2] = x_E;
         break;
      case 6:
         command[2] = x_F;
         break;
      case 7:
         command[2] = x_G;
         break;
      case 8:
         command[2] = x_H;
         break;
      case 9:
         command[2] = x_I;
         break;
      case 10:
         command[2] = x_J;
         break;
      case 11:
         command[2] = x_K;
         break;
      case 12:
         command[2] = x_L;
         break;
      case 13:
         command[2] = x_M;
         break;
      case 14:
         command[2] = x_N;
         break;
      case 15:
         command[2] = x_O;
         break;
      case 16:
         command[2] = x_P;
         break;
      default:
         break;
   } //switch
	switch (d) {
      case 1:
         command[3] = x_1;
         break;
      case 2:
         command[3] = x_2;
         break;
      case 3:
         command[3] = x_3;
         break;
      case 4:
         command[3] = x_4;
         break;
      case 5:
         command[3] = x_5;
         break;
      case 6:
         command[3] = x_6;
         break;
      case 7:
         command[3] = x_7;
         break;
      case 8:
         command[3] = x_8;
         break;
      case 9:
         command[3] = x_9;
         break;
      case 10:
         command[3] = x_10;
         break;
      case 11:
         command[3] = x_11;
         break;
      case 12:
         command[3] = x_12;
         break;
      case 13:
         command[3] = x_13;
         break;
      case 14:
         command[3] = x_15;
         break;
      case 15:
         command[3] = x_15;
         break;
      case 16:
         command[3] = x_16;
         break;
      default:
         break;
   } //switch
   switch (s) {
      case 1:
         command[4] = x_on;
         break;
      case 2:
         command[4] = x_off;
         break;
      default:
         break;
   } //switch
   if (txrx == 1) {
      command[0] = startcommand;
      command[1] = sendx10;
      command[5] = send1;
      printf("
Initializing %s.
", command);
      serXwrite(myserport, command, sizeof(command));
   }
   else if (txrx == 0) {
      cmdsent[0] = ack;
      cmdsent[1] = creturn;
      cmdsent[2] = x10rcvd;
      cmdsent[3] = command[2];
      cmdsent[4] = command[3];
      cmdsent[5] = sent1;
      cmdsent[6] = creturn;
      cmdsent[7] = x10rcvd;
      cmdsent[8] = command[2];
      cmdsent[9] = command[4];
      cmdsent[10] = sent1;
      cmdsent[11] = creturn;
      printf("
Initializing
%s
", cmdsent);
      serXwrite(myserport, cmdsent, sizeof(cmdsent));
   }
} //txcmd

int* rx(void) {
   int cnt, max, tr, pos;
   char p;
   char cmd_rx[3];
   int *rcvdcmd;
   strcpy(cmd_rx, "   ");
   pos = 0;
   cnt = 0;
   max = 12;

   while (cnt < max) {
      printf("receiving...
");
      p = serXgetc(myserport);
      if (p == startcommand) {
         tr = 0;
         max = 5;
         cnt=cnt+1;
      }
      else if (p == sendx10) {
         cnt=cnt+1;
      } //else if
      else if (p == ack) {
         tr = 1;
         max = 11;
         cnt=cnt+1;
      } //if
      else if (p == creturn) {
         cnt=cnt+1;
      } //else if
      else if (p == x10rcvd) {
         cnt=cnt+1;
      } //else if
      else if ((p >= send1)&&(p <= send15)&&((cnt == 5)&&(tr == 1))) {  //number of times to send the message
         cnt=cnt+1;
      } //else if
      else if ((p >= sent1)&&(p <= sent15)) {  //number of times the other end sent the message
         cnt=cnt+1;
      } //else if
      else if ((p >= x_M)&&(p <= x_J)&&(((cnt == 3)&&(tr == 1))||((cnt == 2)&&(tr == 0)))) { //x_M = 40, x_J = 4F
         cmd_rx[pos] = p;
         pos=pos+1;
         cnt=cnt+1;
      } //else if
      else if ((p >= x_13)&&(p <= x_10)&&(((cnt == 4)&&(tr == 1))||((cnt == 3)&&(tr == 0)))) { //x_13 = 40, x_10 = 5E
         cmd_rx[pos] = p;
         pos=pos+1;
         cnt=cnt+1;
      } //else if
      else if ((p >= x_M)&&(p <= x_J)&&(cnt == 8)) { //forget 2nd House Code
         cnt=cnt+1;
      } //if
      else if ((p >= x_alloff)&&(p <= x_statusreq)&&(((cnt == 9)&&(tr == 1))||((cnt == 4)&&(tr == 0)))) { //x_alloff = 41, x_statusreq = 5F
         cmd_rx[pos] = p;
         cnt=cnt+1;
      } //else if
      else if (p == nak) {
         break;
      } //else if
   } //while
   if (tr == 1) {
      printf("
Ensuring Receipt...
");
      rcvdcmd = decode(cmd_rx, tr);
      strcpy(cmd_rx, "   ");
      return rcvdcmd;
   } //if
   else if (tr == 0) {
      printf("
Incoming Request...
");
      rcvdcmd = decode(cmd_rx, tr);
      strcpy(cmd_rx, "   ");
      return rcvdcmd;
   }
   else {
      printf("
Sorry didn't work
");
   } // else
} //end rx

int* decode(char *rx, int tr) {
   int r, d, s;
   int rcvdcmd[4];
   char *c;
   switch (rx[0]) {
      case x_A:
         r = 1;
         break;
      case x_B:
         r = 2;
         break;
      case x_C:
         r = 3;
         break;
      case x_D:
         r = 4;
         break;
      case x_E:
         r = 5;
         break;
      case x_F:
         r = 6;
         break;
      case x_G:
         r = 7;
         break;
      case x_H:
         r = 8;
         break;
      case x_I:
         r = 9;
         break;
      case x_J:
         r = 10;
         break;
      case x_K:
         r = 11;
         break;
      case x_L:
         r = 12;
         break;
      case x_M:
         r = 13;
         break;
      case x_N:
         r = 14;
         break;
      case x_O:
         r = 15;
         break;
      case x_P:
         r = 16;
         break;
      default:
         r = 0;
         break;
   } //switch
	switch (rx[1]) {
      case x_1:
         d = 1;
         break;
      case x_2:
         d = 2;
         break;
      case x_3:
         d = 3;
         break;
      case x_4:
         d = 4;
         break;
      case x_5:
         d = 5;
         break;
      case x_6:
         d = 6;
         break;
      case x_7:
         d = 7;
         break;
      case x_8:
         d = 8;
         break;
      case x_9:
         d = 9;
         break;
      case x_10:
         d = 10;
         break;
      case x_11:
         d = 11;
         break;
      case x_12:
         d = 12;
         break;
      case x_13:
         d = 13;
         break;
      case x_14:
         d = 15;
         break;
      case x_15:
         d = 15;
         break;
      case x_16:
         d = 16;
         break;
      default:
         d = 0;
         break;
   } //switch
   switch (rx[2]) {
      case x_on:
         s = 1;
         c = "ON";
         break;
      case x_off:
         s = 2;
         c = "OFF";
         break;
      default:
         s = 0;
         c = "in error";
         printf ("
Something is %s with Room %d Device %d
",r,d,c);
         break;
   } //switch
   rcvdcmd[0] = r;
   rcvdcmd[1] = d;
   rcvdcmd[2] = s;
   rcvdcmd[3] = tr;

   if (tr == 1) {
      printf ("
Room %d Device %d is %s.
",r,d,c);
      return rcvdcmd;
   } //if
   if (tr == 0) {
      printf ("
Room %d Device %d wants to go %s.
",r,d,c);
      return rcvdcmd;
   }
} //end decode