diff -r 003cc3c63855 -r f49e5a6b7804 doc/doxygen/html/can__uvccm__win32_8cpp-source.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/doxygen/html/can__uvccm__win32_8cpp-source.html Fri Jun 08 09:23:56 2007 +0200 @@ -0,0 +1,357 @@ + +
+00001 // can_uvccm_win32 adapter (http://www.gridconnect.com) +00002 // driver for CanFestival-3 Win32 port +00003 // Copyright (C) 2007 Leonid Tochinski, ChattenAssociates, Inc. +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 // build can_uvccm_win32 command string +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 // wait for write operation completion +00069 enum { WRITE_TIMEOUT = 1000 }; +00070 ::WaitForSingleObject(overlapped.hEvent, WRITE_TIMEOUT); +00071 // get number of bytes written +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 // get number of bytes in the input que +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 // wait for read operation completion +00121 ::WaitForSingleObject(overlapped.hEvent, READ_TIMEOUT); +00122 // get number of bytes read +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, // exclusive access +00147 NULL, // no security +00148 OPEN_EXISTING, +00149 FILE_FLAG_OVERLAPPED, // overlapped I/O +00150 NULL); // null template +00151 +00152 // Check the returned handle for INVALID_HANDLE_VALUE and then set the buffer sizes. +00153 if (m_port == INVALID_HANDLE_VALUE) +00154 return false; +00155 +00156 // SetCommMask(m_hCom,EV_RXCHAR|EV_TXEMPTY|EV_CTS|EV_DSR|EV_RLSD|EV_BREAK|EV_ERR|EV_RING); // +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); // set buffer sizes +00169 +00170 // Port settings are specified in a Data Communication Block (DCB). The easiest way to initialize a DCB is to call GetCommState to fill in its default values, override the values that you want to change and then call SetCommState to set the values. +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; // '\n' character +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 // build can_uvccm_win32 command string +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 +