00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
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
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
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
00423
00424
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 }