LabWindows/CVI

cancel
Showing results for 
Search instead for 
Did you mean: 

add 0x before sending RS232 messages

Hi, I have an issue using comwrt function, the message I d like to send is like 0103040F000F unfortunately comwrt function convert each character as  hexadecimal ascii so the message sent looks like 30 31 33 ...... and I actually like to send the exact message 0103040F000F  on port so I have tried to use comwrtbyte function sending my datas byte per byte 01, 03 but I cannot send A to F values literally I must put a 0x before each, but I don't know how to put the whole thing in a variable,

int SendMessage (char *in)
{
    int len = 0;
    int i=0;
    int val=0;
    int ByteToSend;
    char *CharByteToSend;
    char Hexa[3]; Hexa[2]=0;
    len = strlen(in);

   
    CharByteToSend=(char*)malloc(5*sizeof(char));
 
    CharByteToSend[0]='0';
    CharByteToSend[1]='x';
   
    do                                 
    {
    
        strncpy(CharByteToSend+2, in+i, 2);  CharByteToSend[4] = 0;
   
        ByteToSend = atoi(CharByteToSend);
             
        ComWrtByte(1, ByteToSend);
        
        i++;
        *in++;
    
    }
    while(i<len);
   
    return 0;
}



0 Kudos
Message 1 of 9
(6,277 Views)
Hi Olivier,
it seems to me that you are a bit confused as to how numbers are stored and represented. I saw some days ago this gem from dummy_decoy:

computer science course, lesson 1: A VARIABLE STORES A NUMBER, NOT THE REPRESENTATION OF A NUMBER !

e.g.:
int a = 8;
'a' contains the value which is commonly represented by humans as 8 in decimal. but it is also 1000 in binary or 10 in octal of 8 in hexadecimal. thus, all those tests are true without performing any 'conversion' on the variable:
a == 8      // decimal
a == 0x8  // hexadecimal
a == 010  // octal

(food for thought: decimal is a weird representation used by humans only because they have 10 fingers. imagine if we had 4 fingers on one hand, and 3 on the other)


To explain: how is your message being created? Only in case you have a string that actually reads "0103040F000F" you will need to read it two characters at a time and convert from
(hex) string to a value. If you are creating your message at run-time, instead, you can do the following:
 
char   d[10];
 
d[0] = 0x01;
d[1] = 0x03;
d[2] = 0x04;
d[3] = 0x0F;  and so on
 
and write it using ComWrt.


Proud to use LW/CVI from 3.1 on.

My contributions to the Developer Community
________________________________________
If I have helped you, why not giving me a kudos?
0 Kudos
Message 2 of 9
(6,267 Views)
Hi Roberto,
correct me if I am wrong but I am picking up the message from  a string control and when I try to use comwrt function it automatically make the conversion to ascii hexa then the values sent on the port are not what I have expected,
But I have already found a way, it tooks me a day for this easy point but now it works,
int SendMessage (char *in)
{
    int len = 0;
    int i=0;

    int ByteToSend=0;
    char *CharByteToSend;

    len = strlen(in);

   
    CharByteToSend=(char*)malloc(8*sizeof(char));

    do                                 
    {

        strncpy(CharByteToSend, in+2*i, 2);  CharByteToSend[2] = 0; 
       
        Fmt(&ByteToSend, "%x<%s", CharByteToSend);
       
        ComWrtByte(1, ByteToSend);

        i++;

    }
    while(2*i<len-1);
   
    return 0;
}

I just used the format function on the two characters
Thanks anyway and sry for this trivial question
0 Kudos
Message 3 of 9
(6,256 Views)

You're absolutely right, Olivier: coming from an actual string you must scan 2 characters at a time and retrieve their value. Your solution is correct, but may I suggest a more compact way of solving your problem?

#include <formatio.h>
#include <ansi_c.h>
int  i, ch;
char   src[20], dst[20];

strcpy (src, "0103040F102030");
for (i = 0; i < strlen (src) / 2; i++) {
    Scan (src, "%s[i*w2]>%i[r16]", i * 2, &ch);
    sprintf (dst[i], "%c", ch);
}
ComWrt (port, dst, strlen (src) / 2);

A disadvantage of this solution is that it uses CVI Formatting and I/O library function Scan, so if portability to non-CVI compilers is one of your issues you can forgive it.
Remember that you cannot use strlen on destination string "dst" since it may contain non ascii characters and it will return incorrect results.



Proud to use LW/CVI from 3.1 on.

My contributions to the Developer Community
________________________________________
If I have helped you, why not giving me a kudos?
0 Kudos
Message 4 of 9
(6,244 Views)
Hi,
I have an issue calculating the CRC for Modbus RTU protocol, I have programed this function according to the algorithm given by the speed drive constructor I must control (leroy somer)

algorithm:
START
CRC=0xFFFF;
NumberOfTreatedBytes = 0;
NextByte = FirstByte;
Repeat until all Octets have been treated
{
    ActualByte = NextByte;
    CRC=CRC xor ActualByte;
    Repeat 8 times
         {
          if(CRC is odd) CRC=CRC/2 xor 0xA001;
          else CRC= CRC/2;
         }
}
END

Function:

char *CRCcalculation(unsigned char *Adresse_tab)
{
    unsigned int Crc = 0xFFFF;
    unsigned int Polynome = 0xA001; // Polynôme = 2^15 + 2^13 + 2^0 = 0xA001.   
    unsigned char CptOctet = 0;
    unsigned char CptBit = 0;
    unsigned char Parity= 0;
    char *CRC;
    char *RTUBuff;
    int len=0;
    
    RTUBuff=(char*)malloc(109*sizeof(char));
                                                                          
    
    strcpy(RTUBuff, Adresse_tab);
    
    len = strlen(RTUBuff);
    
    CRC=(char*)malloc(20*sizeof(char));
    
    for ( CptOctet= 0 ; CptOctet < len ; CptOctet++)
    {
     
        Crc ^= *( Adresse_tab + CptOctet); //Ou exculsif entre octet message et CRC

     
        for ( CptBit = 0; CptBit <= 7 ; CptBit++) // Mise a 0 du compteur nombre de bits
         
        {
            
            
             if (Crc%2 == 1)// Test si nombre impair -> Apres decalage à droite il y aura une retenue
             {
                
                   Crc ^= Polynome; // "ou exclusif" entre le CRC et le polynome generateur.
                
                   Crc >>= 1; // Décalage a droite du crc 
             }
             else Crc >>= 1; // Décalage a droite du crc  
        }
    }
 
 sprintf(CRC, "%X", Crc);
 
 printf("%s", CRC);

 return(CRC);
 
}

But I have tried to use the Modbuspoll software which is able to send Modbus RTU frames and thus calculate the right CRC and it does not give me the same CRC value as my function does
for example, sending this frame 010602750001 the CRC calculated by Modbuspoll is 58 68  and my function return 7F 68.

Do you see any error in my code  or maybe do you know where to find the correctly working function?
Thanks for your help again.
0 Kudos
Message 5 of 9
(6,216 Views)
Hi Olivier,
I am attaching the code fragments I use for CRC calculation and control in Modbus protocol: take a look and see if they give you the correct results. These have been used with several instruments (Siemens S7 plc, CHINO and CAL Controls temperature regulators and so on) so they should be ok for you too.
 
 
Before any instruction:
 
#define CRC16  0xA001     // To calculate CRC tables
static unsigned char crc_table_1[256];  // Table for CRC1 calculation
static unsigned char crc_table_2[256];  // Table for CRC2 calculation
 
 
At program start (or before you begin preparing Modbus messages with their CRC):
 
//-------------------------------------------------------------------------------------------------
//                             Initialize tables for CRC calculation
//-------------------------------------------------------------------------------------------------
void InitCRC(void)
{
 unsigned char i;
 unsigned int mask, crc, mem;

 for (mask = 0; mask < 256; mask++) {
  crc = mask;
  for (i = 0; i < 8; i++) {
   mem = (unsigned int)(crc & 0x0001) ;
   crc /= 2;
   if (mem)
    crc ^= CRC16 ;
  }
  crc_table_2[mask] = (unsigned char) (crc & 0xff); // lobyte
  crc_table_1[mask] = (unsigned char) (crc >> 8);   // hibyte
 }
 return;
}
 
 
Calculate CRC when preparing a message to send out:
 
//-------------------------------------------------------------------------------------------------
//
//          Computes the CRC and append to the buffer with the data to be transmitted
//
// Parameters:    buf = message buffer
//                size = lengh of message buffer excluding the crc (crc will be appended to buf
//                         so you must pass a buffer with extra lenght)
//
// Return values: none
//
//-------------------------------------------------------------------------------------------------
void CalcCRC(unsigned char * buf, unsigned char size)
{
 unsigned char car, i;
 unsigned char crc0, crc1;

 crc0 = 0xff;
 crc1 = 0xff;

 for (i = 0; i < size; i++) {
  car  = buf[i];
  car  = * ((unsigned char *) buf + i);
  car ^= crc0;
  crc0 = (unsigned char) (crc1 ^ crc_table_2[car]);
  crc1 = crc_table_1[car];
 }
 * (buf + size)     = crc0;  // CRC low
 * (buf + size + 1) = crc1;  // CRC high
 return;
}
 
 
When checking CRC on a received message:
 
//-------------------------------------------------------------------------------------------------
//
//           CRC check and match with the CRC found on the received data buffer
//
// Parameters:    buf = message buffer
//                size = lengh of message buffer excluding the crc
//
// Return values: 0 if CRC ok
//                1 if CRC bad
//                If CRC is bad the data packet is corrupted, so it is necessary to discard it.
//
//-------------------------------------------------------------------------------------------------
int CheckCRC(unsigned char * buf, unsigned char size)
{
  unsigned char car, i;
  unsigned char crc0, crc1;
  unsigned int  crc_calc, crc_read;

  crc0 = 0xff;
  crc1 = 0xff;

  for(i = 0; i < size; i++) {
    car  = buf[i];
    car  = * ((unsigned char *) buf + i);
    car ^= crc0;
    crc0 = (unsigned char) (crc1 ^ crc_table_2[car]);
    crc1 = crc_table_1[car];
  }
  crc_calc  = (crc1 << 😎 + crc0;
  crc_read = * (buf + size) + 256 * (* (buf + size + 1));
  return (crc_read != crc_calc);
}

 


Proud to use LW/CVI from 3.1 on.

My contributions to the Developer Community
________________________________________
If I have helped you, why not giving me a kudos?
0 Kudos
Message 6 of 9
(6,210 Views)

hi,

 

in the above thread u  have mentioned

" d[0] = 0x01;
  d[1] = 0x03;                 /* this is fine */
  d[2] = 0x04;
  d[3] = 0x0F;  and so on   "
if the next step is d[4] = 0x00, d[5] = 0x1B, d[6] = 0xC0     /* 00 taken as null character*/
while writing ComWrt it assumes d[4] th value as null character and discards sending the rest of the message d[5] and d[6].
what will be solution to send entire msg which includes 00 also
0 Kudos
Message 7 of 9
(5,219 Views)

ComWrt(port, buffer, count) will not stop when it sees a 0x00 character in buffer - it will only stop when count bytes have been sent, whatever they are. But please bear in mind that most C functions (and the debugger) will probably assume the end of a string when they see a 0x00 and this can give misleading results when trying to diagnose problems. Motto: don't use string based functions to work with binary data. ComWrt() works with binary data.

 

JR

0 Kudos
Message 8 of 9
(5,202 Views)

JR is absolutely right, as you can prove by checking ComWrt return value: it will be equal to the number of bytes transmitted, including any embedded nul byte, if any.



Proud to use LW/CVI from 3.1 on.

My contributions to the Developer Community
________________________________________
If I have helped you, why not giving me a kudos?
0 Kudos
Message 9 of 9
(5,200 Views)