--- /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 <sstream>
+#include <iomanip>
+#if 0 // change to 1 if you use boost
+#include <boost/algorithm/string/case_conv.hpp>
+#else
+#include <algorithm>
+#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<can_uvccm_win32*>(fd0)->receive(m)));
+ }
+
+extern "C"
+ UNS8 canSend_driver(CAN_HANDLE fd0, Message *m)
+ {
+ return (UNS8)reinterpret_cast<can_uvccm_win32*>(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<can_uvccm_win32*>(inst);
+ return 1;
+ }
+
+
+
\ No newline at end of file