Jump to content
yyrkoon

SocketCAN help needed

Recommended Posts

Had a little time this morning to do a bit more coding. got 3 fields extracted out of fastpacket->buffer. The rest I'm not sure matter. . .

william@debian-can:~$ gcc -Wall cantest2.c -o cantest
william@debian-can:~$ ./cantest

 AC Output Status
 239.31v  16.30A  59.99Hz


 AC Output Status
 232.95v  0.70A  59.99Hz


 AC Output Status
 238.72v  16.20A  59.99Hz


 AC Output Status
 233.00v  0.00A  59.98Hz

^C
william@debian-can:~$

 

Share this post


Link to post
Share on other sites

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.

 

 

First, I am not a professional developer. I have been programming in multiple languages since the 90's. But always as a hobby, and in my spare time. If i am pasting code snippets it is because I am looking for advice, or I am unhappy with what I have code wise in that snippet.  Right now, my code is a mess and needs serious refactoring, Until I am reasonably happy with it, I probably will not be pasting the whole bit. When I am happy with it, it will probably go on github. With that said, it is my intention to give information about the subject. Not to write code for someone else to commercialize. . .

 

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.

 

 

http://en.wikipedia.org/wiki/Modbus

 

My understanding of Modbus is that it is the old Modicon ( Schneider electric now ) protocol originally implemented over RS485, but on / over CANBus. I do not pretend to understand it in great detail. The only reason I mentioned it early on is that I read a post from a forum( somewhere ) that XanBus was based on ModBus. Perhaps it was at some point, but what we're dealing with is based on NEMA 2000 + NEMA 2000 fast packet protocols. Which are in turn somehow based on the J1939 protocol. Again, I do not know everything, but believe that I understand enough to achieve what I have in mind.

Share this post


Link to post
Share on other sites

First, I am not a professional developer. I have been programming in multiple languages since the 90's. But always as a hobby, and in my spare time. If i am pasting code snippets it is because I am looking for advice, or I am unhappy with what I have code wise in that snippet.  Right now, my code is a mess and needs serious refactoring,

 

 About this, sorry, I am professional developer and programming teacher too, first you have to don't mess up other, so try in first focus your target, when this is clear refine step by step one thing at time.

 Posting in a disordered manner just confuse you and other try to help you confused by you.. This is impossible to clean and final result can be more crappy and time consuming task to all as you think.

 

 Again I am using modbus from a very long time, are modbus packet transported by CANBUS? So you are dealing just with packets free of timing constraint of RS485?

Is CANBUS your single transport BUS Media?

 Is your goal to encode decode packet from and to devices are you using?

If so try prepare some **SEPARATE** tables of data mapping, post one at time and don't intermix them, title them to get data and progress at single watch.

If you provide hint and contribute to community maybe you get more clean and useful help.

 So I can try help you if I can get something helpful for me and other, I cannot try confuse myself and other on a similar mess.

 I hope this can help cleaning your troubles.

 Roberto

Share this post


Link to post
Share on other sites

Right now, I am working on cleaning up my code. But right now am very busy doing other things that are more important. So coding comes last since it is not currently paying the bills.

 

If so try prepare some **SEPARATE** tables of data mapping, post one at time and don't intermix them, title them to get data and progress at single watch.

If you provide hint and contribute to community maybe you get more clean and useful help.

 So I can try help you if I can get something helpful for me and other, I cannot try confuse myself and other on a similar mess.

 I hope this can help cleaning your troubles.

 Roberto

 

The problem is, my friend decoded this protocol, and he is not a programmer. He is a hardware engineer though - for 35+ years now. So, I am using his data, and it is often confusing, or just wrong. The bit fields he has "documented" are close enough for me to make a few guesses, but I often spend time decoding, his job at decoding the values. Plus, I have never really worked with data in this way with C before. Anyway, these are not excuses really, just telling you that it is not easy, but I am confident that I will eventually get it all done. It is a lot to learn, but I enjoy learning, and if it was not a challenge, I probably would not be interested in it.

 

To be clear. This is not Modbus. This is CAN on the physical layer, using socketCAN on the low level software layer, and NEMA 2000 + NEMA 2000 fast packet high level protocols. Using custom PGNs. Perhaps even registered with NEMA, but they're not documented publicly as far as I've been able to find so far.

 

[EDIT]

 

After talking with my friend it seems that I misunderstood what Modbus *is*. According to what I've just been told, Modbus is either serial, or Modbus over TCP/IP. Not sure where I got the impression that Modbus is the old Modicon serial protocol over CANBus, but I was wrong it seems.

Share this post


Link to post
Share on other sites
Again I am using modbus from a very long time, are modbus packet transported by CANBUS? So you are dealing just with packets free of timing constraint of RS485?

 

 

No, not using Modbus. Yes using CANBus, but it is not free of timing constraints. In order to comunicate with the CANBus, from Linux using socketCAN, you have to set baud. When using the beaglebone black + Serial / CAN cape, communicating directly with the inverter. This baud rate is 250kbps. When using a virtual CANBus driver on the Linux development machine, playing back a long candump log file. I do not have to set baud rate. As timestamps are included in this log file.

 

Is CANBUS your single transport BUS Media?

 

If I understand what you're asking. Yes, CANBus is the only physical layer.

 

Is your goal to encode decode packet from and to devices are you using?

Only from( read ). As setting an arbitrary value when not knowing what you're setting can be dangerous in this situation.

 

If so try prepare some **SEPARATE** tables of data mapping, post one at time and don't intermix them, title them to get data and progress at single watch.

If you provide hint and contribute to community maybe you get more clean and useful help.

 So I can try help you if I can get something helpful for me and other, I cannot try confuse myself and other on a similar mess.

 I hope this can help cleaning your troubles.

 

I will try. I am understanding more each day I get the chance to examine the output. Right now I am still working on code, and thinking how I can best show what the fields mean. For instance, each PGN has a set amount of 8 byte frames. In the case of AC Output status, there are 11 total frames. The first byte of each frame is what I now understand as a frame sequence number. Where only the least significant nibble matters for frame sequence tracking [0-A]. The second byte in the first frame is the byte count of the data sent in all 11 frames. Minus reserved / unused bytes marked with 0xFF. The next value is a 32 bit / 4 byte value that is unknown to me. Immediately after this, is what is known as a "line number". Line numbers we believe to represent grid power, generator, and DC power source. There are 3 line numbers 01, 02, 03. And 03 is where I am pulling my data from. 01, and 02 would have to represent grid power, and generator values, where we can not test for grid power. As we are completely off grid. Meaning we have no utility power. We can at some point test for generator power, but it will be some time.

 

Anyway, I know English is not your first language, so I do not expect you to completely understand what I'm saying. This is ok, It will probably make more sense to you when I write up a complete document for AC Output Status. It may take some time however as I'm normally busy during the day doing things that are not as fun, but pay well enough . . .

 

To help illustrate this some . . .

typedef struct {
    int voltage   : 32;
    int frmNum    :  8;
    int current   : 16;
    int unknown   : 16;
    int unknown   :  8;
    int freq      : 16;
}ac_output_line3;

a - Values with underline are frame sequence numbers

b - Bold values are "line numbers"

c - red is RMS voltage

d - green is current

e - light blue is unknown field 16bit and unknown 8bit field.

f - dark blue is frequency

 

 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

 

e - light blue is unknown field 16bit and unknown 8bit field.

 

 

The value for the whole 24bits seems to be 589824. When scaled by .01 this *could* one of the power related fields. I am not sure, I have not done the math, but it is close. However when aligning this 24bit field into an int : 24; struct field. The values after ( left to right, and top to bottom ) go out of alignment. I'm sure there is a good reason for this, but I have not figured it out yet . . .

 

Never mind based on voltage * current we'd get 3773.198 watts, so probably not a single field but two separate fields.

 

More guessing . . .

 

29 FF FF 7A 01 00 00 57

2A 01 00 00 08 FF FF FF

 

First bolded 16bit field seems to be apparent power and second bolded 16bits seems to be real power. Again working left to right, top to bottom. For the record the data seems to be little endian . . . *I think* Oh, and right, these values would be multiplied by 10. So -> power = ( value * 10 ), and rounded to the nearest ten;

Share this post


Link to post
Share on other sites

I would like everyone to know that since this is a learning experience for me. It is in my nature to speculate a lot, and while learning I am doing a lot of speculating . . .

 

With this is mind. I am still trying to nail down first frame 2nd byte "byte count" as to what all is counted in this value. So let me say that I *think* now, that this byte counts all data contained within line numbers, including the line numbers themselves. data values 0xFF are still reserved, or unused for data, but are counted too.

Share this post


Link to post
Share on other sites

For those interested, a picture of our inverter setup as it sits right now. The beaglebone black + logic supply serial / CAN cape is in the top center. Right of the beaglebone black is a CAN block "switch". To the left of the beaglebone black is an ethernet switch. then to the far left of the beaglebone black is a Scheider electric commbox. This commbox provides a web interface for Schneider / Xantrex devices on our CANBus network. The two inverters are of course on the far right, one above the other.

 

https://photos.google.com/album/AF1QipNlHToIxpQz4gDe3_ZItd3kcGdIkWX8XRSXNEmv/photo/AF1QipPShWUq0b0w3pvvZnwgL5TdP500pfrk3_RMs-Ci

Share this post


Link to post
Share on other sites

For those interested, a picture of our inverter setup as it sits right now. The beaglebone black + logic supply serial / CAN cape is in the top center. Right of the beaglebone black is a CAN block "switch". To the left of the beaglebone black is an ethernet switch. then to the far left of the beaglebone black is a Scheider electric commbox. This commbox provides a web interface for Schneider / Xantrex devices on our CANBus network. The two inverters are of course on the far right, one above the other.

 

https://photos.google.com/album/AF1QipNlHToIxpQz4gDe3_ZItd3kcGdIkWX8XRSXNEmv/photo/AF1QipPShWUq0b0w3pvvZnwgL5TdP500pfrk3_RMs-Ci

404

Share this post


Link to post
Share on other sites

I'll have to charge up the trusty DSLR battery to get better pictures. Used an android phone for that, and the image quality sure is crappy. But yeah wulf did all that himself including the inverter install, and he did not want to tear up our nice drywall job we did a few years back.

 

So, what I'm thinking right now for code to extract values from a frame set is to use functions + union / struct byte alignment for 8, 16, and 32 bit values. With defines for offset / length parameters. What do you all think ? does this sound reasonable ? Well actually would not need for 8 bit values, but 16 / 32 bit values would probably be needed. *OR* use more bit shifting . . . maybe a little faster, maybe not but end result should be about the same.

Share this post


Link to post
Share on other sites

Just an update.

 

I have not really had much time to work on this since my last post. But when I have had some time, I've been reading on GNU make, and spent some time modularizing my code. So I have not really made any forward progress concerning XanBus.  Except I did notice in my explanation for AC_OUTPUT_STATUS I did notice that for frequency I was off by a byte. I will correct that now. But it should be shifted "right" 8 bits or a byte, Giving 16 bits uknown field, followed by 8 more bits unknown, then 16 bits for frequency.

Share this post


Link to post
Share on other sites

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 . . .

To answer my own question. "packed" unions. Which for me is kind of funny, since I've always viewed unions as something I'd never need. However as my understanding of how they work, and how they can be used is increasing. I can not believe I have not thought of using them much before. As an example . . .

struct ac_output_data{
    unsigned char length;        // 0x49 for AC_OUTPUT_STATUS
    unsigned char unknown[4];
    unsigned char line1[23];    // L1 equivalent to L3
    unsigned char line2[23];    // L2 equivalent to L3
    unsigned int line3                 : 8;
    unsigned int L3_rms_voltage        : 32;
    unsigned int L3_current             : 16;
    unsigned int L3_unknown1        : 16;
    unsigned int L3_unknown2        : 8;
    unsigned int L3_frequency        : 16;
    unsigned char line3_unknown2[11]; // Related to power values.
    unsigned char padding[2];
    unsigned char srcid;        // Stealing a padding char to store sourceid into.      
};

typedef union{
    struct ac_output_data acdata;
    unsigned char *buffer;
}statistics_t;

struct fast_packet{
    unsigned int sourceid : 8;
    unsigned int seqnumber : 8;
    unsigned int pgn;
    unsigned char *buffer;
};

...

unsigned char *ptr = &(fastpacket->buffer[(framecount * nbytes) - 1]);
*ptr = (unsigned char)sourceid;
statistics_t *statistics = (statistics_t *)fastpacket->buffer;            
DeleteFastpacket(fastpacket);
fastpacket = NULL;        
...

So keeping in mind that union members align in memory. So . . .

typedef union{
    struct ac_output_data acdata;
    unsigned char *buffer;
}statistics_t;

members acdata, and *buffer both share a starting address of 0 in relation to the unions position in memory.  Where this gets interesting is in the use of representing multiple data types. Essentially, having the ability to represent multiple data type( only one at a time, kind of ), while only using the memory space of the largest member. Which of course is very handy. Of course the very simple example above: Both members are exactly the same size. But if you added say another struct member, it would not necessarily have to be the same size as ac_output_status. Nor would that struct have to even remotely resemble ac_output_status. So long as the data passed into *buffer was sized appropriately for that struct.

 

The above illustrated the need I had to build a packet( 88 bytes - or 11  frames), one 8 byte frame at a time( *buffer ), then somehow represent this data in a meaningful form( acdata ). To be sure, I do need to represent more types ( similar to, but smaller in size than ac_output_status ), but because of how unions work. I can rest assured that my "generic data type" will never use more than 77 bytes of memory( the first byte of each frame is actually not data, but a frame sequence number ). But can be used to represent multiple data types. That is to say. Unless used irresponsibly. Then perhaps your program seg faults - If lucky.

 

Anyway, it is my hope this might help someone else who has struggled / is struggling to make something similar work. As to learn of this technique took me a considerable amount of time to figure out on my own. With that in mind, do realize that I have no formal training in programming, So for you more experienced / advanced programmers in the group . . . I'm laughing my backside off with you ( at myself ) ;)

 

EDIT:

I should also point out in case if it comes up . . . That in my example above, *fastpacket is allocated on the heap, where as *statistics is allocated on the stack. One of the cool features of Linux - > cat /proc/self/maps in conjunction with printf("%p" . . .). No need to dig through the symbol table to figure this all out.

 

In case anyone is wondering how I found out these various things mentioned in this post. All the answers I found online were in relation to job placement questions answered on stack overflow. So perhaps those books I've seen online similar to "2005 job placement question . . ." etc are actually handy for the intermediate to advanced programmer ?

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...