diff --git a/include/model_car_driver_base.h b/include/model_car_driver_base.h index 0ff074a285e02124d1503fdbe49ba855b66765da..56882265c38752091694cd8a1e103d7c35e21a80 100644 --- a/include/model_car_driver_base.h +++ b/include/model_car_driver_base.h @@ -4,28 +4,24 @@ #include "rs232.h" #include "commexceptions.h" #include "threadserver.h" -// #include "eventserver.h" +#include "eventserver.h" #include "eventexceptions.h" -#include "model_car_exceptions.h" #include "model_car_protocol.h" -#include <iostream> -#include <iomanip> -#include <vector> -#include <dirent.h> -#include <chrono> -#include <thread> + +#define DEFAULT_TIMEOUT 200 +#define NO_RX_TIMEOUT -1.0 enum sm_state { WAIT_START, READ_ID, READ_DATA_LENGTH, READ_TIMESTAMP, READ_DATA, READ_CRC, READ_END}; union TTimeStampUnion { - unsigned char raw[4]; + uint8_t raw[4]; uint32_t time_stamp; }; union TCRCUnion { - unsigned char raw[2]; + uint8_t raw[2]; uint16_t crc; }; @@ -39,17 +35,18 @@ class CModelCarDriverBase { private: std::string name; - uint arduino_id; + std::string device; CRS232 *serial_port; CMutex port_mutex; - uint id; - uint sw_version; + uint8_t arduino_id; + uint8_t detected_id; + uint16_t sw_version; + uint32_t rx_timeout; + uint32_t timestamp; /* event attributes */ - CEventServer *event_server; std::string finish_thread_event_id; - std::string new_data_event_id; std::string new_info_event_id; /* thread attributes */ @@ -58,25 +55,26 @@ class CModelCarDriverBase protected: CMutex data_mutex; + CEventServer *event_server; + std::string new_data_event_id; + bool open_dev(std::string &serial_dev); static void *data_thread(void *param); - bool process_byte(THeader &header, TDataUnion &data_union, TCRCUnion &crc_union, unsigned char byte); - bool get_id(uint8_t & id); void send_request(uint8_t id, uint8_t data_length, uint8_t *data); - sm_state process_data(THeader & header, TDataUnion & data_union, TCRCUnion & crc_union); - virtual void process_data_frame(uint8_t id,uint32_t timestamp, TDataUnion data_union)=0; - void stuff_frame(uint8_t const *frame_in, uint8_t const size_in, uint8_t **frame_out, uint8_t & size_out); - uint16_t fletcher16(uint8_t const *data, uint8_t bytes); - void delete_thread_and_events(void); - + void stuff_frame(uint8_t *frame_in, uint8_t size_in, uint8_t **frame_out, uint8_t &size_out); + bool process_byte(THeader &header, TDataUnion &data_union, TCRCUnion &crc_union, uint8_t byte); + void process_data(THeader & header, TDataUnion & data_union, TCRCUnion & crc_union); + virtual void process_data_frame(uint8_t id,TDataUnion data_union)=0; + uint16_t fletcher16(uint8_t *data, uint8_t bytes); public: CModelCarDriverBase(std::string name, ARDUINO_ID arduino_id); - void open(); - bool open_dev(std::string &serial_dev); + void open(void); + uint8_t get_id(void); + void set_rx_timeout(double time_s); + double get_rx_timeout(void); + uint32_t get_last_timestamp(void); void close(void); std::string get_new_data_event_id(void); - void cout_data(unsigned char * data, unsigned int size, std::string name="data"); - virtual ~CModelCarDriverBase(void); }; diff --git a/src/model_car_driver_base.cpp b/src/model_car_driver_base.cpp index 931eec545d7c0ea6e5ad7376eb7260eaa345e642..e089b007c245b62b028de8e3ba7da5e430d6efac 100644 --- a/src/model_car_driver_base.cpp +++ b/src/model_car_driver_base.cpp @@ -1,27 +1,20 @@ #include "model_car_driver_base.h" -//#include "eventexceptions.h" - -struct HexCharStruct -{ - unsigned char c; - HexCharStruct(unsigned char _c) : c(_c) { } -}; - -inline std::ostream& operator<<(std::ostream& o, const HexCharStruct& hs) -{ - return (o << std::setw(2) << std::setfill('0') << std::hex << (int)hs.c << std::dec); -} - -inline HexCharStruct hex(unsigned char _c) -{ - return HexCharStruct(_c); -} +#include <iostream> +#include <vector> +#include <dirent.h> CModelCarDriverBase::CModelCarDriverBase(std::string name, ARDUINO_ID arduino_id) { this->name=name; - this->arduino_id=arduino_id; + this->device=""; this->serial_port=NULL; + + this->arduino_id=arduino_id; + this->detected_id=-1; + this->sw_version=-1; + this->rx_timeout=DEFAULT_TIMEOUT; + this->timestamp=0; + /* init events */ this->event_server=CEventServer::instance(); this->finish_thread_event_id=this->name+"_finish_thread_event"; @@ -38,45 +31,6 @@ CModelCarDriverBase::CModelCarDriverBase(std::string name, ARDUINO_ID arduino_id this->thread_server->attach_thread(this->data_thread_id,this->data_thread,this); } -void CModelCarDriverBase::open() -{ - std::vector<std::string> dev_list; - - this->close(); - - std::cout << "CModelCarDriverBase::open(): scanning ttyACM* devices in /sys/class/tty directory" << std::endl; - std::string path = "/sys/class/tty"; - std::string str = "ttyACM"; - - DIR *dir; - struct dirent *ent; - if ((dir = opendir (path.c_str())) != NULL) - { - while ((ent = readdir (dir)) != NULL) - { - std::size_t found = std::string(ent->d_name).find(str); - if (found!=std::string::npos) - { - std::string dev = "/dev/"+std::string(ent->d_name); - std::cout << " Found ttyACM* dev: " << dev << std::endl; - dev_list.push_back(dev); - } - } - closedir (dir); - } - else - { - std::cout << "CModelCarDriverBase: ERROR can't open dir " << path << std::endl; - } - - std::cout << "CModelCarDriverBase: looking for device matching Address arduino_id = " << this->arduino_id << std::endl; - for(unsigned int i=0; i<dev_list.size();i++) - { - if(this->open_dev(dev_list[i])) - break; - } -} - bool CModelCarDriverBase::open_dev(std::string &serial_dev) { bool ok=false; @@ -88,93 +42,49 @@ bool CModelCarDriverBase::open_dev(std::string &serial_dev) serial_config.parity=none; serial_config.stop_bits=1; this->serial_port = new CRS232(this->name); - std::cout << "CModelCarDriverBase: Opening " << serial_dev << std::endl; this->serial_port->open((void *)&serial_dev); this->serial_port->config(&serial_config); this->thread_server->start_thread(this->data_thread_id); - uint8_t current_id; - if(!this->get_id(current_id)) - { - std::cout << "CModelCarDriverBase: couldn't get id. Skipping." << std::endl; + if(this->get_id()==-1) this->close(); - } else { - this->data_mutex.enter(); - bool match = (this->arduino_id == current_id); - this->data_mutex.exit(); - if(match) + if(this->arduino_id == this->detected_id) { std::cout << "CModelCarDriverBase: correct arduino found!" << std::endl; + this->device=serial_dev; ok=true; } else - { - std::cout << "CModelCarDriverBase: incorrect arduino" << std::endl; this->close(); - } } } catch(CException &e) { - std::cout << e.what() << std::endl; this->close(); - throw; + throw e; } - return ok; -} -void CModelCarDriverBase::close() -{ - if(this->thread_server->get_thread_state(this->data_thread_id)==starting || - this->thread_server->get_thread_state(this->data_thread_id)==active) - { - this->event_server->set_event(this->finish_thread_event_id); - this->thread_server->end_thread(this->data_thread_id); - this->event_server->reset_event(this->finish_thread_event_id); - } - else - std::cout << "CModelCarDriverBase::close(): data thread already ended" << std::endl; - - this->port_mutex.enter(); - if(this->serial_port!=NULL) - { - this->serial_port->close(); - delete this->serial_port; - this->serial_port=NULL; - } - else - std::cout << "CModelCarDriverBase::close(): serial port already closed" << std::endl; - this->port_mutex.exit(); -} - -void CModelCarDriverBase::delete_thread_and_events() -{ - this->thread_server->detach_thread(this->data_thread_id); - this->thread_server->delete_thread(this->data_thread_id); - this->data_thread_id=""; - this->event_server->delete_event(this->finish_thread_event_id); - this->finish_thread_event_id=""; - this->event_server->delete_event(this->new_data_event_id); - this->new_data_event_id=""; + return ok; } void *CModelCarDriverBase::data_thread(void *param) { CModelCarDriverBase *driver=(CModelCarDriverBase *)param; + uint8_t *frame_data=NULL; + TRS232_config serial_config; + uint32_t num,index; bool end=false; - - unsigned char * frame_data=NULL; - unsigned int num; - THeader header; + THeader header; TDataUnion data_union; - TCRCUnion crc_union; + TCRCUnion crc_union; std::list<std::string> events; events.push_back(driver->serial_port->get_rx_event_id()); + events.push_back(driver->finish_thread_event_id); while(!end) { @@ -185,74 +95,66 @@ void *CModelCarDriverBase::data_thread(void *param) if(num==0) { driver->port_mutex.exit(); - driver->event_server->wait_all(events,1000); + index=driver->event_server->wait_first(events,driver->rx_timeout); driver->port_mutex.enter(); num=driver->serial_port->get_num_data(); } + else + index=0; - frame_data = new unsigned char[num]; - driver->serial_port->read(frame_data,num); - driver->port_mutex.exit(); - - //driver->cout_data(frame_data,num,"frame_data"); - - for(unsigned int i=0; i<num; i++) + if(index==0) { - bool frame_ready = driver->process_byte(header, data_union, crc_union, frame_data[i]); - if(frame_ready) - driver->process_data(header, data_union, crc_union); - else + frame_data = new uint8_t[num]; + driver->serial_port->read(frame_data,num); + driver->port_mutex.exit(); + for(uint32_t i=0;i<num;i++) { - if(i==num-1) - std::cout<< "CModelCarDriverBase::data_thread: buffer ended and frame not fully read" << std::endl; + if(driver->process_byte(header, data_union, crc_union, frame_data[i])) + driver->process_data(header, data_union, crc_union); } + delete[] frame_data; + } + else + { + driver->port_mutex.exit(); + end=true; } - if(frame_data!=NULL) - delete []frame_data; } catch(CEventTimeoutException &e) { - //do nothing; - //std::cout << "CModelCarDriverBase::data_thread: " << e.what() << std::endl; + serial_config.baud=115200; + serial_config.num_bits=8; + serial_config.parity=none; + serial_config.stop_bits=1; + driver->serial_port->close(); + driver->serial_port->open((void *)&driver->device); + driver->serial_port->config(&serial_config); } - catch(CException &e) - { - std::cout << "CModelCarDriverBase::data_thread: " << e.what() << std::endl; + catch(CException &e){ + std::cout << e.what() << std::endl; } - - if(driver->event_server->event_is_set(driver->finish_thread_event_id)) - end=true; } pthread_exit(NULL); } - - -bool CModelCarDriverBase::process_byte(THeader &header, TDataUnion &data_union, TCRCUnion &crc_union, unsigned char byte) +bool CModelCarDriverBase::process_byte(THeader &header, TDataUnion &data_union, TCRCUnion &crc_union, uint8_t byte) { bool frame_ready=false; - - static sm_state state=WAIT_START; - static bool escaped =false; - static int ts_count =0; - static int data_count=0; - static int crc_count =0; - TTimeStampUnion ts_union; + static sm_state state=WAIT_START; + static bool escaped=false; + static int ts_count=0; + static int data_count=0; + static int crc_count=0; + static TTimeStampUnion ts_union; if(byte==ESCAPE_BYTE && !escaped) escaped=true; else { if(byte==START_BYTE && !escaped && state!=WAIT_START) - { - std::cout << "CModelCarDriverBase::data_thread: WARNING, found unexpected START_BYTE" << std::endl; state=READ_ID; - } else if(byte==END_BYTE && !escaped && state!=READ_END) - { - std::cout << "CModelCarDriverBase::data_thread: WARNING, found unexpected END_BYTE" << std::endl; state=WAIT_START; - } switch(state) { @@ -336,7 +238,6 @@ bool CModelCarDriverBase::process_byte(THeader &header, TDataUnion &data_union, { if(escaped) escaped=false; - std::cout << "CModelCarDriverBase::data_thread: error, no END BYTE found" << std::endl; state=WAIT_START; } break; @@ -345,43 +246,33 @@ bool CModelCarDriverBase::process_byte(THeader &header, TDataUnion &data_union, return frame_ready; } -sm_state CModelCarDriverBase::process_data(THeader & header, TDataUnion & data_union, TCRCUnion & crc_union) +void CModelCarDriverBase::process_data(THeader & header, TDataUnion & data_union, TCRCUnion & crc_union) { - sm_state state; - unsigned char * single_frame=NULL; + uint8_t * single_frame=NULL; uint16_t calculated_crc; - TInfoData info_data; + uint8_t frame_size; TErrorData error_data; - - unsigned int frame_size = sizeof(THeader)+header.data_length; - single_frame = new unsigned char[frame_size]; - + + frame_size = sizeof(THeader)+header.data_length; + single_frame = new uint8_t[frame_size]; memcpy(single_frame, &header, sizeof(THeader)); memcpy(&single_frame[sizeof(THeader)], &data_union, header.data_length); - calculated_crc = this->fletcher16(single_frame, frame_size); - - if(single_frame!=NULL) - delete []single_frame; + delete[] single_frame; if (calculated_crc != crc_union.crc) - { std::cout << "CModelCarDriverBase: error, frame CRC invalid. Skipping frame" << std::endl; - state=WAIT_START; - } else { switch(header.id) { case ID_ARD_SENSOR_INFO: this->data_mutex.enter(); - info_data.arduino_address = data_union.info.arduino_address; - info_data.arduino_version = data_union.info.arduino_version; - this->id = info_data.arduino_address; - this->sw_version = info_data.arduino_version; + this->detected_id = data_union.info.arduino_address; + this->sw_version = data_union.info.arduino_version; this->data_mutex.exit(); - this->event_server->set_event(this->new_info_event_id); - std::cout << "CModelCarDriverBase: processed info data, Address="<< unsigned(info_data.arduino_address) << ", Version="<< unsigned(info_data.arduino_version) << std::endl; + if(!this->event_server->event_is_set(this->new_info_event_id)) + this->event_server->set_event(this->new_info_event_id); break; case ID_ARD_SENS_ERROR: error_data.error_number = data_union.error.error_number; @@ -429,113 +320,79 @@ sm_state CModelCarDriverBase::process_data(THeader & header, TDataUnion & data_u break; default: this->data_mutex.enter(); - this->process_data_frame(header.id, header.time_stamp, data_union); - if(!this->event_server->event_is_set(this->new_data_event_id)) - this->event_server->set_event(this->new_data_event_id); + this->process_data_frame(header.id, data_union); this->data_mutex.exit(); break; } } - state=WAIT_START; - return state; } -bool CModelCarDriverBase::get_id(uint8_t & id) +uint8_t CModelCarDriverBase::get_id(void) { - bool ok=false; - this->send_request(ID_ARD_ACT_REQUEST,0,NULL); - std::list<std::string> events; + events.push_back(this->new_info_event_id); - try - { - this->event_server->wait_all(events,1000); + this->send_request(ID_ARD_ACT_REQUEST,0,NULL); + try{ + this->event_server->wait_all(events,100); } - catch(CEventTimeoutException &e) - { - std::cout << e.what() << std::endl; + catch(CEventTimeoutException &e){ + return -1; } - ok=true; - id=this->id; - return ok; + return this->detected_id; } void CModelCarDriverBase::send_request(uint8_t id, uint8_t data_length, uint8_t *data) { - unsigned int req_frame_size = sizeof(uint8_t)+sizeof(uint8_t)+sizeof(TTimeStampUnion)+data_length; - unsigned char *frame; - frame = new unsigned char[req_frame_size]; - std::fill(frame, frame + req_frame_size, 0x00); - - TTimeStampUnion ts={0x00,0x00,0x00,0x00}; - - memcpy(frame, &id, sizeof(uint8_t)); - memcpy(frame+sizeof(uint8_t), &data_length, sizeof(uint8_t)); - memcpy(frame+2*sizeof(uint8_t), &ts, sizeof(TTimeStampUnion)); - - for(unsigned int i=0; i<data_length; i++) - memcpy(frame+2*sizeof(uint8_t)+sizeof(TTimeStampUnion), &data[i], sizeof(uint8_t)); - - uint16_t calculated_crc = fletcher16(frame, uint8_t(req_frame_size)); - - unsigned char *frame_with_crc; - frame_with_crc = new unsigned char[req_frame_size+sizeof(uint16_t)]; - std::fill(frame_with_crc, frame_with_crc + req_frame_size+sizeof(uint16_t), 0x00); - memcpy(frame_with_crc, frame, req_frame_size); - memcpy(frame_with_crc+req_frame_size, &calculated_crc, sizeof(uint16_t)); - - req_frame_size+=sizeof(uint16_t); - - delete []frame; - uint8_t *stuffed_frame=NULL; - uint8_t stuffed_frame_size=0; - - this->stuff_frame(frame_with_crc,req_frame_size,&stuffed_frame,stuffed_frame_size); - delete []frame_with_crc; + uint8_t req_frame_size=sizeof(uint8_t)+sizeof(uint8_t)+sizeof(TTimeStampUnion)+data_length+sizeof(uint16_t),stuffed_frame_size; + uint16_t crc_value; + uint8_t *frame=NULL,*stuffed_frame=NULL; + + frame = new uint8_t[req_frame_size]; + frame[0]=id; + frame[1]=data_length; + memset(frame+2*sizeof(uint8_t), 0x00, sizeof(TTimeStampUnion)); + memcpy(frame+2*sizeof(uint8_t)+sizeof(TTimeStampUnion),data,data_length); + crc_value=fletcher16(frame,req_frame_size-sizeof(uint16_t)); + memcpy(frame+sizeof(uint8_t)+sizeof(uint8_t)+sizeof(TTimeStampUnion)+data_length,&crc_value,sizeof(uint16_t)); + this->stuff_frame(frame,req_frame_size,&stuffed_frame,stuffed_frame_size); this->port_mutex.enter(); this->serial_port->write(stuffed_frame,stuffed_frame_size); - //cout_data(stuffed_frame,stuffed_frame_size,"stuffed_frame"); this->port_mutex.exit(); - delete []stuffed_frame; + delete[] stuffed_frame; + delete[] frame; } -void CModelCarDriverBase::stuff_frame(uint8_t const *frame_in, uint8_t const size_in, uint8_t **frame_out, uint8_t & size_out) +void CModelCarDriverBase::stuff_frame(uint8_t *frame_in, uint8_t size_in, uint8_t **frame_out, uint8_t & size_out) { - unsigned int esc_num=0; - for(unsigned int i=0; i<(unsigned int)size_in; i++) - { + uint8_t esc_num=0; + + for(uint8_t i=0;i<size_in; i++) if( (frame_in[i]==START_BYTE) || (frame_in[i]==END_BYTE) || (frame_in[i]==ESCAPE_BYTE ) ) esc_num++; - } - size_out = (unsigned int)size_in+esc_num+2; + size_out = size_in+esc_num+2; *frame_out = new uint8_t[size_out]; - std::fill(*frame_out, *frame_out + (unsigned int)size_out, 0x00); - - unsigned int ii=1; (*frame_out)[0]=START_BYTE; - (*frame_out)[(unsigned int)size_out-1]=END_BYTE; - for(unsigned int i=0; i<(unsigned int)size_in; i++) + for(uint8_t input_byte=0,output_byte=1;input_byte<size_in;input_byte++) { - if( (frame_in[i]==START_BYTE) || (frame_in[i]==END_BYTE) || (frame_in[i]==ESCAPE_BYTE ) ) - { - (*frame_out)[ii]=ESCAPE_BYTE; - ii++; - (*frame_out)[ii]=frame_in[i]; - ii++; - } - else + if( (frame_in[input_byte]==START_BYTE) || (frame_in[input_byte]==END_BYTE) || (frame_in[input_byte]==ESCAPE_BYTE ) ) { - (*frame_out)[ii]=frame_in[i]; - ii++; + (*frame_out)[output_byte]=ESCAPE_BYTE; + output_byte++; } + (*frame_out)[output_byte]=frame_in[input_byte]; + output_byte++; } + (*frame_out)[size_out-3]=frame_in[size_in-2]; + (*frame_out)[size_out-2]=frame_in[size_in-1]; + (*frame_out)[size_out-1]=END_BYTE; } -uint16_t CModelCarDriverBase::fletcher16(uint8_t const *data, uint8_t bytes) +uint16_t CModelCarDriverBase::fletcher16(uint8_t *data, uint8_t bytes) { uint16_t sum1 = 0xff, sum2 = 0xff; @@ -554,24 +411,111 @@ uint16_t CModelCarDriverBase::fletcher16(uint8_t const *data, uint8_t bytes) /* Second reduction step to reduce sums to 8 bits */ sum1 = (sum1 & 0xff) + (sum1 >> 8); sum2 = (sum2 & 0xff) + (sum2 >> 8); + return sum2 << 8 | sum1; } -std::string CModelCarDriverBase::get_new_data_event_id(void) +void CModelCarDriverBase::open(void) { - return this->new_data_event_id; + std::vector<std::string> dev_list; + std::stringstream error; + bool found=false; + + this->close(); + + std::string path = "/sys/class/tty"; + std::string str = "ttyACM"; + + DIR *dir; + struct dirent *ent; + if ((dir = opendir (path.c_str())) != NULL) + { + while ((ent = readdir (dir)) != NULL) + { + std::size_t found = std::string(ent->d_name).find(str); + if (found!=std::string::npos) + { + std::string dev = "/dev/"+std::string(ent->d_name); + dev_list.push_back(dev); + } + } + closedir (dir); + } + else + { + error << "Can't open folder " << path; + throw CException(_HERE_,error.str()); + } + + for(uint32_t i=0; i<dev_list.size();i++) + { + found=this->open_dev(dev_list[i]); + if(found) + return; + } + error << "Impossible to find arduino with ID " << (int)this->arduino_id; + throw CException(_HERE_,error.str()); +} + +void CModelCarDriverBase::close(void) +{ + if(this->thread_server->get_thread_state(this->data_thread_id)==starting || + this->thread_server->get_thread_state(this->data_thread_id)==active) + { + this->event_server->set_event(this->finish_thread_event_id); + this->thread_server->end_thread(this->data_thread_id); + } + + this->port_mutex.enter(); + if(this->serial_port!=NULL) + { + this->serial_port->close(); + delete this->serial_port; + this->serial_port=NULL; + } + this->port_mutex.exit(); +} + +void CModelCarDriverBase::set_rx_timeout(double time_s) +{ + std::stringstream error; + + if(time_s<0.0 && time_s!=NO_RX_TIMEOUT) + { + error << "Invalid timeout value " << time_s; + throw CException(_HERE_,error.str()); + } + if(time_s==NO_RX_TIMEOUT) + this->rx_timeout=-1; + else + this->rx_timeout=(int)(time_s*1000.0); +} + +double CModelCarDriverBase::get_rx_timeout(void) +{ + return this->rx_timeout; } -void CModelCarDriverBase::cout_data(unsigned char * data, unsigned int size, std::string name) +uint32_t CModelCarDriverBase::get_last_timestamp(void) { - std::cout << "CModelCarDriverBase::cout_data: " << name << "= "; - for(unsigned int i=0; i<size; i++) - std::cout << hex(data[i]) << "," << std::dec; - std::cout << std::endl; + return this->timestamp; +} + +std::string CModelCarDriverBase::get_new_data_event_id(void) +{ + return this->new_data_event_id; } CModelCarDriverBase::~CModelCarDriverBase() { this->close(); - this->delete_thread_and_events(); + this->thread_server->detach_thread(this->data_thread_id); + this->thread_server->delete_thread(this->data_thread_id); + this->data_thread_id=""; + this->event_server->delete_event(this->finish_thread_event_id); + this->finish_thread_event_id=""; + this->event_server->delete_event(this->new_data_event_id); + this->new_data_event_id=""; + this->event_server->delete_event(this->new_info_event_id); + this->new_info_event_id=""; }