diff --git a/src/can/can.cpp b/src/can/can.cpp index 3f8f55f59a9f2db22ccb07b22528d01032a3d20d..920f70f76e0ac1628ea19db9c9ebd09b13a9d417 100755 --- a/src/can/can.cpp +++ b/src/can/can.cpp @@ -1,24 +1,79 @@ #include "can.h" +#include "commexceptions.h" +#include <string.h> +#include <iostream> +#include <math.h> +#include <errno.h> CCAN::CCAN(const std::string &comm_id) : CComm(comm_id) { - + this->can_socket_fd=-1; + this->req_can_id=-1; + // initialize the thread attributes + this->thread_server=CThreadServer::instance(); + this->can_thread_id=comm_id + "_can_thread"; + this->thread_server->create_thread(this->can_thread_id); + this->thread_server->attach_thread(this->can_thread_id,this->can_thread,this); + // initialize the event atributes + this->event_server=CEventServer::instance(); + this->new_frame_event_id=comm_id + "_new_frame_event_id"; + this->event_server->create_event(this->new_frame_event_id); + this->frame_error_event_id=comm_id + "_frame_error_event_id"; + this->event_server->create_event(this->frame_error_event_id); + this->data_requested_event_id=comm_id + "_data_requested_event_id"; + this->event_server->create_event(this->data_requested_event_id); + this->finish_can_thread_event_id=comm_id + "_finish_can_thread_event_id"; + this->event_server->create_event(this->finish_can_thread_event_id); } void CCAN::hard_open(void *comm_dev) { + std::string *can_dev=(std::string *)comm_dev; + struct sockaddr_can addr; + struct ifreq ifr; + + if ((this->can_socket_fd = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) + { + /* handle exceptions */ + throw CCommException(_HERE_,"impossible to create the socket-CAN",this->get_id()); + } + addr.can_family = AF_CAN; + std::cout << *can_dev << std::endl; + strcpy(ifr.ifr_name, can_dev->c_str()); + ioctl(this->can_socket_fd, SIOCGIFINDEX, &ifr); + addr.can_ifindex = ifr.ifr_ifindex; + if (bind(this->can_socket_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) + { + /* handle exceptions */ + throw CCommException(_HERE_,"impossible to connect the socket-CAN",this->get_id()); + } } void CCAN::hard_config(void *config) { - /* do nothing */ + // start the can thread + this->thread_server->start_thread(this->can_thread_id); } int CCAN::hard_read(unsigned char *data, int len) { int num_read=0; + if(this->can_socket_fd!=-1) + { + if((num_read=::read(this->can_socket_fd,data,len))==-1) + { + /* handle exceptions */ + throw CCommException(_HERE_,"Error while reading from the socket.",this->comm_id); + } + } + else + { + /* handle exceptions */ + throw CCommException(_HERE_,"The socket-CAN has not been properly opened.",this->comm_id); + } + return num_read; } @@ -26,28 +81,239 @@ int CCAN::hard_write(unsigned char *data, int len) { int num_write=0; + if(this->can_socket_fd!=-1) + { + if((num_write=::write(this->can_socket_fd,data,len))==-1) + { + /* handle exceptions */ + throw CCommException(_HERE_,"Error while writing to the socket.",this->comm_id); + } + } + else + { + /* handle exceptions */ + throw CCommException(_HERE_,"The socket-CAN has not been properly opened.",this->comm_id); + } + return num_write; } int CCAN::hard_get_num_data(void) { + unsigned char data[1024]; int num; + if(this->can_socket_fd!=-1) + { + if((num=recv(this->can_socket_fd,data,1024,MSG_PEEK))==-1) +// if(ioctl(this->can_socket_fd,FIONREAD,&num)==-1) + { + std::cout << errno << std::endl; + /* handle exceptions */ + throw CCommException(_HERE_,"Error while getting the number of bytes available from the socket.",this->comm_id); + } + } + else + { + /* handle exceptions */ + throw CCommException(_HERE_,"The socket-CAN has not been properly opened.",this->comm_id); + } + return num; } int CCAN::hard_wait_comm_event(void) { + fd_set receive_set,error_set; + int max_fd,wait_result=0; + + max_fd=this->can_socket_fd+1; + FD_ZERO(&receive_set); + FD_SET(this->can_socket_fd,&receive_set); + FD_ZERO(&error_set); + FD_SET(this->can_socket_fd,&error_set); + wait_result=select(max_fd,&receive_set,NULL,&error_set,NULL); + if(wait_result==-1) + { + /* handle exceptions */ + throw CCommException(_HERE_,"Error while waiting for socket events",this->comm_id); + } + else + { + if(FD_ISSET(this->can_socket_fd,&receive_set))/* data has been received */ + return 1; + if(FD_ISSET(this->can_socket_fd,&error_set)) + return 2; + } + return -1; } void CCAN::hard_close(void) { + // close the can device + if(this->can_socket_fd!=-1) + ::close(this->can_socket_fd); + // free all the resources + if(this->finish_can_thread_event_id!="") + { + this->event_server->set_event(this->finish_can_thread_event_id); + this->thread_server->end_thread(this->can_thread_id); + this->thread_server->detach_thread(this->can_thread_id); + this->thread_server->delete_thread(this->can_thread_id); + this->can_thread_id=""; + this->event_server->delete_event(this->finish_can_thread_event_id); + this->finish_can_thread_event_id=""; + } + if(this->new_frame_event_id!="") + { + this->event_server->delete_event(this->new_frame_event_id); + this->new_frame_event_id=""; + } + if(this->frame_error_event_id!="") + { + this->event_server->delete_event(this->frame_error_event_id); + this->frame_error_event_id=""; + } + if(this->data_requested_event_id!="") + { + this->event_server->delete_event(this->data_requested_event_id); + this->data_requested_event_id=""; + } +} +void *CCAN::can_thread(void *param) +{ + static struct can_frame new_frame; + std::list<std::string> events; + CCAN *can=(CCAN *)param; + unsigned int event_id,num; + bool end=false; + + events.push_back(can->finish_can_thread_event_id); + events.push_back(can->get_rx_event_id()); + while(!end) + { + event_id=can->event_server->wait_first(events); + if(event_id==0) + end=true; + else + { + can->can_access.enter(); + // process the incomming data + num=can->get_num_data(); + while(num>=sizeof(struct can_frame))// there is a whole frame in the input buffer + { + can->read((unsigned char *)&new_frame,sizeof(struct can_frame)); + if(new_frame.can_id&CAN_RTR_FLAG) + { + // save the requested can_id + can->req_can_id=new_frame.can_id; + // activate the event + can->event_server->set_event(can->data_requested_event_id); + } + else + { + //puch the new frame into the queue + can->rx_frames.push(new_frame); + // activate the event + can->event_server->set_event(can->new_frame_event_id); + } + num-=sizeof(struct can_frame); + } + can->can_access.exit(); + } + } + + pthread_exit(NULL); } -CCAN::~CCAN() +void CCAN::open(const std::string &can_dev) +{ + CComm::open((void *)&can_dev); + this->config(); +} + +std::string CCAN::get_new_frame_event_id(void) +{ + return this->new_frame_event_id; +} + +std::string CCAN::get_frame_error_event_id(void) +{ + return this->frame_error_event_id; +} + +std::string CCAN::get_data_requested_event_id(void) +{ + return this->data_requested_event_id; +} + +unsigned int CCAN::get_requested_can_id(void) +{ + return this->req_can_id; +} + +void CCAN::write_frame(unsigned int can_id, unsigned char *data, int len) { + int num_frames=ceil((double)len/8.0),i,j; + struct can_frame frame; + + // check the identifier format + if((can_id&(~CAN_SFF_MASK))!=0)// it's an extended identifier + can_id=can_id|CAN_EFF_FLAG; + + for(i=0;i<num_frames;i++) + { + // generate all the frames + frame.can_id=can_id; + if((len-8*i)<8) + frame.can_dlc=len-8*i; + else + frame.can_dlc=8; + for(j=0;j<frame.can_dlc;j++) + frame.data[j]=data[i*8+j]; + // send the frames + this->write((unsigned char *)&frame,sizeof(struct can_frame)); + } +} + +void CCAN::read_frame(unsigned int *can_id, unsigned char *data, int *len) +{ + struct can_frame frame; + int i=0; + + this->can_access.enter(); + if(!this->rx_frames.empty()) + { + frame=this->rx_frames.front(); + this->rx_frames.pop(); + *can_id=frame.can_id; + *len=frame.can_dlc; + for(i=0;i<frame.can_dlc;i++) + data[i]=frame.data[i]; + } + else + { + /* handle exceptions */ + } + this->can_access.exit(); +} +void CCAN::add_id_filter(unsigned short int start_id, unsigned short int end_id) +{ + +} + +void CCAN::clear_id_filters(void) +{ + +} + +CCAN::~CCAN() +{ + // close the can device + if(this->can_socket_fd!=-1) + this->close(); } diff --git a/src/can/can.h b/src/can/can.h index 8c9630dcfc2bd5565b17cd13949e85a69326d246..6cbd314c51c12b6f62799d4e5dbf4ca1f48b349f 100755 --- a/src/can/can.h +++ b/src/can/can.h @@ -4,14 +4,41 @@ #include "comm.h" #include "mutex.h" +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <sys/uio.h> +#include <net/if.h> +#include <linux/can.h> +#include <linux/can/bcm.h> + +#include "threadserver.h" +#include "eventserver.h" +#include <queue> + /** * \brief CAN driver * */ -class CCAN : public CComm +class CCAN : protected CComm { private: + // can device identifier + int can_socket_fd; + unsigned int req_can_id; + // thread attributes + CThreadServer *thread_server; + std::string can_thread_id; + // event attributes + CEventServer *event_server; + std::string new_frame_event_id;// public event + std::string frame_error_event_id;// public event + std::string data_requested_event_id;// public event + std::string finish_can_thread_event_id;// private event + // intranal received frame buffer + std::queue<struct can_frame> rx_frames; + CMutex can_access; protected: /** * \brief Function to actually open the device @@ -147,6 +174,10 @@ class CCAN : public CComm * exception class defined by the inherited class. */ virtual void hard_close(void); + /** + * \brief + */ + static void *can_thread(void *param); public: /** * \brief default constructor @@ -160,6 +191,42 @@ class CCAN : public CComm * class. */ CCAN(const std::string &comm_id); + /** + * \brief + */ + void open(const std::string &can_dev); + /** + * \brief + */ + std::string get_new_frame_event_id(void); + /** + * \brief + */ + std::string get_frame_error_event_id(void); + /** + * \brief + */ + std::string get_data_requested_event_id(void); + /** + * \brief + */ + unsigned int get_requested_can_id(void); + /** + * \brief + */ + void write_frame(unsigned int can_id, unsigned char *data, int len); + /** + * \brief + */ + void read_frame(unsigned int *can_id, unsigned char *data, int *len); + /** + * \brief + */ + void add_id_filter(unsigned short int start_id, unsigned short int end_id=-1); + /** + * \brief + */ + void clear_id_filters(void); /** * \brief Destructor * diff --git a/src/examples/CMakeLists.txt b/src/examples/CMakeLists.txt index e90ba1216e40736893f854cbed0c5e47597b159f..2f64dc6df46887e61623f5955f9986e1a3987c5e 100644 --- a/src/examples/CMakeLists.txt +++ b/src/examples/CMakeLists.txt @@ -4,6 +4,18 @@ ADD_EXECUTABLE(test_rs232 test_rs232.cpp) # edit the following line to add the necessary libraries TARGET_LINK_LIBRARIES(test_rs232 ${IRIUTILS_LIBRARY} comm pthread) +# edit the following line to add the source code for the example and the name of the executable +ADD_EXECUTABLE(test_can test_can.cpp) + +# edit the following line to add the necessary libraries +TARGET_LINK_LIBRARIES(test_can ${IRIUTILS_LIBRARY} comm pthread) + +# edit the following line to add the source code for the example and the name of the executable +ADD_EXECUTABLE(test_can_rx test_can_rx.cpp) + +# edit the following line to add the necessary libraries +TARGET_LINK_LIBRARIES(test_can_rx ${IRIUTILS_LIBRARY} comm pthread) + IF(BUILD_FTDI) ADD_EXECUTABLE(test_ftdi test_ftdi.cpp) diff --git a/src/examples/test_can.cpp b/src/examples/test_can.cpp new file mode 100755 index 0000000000000000000000000000000000000000..9fdb13c795704c37778843dc87251e7983eba67e --- /dev/null +++ b/src/examples/test_can.cpp @@ -0,0 +1,45 @@ +#include "eventserver.h" +#include "threadserver.h" +#include "commexceptions.h" +#include "can.h" +#include <stdio.h> +#include <unistd.h> +#include <string> +#include <iostream> + +#include <linux/can/raw.h> +#include <linux/can.h> + +const std::string can_dev="can0"; + +/** + * \example test_can.cpp + * + */ +int main(int argc,char *argv[]) +{ + CCAN can_port("can_port"); + unsigned char data[10]; + int i=0; + + try{ + can_port.open(can_dev); + data[0]=0x01; + data[1]=0x02; + data[2]=0x03; + data[3]=0x04; + data[4]=0x05; + data[5]=0x06; + data[6]=0x07; + data[7]=0x08; + data[8]=0x09; + data[9]=0x0A; + for(i=0;i<5;i++) + { + can_port.write_frame(0x200,data,10); + sleep(1); + } + }catch(CCommException &e){ + std::cout << e.what() << std::endl; + } +} diff --git a/src/examples/test_can_rx.cpp b/src/examples/test_can_rx.cpp new file mode 100755 index 0000000000000000000000000000000000000000..ba541bcf1adb917397456f1280e39e24ac8ae463 --- /dev/null +++ b/src/examples/test_can_rx.cpp @@ -0,0 +1,45 @@ +#include "eventserver.h" +#include "threadserver.h" +#include "commexceptions.h" +#include "can.h" +#include <stdio.h> +#include <unistd.h> +#include <string> +#include <iostream> + +#include <linux/can/raw.h> +#include <linux/can.h> + +const std::string can_dev="can1"; + +/** + * \example test_can.cpp + * + */ +int main(int argc,char *argv[]) +{ + CEventServer *event_server=CEventServer::instance(); + std::list<std::string> events; + CCAN can_port("can_port"); + unsigned char data[8]; + unsigned int can_id; + int i=0,len; + + events.push_back(can_port.get_new_frame_event_id()); + try{ + can_port.open(can_dev); + while(1) + { + event_server->wait_all(events); + can_port.read_frame(&can_id,data,&len); + std::cout << "can id: 0x" << std::hex << can_id << std::endl; + std::cout << "length: " << len << std::endl; + std::cout << "data: "; + for(i=0;i<len;i++) + std::cout << "0x" << std::hex << (int)data[i]; + std::cout << std::endl; + } + }catch(CCommException &e){ + std::cout << e.what() << std::endl; + } +}