Jump to content
yyrkoon

SocketCAN help needed

Recommended Posts

Also I know I need to keep count of frames for each PGN type, but am not sure how I should go about that. Based on a count [1-11] for example I'd have an offset to know where to put the next frame payload in a byte field. But how would I do that without a global for every PGN I'm tracking ?

 

I could do this as a variable in main(), but main will be in the stack for the duration of the program, so in that case the variable may as well be a global . . .

Share this post


Link to post
Share on other sites

Not sure what your question is. Can you decode/parse in real time as in look for the start of frame. The next byte will tell you the number of bytes you need to pull in. Once you have all the bytes, parse the frame for data you need. You may have to have two buffers - one for incoming data and one for parsing data. Incoming data buffer feeds into the parsing buffer.

 @@bluehash More concisely, how would you do that to ensure data is ordered correctly. I've yet to see out of order frames, but there is no guarantee that frames will be in sequential order. Or that a higher priority frame will not come in in the middle of a fast packet frame set. I'm imagining a large if / else chain, or perhaps a "fall through" switch block. Neither of these two cases really appeal to me, and I'm not sure how else I could do this.

Share this post


Link to post
Share on other sites

Spending a lot of time scratching my head *thinking* but so far this is what I have in mind.

struct Fastpacket {
  unsigned char *buffer;
  unsigned char bufferPos;
  unsigned char size;
};

struct Fastpacket *newFastpacket(size_t size){

  struct Fastpacket *retVal = malloc(sizeof(struct Fastpacket));
  if(retVal == NULL){
    return NULL;
  }

  retVal->buffer = malloc( size * sizeof(unsigned char));
  if(retVal->buffer == NULL){
    free(retVal);
    return NULL;
  }

  retVal->bufferPos = 0;
  retVal->size = size;
  return retVal;
}

void delFastpacket(struct Fastpacket *fastpacket){
  if(fastpacket != NULL){
    free(fastpacket->buffer);
    free(fastpacket);
  }

}

Share this post


Link to post
Share on other sites

Well . . . it's not pretty, and not complete but it works . . .

 

code:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>

// Simulated frame set - real values from frame.data[8] are __u8 which
// are not exactly portable.
unsigned char msg01[8] = {0x40, 0x49, 0x03, 0xFC, 0x33, 0x01, 0x01, 0x00};
unsigned char msg02[8] = {0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
unsigned char msg03[8] = {0x42, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00};
unsigned char msg04[8] = {0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
unsigned char msg05[8] = {0x44, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
unsigned char msg06[8] = {0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF};
unsigned char msg07[8] = {0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
unsigned char msg08[8] = {0x47, 0x00, 0x00, 0x03, 0x36, 0x9E, 0x03, 0x00};
unsigned char msg09[8] = {0x48, 0x3E, 0x08, 0x00, 0x00, 0x0C, 0x6F, 0x17};
unsigned char msg10[8] = {0x49, 0xFF, 0xFF, 0xF4, 0x01, 0x00, 0x00, 0xB2};
unsigned char msg11[8] = {0x4A, 0x01, 0x00, 0x00, 0x0A, 0xFF, 0xFF, 0xFF};

struct Fastpacket {
  unsigned char *buffer;
  unsigned char bufferPos;
  unsigned char size;
};

struct Fastpacket *newFastpacket(size_t size){

  struct Fastpacket *retVal = malloc(sizeof(struct Fastpacket));
  if(retVal == NULL){
    return NULL;
  }

  retVal->buffer = malloc( size * sizeof(unsigned char));
  if(retVal->buffer == NULL){
    free(retVal);
    return NULL;
  }

  retVal->bufferPos = 0;
  retVal->size = size;
  return retVal;
}

void delFastpacket(struct Fastpacket *fastpacket){
  if(fastpacket != NULL){
    free(fastpacket->buffer);
    free(fastpacket);
  }

}

void appendFrame(struct Fastpacket *fastpacket, unsigned char *msg){
 
  int i;

  for (i = 0; i < 8 && fastpacket->bufferPos < fastpacket->size; ++i){
    fastpacket->buffer[fastpacket->bufferPos] = msg[i];
    fastpacket->bufferPos += 1;
  }
}

int main(int argc, char *argv[]) {

  int i;
  struct Fastpacket *fastpacket = newFastpacket(88);
 
  appendFrame(fastpacket, msg01);
  appendFrame(fastpacket, msg02);
  appendFrame(fastpacket, msg03);
  appendFrame(fastpacket, msg04);
  appendFrame(fastpacket, msg05);
  appendFrame(fastpacket, msg06);
  appendFrame(fastpacket, msg07);
  appendFrame(fastpacket, msg08);
  appendFrame(fastpacket, msg09);
  appendFrame(fastpacket, msg10);
  appendFrame(fastpacket, msg11);

  for(i = 0; i < fastpacket->bufferPos; ++i){
    printf(" %02X" , fastpacket->buffer[i] );
    if((i + 1 ) % 8 == 0){
      printf("\n");
    }
  }

  printf("\n");
  printf(" buffer position is currently at: %d\n", fastpacket->bufferPos);

  delFastpacket(fastpacket);
  return 0;

output:

william@debian-can:~$ gcc -Wall test.c -o test
william@debian-can:~$ ./test
 40 49 03 FC 33 01 01 00
 41 00 00 00 00 00 00 00
 42 00 00 00 FF FF 00 00
 43 00 00 00 00 00 00 00
 44 02 00 00 00 00 00 00
 45 00 00 00 00 00 FF FF
 46 00 00 00 00 00 00 00
 47 00 00 03 36 9E 03 00
 48 3E 08 00 00 0C 6F 17
 49 FF FF F4 01 00 00 B2
 4A 01 00 00 0A FF FF FF

 buffer position is currently at: 88

Still need to consider how I will use frame.data[0] ( line number ) to keep frame payload correct. I'm thinking right now, I'll probably store the first line number of the first frame in the struct above, and compare it to the most current frame as they come in .  . but I dont know, been a long day, and not much chance to code . . .
 

Share this post


Link to post
Share on other sites

Nothing wrong with what you have written.

 

If you want it a little faster and smaller with a little less memory fragmentation, here is some optimized code...

 

struct Fastpacket {
  unsigned char *bufferEnd;		// End of buffer + 1
  unsigned char *bufferPos;		// Next char goes here
};

struct Fastpacket *newFastpacket(size_t const size){

    // Allocate enough memory for the structure and the buffer
    struct Fastpacket *retVal = malloc(sizeof(struct Fastpacket) + (size * sizeof(unsigned char)));

    if(retVal) {
          // Buffer begins after the structure
	  retVal->bufferPos = (unsigned char *)(retVal + 1);
	  retVal->bufferEnd = retVal->bufferPos + size;
    }

    return retVal;
}

void delFastpacket(struct Fastpacket *fastpacket){
    if(fastpacket) free(fastpacket);
}

void appendFrame(struct Fastpacket *fastpacket, unsigned char const *msg){

    unsigned char const * const msgEnd = msg + 8;

    while((msg < msgEng) && (fastpacket->bufferPos < fastpacket->bufferEnd))
        *(fastpacket->bufferPos)++ = *msg++;
}

int main(int argc, char *argv[]) {

  int i;
  struct Fastpacket *fastpacket = newFastpacket(88);
  if(!fastpacket) return -1;
 
  appendFrame(fastpacket, msg01);
  appendFrame(fastpacket, msg02);
  appendFrame(fastpacket, msg03);
  appendFrame(fastpacket, msg04);
  appendFrame(fastpacket, msg05);
  appendFrame(fastpacket, msg06);
  appendFrame(fastpacket, msg07);
  appendFrame(fastpacket, msg08);
  appendFrame(fastpacket, msg09);
  appendFrame(fastpacket, msg10);
  appendFrame(fastpacket, msg11);

  unsigned char const *b = (unsigned char*)(fastpacket + 1);
  int const len = fastpacket->bufferPos - b;
  for(i = 0; i < len; ++i)
    printf("%02X%s" , *b++, ((i & 7) == 7) ? "\n" : " ");

  printf("\nBuffer position is currently at: %d\n", len);

  delFastpacket(fastpacket);
  return 0;
}

Share this post


Link to post
Share on other sites

Checking for proper sequence...

(only changed code shown)

 

struct Fastpacket {
  unsigned char *bufferEnd;		// End of buffer + 1
  unsigned char *bufferPos;		// Next char goes here
  unsigned char seq;                    // Next char in sequence
};

struct Fastpacket *newFastpacket(size_t const size){

    // Allocate enough memory for the structure and the buffer
    struct Fastpacket *retVal = malloc(sizeof(struct Fastpacket) + (size * sizeof(unsigned char)));

    if(retVal) {
          // Buffer begins after the structure
	  retVal->bufferPos = (unsigned char *)(retVal + 1);
	  retVal->bufferEnd = retVal->bufferPos + size;
          retVal->seq = 0x40;
    }

    return retVal;
}

int appendFrame(struct Fastpacket *fastpacket, unsigned char const *msg){

    if(msg[0] != fastpacket->seq) { // Check if incorrect sequence
       fastpacket->seq = 0x40;      // Start over
       return -1;                   // Return error
    }

    ++fastpacket->seq;              // Increment sequence

    unsigned char const * const msgEnd = msg + 8;

    while((msg < msgEng) && (fastpacket->bufferPos < fastpacket->bufferEnd))
        *(fastpacket->bufferPos)++ = *msg++;

    return 0;
}

Share this post


Link to post
Share on other sites

Still newb when it comes to malloc(). calloc(), realloc(), and free(). pointers too really.

 

But experimenting last night with creating / deleting these structs. I observed what seemed to be a dangling pointer. So after using delFastpacket(fastpacket); I was still able to access fastpacket->size, or fastpacket->bufferPos. But do not remember what all I experimented with. One thing for sure is that if you try and free() the same object twice, you wind up with a kernel panic. heh.

 

So, what is the best way to avoid this situation ? It can not be as simple as *pointer = NULL; can it ?

 

[EDIT]

 

Yes, according to this post http://stackoverflow.com/questions/6054271/freeing-pointers-from-inside-other-functions-in-cit can be just about that simple.

Share this post


Link to post
Share on other sites

Checking for proper sequence...

(only changed code shown)

 

struct Fastpacket {
  unsigned char *bufferEnd;		// End of buffer + 1
  unsigned char *bufferPos;		// Next char goes here
  unsigned char seq;                    // Next char in sequence
};

struct Fastpacket *newFastpacket(size_t const size){

    // Allocate enough memory for the structure and the buffer
    struct Fastpacket *retVal = malloc(sizeof(struct Fastpacket) + (size * sizeof(unsigned char)));

    if(retVal) {
          // Buffer begins after the structure
	  retVal->bufferPos = (unsigned char *)(retVal + 1);
	  retVal->bufferEnd = retVal->bufferPos + size;
          retVal->seq = 0x40;
    }

    return retVal;
}

int appendFrame(struct Fastpacket *fastpacket, unsigned char const *msg){

    if(msg[0] != fastpacket->seq) { // Check if incorrect sequence
       fastpacket->seq = 0x40;      // Start over
       return -1;                   // Return error
    }

    ++fastpacket->seq;              // Increment sequence

    unsigned char const * const msgEnd = msg + 8;

    while((msg < msgEng) && (fastpacket->bufferPos < fastpacket->bufferEnd))
        *(fastpacket->bufferPos)++ = *msg++;

    return 0;
}

 Just to clear things up a bit. I know I am kind of giving information a bit at a time, but there is a lot for me, and for those reading my posts here to absorb. So, our setup. We have two AC inverters. One operates all the time, and is what is called the master. The second inverter is called a slave, and only comes on when the first is outputting more than a configurable amount of current ( power ).

 

With this in mind, the ID field I mentioned in previous posts for each PGN( concerning the inverters ) can vary. At the time of that candump they were 01, and 02  Also, the first byte of each frame.data[] payload ( line number ) is not a set value. In the candump snippet I showed before it started with 0x40, but there is no guarantee it will start with 0x40 as a line number. But once a new Fast packet  data set starts, these numbers will be in sequence (value += 1;) *Assuming* a full data set. I have seen one case where a fast packet data set did not finish . . .e.g. it stopped after 4 frame sets when interrupted by what I am guessing was a higher priority frame, and then never continued.

 

So here are two fast packet frame sets. Two different inverters( IDs ) but note the sequence numbers in the first byte of each frame.data[] payload.

  can1  19F00601   [8]  40 49 03 FC 33 01 01 00
  can1  19F00601   [8]  41 00 00 00 00 00 00 00
  can1  19F00601   [8]  42 00 00 00 FF FF 00 00
  can1  19F00601   [8]  43 00 00 00 00 00 00 00
  can1  19F00601   [8]  44 02 00 00 00 00 00 00
  can1  19F00601   [8]  45 00 00 00 00 00 FF FF
  can1  19F00601   [8]  46 00 00 00 00 00 00 00
  can1  19F00601   [8]  47 00 00 03 36 9E 03 00
  can1  19F00601   [8]  48 3E 08 00 00 0C 6F 17
  can1  19F00601   [8]  49 FF FF F4 01 00 00 B2
  can1  19F00601   [8]  4A 01 00 00 0A FF FF FF


  can1  19F00602   [8]  20 49 03 FC 33 01 01 00
  can1  19F00602   [8]  21 00 00 00 00 00 00 00
  can1  19F00602   [8]  22 00 00 00 FF FF 00 00
  can1  19F00602   [8]  23 00 00 00 00 00 00 00
  can1  19F00602   [8]  24 02 00 00 00 00 00 00
  can1  19F00602   [8]  25 00 00 00 00 00 FF FF
  can1  19F00602   [8]  26 00 00 00 00 00 00 00
  can1  19F00602   [8]  27 00 00 03 E0 7B 03 00
  can1  19F00602   [8]  28 1E 00 00 00 00 70 17
  can1  19F00602   [8]  29 FF FF 06 00 00 00 00
  can1  19F00602   [8]  2A 00 00 00 00 FF FF FF

Anyway, what I am having difficulty with is trying to figure out. Is how does my program know when a frame set is complete? I *could* hard code some value like bytes(77) for data only no line numbers, or frame sets(11). But If I learned anything from you oPossum, or Rick is that hard coding stuff like leads to less flexible / more redundant code. But in this case I'm not sure I have another option. However, the second byte of the first frame *does* give us the length of the data field so . . . there may be a way out of hard coding, once I wrap my brain around *how* to use that value to my advantage.

 

More thinking to do . . .

Share this post


Link to post
Share on other sites

Have you ever seen any frames with more than 16 packets? Maybe the lower nibble of the first byte is the packet sequence and the upper nibble can be ignored.

No, in fact I've only noticed frame sets of 1 with either 4 or 6 byte payload lengths. Or 11 frame set of 8 bytes of each frame.

 

However I have not examined all the PGNs that my buddy wulfman has decoded by hand. I'm thinking there could also be one or two PGN payloads that are one frame 8 bytes each too. However, there are also PGN payloads that I'm not going to worry about. Like ISO_CLAIM, or ADDRESS_CLAIM. Also there does seem to be a few PGN payloads that are redundant. such as AC_INPUT_STATUS and BATTERY_STATUS . . . they're the same, except perhaps BATTERY_STATUS includes data for battery temperature. etc.

 

He did make an xml file for the people at CANaconda (a python github project ), in hopes they would be able to do something with the data. Me on the other hand, I have different ideas. It's not that I care that the information is out there. Because I think that is great. But I'm working on my own angle because I find this an interesting challenge / learning experience. I also have a couple ideas in mind as to how I want to use my application.

 

Do I want to write a program that decodes the data on the fly using ncurses to display the data ?

 

or

 

Would I like to use candump + netcat to log all the data on a remote system. Then use my app to graph the saved information ?

 

I do not know yet . . .

Share this post


Link to post
Share on other sites

So here is one such "message" from the XML file wulfman created. You can tell he is no programmer as values are mixed hex, decimal, and bytes / bits ? Hard for me to tell but he's not commented in the file  . . . but I can say that size ="49" should be "0x49"  or 73 in decimal.

<messageInfo name = "AC Output Status" pgn = "126982" size = "49" protocol = "nmea2000" type = "fast-packet">
        <desc>0x1F006 AC Output Status RMS. needs a lot of work</desc>
        <field
        name = "Message count"
        type = "int"
        offset = "2"
        length = "6"
        />
        <field
        name = "Total bytes"
        type = "int"
        offset = "8"
        length = "8"
        signed = "no"
        />
        <field
        name = "Unknown"
        type = "int"
        offset = "16"
        length = "16"
        />
        <field
        name = "Unknown"
        type = "int"
        offset = "32"
        length = "8"
        />
        <field
        name = "Unknown"
        type = "int"
        offset = "40"
        length = "8"
        />
        <field
        name = "Line1"
        type = "int"
        offset = "48"
        length = "8"
        />
        <field
        name = "L1Voltage"
        type = "int"
        offset = "56"
        length = "32"
        />
        <field
        name = "L1Current"
        type = "int"
        offset = "88"
        length = "32"
        />
        <field
        name = "L1CurrentPer"
        type = "int"
        offset = "120"
        length = "8"
        />
        <field
        name = "L1Freq"
        type = "int"
        offset = "128"
        length = "32"
        />
        <field
        name = "L1BreakerSz"
        type = "int"
        offset = "160"
        length = "32"
        />
        <field
        name = "L1ApparentPwr"
        type = "int"
        offset = "192"
        length = "16"
        />
        <field
        name = "L1RealPwr"
        type = "int"
        offset = "208"
        length = "16"
        />
        <field
        name = "L1RealPwrPer"
        type = "int"
        offset = "224"
        length = "8"
        />
        <field
        name = "Line2"
        type = "int"
        offset = "232"
        length = "16"
        />
        <field
        name = "L2Voltage"
        type = "int"
        offset = "238"
        length = "32"
        />
        <field
        name = "L2Current"
        type = "int"
        offset = "270"
        length = "32"
        />
        <field
        name = "L2CurrentPer"
        type = "int"
        offset = "302"
        length = "8"
        />
        <field
        name = "L2Freq"
        type = "int"
        offset = "310"
        length = "32"
        />
        <field
        name = "BreakerSz"
        type = "int"
        offset = "342"
        length = "32"
        />
        <field
        name = "L2ApparentPwr"
        type = "int"
        offset = "374"
        length = "16"
        />
        <field
        name = "L2RealPwr"
        type = "int"
        offset = "390"
        length = "16"
        />
        <field
        name = "L2RealPwrPer"
        type = "int"
        offset = "406"
        length = "8"
        />
        <field
        name = "Line3"
        type = "int"
        offset = "414"
        length = "16"
        />
        <field
        name = "L3Voltage"
        type = "int"
        offset = "430"
        length = "32"
        />
        <field
        name = "L3Current"
        type = "int"
        offset = "462"
        length = "32"
        />
        <field
        name = "L3CurrentPer"
        type = "int"
        offset = "494"
        length = "8"
        />
        <field
        name = "L3Freq"
        type = "int"
        offset = "504"
        length = "32"
        />
        <field
        name = "L3BreakerSz"
        type = "int"
        offset = "536"
        length = "32"
        />
        <field
        name = "L3ApparentPwr"
        type = "int"
        offset = "568"
        length = "16"
        />
        <field
        name = "L3RealPwr"
        type = "int"
        offset = "584"
        length = "16"
        />
        <field
        name = "L3RealPwrPer"
        type = "int"
        offset = "600"
        length = "8"
        />
    </messageInfo

[EDIT]

 

Ok so I just talked with him in person, and if his decoding is right, this will require union + struct bit alignment. No way around it. As some values according to him may be as small as 1-2 bits. Which doesn't exactly mke much sense to me, but it doesn't have to . . .

 

Also his bit calculations are off. As a length of 73 bytes is only 584 bits. Yet at least 2 of the values are out of that range. 77 bytes however would be in range with 8 bits left over I think. SO I'll have to double check his work and see what going on. Perhaps he was discounting reserved / unused bits ( 0xFF ) ? *shrug*

Share this post


Link to post
Share on other sites

oPossum,

 

So I've had a chance to examine many frames / frame sets. It seems what you suggest about ignoring the first nibble of each line number is correct. The second nibble also seems to starts with 0 on the first frame of a frame set. Thanks for pointing that out, it surely will make things easier to deal with.

 

From candump there seems to be 4 different frame sizes. 3,4,6, and 8 bytes.  The 3, 4, and 6  byte length frames do not seem to have line numbers. Where the 8 byte frames all seem to have them. I've also noticed now that I'm paying closer attention that these fast packet frame sets do vary in size. I noticed one from candump that showed a byte size of 0x15. This one in particular was only 4 frames for the complete set. Also reading through the XML file wulfman made, it seems there are a few that can be one 8 byte frame in size. But these I am not bothering with yet. But the largest I've noticed yet is 88 bytes, or 11 frame sets in length. Total, including "filer"

 

So, it seems I'll have to use a large if /else or switch block anyway. As it seems there are many different frame set sizes. For different fastpacket lengths. But at least, and for now I can safely "discard" frames with a frame.can_dlc < 8.

Share this post


Link to post
Share on other sites

ug, why does this scare me ?

 

 

code:

static void process_frame(struct can_frame *frame){

    int i;
    int canid;

    if(frame->can_id & CAN_ERR_FLAG){
        canid = frame->can_id & (CAN_ERR_MASK|CAN_ERR_FLAG);
    }

    else if (frame->can_id & CAN_EFF_FLAG) {
        canid = frame->can_id & CAN_EFF_MASK;
    }
    
    unsigned int pgn = decode_pgn(canid);
    unsigned int srcid = decode_srcid(canid);
    
    switch (pgn){

        case AC_OUTPUT_STATUS:
            // If first frame and fastpacket is not initialized.
            if((frame->data[0] & 0x0F ) == 0 && fastpacket == NULL){
                // TODO: replace "magic" number "88" with a define or an enum - AC_OUTPUT_STATUS_SIZE
                fastpacket = newFastpacket(88, srcid);
                fastpacket->srcid = srcid;
                appendFrame(fastpacket, frame->data);
                fastpacket->seq++;
            } // TODO: More magic nubers . . .
            else if((frame->data[0] & 0x0F) == fastpacket->seq && fastpacket->srcid == srcid){
                appendFrame(fastpacket, frame->data);
                fastpacket->seq++;
            }
            else if((frame->data[0] & 0x0F) != fastpacket->seq || fastpacket->srcid != srcid){
                delFastpacket(fastpacket);
                fastpacket = NULL;
            }
            //TODO: define good . . . magic number . . . baaaaad!
            if(fastpacket->seq == 11){
                printf("PGN: %05X  src_id:  %d\n", pgn, srcid );
                for(i = 0; i < fastpacket->bufferPos; i++){
                    printf(" %02X" , fastpacket->buffer[i] );
                    if((i + 1 ) % 8 == 0){
                          printf("\n");
                    }
                  }
                  delFastpacket(fastpacket);
                  fastpacket = NULL;
            }

        break;

        default:
        break;

    }

}

output:

...

PGN: 1F006  src_id:  1
 20 49 03 FC 33 01 01 00
 21 00 00 00 00 00 00 00
 22 00 00 00 FF FF 00 00
 23 00 00 00 00 00 00 00
 24 02 00 00 00 00 00 00
 25 00 00 00 00 00 FF FF
 26 00 00 00 00 00 00 00
 27 00 00 03 DA A4 03 00
 28 2C 06 00 00 09 6F 17
 29 FF FF 7A 01 00 00 57
 2A 01 00 00 08 FF FF FF
PGN: 1F006  src_id:  2
 C0 49 03 FC 33 01 01 00
 C1 00 00 00 00 00 00 00
 C2 00 00 00 FF FF 00 00
 C3 00 00 00 00 00 00 00
 C4 02 00 00 00 00 00 00
 C5 00 00 00 00 00 FF FF
 C6 00 00 00 00 00 00 00
 C7 00 00 03 7C 94 03 00
 C8 00 00 00 00 00 6F 17
 C9 FF FF 00 00 00 00 00
 CA 00 00 00 00 FF FF FF

...

[EDIT]

 

Also I made *fastpacket a global. Not sure its a good idea, but in the context of stack size, *fastpacket will *always* be on the stack regardless.

Share this post


Link to post
Share on other sites

ug, why does this scare me ?

 

 

 Hi, I am interested to follow your post but you are posting a huge coding at every post, this result in long pages where similar part of code appear and need be compared.

 IMHO it can be better expose your need and progress, dedicate more word to progress and insert code as attachment.

 Anyway question of dangling reference, assign null value to pointer before to use and when disposed, this help check not allocating twice and nor try deallocate memory is no more committed to your pointer. free of a null pointer is less troubling than a dangling pointer.

 

 Modbus is modbus over CAN or rs485? Modbus is a standard on automation/industrial devices, CANBUS is slowly getting space as emerging new standard but require some time to take time of all old market rework all existing devices.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • Create New...