CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

Converting characters in a serial buffer....

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
JAM2014



Joined: 24 Apr 2014
Posts: 138

View user's profile Send private message

Converting characters in a serial buffer....
PostPosted: Thu Sep 10, 2020 8:47 am     Reply with quote

Hi All,

I'm receiving a serial message in the format:

Quote:
!N3:Q1


In this case, the '3' is the node number of a remote device, and can be any number from 1 to 5, and '1' is the state of this devices output, and can be any number from 0 to 2. In my code, I have an array 'NodeStatus' that contains the output state for all the connected nodes. So, I need to extract the node number and the output state contained in the serial message to fill my array.

NodeStatus is defined as:
Code:

int8 NodeStatus[6] = {0,0,0,0,0,0}; //0 = Unavailable, 1 = Off, 2 = On



I'm doing it like this:
Code:

//Here we check if there are any pending Node reply messages!
if (Node_Msg_Ready == True){
   Node_Msg_Ready = False;
   fprintf(Diag, "Node Reply Msg: %s\n\r", Node_Msg_Buffer);
   fprintf(Diag, "Node Number Received: %u\n\r", AsciiToHex(Node_Msg_Buffer[2]));
   fprintf(Diag, "Node Value Received: %u\n\r", AsciiToHex(Node_Msg_Buffer[5]));
   //Note: We subtract 1 from the node number as our NodeStatus array is 0 based.
   NodeStatus[AsciiToHex(Node_Msg_Buffer[2]) - 1] = AsciiToHex(Node_Msg_Buffer[5]);
         
}


Here is my AsciiToHex routine:
Code:

char AsciiToHex(char Digit)
{
//This routine takes an uppercase ASCII hex character (0 - 9) and (A - F) and converts
//the character to a binary representation.

    //Here we check if the char is an ASCII hex char
   if ((Digit < '0') || (Digit > 'F') || ((Digit < 'A') && (Digit > '9')))
       break;

   //Here we convert the ASCII hex char to binary and return the value
   Digit -= 0x30;   
    if(Digit > 9)
       Digit -= 7;
   
   return(Digit);
}


My issue is that his code correctly extracts the node number and state, but does not seem to manipulate the array correctly. I suspect that the printf statement is formatting these values to appear correct, but that I'm actually not working with what I think?

Here is the diagnostics that are printed when a serial message is received:

Quote:

Node Reply Msg: !N3:Q1
Node Number Received: 3
Node Value Received: 1

NodeStatus[0] = 0
NodeStatus[1] = 0
NodeStatus[2] = 0
NodeStatus[3] = 0
NodeStatus[4] = 0


Any thoughts on what I'm doing wrong?

Thanks,

Jack
jeremiah



Joined: 20 Jul 2010
Posts: 1345

View user's profile Send private message

PostPosted: Thu Sep 10, 2020 10:06 am     Reply with quote

Your IF statement is wonky. The 3rd check (<'A') will fail if you receive a number '0' to '9' as all of those are less than 'A'.

Also, even if you get through with a letter, you are subtracting 0x30 from the letter which doesn't work out mathematically. For example, 'A' is 0x41. 0x41-0x30 = 0x10 = 16 decimal, and it is supposed to be 10 decimal. Even with your -7, it would be incorrect.

Start with fixing your IF and then fix math. When you do your math, you will need two different equations, one for numbers and one for the letters.

There are functions like atoi() available that can do this for you as well, though you will need to convert your character to a short string with a null character at the end.

EDIT: If I were gonna do it, I would break this up into 3 sections:
1. Digit between '0' and '9': subtract '0' from the result
2. Digit between 'A' and 'F' subtract 'A' from the result and add 10 decimal
3. return an error (0xFF for example) if the input does not fit the first two (but you would need to check this in your code before using it..you wouldn't want to access a bad array value if you had an error)
JAM2014



Joined: 24 Apr 2014
Posts: 138

View user's profile Send private message

PostPosted: Mon Sep 14, 2020 1:06 pm     Reply with quote

Hi All,

Well, thanks for the input! In the end, I was never able to get the method of converting the ASCII character representing '0' to '5' to the numerical value 0 to 5. That approach would seem to work for a while, and then my program would start behaving very strangely, and/or crash, so I suspect I was coming up with an occasional array indices that was out-of-bounds....

So, I swallowed my pride and took a much more 'brute force' approach like this:

Code:

if (Node_Msg_Buffer[5] == '0') TempVar = 1; else TempVar = 2;
         switch (Node_Msg_Buffer[2]){
            Case '1':
               NodeStatus[0] = TempVar;
               break;
            Case '2':
               NodeStatus[1] = TempVar;
               break;
            Case '3':
               NodeStatus[2] = TempVar;
               break;
            Case '4':
               NodeStatus[3] = TempVar;
               break;
            Case '5':
               NodeStatus[4] = TempVar;
               break;
         }


Pretty? No! Working? Yup!!

Jack (hanging my head in 'C' shame.....)
temtronic



Joined: 01 Jul 2010
Posts: 9221
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Mon Sep 14, 2020 2:32 pm     Reply with quote

Hay if it works, it's GOOD !!
I was thinking the CCS function ATOI() might somehow be used but.....as long as what you code works, and YOU understand it, that's all that really matters.
I ain't no 'C' wizard either !! Laughing
I mumble and fumble but in the end 'stuff works'.
Besides I'm too old to goto school !
Jay
AESPOSITO



Joined: 28 Jul 2020
Posts: 4
Location: Arizona

View user's profile Send private message Visit poster's website

Num2Hex2Num
PostPosted: Thu Sep 17, 2020 2:19 pm     Reply with quote

I keep files I call "Globals.c" and "Globals.h" for various projects;

The snippets here avoid using any string functions for speed.

Code:

Header file:
//----------------------------------------------------------------------------
#DEFINE Num2Hex(i) if(i>9){i+=0x37;}else{i+=0x30;} 
// converts 0-15 to hexadecimal character (4 bit nibble)
int8 HEXnibble[2]; // declare
// use union for converting to and from different bit-length operations
union uxl { 
  int32 asLong;  // Long is actually double long 
  int16 asWord[2];
signed int16 asSWord[2];
  int8 asByte[4];
signed int8 asSByte[4]; 
  int1 asBit[32]; 
} XferLW; 
//---------------------------------------------------------------------------- 

C file:
//---------------------------------------------------------------------------- 
int8 Hex2Num(char h) {  // convert ASCII Hexadecimal characters
int8 x=0;
 if(h<65) {
   if((h<58)&&(h>47)) { x=h-48; }  // numbers
   if(h<16) { x=h; }  // hexnumber
 }
 else {
   if(h<71) { x=h-55; } // upper case 
   else { x=h-87; } // lower case       
 }
return x;   

//----------------------------------------------------------------------------
int8 Hex2Byte(char a,b) {  // convert 2 Hexadecimal characters 
int8 x,y;
 x=Hex2Num(a); y=Hex2Num(b);
 x<<=4;  x+=y;
return x;   
}
//----------------------------------------------------------------------------
int16 Hex2Word(char a,b,c,d) {  // MSB-LSB convert 4 Hexadecimal characters
int16 x,y;
 x=Hex2Byte(a,b); y=Hex2Byte(c,d);
 x<<=8;  x+=y;
return x;                                 
}     
//----------------------------------------------------------------------------
void HEXnibbles(int8 b) {  // convert Byte to Hexadecimal characters
// HEXnibble[0/1] BYTE BECOMES HEX CHARACTER USED BY OTHER ROUTINES
 HEXnibble[0]=0x0F&b; // low nibble
 swap(b);                           
 HEXnibble[1]=0x0F&b;  // high nibble
// convert decimal value to Hex character's Ascii value 
 Num2Hex(HEXnibble[0]);  Num2Hex(HEXnibble[1]);  // #Defined
}
//----------------------------------------------------------------------------
int16 Byte2Hex(int8 b) {  // convert Byte to 2 Hexadecimal characters 
int16 x;
 HEXnibbles(b); x=make16(HEXnibble[1],HEXnibble[0]);
return x; // Word contains 2 character values for HEX numbers     
}
//----------------------------------------------------------------------------
int32 Word2Hex(int16 w) {  // convert Word to 4 Hexadecimal character values 
int16 x;                                 
 XferLW.asWord[0]=w; 
 HEXnibbles(XferLW.asByte[1]);
 x=make16(HEXnibble[1],HEXnibble[0]);
 HEXnibbles(XferLW.asByte[0]);
 XferLW.asWord[0]=make16(HEXnibble[1],HEXnibble[0]);                                       
 XferLW.asWord[1]=x;         
return XferLW.asLong;  // contains 4 character values for HEX numbers 
}         
//----------------------------------------------------------------------------



This has been working for about 2 decades now

Very Happy
_________________
A Esposito, CEO
Avatar Engineering Corp.
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group