2012-05-06 13 views
9

Stavo pensando di utilizzare Boost Asio per leggere i dati da un Socket CAN. Non c'è niente di interessante in linux/can.h, e il dispositivo dovrebbe comportarsi come l'interfaccia di loopback e essere utilizzato con un socket non elaborato.boost :: asio over SocketCAN

Guardando a livello di interfaccia basic_raw_socket sembra che io possa fare uso di basic_raw_socket::assign da assegnare alla presa nativo creata con

socket(PF_CAN, SOCK_RAW, CAN_RAW); 

Questo è quello che ho finora

namespace can { 
     class CanSocket { 
     public: 
       typedef boost::asio::ip::basic_endpoint<CanSocket> endpoint; 
       typedef boost::asio::ip::basic_resolver_query<CanSocket> resolver_query; 
       typedef boost::asio::ip::basic_resolver_iterator<CanSocket> resolver_iterator; 
       typedef boost::asio::basic_raw_socket<CanSocket> socket; 
       typedef boost::asio::ip::basic_resolver<CanSocket> resolver; 

       CanSocket() 
         : _protocol(CAN_RAW) 
         , _family(PF_CAN) 
       { 
       } 

       static CanSocket v4() 
       { 
         return CanSocket(); 
       } 
       static CanSocket v6(); 
       int type() const; 
       int protocol() const; 
       int family() const; 

       friend bool operator==(const CanSocket& p1, const CanSocket& p2) 
       { 
         return p1._protocol != p2._protocol || p1._family != p2._family; 
       } 
       friend bool operator!=(const CanSocket& p1, const CanSocket& p2) 
       { 
         return p1._protocol == p2._protocol || p1._family == p2._family; 
       } 

     private: 
       int _protocol; 
       int _family; 
}; 
} 

e questo è come lo uso nella mia applicazione

boost::asio::io_service ioserv; 

    CanSocket::socket s(ioserv); 

    int sock = socket(PF_CAN, SOCK_RAW, CAN_RAW); 

    s.assign(CanSocket::v4(), sock); 

    struct ifreq ifr; 
    strcpy(ifr.ifr_name, "vcan0"); 
    ioctl(sock, SIOCGIFINDEX, &ifr); /* ifr.ifr_ifindex gets filled 
           * with that device's index */ 

    /* Select that CAN interface, and bind the socket to it. */ 

    /* this should be the endpoint */ 
    struct sockaddr_can addr; 
    addr.can_family = AF_CAN; 
    addr.can_ifindex = ifr.ifr_ifindex; 

    /* s.bind (....) */ 
    bind(sock, (struct sockaddr*)&addr, sizeof(addr)); 

Ciò che non riesco a ottenere è esattamente come faccio a binds per l'endpoint locale? Non ci sono IP o porte coinvolte.

C'è qualcos'altro che dovrebbe essere implementato oltre all'endpoint per farlo funzionare?

risposta

3

La soluzione è utilizzare posix::stream_descriptor.

Basta aprire il socket nativo, associare e quindi utilizzare posix::basic_stream_descriptor::assign.

+0

La prego di fornire l'esempio completo per la lettura/scrittura può telai, proprio come ho fatto per Python: http: //libbits.wordpress .com/2012/05/22/socketcan-support-in-python/Lo posizionerei su http://elinux.org/CAN_Bus#SocketCAN_Support_in_Programming_Languages.2FEnvironments – yegorich

4

Questo vuole essere esempio di lavoro che ho assemblato con l'aiuto di questa discussione

/// Encapsulates the flags needed for socket CAN. 
/** 
    * The can class contains flags necessary for CAN sockets. 
    */ 

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

#include <net/if.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <sys/ioctl.h> 

#include <linux/can.h> 
#include <linux/can/raw.h> 

#include <boost/asio.hpp> 
#include <boost/bind.hpp> 

void data_send(void) 
{ 
    std::cout << "omg sent" << std::endl; 
} 

void data_rec(struct can_frame& rec_frame,boost::asio::posix::basic_stream_descriptor<>& stream) 
{ 
    std::cout << std::hex << rec_frame.can_id << " "; 
    for(int i=0;i<rec_frame.can_dlc;i++) 
    { 
     std::cout << std::hex << int(rec_frame.data[i]) << " "; 
    } 
    std::cout << std::dec << std::endl; 
    stream.async_read_some(boost::asio::buffer(&rec_frame, sizeof(rec_frame)),boost::bind(data_rec,boost::ref(rec_frame),boost::ref(stream))); 

} 


int main(void) 
{ 
    //int nbytes; 
    struct sockaddr_can addr; 
    struct can_frame frame; 
    struct can_frame rec_frame; 
    struct ifreq ifr; 

    int natsock = socket(PF_CAN, SOCK_RAW, CAN_RAW); 


    strcpy(ifr.ifr_name, "vcan0"); 
    ioctl(natsock, SIOCGIFINDEX, &ifr); 

    addr.can_family = AF_CAN; 
    addr.can_ifindex = ifr.ifr_ifindex; 
    if(bind(natsock,(struct sockaddr *)&addr,sizeof(addr))<0) 
    { 
     perror("Error in socket bind"); 
     return -2; 
    } 

    frame.can_id = 0x123; 
    frame.can_dlc = 2; 
    frame.data[0] = 0x11; 
    frame.data[1] = 0x23; 


    boost::asio::io_service ios; 
    boost::asio::posix::basic_stream_descriptor<> stream(ios); 
    stream.assign(natsock); 

    stream.async_write_some(boost::asio::buffer(&frame, sizeof(frame)),boost::bind(data_send)); 
    stream.async_read_some(boost::asio::buffer(&rec_frame, sizeof(rec_frame)),boost::bind(data_rec,boost::ref(rec_frame),boost::ref(stream))); 
    ios.run(); 

}