00001
00002
00003
00004
00005
00006 #include <sstream>
00007 #include <iomanip>
00008 #if 0 // change to 1 if you use boost
00009 #include <boost/algorithm/string/case_conv.hpp>
00010 #else
00011 #include <algorithm>
00012 #endif
00013
00014 extern "C" {
00015 #include "can_driver.h"
00016 }
00017 class can_uvccm_win32
00018 {
00019 public:
00020 class error
00021 {
00022 };
00023 can_uvccm_win32(s_BOARD *board);
00024 ~can_uvccm_win32();
00025 bool send(const Message *m);
00026 bool receive(Message *m);
00027 private:
00028 bool open_rs232(int port = 1, int baud_rate = 57600);
00029 bool close_rs232();
00030 bool get_can_data(const char* can_cmd_buf, long& bufsize, Message* m);
00031 bool set_can_data(const Message& m, std::string& can_cmd);
00032 private:
00033 HANDLE m_port;
00034 HANDLE m_read_event;
00035 HANDLE m_write_event;
00036 std::string m_residual_buffer;
00037 };
00038
00039 can_uvccm_win32::can_uvccm_win32(s_BOARD *board) : m_port(INVALID_HANDLE_VALUE),
00040 m_read_event(0),
00041 m_write_event(0)
00042 {
00043 if (strcmp( board->baudrate, "125K") || !open_rs232(1))
00044 throw error();
00045 }
00046
00047 can_uvccm_win32::~can_uvccm_win32()
00048 {
00049 close_rs232();
00050 }
00051
00052 bool can_uvccm_win32::send(const Message *m)
00053 {
00054 if (m_port == INVALID_HANDLE_VALUE)
00055 return false;
00056
00057
00058 std::string can_cmd;
00059 set_can_data(*m, can_cmd);
00060
00061 OVERLAPPED overlapped;
00062 ::memset(&overlapped, 0, sizeof overlapped);
00063 overlapped.hEvent = m_write_event;
00064 ::ResetEvent(overlapped.hEvent);
00065
00066 unsigned long bytes_written = 0;
00067 ::WriteFile(m_port, can_cmd.c_str(), (unsigned long)can_cmd.size(), &bytes_written, &overlapped);
00068
00069 enum { WRITE_TIMEOUT = 1000 };
00070 ::WaitForSingleObject(overlapped.hEvent, WRITE_TIMEOUT);
00071
00072 ::GetOverlappedResult(m_port, &overlapped, &bytes_written, FALSE);
00073
00074 bool result = (bytes_written == can_cmd.size());
00075
00076 return result;
00077 }
00078
00079
00080 bool can_uvccm_win32::receive(Message *m)
00081 {
00082 if (m_port == INVALID_HANDLE_VALUE)
00083 return false;
00084
00085 long res_buffer_size = (long)m_residual_buffer.size();
00086 bool result = get_can_data(m_residual_buffer.c_str(), res_buffer_size, m);
00087 if (result)
00088 {
00089 m_residual_buffer.erase(0, res_buffer_size);
00090 return true;
00091 }
00092
00093 enum { READ_TIMEOUT = 500 };
00094
00095 OVERLAPPED overlapped;
00096 ::memset(&overlapped, 0, sizeof overlapped);
00097 overlapped.hEvent = m_read_event;
00098 ::ResetEvent(overlapped.hEvent);
00099 unsigned long event_mask = 0;
00100
00101 if (FALSE == ::WaitCommEvent(m_port, &event_mask, &overlapped) && ERROR_IO_PENDING == ::GetLastError())
00102 {
00103 if (WAIT_TIMEOUT == ::WaitForSingleObject(overlapped.hEvent, READ_TIMEOUT))
00104 return false;
00105 }
00106
00107
00108 COMSTAT stat;
00109 ::memset(&stat, 0, sizeof stat);
00110 unsigned long errors = 0;
00111 ::ClearCommError(m_port, &errors, &stat);
00112 if (stat.cbInQue == 0)
00113 return false;
00114 char buffer[3000];
00115
00116 unsigned long bytes_to_read = min(stat.cbInQue, sizeof (buffer));
00117
00118 unsigned long bytes_read = 0;
00119 ::ReadFile(m_port, buffer, bytes_to_read, &bytes_read, &overlapped);
00120
00121 ::WaitForSingleObject(overlapped.hEvent, READ_TIMEOUT);
00122
00123 ::GetOverlappedResult(m_port, &overlapped, &bytes_read, FALSE);
00124 result = false;
00125 if (bytes_read > 0)
00126 {
00127 m_residual_buffer.append(buffer, bytes_read);
00128 res_buffer_size = (long)m_residual_buffer.size();
00129 result = get_can_data(m_residual_buffer.c_str(), res_buffer_size, m);
00130 if (result)
00131 m_residual_buffer.erase(0, res_buffer_size);
00132 }
00133 return result;
00134 }
00135
00136 bool can_uvccm_win32::open_rs232(int port, int baud_rate)
00137 {
00138 if (m_port != INVALID_HANDLE_VALUE)
00139 return true;
00140
00141 std::ostringstream device_name;
00142 device_name << "COM" << port;
00143
00144 m_port = ::CreateFile(device_name.str().c_str(),
00145 GENERIC_READ | GENERIC_WRITE,
00146 0,
00147 NULL,
00148 OPEN_EXISTING,
00149 FILE_FLAG_OVERLAPPED,
00150 NULL);
00151
00152
00153 if (m_port == INVALID_HANDLE_VALUE)
00154 return false;
00155
00156
00157 ::SetCommMask(m_port, EV_RXFLAG);
00158
00159 COMMTIMEOUTS timeouts;
00160 ::memset(&timeouts, 0, sizeof (timeouts));
00161 timeouts.ReadIntervalTimeout = -1;
00162 timeouts.ReadTotalTimeoutConstant = 0;
00163 timeouts.ReadTotalTimeoutMultiplier = 0;
00164 timeouts.WriteTotalTimeoutConstant = 5000;
00165 timeouts.WriteTotalTimeoutMultiplier = 0;
00166 SetCommTimeouts(m_port, &timeouts);
00167
00168 ::SetupComm(m_port, 1024, 512);
00169
00170
00171 DCB dcb;
00172 ::memset(&dcb, 0, sizeof (dcb));
00173 ::GetCommState(m_port, &dcb);
00174 dcb.BaudRate = baud_rate;
00175 dcb.ByteSize = 8;
00176 dcb.Parity = NOPARITY;
00177 dcb.StopBits = ONESTOPBIT;
00178 dcb.fAbortOnError = TRUE;
00179 dcb.EvtChar = 0x0A;
00180 ::SetCommState(m_port, &dcb);
00181
00182 ::PurgeComm(m_port, PURGE_RXABORT | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_TXCLEAR);
00183
00184 m_read_event = ::CreateEvent(NULL, TRUE, FALSE, NULL);
00185 m_write_event = ::CreateEvent(NULL, TRUE, FALSE, NULL);
00186
00187 return true;
00188 }
00189
00190 bool can_uvccm_win32::close_rs232()
00191 {
00192 if (m_port != INVALID_HANDLE_VALUE)
00193 {
00194 ::PurgeComm(m_port, PURGE_RXABORT | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_TXCLEAR);
00195 ::CloseHandle(m_port);
00196 m_port = INVALID_HANDLE_VALUE;
00197 ::CloseHandle(m_read_event);
00198 m_read_event = 0;
00199 ::CloseHandle(m_write_event);
00200 m_write_event = 0;
00201 m_residual_buffer.clear();
00202 }
00203 return true;
00204 }
00205
00206 bool can_uvccm_win32::get_can_data(const char* can_cmd_buf, long& bufsize, Message* m)
00207 {
00208 if (bufsize < 5)
00209 {
00210 bufsize = 0;
00211 return false;
00212 }
00213
00214 Message msg;
00215 ::memset(&msg, 0 , sizeof (msg));
00216 char colon = 0, type = 0, request = 0;
00217 std::istringstream buf(std::string(can_cmd_buf, bufsize));
00218 buf >> colon >> type >> std::hex >> msg.cob_id.w >> request;
00219 if (colon != ':' || (type != 'S' && type != 'X'))
00220 {
00221 bufsize = 0;
00222 return false;
00223 }
00224 if (request == 'N')
00225 {
00226 msg.rtr = 0;
00227 for (msg.len = 0; msg.len < 8; ++msg.len)
00228 {
00229 std::string data_byte_str;
00230 buf >> std::setw(2) >> data_byte_str;
00231 if (data_byte_str[0] == ';')
00232 break;
00233 long byte_val = -1;
00234 std::istringstream(data_byte_str) >> std::hex >> byte_val;
00235 if (byte_val == -1)
00236 {
00237 bufsize = 0;
00238 return false;
00239 }
00240 msg.data[msg.len] = (UNS8)byte_val;
00241 }
00242 if (msg.len == 8)
00243 {
00244 char semicolon = 0;
00245 buf >> semicolon;
00246 if (semicolon != ';')
00247 {
00248 bufsize = 0;
00249 return false;
00250 }
00251 }
00252
00253 }
00254 else if (request == 'R')
00255 {
00256 msg.rtr = 1;
00257 buf >> msg.len;
00258 }
00259 else
00260 {
00261 bufsize = 0;
00262 return false;
00263 }
00264
00265 bufsize = buf.tellg();
00266
00267 *m = msg;
00268 return true;
00269 }
00270
00271 bool can_uvccm_win32::set_can_data(const Message& m, std::string& can_cmd)
00272 {
00273
00274 std::ostringstream can_cmd_str;
00275 can_cmd_str << ":S" << std::hex << m.cob_id.w;
00276 if (m.rtr == 1)
00277 {
00278 can_cmd_str << 'R' << (long)m.len;
00279 }
00280 else
00281 {
00282 can_cmd_str << 'N';
00283 for (int i = 0; i < m.len; ++i)
00284 can_cmd_str << std::hex << std::setfill('0') << std::setw(2) << (long)m.data[i];
00285 }
00286 can_cmd_str << ';';
00287 can_cmd = can_cmd_str.str();
00288 #ifdef BOOST_VERSION
00289 boost::to_upper(can_cmd);
00290 #else
00291 std::transform(can_cmd.begin(),can_cmd.end(),can_cmd.begin(),::toupper);
00292 #endif
00293 return true;
00294 }
00295
00296
00297
00298 extern "C"
00299 UNS8 canReceive_driver(CAN_HANDLE fd0, Message *m)
00300 {
00301 return (UNS8)(!(reinterpret_cast<can_uvccm_win32*>(fd0)->receive(m)));
00302 }
00303
00304 extern "C"
00305 UNS8 canSend_driver(CAN_HANDLE fd0, Message *m)
00306 {
00307 return (UNS8)reinterpret_cast<can_uvccm_win32*>(fd0)->send(m);
00308 }
00309
00310 extern "C"
00311 CAN_HANDLE canOpen_driver(s_BOARD *board)
00312 {
00313 try
00314 {
00315 return (CAN_HANDLE) new can_uvccm_win32(board);
00316 }
00317 catch (can_uvccm_win32::error&)
00318 {
00319 return NULL;
00320 }
00321 }
00322
00323 extern "C"
00324 int canClose_driver(CAN_HANDLE inst)
00325 {
00326 delete reinterpret_cast<can_uvccm_win32*>(inst);
00327 return 1;
00328 }
00329
00330
00331