diff -r 3ebf16150b2e -r e747d2e26af0 drivers/can_uvccm_win32/can_uvccm_win32.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/drivers/can_uvccm_win32/can_uvccm_win32.cpp Wed Apr 04 13:04:31 2007 +0200 @@ -0,0 +1,331 @@ +// can_uvccm_win32 adapter (http://www.gridconnect.com) +// driver for CanFestival-3 Win32 port +// Copyright (C) 2007 Leonid Tochinski, ChattenAssociates, Inc. + + +#include +#include +#if 0 // change to 1 if you use boost +#include +#else +#include +#endif + +extern "C" { +#include "can_driver.h" +} +class can_uvccm_win32 + { + public: + class error + { + }; + can_uvccm_win32(s_BOARD *board); + ~can_uvccm_win32(); + bool send(const Message *m); + bool receive(Message *m); + private: + bool open_rs232(int port = 1, int baud_rate = 57600); + bool close_rs232(); + bool get_can_data(const char* can_cmd_buf, long& bufsize, Message* m); + bool set_can_data(const Message& m, std::string& can_cmd); + private: + HANDLE m_port; + HANDLE m_read_event; + HANDLE m_write_event; + std::string m_residual_buffer; + }; + +can_uvccm_win32::can_uvccm_win32(s_BOARD *board) : m_port(INVALID_HANDLE_VALUE), + m_read_event(0), + m_write_event(0) + { + if (strcmp( board->baudrate, "125K") || !open_rs232(1)) + throw error(); + } + +can_uvccm_win32::~can_uvccm_win32() + { + close_rs232(); + } + +bool can_uvccm_win32::send(const Message *m) + { + if (m_port == INVALID_HANDLE_VALUE) + return false; + + // build can_uvccm_win32 command string + std::string can_cmd; + set_can_data(*m, can_cmd); + + OVERLAPPED overlapped; + ::memset(&overlapped, 0, sizeof overlapped); + overlapped.hEvent = m_write_event; + ::ResetEvent(overlapped.hEvent); + + unsigned long bytes_written = 0; + ::WriteFile(m_port, can_cmd.c_str(), (unsigned long)can_cmd.size(), &bytes_written, &overlapped); + // wait for write operation completion + enum { WRITE_TIMEOUT = 1000 }; + ::WaitForSingleObject(overlapped.hEvent, WRITE_TIMEOUT); + // get number of bytes written + ::GetOverlappedResult(m_port, &overlapped, &bytes_written, FALSE); + + bool result = (bytes_written == can_cmd.size()); + + return result; + } + + +bool can_uvccm_win32::receive(Message *m) + { + if (m_port == INVALID_HANDLE_VALUE) + return false; + + long res_buffer_size = (long)m_residual_buffer.size(); + bool result = get_can_data(m_residual_buffer.c_str(), res_buffer_size, m); + if (result) + { + m_residual_buffer.erase(0, res_buffer_size); + return true; + } + + enum { READ_TIMEOUT = 500 }; + + OVERLAPPED overlapped; + ::memset(&overlapped, 0, sizeof overlapped); + overlapped.hEvent = m_read_event; + ::ResetEvent(overlapped.hEvent); + unsigned long event_mask = 0; + + if (FALSE == ::WaitCommEvent(m_port, &event_mask, &overlapped) && ERROR_IO_PENDING == ::GetLastError()) + { + if (WAIT_TIMEOUT == ::WaitForSingleObject(overlapped.hEvent, READ_TIMEOUT)) + return false; + } + + // get number of bytes in the input que + COMSTAT stat; + ::memset(&stat, 0, sizeof stat); + unsigned long errors = 0; + ::ClearCommError(m_port, &errors, &stat); + if (stat.cbInQue == 0) + return false; + char buffer[3000]; + + unsigned long bytes_to_read = min(stat.cbInQue, sizeof (buffer)); + + unsigned long bytes_read = 0; + ::ReadFile(m_port, buffer, bytes_to_read, &bytes_read, &overlapped); + // wait for read operation completion + ::WaitForSingleObject(overlapped.hEvent, READ_TIMEOUT); + // get number of bytes read + ::GetOverlappedResult(m_port, &overlapped, &bytes_read, FALSE); + result = false; + if (bytes_read > 0) + { + m_residual_buffer.append(buffer, bytes_read); + res_buffer_size = (long)m_residual_buffer.size(); + result = get_can_data(m_residual_buffer.c_str(), res_buffer_size, m); + if (result) + m_residual_buffer.erase(0, res_buffer_size); + } + return result; + } + +bool can_uvccm_win32::open_rs232(int port, int baud_rate) + { + if (m_port != INVALID_HANDLE_VALUE) + return true; + + std::ostringstream device_name; + device_name << "COM" << port; + + m_port = ::CreateFile(device_name.str().c_str(), + GENERIC_READ | GENERIC_WRITE, + 0, // exclusive access + NULL, // no security + OPEN_EXISTING, + FILE_FLAG_OVERLAPPED, // overlapped I/O + NULL); // null template + + // Check the returned handle for INVALID_HANDLE_VALUE and then set the buffer sizes. + if (m_port == INVALID_HANDLE_VALUE) + return false; + + // SetCommMask(m_hCom,EV_RXCHAR|EV_TXEMPTY|EV_CTS|EV_DSR|EV_RLSD|EV_BREAK|EV_ERR|EV_RING); // + ::SetCommMask(m_port, EV_RXFLAG); + + COMMTIMEOUTS timeouts; + ::memset(&timeouts, 0, sizeof (timeouts)); + timeouts.ReadIntervalTimeout = -1; + timeouts.ReadTotalTimeoutConstant = 0; + timeouts.ReadTotalTimeoutMultiplier = 0; + timeouts.WriteTotalTimeoutConstant = 5000; + timeouts.WriteTotalTimeoutMultiplier = 0; + SetCommTimeouts(m_port, &timeouts); // + + ::SetupComm(m_port, 1024, 512); // set buffer sizes + + // 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. + DCB dcb; + ::memset(&dcb, 0, sizeof (dcb)); + ::GetCommState(m_port, &dcb); + dcb.BaudRate = baud_rate; + dcb.ByteSize = 8; + dcb.Parity = NOPARITY; + dcb.StopBits = ONESTOPBIT; + dcb.fAbortOnError = TRUE; + dcb.EvtChar = 0x0A; // '\n' character + ::SetCommState(m_port, &dcb); + + ::PurgeComm(m_port, PURGE_RXABORT | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_TXCLEAR); + + m_read_event = ::CreateEvent(NULL, TRUE, FALSE, NULL); + m_write_event = ::CreateEvent(NULL, TRUE, FALSE, NULL); + + return true; + } + +bool can_uvccm_win32::close_rs232() + { + if (m_port != INVALID_HANDLE_VALUE) + { + ::PurgeComm(m_port, PURGE_RXABORT | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_TXCLEAR); + ::CloseHandle(m_port); + m_port = INVALID_HANDLE_VALUE; + ::CloseHandle(m_read_event); + m_read_event = 0; + ::CloseHandle(m_write_event); + m_write_event = 0; + m_residual_buffer.clear(); + } + return true; + } + +bool can_uvccm_win32::get_can_data(const char* can_cmd_buf, long& bufsize, Message* m) + { + if (bufsize < 5) + { + bufsize = 0; + return false; + } + + Message msg; + ::memset(&msg, 0 , sizeof (msg)); + char colon = 0, type = 0, request = 0; + std::istringstream buf(std::string(can_cmd_buf, bufsize)); + buf >> colon >> type >> std::hex >> msg.cob_id.w >> request; + if (colon != ':' || (type != 'S' && type != 'X')) + { + bufsize = 0; + return false; + } + if (request == 'N') + { + msg.rtr = 0; + for (msg.len = 0; msg.len < 8; ++msg.len) + { + std::string data_byte_str; + buf >> std::setw(2) >> data_byte_str; + if (data_byte_str[0] == ';') + break; + long byte_val = -1; + std::istringstream(data_byte_str) >> std::hex >> byte_val; + if (byte_val == -1) + { + bufsize = 0; + return false; + } + msg.data[msg.len] = (UNS8)byte_val; + } + if (msg.len == 8) + { + char semicolon = 0; + buf >> semicolon; + if (semicolon != ';') + { + bufsize = 0; + return false; + } + } + + } + else if (request == 'R') + { + msg.rtr = 1; + buf >> msg.len; + } + else + { + bufsize = 0; + return false; + } + + bufsize = buf.tellg(); + + *m = msg; + return true; + } + +bool can_uvccm_win32::set_can_data(const Message& m, std::string& can_cmd) + { + // build can_uvccm_win32 command string + std::ostringstream can_cmd_str; + can_cmd_str << ":S" << std::hex << m.cob_id.w; + if (m.rtr == 1) + { + can_cmd_str << 'R' << (long)m.len; + } + else + { + can_cmd_str << 'N'; + for (int i = 0; i < m.len; ++i) + can_cmd_str << std::hex << std::setfill('0') << std::setw(2) << (long)m.data[i]; + } + can_cmd_str << ';'; + can_cmd = can_cmd_str.str(); +#ifdef BOOST_VERSION + boost::to_upper(can_cmd); +#else + std::transform(can_cmd.begin(),can_cmd.end(),can_cmd.begin(),::toupper); +#endif + return true; + } + + +//------------------------------------------------------------------------ +extern "C" + UNS8 canReceive_driver(CAN_HANDLE fd0, Message *m) + { + return (UNS8)(!(reinterpret_cast(fd0)->receive(m))); + } + +extern "C" + UNS8 canSend_driver(CAN_HANDLE fd0, Message *m) + { + return (UNS8)reinterpret_cast(fd0)->send(m); + } + +extern "C" + CAN_HANDLE canOpen_driver(s_BOARD *board) + { + try + { + return (CAN_HANDLE) new can_uvccm_win32(board); + } + catch (can_uvccm_win32::error&) + { + return NULL; + } + } + +extern "C" + int canClose_driver(CAN_HANDLE inst) + { + delete reinterpret_cast(inst); + return 1; + } + + + \ No newline at end of file