Jump to content
yyrkoon

SocketCAN help needed

Recommended Posts

Update,

 

Ok, I'm getting ready to move these posts to the projects sub forum, but will be doing more work, to iron things out as I go. Today I had a very long and frustrating battle with my "generic" data type. I had to refactor out a few things, but the main problem was lack of _attribute_packed_  for the various structs, and the single union I'm using. I had also destroyed the second PGN I started trying to track as well by manipulating a position in the buffer for the first struct I built. So I had to remove all that garbage, and well had to restructure my fastpacket building routine - Somewhat. Heres 3 complete PGNs, but I'm only able to track two of these with our current system.

enum pgn_ids {
    DC_SOURCE_STATUS                = 126977,
    AC_OUTPUT_STATUS                 = 126982,
    HV_DC_BUS_STATUS                = 126987,
    BATT_MNTR_STATUS                = 127003,
    BATT_DUEX_STATUS                = 127172
};

struct dc_source_status{
    int rsv_bits                    :2;        /* Reserved bits */
    int msg_count                    :6;        /* Message count */
    int dc_src_id                    :8;        /* DC source identifier */
    int voltage                     :32;    /* DC Voltage */
    int current                     :32;    /* DC current */
    int temp_sens_id                :8;        /* Temperature sensor identifier */
    int temperature                    :16;    /* Temperature at the source */
    int soc                            :8;        /* State of charge */
    int time_remain                    :16;    /* Battery time remaining*/
    int soh                            :8;        /* State of health*/
    int bcr                            :16;    /* Battery capacity remaining */
    int bcp                            :8;        /* Battery capacity percentage of maximum */
    int power                        :32;    /* Power - Used when power is measured differently than P=EI */
};

struct ac_output_status{
    unsigned int rsv_bits            :2;
    unsigned int msg_count            :6;
    unsigned int total_flag            :2;
    unsigned int rsv_bits2            :6;
    unsigned int ac_src_id            :8;
    unsigned int waveform            :8;
    unsigned int line                 :8;
    unsigned char line1[23];        // L1 equivelent to L3
    unsigned char line2[23];        // L2 Equivelent to L3
    unsigned int line3                 :8;
    unsigned int L3_rms_voltage        :32;
    unsigned int L3_current             :32;
    unsigned int L3_current_per        :8;
    unsigned int L3_frequency        :16;
    unsigned int L3_breaker_sz        :16;
    unsigned int L3_apparent_pwr    :32;
    unsigned int L3_real_pwr        :32;
    unsigned int L3_real_pwr_per    :8;
    unsigned int src_id             :8;
    unsigned char padding[2];
};

struct batt_duex_status{
    unsigned int msg_count            :8;
    unsigned int dc_src_id            :8;
    unsigned int src_id             :8;
    int voltage                     :32;
    int current                     :32;
    unsigned int power                 :32;
    unsigned int ripple_voltage        :32;
    unsigned int temp_sens_id        :8;
    unsigned int temperature         :16;
    unsigned int soc                  :8;
    unsigned int soh                :8;
    unsigned int batt_cap_remain    :16;
    unsigned int batt_cap_per        :8;
    unsigned int time_remaining        :16;
    unsigned int energy_remaining    :32;
    unsigned int time_to_full        :16;
    unsigned int battery_type        :8;
    unsigned int nom_batt_voltage    :8;
    unsigned char padding[6];
};

Share this post


Link to post
Share on other sites

By the way, struct dc_source_status in my code pasting above isn't complete. The fields are all there except the end padding bits. Which I have no way to test yet as we're not getting this PGN. But basically, even though we know the PGN's, and the field values. There is still lots of byte counting etc - To make sure the struct is properly aligned in the union.

Share this post


Link to post
Share on other sites

Grrr, keep forgetting stuff.

 

Right now I'm tracking 10 samples /second - From just 2 PGN's, the code is still  pretty fast. Just for giggles, here m current output.

{ "t": "bds", "i": 3, "v": 25010, "a": 270, "p": 6 }
{ "t": "aos", "i": 2, "v": 236110, "a": 40, "f": 5998 }
{ "t": "bds", "i": 1, "v": 24830, "a": -10870, "p": 269 }
{ "t": "aos", "i": 1, "v": 237260, "a": 1610, "f": 5999 }
{ "t": "bds", "i": 2, "v": 24860, "a": 0, "p": 0 }
{ "t": "bds", "i": 3, "v": 25030, "a": 270, "p": 6 }
{ "t": "aos", "i": 2, "v": 235630, "a": 10, "f": 6000 }
{ "t": "bds", "i": 1, "v": 24850, "a": -11290, "p": 280 }
{ "t": "aos", "i": 1, "v": 236270, "a": 1750, "f": 5999 }
{ "t": "bds", "i": 2, "v": 24850, "a": 0, "p": 0 }
{ "t": "bds", "i": 3, "v": 25030, "a": 270, "p": 6 }
{ "t": "aos", "i": 2, "v": 236200, "a": 0, "f": 5999 }
{ "t": "bds", "i": 1, "v": 24830, "a": -10870, "p": 269 }
{ "t": "aos", "i": 1, "v": 236300, "a": 1590, "f": 5999 }
{ "t": "bds", "i": 2, "v": 24860, "a": 0, "p": 0 }
{ "t": "bds", "i": 3, "v": 25030, "a": 270, "p": 6 }
{ "t": "aos", "i": 2, "v": 236370, "a": 50, "f": 5999 }
{ "t": "bds", "i": 1, "v": 24830, "a": -11080, "p": 275 }
{ "t": "aos", "i": 1, "v": 236300, "a": 1670, "f": 5999 }
{ "t": "bds", "i": 2, "v": 24850, "a": 0, "p": 0 }
{ "t": "bds", "i": 3, "v": 25030, "a": 270, "p": 6 }
{ "t": "aos", "i": 2, "v": 236140, "a": 0, "f": 5999 }

Share this post


Link to post
Share on other sites

More problems . . .

 

So, last night I implemented a third PGN to track in code. Which confuses me, because it causes a kernel ooops. Once I figured this out I simply commented out a conditional statement meant to let the fastpacket routine know this packet set is interesting - track it. The code works fine. later . . . as in now . . . I uncomment this same conditional statement, hoping to track the problem down - And it seems to work fine . . . Implement a bit more code . . .

*** glibc detected *** ./test: free(): invalid next size (fast): 0x08459040 ***

On the surface this error seems to indicate that I'm overwriting memory outside of my buffer. But I'm not so sure. I'm tracking two other PGNs, using a similar buffer with no problems. Sizing / clearing is done programmatically. Can anyone suggest where / what I can look into ? Several hits on stackoverflow discuss boundary overstepping only. So far as I've seen anyway. I have run strace on the executable, which left me even more confused . . .

 

Isn't coding fun ?

 

EDIT:

 

It may be worth noting that I am using malloc() and free() several times a second. Tracking 2 PGNs, my data rate is 10 samples a second. With the third, I'm not sure, as the program does not run long enough to check this data.

Share this post


Link to post
Share on other sites

@@oPossum

 

Ok so I figured out the correct way to filter PGN's from frame.can_id, and source id( which wasn't too hard). Do not ask me why I have to pass off the whole frame, but experimentation tells me if I just pass in the can_id, it doesn't come out right. For some odd reason . . .

int ProcessCanid(struct can_frame frame){
    unsigned 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;
    }
    else{
        canid = frame.can_id & CAN_SFF_MASK;
    }

    return canid;
}
int canid = ProcessCanid(frame);
int pgn = (canid >> 8) & 0x1FFFF;
int srcid = canid & 0x000F;
printf("%08X %05X %02X\n", canid, pgn, srcid);

output:

19F80E00 1F80E 00
0DF80900 1F809 00
19F0C403 1F0C4 03

The interesting ones here are the first two. Which I was not able to track prior to figuring this out. They are in the documentation as well.

 

Software Version Status PGN: 129038 (0x01F80E)

Date and Time Status PGN: 129033 (0x01F809)

 

There is still one more I am unable to track.

18EEFF01 0EEFF 01

No idea what this is, but I'm fairly sure it's not a fastpacket PGN, and it comes in off all non zero devices periodically. 4 bytes total I believe is the data payload.

 

Share this post


Link to post
Share on other sites

Update.

 

Ok, so I've made yet more changes to this project - Which is really me experimenting with different ways to do the same thing. In a way that I think most consistent with a web interface.

 

That is to say - I've changed to a "subscribe" model. By this I mean that now each PGN + src id runs in it own processes via fork() + execv(). Thusly . . .

#include "defines.h"
#include "includes.h"
#include "structs.h"

void init_shared_memory(void)
{    
    int shm_fd = shm_open("acme", O_CREAT | O_RDWR, FILE_PERMS);
    if(shm_fd == -1)
        HandleError(strerror(errno));

    const int retval = ftruncate(shm_fd, sizeof(struct shm_data));
    if(retval == -1)
        HandleError(strerror(errno));

    struct shm_data *smd;
    smd = mmap(NULL, sizeof(struct shm_data),
        PROT_READ|PROT_WRITE, MAP_SHARED, shm_fd, 0);
    
    close(shm_fd);

    smd->access = 0;
    memset(&smd->data, 0, sizeof(smd->data));
}

int fork_exec(char *file, char *interface, char *srcid)
{
    pid_t pid = fork();
    if(pid == -1){
        printf("%s\n", "error");
    }
    else if(pid == 0){
        char *args[] ={file, interface, srcid, NULL};
        return execv(args[0], args);
    }
}

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

    char *acoutsts = "./126982\0";
    char *batdxsts = "./127172\0";
    char *interface = "vcan0\0";
    char *id1 = "1";
    char *id2 = "2";
    char *id3 = "3";

    fork_exec(acoutsts, interface, id1);
    fork_exec(acoutsts, interface, id2);
    // fork_exec(batdxsts, interface, id1);
    // fork_exec(batdxsts, interface, id2);
    // fork_exec(batdxsts, interface, id3);
    wait(NULL);

    printf("%s\n", "exiting");
    return 0;
}

So far I like this model a lot, and I think it should give me a good amount of flexibility when working with a web interface. The code is still in progress, as I'm learning to deal with various aspects of fork(). Primarily on my mind right now is signal trapping, and dealing with zombie processes. e.g. sometimes ctrl + c does not signal the OS that processes created by this executable need to be terminated ( zombies ). I need to figure out how to bullet proof that.

 

Also so far, this seems to work really well.

Share this post


Link to post
Share on other sites

Here is a scary thought . . .

 

https://picasaweb.google.com/106867156582775247949/September102015?authuser=0&authkey=Gv1sRgCIfQzrb5uoH89QE&feat=directlink

 

Yes, those are the actual readings coming off the inverter. Which did a quick power reset . . . hence why this web interface reads disconnected, As this reset the ethernet switch in my room, leaving it in "limbo" which also caused the beaglebone to lock up since it's rootfs comes from a server in my room . . .

Share this post


Link to post
Share on other sites

@yyrkoon

 

I've been working on decoding various messages on my RV-C network.  It looks like you have been able to decoded PGNs such as 1F0C4 (BATT_DUEX_STATUS) and 1F0C5  (DC Source  Status).

Are these PGN's documented somewhere?  I've been searching the web and haven't found them yet.  Just came across you very helpful posts.  Thanks

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