• Main Page
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

xid_con_t.cpp

Go to the documentation of this file.
00001 /* Copyright (c) 2010, Cedrus Corporation
00002  * All rights reserved.
00003  *
00004  * Redistribution and use in source and binary forms, with or without
00005  * modification, are permitted provided that the following conditions are
00006  * met:
00007  *
00008  * Redistributions of source code must retain the above copyright notice,
00009  * this list of conditions and the following disclaimer.  
00010  *
00011  * Redistributions in binary form must reproduce the above copyright
00012  * notice, this list of conditions and the following disclaimer in the
00013  * documentation and/or other materials provided with the distribution.
00014  *
00015  * Neither the name of Cedrus Corporation nor the names of its
00016  * contributors may be used to endorse or promote products derived from
00017  * this software without specific prior written permission.
00018  *
00019  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00020  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00021  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
00022  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
00023  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00024  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00025  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00026  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00027  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00028  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
00029  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00030  */
00031 
00032 #include "xid_con_t.h"
00033 #include "constants.h"
00034 
00035 cedrus::xid_con_t::xid_con_t(
00036     const std::wstring &port_name,
00037     int port_speed,
00038     int delay_ms,
00039     port_settings_t::bytesize byte_size,
00040     port_settings_t::bitparity bit_parity,
00041     port_settings_t::stopbits stop_bits
00042     )
00043     : in_buffer_size_(2048),
00044       out_buffer_size_(2048),
00045       model_id_(0),
00046       device_id_(NULL),
00047       delay_(delay_ms),
00048       bytes_in_buffer_(0),
00049       invalid_port_bits_(0x0C),
00050       timer_rate_(1),
00051       first_valid_xid_packet_(INVALID_PACKET_INDEX),
00052       num_keys_down_(0),
00053       last_resp_port_(-1),
00054       last_resp_key_(-1),
00055       last_resp_pressed_(false),
00056       last_resp_rt_(-1),
00057       lines_state_(0),
00058       needs_interbyte_delay_(true)
00059 
00060 {
00061     wsprintf(port_name_, L"\\\\.\\%s", port_name.c_str());
00062     port_settings_ = port_settings_t(port_name_, 
00063                                      port_speed,
00064                                      byte_size,
00065                                      bit_parity,
00066                                      stop_bits);
00067 
00068     for(int i = 0; i < INPUT_BUFFER_SIZE; ++i)
00069     {
00070         input_buffer_[i] = '\0';
00071     }
00072 
00073     set_lines_cmd_[0] = 'a';
00074     set_lines_cmd_[1] = 'h';
00075     set_lines_cmd_[2] = '\0';
00076     set_lines_cmd_[3] = '\0';
00077 }
00078 
00079 
00080 cedrus::xid_con_t::~xid_con_t(void)
00081 {
00082     if(device_id_ != 0)
00083         close();
00084 }
00085 
00086 int cedrus::xid_con_t::close()
00087 {
00088     if(CloseHandle(device_id_) == 0)
00089         return ERROR_CLOSING_PORT;
00090 
00091     device_id_ = 0;
00092     return NO_ERR;
00093 }
00094 
00095 int cedrus::xid_con_t::flush_input()
00096 {
00097     int status = NO_ERR;
00098 
00099     if(PurgeComm(device_id_, PURGE_RXABORT|PURGE_RXCLEAR) == 0)
00100     {
00101         status = ERROR_FLUSHING_PORT;
00102     }
00103 
00104     return status;
00105 }
00106 
00107 int cedrus::xid_con_t::flush_output()
00108 {
00109     int status = NO_ERR;
00110 
00111     if(PurgeComm(device_id_, PURGE_TXABORT|PURGE_TXCLEAR) == 0)
00112     {
00113         status = ERROR_FLUSHING_PORT;
00114     }
00115 
00116     return status;
00117 }
00118 
00119 int cedrus::xid_con_t::open()
00120 {
00121     int status = NO_ERR;
00122 
00123     device_id_ = CreateFile(
00124         port_name_,
00125         GENERIC_READ|GENERIC_WRITE,
00126         0,
00127         NULL,
00128         OPEN_EXISTING,
00129         0,
00130         0);
00131 
00132     if(device_id_ == INVALID_HANDLE_VALUE)
00133     {
00134         device_id_ = 0;
00135         status = PORT_NOT_AVAILABLE;
00136     }
00137     else
00138     {
00139         status = setup_com_port();
00140         PurgeComm(device_id_,
00141             PURGE_RXCLEAR|PURGE_TXCLEAR|PURGE_RXABORT|PURGE_TXABORT);
00142     }
00143 
00144     return status;
00145 }
00146 
00147 int cedrus::xid_con_t::setup_com_port()
00148 {
00149     DCB dcb;
00150     int status = NO_ERR;
00151 
00152     if(SetupComm(device_id_, in_buffer_size_, out_buffer_size_) == 0)
00153     {
00154         status = ERROR_SETTING_UP_PORT;
00155         return status;
00156     }
00157 
00158     if(GetCommState(device_id_, &dcb) == 0)
00159     {
00160         status = ERROR_SETTING_UP_PORT;
00161         return status;
00162     }
00163 
00164     setup_dcb(dcb);
00165 
00166     if(SetCommState(device_id_, &dcb) == 0)
00167     {
00168         status = ERROR_SETTING_UP_PORT;
00169         return status;
00170     }
00171 
00172     COMMTIMEOUTS ct;
00173     if(GetCommTimeouts(device_id_, &ct) == 0)
00174     {
00175         status = ERROR_SETTING_UP_PORT;
00176         return status;
00177     }
00178 
00179     setup_timeouts(ct);
00180     
00181     if(SetCommTimeouts(device_id_, &ct) == 0)
00182     {
00183         status = ERROR_SETTING_UP_PORT;
00184         return status;
00185     }
00186 
00187     status = flush_input();
00188     if(status == NO_ERR)
00189         status = flush_output();
00190 
00191     return status;
00192 }
00193 
00194 void cedrus::xid_con_t::setup_dcb(DCB &dcb) const
00195 {
00196     dcb.BaudRate = port_settings_.baud_rate();
00197     dcb.ByteSize = static_cast<BYTE>(port_settings_.byte_size());
00198     dcb.Parity   = static_cast<BYTE>(port_settings_.bit_parity());
00199     dcb.StopBits = static_cast<BYTE>(port_settings_.stop_bits());
00200     dcb.fBinary  = 1;
00201 }
00202 
00203 void cedrus::xid_con_t::setup_timeouts(COMMTIMEOUTS &ct) const
00204 {
00205     ct.ReadIntervalTimeout         = MAXDWORD;
00206     ct.ReadTotalTimeoutConstant    = 0;
00207     ct.ReadTotalTimeoutMultiplier  = 0;
00208     ct.WriteTotalTimeoutConstant   = 0;
00209     ct.WriteTotalTimeoutMultiplier = 500;
00210 }
00211 
00212 int cedrus::xid_con_t::read(
00213     unsigned char *in_buffer,
00214     int bytes_to_read,
00215     int &bytes_read)
00216 {
00217     DWORD read = 0;
00218         
00219     int status = NO_ERR;
00220 
00221     if(ReadFile(device_id_, in_buffer, bytes_to_read, &read, NULL) == 0)
00222     {
00223         status = ERROR_READING_PORT;
00224     }
00225     else
00226     {
00227         bytes_read = read;
00228     }
00229     
00230     return status;
00231 }
00232 
00233 int cedrus::xid_con_t::write(
00234     unsigned char * const in_buffer,
00235     int bytes_to_write,
00236     int &bytes_written)
00237 {
00238     unsigned char *p = in_buffer;
00239     int status = NO_ERR;
00240     DWORD written = 0;
00241     
00242     if(needs_interbyte_delay_)
00243     {
00244         for(int i = 0; i < bytes_to_write && status == NO_ERR; ++i)
00245         {
00246             DWORD  byte_count;
00247             if(WriteFile(device_id_, p, 1, &byte_count, NULL) == 0)
00248             {
00249                 status = ERROR_WRITING_TO_PORT;
00250                 break;
00251             }
00252             
00253             written += byte_count;
00254 
00255             if(written == bytes_to_write)
00256                 break;
00257 
00258             Sleep(delay_);
00259 
00260             ++p;
00261         }
00262         bytes_written = written;
00263     }
00264     else
00265     {
00266         if(WriteFile(device_id_, p, bytes_to_write, &written, NULL) == 0)
00267         {
00268             status = ERROR_WRITING_TO_PORT;
00269         }
00270         else
00271         {
00272             bytes_written = written;
00273         }
00274     }
00275 
00276     return status;
00277 }
00278 
00279 cedrus::key_state cedrus::xid_con_t::xid_input_found()
00280 {
00281     key_state input_found = NO_KEY_DETECTED;
00282 
00283     if(bytes_in_buffer_ >= 6)
00284     {
00285         const int last_byte_index = bytes_in_buffer_ - XID_PACKET_SIZE;
00286 
00287         for(int i = 0; i <= last_byte_index; ++i)
00288         {
00289             if(input_buffer_[i] == 'k' &&
00290                (input_buffer_[i+1] & invalid_port_bits_) == 0 &&
00291                input_buffer_[i+5] == '\0')
00292             {
00293                 // found a valid XID packet
00294                 first_valid_xid_packet_ = i;
00295                 last_resp_pressed_ = (
00296                     input_buffer_[first_valid_xid_packet_+1] & KEY_RELEASE_BITMASK) ==
00297                     KEY_RELEASE_BITMASK;
00298                 last_resp_port_ = 
00299                     input_buffer_[first_valid_xid_packet_+1] & 0x0F;
00300 
00301                 last_resp_key_ = (
00302                     input_buffer_[first_valid_xid_packet_+1] & 0xE0) >> 5;
00303 
00304                 if(last_resp_key_ == 0)
00305                     last_resp_key_ = 8;
00306                 
00307                 // get reaction time
00308                 union {
00309                     int as_int;
00310                     char as_char[4];
00311                 } rt;
00312 
00313                 for(int n = 0; n < 4; ++n)
00314                 {
00315                     rt.as_char[n] = input_buffer_[first_valid_xid_packet_+2+n];
00316                 }
00317                 
00318                 last_resp_rt_ = rt.as_int;
00319 
00320                 input_found = static_cast<key_state>(
00321                     FOUND_KEY_DOWN + !last_resp_pressed_);
00322 
00323                 if(input_found == FOUND_KEY_DOWN)
00324                     num_keys_down_++;
00325                 else
00326                     num_keys_down_--;
00327             }
00328         }
00329     }
00330     
00331     return input_found;
00332 }
00333 
00334 cedrus::key_state cedrus::xid_con_t::check_for_keypress()
00335 {
00336     int bytes_read = 0;
00337     int status = NO_ERR; 
00338     key_state response_found = NO_KEY_DETECTED;
00339 
00340     status = read(&input_buffer_[bytes_in_buffer_], 6, bytes_read);
00341 
00342     if(bytes_read > 0)
00343     {
00344         bytes_in_buffer_ += bytes_read;
00345         response_found = xid_input_found();
00346     }
00347 
00348     return response_found;
00349 }
00350 
00351 void cedrus::xid_con_t::remove_current_response()
00352 {
00353     if(first_valid_xid_packet_ != INVALID_PACKET_INDEX)
00354     {
00355         unsigned char *dest_char = input_buffer_;
00356         unsigned char *src_char  = &input_buffer_[first_valid_xid_packet_];
00357         int num_bytes = bytes_in_buffer_ - first_valid_xid_packet_;
00358 
00359         for(int i = 0; i < num_bytes; ++i, ++dest_char, ++src_char)
00360         {
00361             dest_char = src_char;
00362         }
00363 
00364         bytes_in_buffer_ -= num_bytes;
00365         first_valid_xid_packet_ = INVALID_PACKET_INDEX;
00366     }
00367 }
00368 
00369 void cedrus::xid_con_t::get_current_response(
00370     int &port, int &key, bool &was_pressed, int &reaction_time)
00371 {
00372     if(first_valid_xid_packet_ != INVALID_PACKET_INDEX)
00373     {
00374         port = last_resp_port_;
00375         key  = last_resp_key_;
00376         was_pressed = last_resp_pressed_;
00377         reaction_time = last_resp_rt_;
00378 
00379         remove_current_response();
00380     }
00381     else
00382     {
00383         port = -1;
00384         key  = -1;
00385         was_pressed = false;
00386         reaction_time = -1;
00387     }
00388 }
00389 
00390 int cedrus::xid_con_t::get_number_of_keys_down()
00391 {
00392     return num_keys_down_;
00393 }
00394 
00395 int cedrus::xid_con_t::send_xid_command(
00396     const char in_command[],
00397     int num_bytes,
00398     char out_response[],
00399     int max_out_response_size,
00400     int expected_bytes_rec,
00401     int timeout,
00402     int command_delay)
00403 {
00404     if(out_response != NULL)
00405     {
00406         memset(out_response, 0x00, max_out_response_size);
00407     }
00408 
00409     if(num_bytes == 0)
00410     {
00411         num_bytes = strlen(in_command);
00412     }
00413 
00414     int bytes_written = 0;
00415     write((unsigned char*)in_command, num_bytes, bytes_written);
00416 
00417     unsigned char in_buff[64];
00418     memset(in_buff, 0x00, sizeof(in_buff));
00419     int bytes_read = 0;
00420     int bytes_stored = 0;
00421 
00422     // sometimes sending a command needs a delay because the 4MHz processors
00423     // in the response pads need a little time to process the command and 
00424     // send a response.
00425     if(command_delay > 0)
00426         Sleep(command_delay);
00427 
00428     DWORD current_time;
00429     DWORD start_time = GetTickCount();
00430     DWORD end_time = start_time + timeout;
00431 
00432     int status = 0;
00433     do
00434     {
00435         if(needs_interbyte_delay_)
00436             Sleep(delay_);
00437 
00438         status = read(
00439             in_buff, sizeof(in_buff), bytes_read);
00440 
00441         if(status != NO_ERR)
00442             break;
00443 
00444         if(bytes_read >= 1)
00445         {
00446             for(int i = 0; (i<bytes_read) && (bytes_stored < max_out_response_size);
00447                 ++i)
00448             {
00449                 out_response[bytes_stored] = in_buff[i];
00450                 bytes_stored++;
00451             }
00452         }
00453         current_time = GetTickCount();
00454     } while (current_time < end_time &&
00455              bytes_stored < max_out_response_size &&
00456              bytes_stored < expected_bytes_rec);
00457 
00458     if(out_response != NULL)
00459         out_response[bytes_stored] = '\0';
00460 
00461     return bytes_stored;
00462 }
00463 
00464 void cedrus::xid_con_t::set_needs_interbyte_delay(bool needs_delay)
00465 {
00466     needs_interbyte_delay_ = needs_delay;
00467 }
00468 
00469 void cedrus::xid_con_t::set_digital_out_prefix(char prefix)
00470 {
00471     set_lines_cmd_[0] = prefix;
00472 }
00473 
00474 void cedrus::xid_con_t::set_digital_output_lines(
00475     unsigned int lines,
00476     bool leave_remaining_lines)
00477 {
00478     if(lines < 0 || lines > 255)
00479         return;
00480 
00481     int bytes_written;
00482 
00483     if(leave_remaining_lines)
00484         lines |= lines_state_;
00485 
00486     if(set_lines_cmd_[0] == 'a')
00487     {
00488         set_lines_cmd_[2] = ~lines;
00489     }
00490     else
00491     {
00492         set_lines_cmd_[2] = lines;
00493     }
00494 
00495     write((unsigned char*)set_lines_cmd_, 4, bytes_written);
00496     lines_state_ = lines;
00497 }
00498 
00499 void cedrus::xid_con_t::clear_digital_output_lines(
00500     unsigned int lines,
00501     bool leave_remaining_lines)
00502 {
00503     if(lines < 0 || lines > 255)
00504         return;
00505 
00506     int bytes_written;
00507     lines = ~lines;
00508 
00509     if(leave_remaining_lines)
00510         lines = lines & lines_state_;
00511 
00512     if(set_lines_cmd_[0] == 'a')
00513     {
00514         set_lines_cmd_[2] = ~lines;
00515     }
00516     else
00517     {
00518         set_lines_cmd_[2] = lines;
00519     }
00520 
00521     write((unsigned char*)set_lines_cmd_, 4, bytes_written);
00522     lines_state_ = lines;
00523 }

Generated on Wed Dec 15 2010 13:17:12 for XID device library by  doxygen 1.7.2