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 #include <iostream>
00031 #include <cerrno>
00032 #include <iomanip>
00033 #include <cassert>
00034 #include <fcntl.h>
00035 #include <unistd.h>
00036 #include <sys/ioctl.h>
00037 #include "fob/fob.h"
00038
00039
00040 #define DEBUG(x)
00041
00042 const fob::mode fob::POSITION = 0x01;
00043 const fob::mode fob::ORIENTATION = 0x02;
00044 const fob::mode fob::BUTTONS = 0x04;
00045
00046 const unsigned char fob::BUTTON_NONE = 0x0;
00047 const unsigned char fob::BUTTON_LEFT = 0x10;
00048 const unsigned char fob::BUTTON_MIDDLE = 0x30;
00049 const unsigned char fob::BUTTON_RIGHT = 0x70;
00050
00051 const unsigned char fob::STREAM = '@';
00052
00053 const unsigned char fob::POINT = 'B';
00054 const unsigned char fob::SLEEP = 'G';
00055
00056 const unsigned char fob::EXAMINE = 'O';
00057 const unsigned char fob::CHANGE = 'P';
00058
00059 const unsigned char fob::MODE_POS = 'V';
00060 const unsigned char fob::MODE_ANG = 'W';
00061 const unsigned char fob::MODE_POS_ANG = 'Y';
00062 const unsigned char fob::MODE_POS_MAT = 'Z';
00063 const unsigned char fob::MODE_POS_QUAT = ']';
00064 const unsigned char fob::MODE_QUAT = 0x5C;
00065 const unsigned char fob::FBB_RESET = '/';
00066 const unsigned char fob::RUN = 'F';
00067
00068 const fob::command fob::HEMISPHERE = { 'L', 2 };
00069 const fob::command fob::BUTTON_MODE = { 'M', 1 };
00070 const fob::command fob::REF_FRAME_1 = { 'H', 12 };
00071 const fob::command fob::REF_FRAME_2 = { 'r', 6 };
00072
00073 const fob::examine_option fob::BIRD_STATUS = { 0, 2 };
00074 const fob::examine_option fob::ERROR_CODE = { 10, 1 };
00075 const fob::examine_option fob::MODEL_ID = { 15, 10 };
00076 const fob::examine_option fob::REF_FRAME_1_EXAMINE = { 17, 1 };
00077 const fob::examine_option fob::ADDR_MODE = { 19, 1 };
00078 const fob::examine_option fob::FLOCK_STATUS = { 36, FOB_MAX_BIRDS };
00079
00080 const fob::change_option fob::REF_FRAME_1_ENABLE = { 17, 1 };
00081 const fob::change_option fob::GROUP = { 35, 1 };
00082 const fob::change_option fob::FBB_AUTO_CONFIG = { 50, 1 };
00083
00084 const float fob::SCALE = 1.0 / 32767.0;
00085 const float fob::ANGLE_SCALE = 180.0 / 32767.0;
00086
00087 static const fob::error_t error_msgs[ ] = {
00088 { "System Ram Failure", fob::FATAL },
00089 { "Non-Volatile Storage Write Failure", fob::FATAL },
00090 { "PCB Configuration Data Corrupt", fob::WARNING1 },
00091 { "Bird Transmitter Calibration Data Corrupt or Not Connected", fob::WARNING1 },
00092 { "Bird Sensor Calibration Data Corrupt or Not Connected", fob::WARNING1 },
00093 { "Invalid RS232 Command", fob::WARNING2 },
00094 { "Not an FBB Master", fob::WARNING2 },
00095 { "No Birds accessible in Device List", fob::WARNING2 },
00096 { "Bird is Not Initialized", fob::WARNING2 },
00097 { "FBB Serial Port Receive Error - Intra Bird Bus", fob::WARNING1 },
00098 { "RS232 Serial Port Receive Error", fob::WARNING1 },
00099 { "FBB Serial Port Receive Error - FBB Host Bus", fob::WARNING1 },
00100 { "No FBB Command Response", fob::WARNING1 },
00101 { "Invalid FBB Host Command", fob::WARNING1 },
00102 { "FBB Run Time Error", fob::FATAL },
00103 { "Invalid CPU Speed", fob::FATAL },
00104 { "No FBB Data", fob::WARNING1 },
00105 { "Illegal Baud Rate", fob::WARNING1 },
00106 { "Slave Acknowledge Error", fob::WARNING1 },
00107 { "Intel 80186 CPU Error", fob::FATAL },
00108 { "Intel 80186 CPU Error", fob::FATAL },
00109 { "Intel 80186 CPU Error", fob::FATAL },
00110 { "Intel 80186 CPU Error", fob::FATAL },
00111 { "Intel 80186 CPU Error", fob::FATAL },
00112 { "Intel 80186 CPU Error", fob::FATAL },
00113 { "Intel 80186 CPU Error", fob::FATAL },
00114 { "Intel 80186 CPU Error", fob::FATAL },
00115 { "CRT Synchronization", fob::WARNING1 },
00116 { "Transmitter Not accessible", fob::WARNING1 },
00117 { "Extended Range Transmitter Not Attached", fob::WARNING2 },
00118 { "CPU Time Overflow", fob::WARNING2 },
00119 { "Sensor Saturated", fob::WARNING1 },
00120 { "Slave Configuration", fob::WARNING1 },
00121 { "Watch Dog Timer", fob::WARNING1 },
00122 { "Over Temperature", fob::WARNING1 }
00123 };
00124
00125
00126
00128 static const char*
00129 error_level_str( fob::error_level lvl )
00130 {
00131 switch( lvl ) {
00132 case fob::WARNING1:
00133 return "warning1";
00134 break;
00135
00136 case fob::WARNING2:
00137 return "warning2";
00138 break;
00139
00140 case fob::FATAL:
00141 return "fatal";
00142 break;
00143
00144 default:
00145 return "unknown";
00146 }
00147 }
00148
00149
00150
00152
00153 static void
00154 unpack( unsigned char *buffer, short *output, int size )
00155 {
00156 for( int i = 0, j = 0; i < size; i += 2 ) {
00157
00158 buffer[ i ] = buffer[ i ] << 1;
00159
00160 output[ j++ ] = ((buffer[ i + 1 ] << 8) | buffer[ i ]) << 1;
00161 }
00162 }
00163
00164
00165
00167 bool
00168 fob::bird::set_mode( fob::mode mask )
00169 {
00170
00171 if( mask == fob::BUTTONS ) {
00172 m_flock.set_error( "fob::bird::set_mode: must specify data mode with buttons" );
00173 return false;
00174 }
00175
00176
00177 if( !m_flock.select_bird( *this ) ) {
00178
00179 return false;
00180 }
00181
00182
00183 if( (mask & (fob::POSITION | fob::ORIENTATION)) ==
00184 (fob::POSITION | fob::ORIENTATION) ) {
00185
00186 DEBUG( "fob::bird::set_mode: pos/angle" );
00187 if( !m_flock.send_cmd( MODE_POS_ANG ) ) {
00188
00189 return false;
00190 }
00191 } else if( mask & fob::POSITION ) {
00192
00193 DEBUG( "fob::bird::set_mode: pos" );
00194 if( !m_flock.send_cmd( MODE_POS ) ) {
00195
00196 return false;
00197 }
00198 } else if( mask & fob::ORIENTATION ) {
00199
00200 DEBUG( "fob::bird::set_mode: angle" );
00201 if( !m_flock.send_cmd( MODE_ANG ) ) {
00202
00203 return false;
00204 }
00205 }
00206
00207
00208 if( !m_flock.select_bird( *this ) ) {
00209
00210 return false;
00211 }
00212
00213
00214 unsigned char button_mode;
00215 if( mask & fob::BUTTONS ) {
00216
00217 DEBUG( "fob::bird::set_mode: enabling buttons" );
00218 button_mode = 0x01;
00219 } else {
00220
00221 button_mode = 0x00;
00222 }
00223
00224
00225 if( !m_flock.send_cmd( BUTTON_MODE, &button_mode ) ) {
00226
00227 return false;
00228 }
00229
00230
00231 m_flock.clear_device( );
00232 if( m_flock.check_error( ) ) {
00233 return false;
00234 }
00235
00236
00237 lock_data( );
00238 m_mode = mask;
00239 unlock_data( );
00240
00241
00242 return true;
00243 }
00244
00245
00246
00248 void
00249 fob::bird::set_rotation( const math::quaternion& quat )
00250 {
00251 m_rotation = quat;
00252 }
00253
00254
00255
00257 bool
00258 fob::bird::unpack_pos_angle( unsigned char *buffer, int size )
00259 {
00260
00261 if( 12 != size ) {
00262
00263 DEBUG( "fob::bird::update: pos/ang size mismatch: " << size );
00264 return false;
00265 }
00266
00267
00268 short unpacked[ 6 ];
00269 unpack( buffer, unpacked, 12 );
00270
00271
00272 lock_data( );
00273
00274
00275
00276
00277 float pos_scale = 36.0 * SCALE;
00278 m_position.set(
00279 static_cast<float>( -unpacked[ 1 ] ) * pos_scale,
00280 static_cast<float>( -unpacked[ 2 ] ) * pos_scale,
00281 static_cast<float>( unpacked[ 0 ] ) * pos_scale
00282
00283 );
00284
00285
00286
00287 m_fob_angles.set(
00288 static_cast<float>( -unpacked[ 4 ] ) * ANGLE_SCALE,
00289 static_cast<float>( -unpacked[ 3 ] ) * ANGLE_SCALE,
00290 static_cast<float>( unpacked[ 5 ] ) * ANGLE_SCALE
00291 );
00292
00293 m_ori_dirty = true;
00294
00295
00296 unlock_data( );
00297
00298
00299 return true;
00300 }
00301
00302
00303
00305 bool
00306 fob::bird::unpack_angle( unsigned char *buffer, int size )
00307 {
00308
00309 if( 6 != size ) {
00310
00311 DEBUG( "fob::bird::update: angle size mismatch" );
00312 return false;
00313 }
00314
00315
00316 short unpacked[ 3 ];
00317 unpack( buffer, unpacked, 6 );
00318
00319
00320 lock_data( );
00321
00322
00323
00324 m_fob_angles.set(
00325 static_cast<float>( -unpacked[ 1 ] ) * ANGLE_SCALE,
00326 static_cast<float>( -unpacked[ 0 ] ) * ANGLE_SCALE,
00327 static_cast<float>( unpacked[ 2 ] ) * ANGLE_SCALE
00328 );
00329
00330
00331 m_ori_dirty = true;
00332
00333
00334 unlock_data( );
00335
00336
00337 return true;
00338 }
00339
00340
00341
00343 bool
00344 fob::bird::unpack_pos( unsigned char *buffer, int size )
00345 {
00346
00347 if( 6 != size ) {
00348
00349 DEBUG( "fob::bird::update: position size mismatch" );
00350 return false;
00351 }
00352
00353
00354 short unpacked[ 3 ];
00355 unpack( buffer, unpacked, 6 );
00356
00357
00358 lock_data( );
00359
00360
00361
00362
00363 float pos_scale = 36.0 * SCALE;
00364 m_position.set(
00365 static_cast<float>( -unpacked[ 1 ] ) * pos_scale,
00366 static_cast<float>( -unpacked[ 2 ] ) * pos_scale,
00367 static_cast<float>( unpacked[ 0 ] ) * pos_scale
00368
00369 );
00370
00371
00372 m_ori_dirty = true;
00373
00374
00375 unlock_data( );
00376
00377
00378 return true;
00379 }
00380
00381
00382
00384 bool
00385 fob::bird::update( unsigned char *buffer, int size )
00386 {
00387
00388 int button_size = 0;
00389
00390 lock_data( );
00391 if( m_mode & fob::BUTTONS ) {
00392 m_buttons = buffer[ size - 1 ];
00393
00394 button_size = 1;
00395 }
00396 unlock_data( );
00397
00398
00399 if( (m_mode & (fob::POSITION | fob::ORIENTATION)) ==
00400 (fob::POSITION | fob::ORIENTATION) ) {
00401
00402 unpack_pos_angle( buffer, size - button_size );
00403 } else if( m_mode & fob::ORIENTATION ) {
00404
00405 unpack_angle( buffer, size - button_size );
00406 } else if( m_mode & fob::POSITION ) {
00407
00408 unpack_pos( buffer, size - button_size );
00409 }
00410
00411
00412 return true;
00413 }
00414
00415
00416
00418
00419 void
00420 fob::bird::update_orientation( void )
00421 {
00422
00423 math::quaternion tmp;
00424 m_quaternion.from_angle_axis( math::to_radians( m_fob_angles.x( ) ),
00425 math::vector3::X_AXIS );
00426 tmp.from_angle_axis( math::to_radians( m_fob_angles.y( ) ),
00427 math::vector3::Y_AXIS );
00428 m_quaternion = tmp * m_quaternion;
00429 m_quaternion.normalize( );
00430
00431
00432
00433 math::vector3 axis;
00434 tmp.set( math::vector3::Z_AXIS, 0.0 );
00435 axis = (m_quaternion * tmp * !m_quaternion).vec( );
00436 axis.normalize( );
00437 tmp.from_angle_axis( math::to_radians( m_fob_angles.z( ) ),
00438 axis );
00439 m_quaternion = tmp * m_quaternion;
00440 m_quaternion.normalize( );
00441
00442
00443 m_quaternion = m_quaternion * m_rotation;
00444 m_quaternion.normalize( );
00445
00446
00447
00448 m_angles = m_fob_angles;
00449
00450
00451 m_quaternion.get_rotation_matrix( m_matrix );
00452 m_matrix.set_translation( m_position );
00453
00454
00455 m_ori_dirty = false;
00456 }
00457
00458
00459
00461 bool
00462 fob::set_rts( bool high )
00463 {
00464 int status;
00465 if( ioctl( m_device, TIOCMGET, &status ) < 0 ) {
00466 set_error( "fob::set_rts: could not read RTS: %s",
00467 std::strerror( errno ) );
00468 return false;
00469 }
00470
00471 if( high ) {
00472 if( status & TIOCM_RTS ) {
00473
00474 return true;
00475 }
00476 } else {
00477 if( !(status & TIOCM_RTS) ) {
00478
00479 return true;
00480 }
00481 }
00482
00483
00484 status ^= TIOCM_RTS;
00485 if( ioctl( m_device, TIOCMSET, &status ) < 0 ) {
00486 set_error( "fob::set_rts: could not set RTS: %s",
00487 std::strerror( errno ) );
00488 return false;
00489 }
00490
00491
00492 return true;
00493 }
00494
00495
00496
00498 bool
00499 fob::select_bird( fob::bird& b )
00500 {
00501 DEBUG( "fob::select_bird: " << b.m_address );
00502 unsigned char address = b.m_address;
00503 address += 0xF0;
00504
00505
00506 cmd_sleep( );
00507 if( write( m_device, &address, 1 ) != 1 ) {
00508 set_error( "fob::select_bird: could not send select bird" );
00509 return false;
00510 }
00511
00512
00513 return true;
00514 }
00515
00516
00517
00519 bool
00520 fob::select_bird( int bird_addr )
00521 {
00522 DEBUG( "fob::select_bird i: " << bird_addr );
00523 unsigned char address = bird_addr;
00524 address += 0xF0;
00525
00526
00527 cmd_sleep( );
00528 if( write( m_device, &address, 1 ) != 1 ) {
00529 set_error( "fob::select_bird: could not send select bird" );
00530 return false;
00531 }
00532
00533
00534 return true;
00535 }
00536
00537
00538
00540
00541
00542 bool
00543 fob::print_bird_status( void )
00544 {
00545 if( m_fly ) {
00546
00547 set_error( "fob::print_bird_status: can not get status while flying" );
00548 return false;
00549 }
00550
00551 unsigned char buffer[ 256 ];
00552 for( unsigned int i = 0; i < m_birds.size( ); ++i ) {
00553
00554 if( !select_bird( *m_birds[ i ] ) ) {
00555 return false;
00556 }
00557
00558
00559 if( !examine( BIRD_STATUS, buffer ) ) {
00560
00561 return false;
00562 }
00563
00564
00565 clear_device( );
00566 if( check_error( ) ) {
00567 return false;
00568 }
00569
00570 std::cout << "bird status: " << i << " ";
00571 for( int b = 1; b >= 0; --b ) {
00572 for( int j = 7; j >= 0; --j ) {
00573 std::cout << ((buffer[ b ] >> j) & 1);
00574 }
00575 std::cout << " ";
00576 }
00577 std::cout << std::endl;
00578 std::cout.flush( );
00579 }
00580
00581
00582 return true;
00583 }
00584
00585
00586
00588 void
00589 fob::clear_device( void )
00590 {
00591
00592
00593 tcflush( m_device, TCIOFLUSH );
00594 }
00595
00596
00597
00599 int
00600 fob::read( unsigned char *buffer, int bytes )
00601 {
00602 assert( bytes > 0 );
00603
00604
00605 unsigned int read_error = 0;
00606 int i, count;
00607 for( i = 0; (i < bytes) && (read_error < 5); ) {
00608
00609
00610 count = ::read( m_device, &buffer[ i ], 1 );
00611 if( count < 0 ) {
00612
00613 if( errno != EINTR ) {
00614
00615
00616 ++read_error;
00617 }
00618 } else if( count < 1 ) {
00619
00620 ++read_error;
00621 } else {
00622
00623 ++i;
00624 }
00625 }
00626
00627 return i;
00628 }
00629
00630
00631
00633 bool
00634 fob::send_cmd( unsigned char cmd )
00635 {
00636
00637 cmd_sleep( );
00638 if( write( m_device, &cmd, 1 ) != 1 ) {
00639 set_error( "fob::send_cmd: could not send command" );
00640 return false;
00641 }
00642
00643
00644 return true;
00645 }
00646
00647
00648
00650 bool
00651 fob::send_cmd( fob::command cmd, unsigned char *options )
00652 {
00653
00654 unsigned char buffer[ 256 ];
00655 buffer[ 0 ] = cmd.cmd;
00656 memcpy( &(buffer[ 1 ]), options, cmd.option_bytes );
00657
00658
00659 cmd_sleep( );
00660 int size = 1 + cmd.option_bytes;
00661 if( write( m_device, buffer, size ) != size ) {
00662 set_error( "fob::send_cmd: could not send command" );
00663 return false;
00664 }
00665
00666
00667 return true;
00668 }
00669
00670
00671
00673 bool
00674 fob::examine( fob::examine_option param, unsigned char *output )
00675 {
00676
00677 unsigned char cmd[ 2 ];
00678 cmd[ 0 ] = EXAMINE;
00679 cmd[ 1 ] = param.param;
00680
00681
00682 cmd_sleep( );
00683 if( write( m_device, cmd, 2 ) != 2 ) {
00684 set_error( "fob::examine: could not send examine command" );
00685 return false;
00686 }
00687
00688
00689 cmd_sleep( );
00690 int reply = read( output, param.reply_bytes );
00691 if( reply < 0 ) {
00692
00693 set_error( "fob::examine: could not recv examine reply: %s",
00694 std::strerror( errno ) );
00695 return false;
00696 } else if( reply < param.reply_bytes ) {
00697
00698 set_error( "fob::examine: not enough data in examine reply: "
00699 "expected %d: recv %d", param.reply_bytes, reply );
00700 return false;
00701 }
00702
00703
00704 return true;
00705
00706 }
00707
00708
00709
00711 bool
00712 fob::change( fob::change_option param, unsigned char *option )
00713 {
00714
00715 unsigned char cmd[ 256 ];
00716 cmd[ 0 ] = CHANGE;
00717 cmd[ 1 ] = param.param;
00718 memcpy( &(cmd[ 2 ]), option, param.option_bytes );
00719
00720
00721 int size = 2 + param.option_bytes;
00722 if( write( m_device, cmd, size ) != size ) {
00723 set_error( "fob::examine: could not send examine command" );
00724 return false;
00725 }
00726
00727
00728 return true;
00729 }
00730
00731
00732
00734 bool
00735 fob::check_address_mode( void )
00736 {
00737 unsigned char buffer[ 256 ];
00738 if( !examine( ADDR_MODE, buffer ) ) {
00739
00740 return false;
00741 }
00742
00743
00744 DEBUG( "fob::check_address_mode: mode: " << (int)(buffer[ 0 ]) );
00745 if( buffer[ 0 ] != 0 ) {
00746 set_error( "fob::check_address_mode: "
00747 "flock must be set in normal addressing mode" );
00748 return false;
00749 }
00750
00751
00752 clear_device( );
00753 if( check_error( ) ) {
00754 return false;
00755 }
00756
00757
00758 return true;
00759 }
00760
00761
00762
00764 bool
00765 fob::load_flock_status( void )
00766 {
00767
00768 unsigned char buffer[ 256 ];
00769 if( !examine( FLOCK_STATUS, buffer ) ) {
00770
00771 return false;
00772 }
00773
00774
00775 clear_device( );
00776 if( check_error( ) ) {
00777 return false;
00778 }
00779
00780
00781
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791 for( int i = 0; i < FOB_MAX_BIRDS; ++i ) {
00792
00793 std::cerr << "flock status: " << i << ": ";
00794 for( int j = 7; j >= 0; --j ) {
00795 std::cerr << ((buffer[ i ] >> j) & 0x1);
00796 }
00797 std::cerr << std::endl;
00798
00799
00800
00801 if( buffer[ i ] & 0x80 ) {
00802 DEBUG( "fob::load_flock_status: bird: " << i + 1 << " accessible" );
00803
00804
00805
00806
00807
00808
00809
00810
00811
00812
00813
00814
00815 bird *b = new bird( *this );
00816 b->m_address = i + 1;
00817 m_birds.push_back( b );
00818
00819
00820
00821 b->m_transmitter = (buffer[ i ] & 0x01);
00822
00823
00824
00825 b->m_sensor = (buffer[ i ] & 0x20);
00826 }
00827 }
00828
00829
00830 bool master_found = false;
00831 m_master = 666;
00832 for( unsigned int i = 0; i < m_birds.size( ); ++i ) {
00833
00834 if( !select_bird( *m_birds[ i ] ) ) {
00835 return false;
00836 }
00837
00838
00839 if( !examine( BIRD_STATUS, buffer ) ) {
00840
00841 return false;
00842 }
00843
00844
00845 clear_device( );
00846 if( check_error( ) ) {
00847 return false;
00848 }
00849
00850
00851
00852
00853 if( buffer[ 1 ] & 0x80 ) {
00854 DEBUG( "fob::load_flock_status: possible master at address " << m_birds[ i ]->m_address );
00855 if( m_birds[ i ]->m_address < m_master ) {
00856
00857 master_found = true;
00858 m_master = m_birds[ i ]->m_address;
00859 }
00860 }
00861 }
00862
00863
00864 if( !master_found ) {
00865 set_error( "fob::load_flock_status: master bird could not be found" );
00866 return false;
00867 }
00868 DEBUG( "fob::load_flock_status: master found at address " << m_master );
00869
00870
00871 return true;
00872 }
00873
00874
00875
00877
00878 bool
00879 fob::auto_configure( unsigned int birds )
00880 {
00881 if( birds == 0 ) {
00882 set_error( "fob::auto_configure: no birds detected" );
00883 return false;
00884 }
00885
00886
00887 DEBUG( "fob::auto_configure: selecting master: " << m_master );
00888 if( !select_bird( m_master ) ) {
00889
00890 return false;
00891 }
00892
00893
00894 DEBUG( "fob::auto_configure: sleeping before autoconfig" );
00895 cmd_sleep( 2000000 );
00896
00897 unsigned char num_birds = (int)birds;
00898 DEBUG( "fob::auto_configure: birds to configure: " << (int)num_birds );
00899 if( !change( FBB_AUTO_CONFIG, &num_birds ) ) {
00900
00901 return false;
00902 }
00903
00904
00905 DEBUG( "fob::auto_configure: sleeping 2 seconds after autoconfig" );
00906 cmd_sleep( 2000000 );
00907
00908
00909 clear_device( );
00910 if( check_error( ) ) {
00911 return false;
00912 }
00913
00914
00915 if( !send_cmd( RUN ) ) {
00916
00917 return false;
00918 }
00919
00920
00921 clear_device( );
00922 if( check_error( ) ) {
00923 return false;
00924 }
00925
00926
00927 return true;
00928 }
00929
00930
00931
00933 bool
00934 fob::set_hemisphere( fob::bird& b, fob::hemisphere hemi )
00935 {
00936
00937 if( !select_bird( b ) ) {
00938
00939 return false;
00940 }
00941
00942
00943 unsigned char cmd[ 2 ];
00944 switch( hemi ) {
00945 case FORWARD:
00946 cmd[ 0 ] = 0x00;
00947 cmd[ 1 ] = 0x00;
00948 break;
00949
00950 case AFT:
00951 cmd[ 0 ] = 0x00;
00952 cmd[ 1 ] = 0x01;
00953 break;
00954
00955 case UP:
00956 cmd[ 0 ] = 0x0C;
00957 cmd[ 1 ] = 0x01;
00958 break;
00959
00960 case DOWN:
00961 cmd[ 0 ] = 0x0C;
00962 cmd[ 1 ] = 0x00;
00963 break;
00964
00965 case LEFT:
00966 cmd[ 0 ] = 0x06;
00967 cmd[ 1 ] = 0x01;
00968 break;
00969
00970 case RIGHT:
00971 cmd[ 0 ] = 0x06;
00972 cmd[ 1 ] = 0x00;
00973 break;
00974
00975 default:
00976 set_error( "fob::set_hemisphere: unknown hemisphere" );
00977 return false;
00978 break;
00979 }
00980
00981
00982 if( !send_cmd( HEMISPHERE, cmd ) ) {
00983
00984 return false;
00985 }
00986
00987
00988 clear_device( );
00989 if( check_error( ) ) {
00990 return false;
00991 }
00992
00993
00994 return true;
00995 }
00996
00997
00998
01000 bool
01001 fob::reset( void )
01002 {
01003 DEBUG( "fob::reset: initiating reset..." );
01004
01005 if( !set_rts( true ) ) {
01006 return false;
01007 }
01008
01009
01010 if( !set_rts( false ) ) {
01011 return false;
01012 }
01013
01014
01015
01016 cmd_sleep( 3000000 );
01017
01018
01019 clear_device( );
01020 if( !send_cmd( FBB_RESET ) ) {
01021
01022 return false;
01023 }
01024 DEBUG( "fob::reset: ...done" );
01025
01026
01027 return true;
01028 }
01029
01030
01031
01033
01034 bool
01035 fob::check_error( void )
01036 {
01037 unsigned char buffer[ 256 ];
01038 if( !examine( ERROR_CODE, buffer ) ) {
01039
01040 return true;
01041 }
01042
01043
01044 int code = (int)(buffer[ 0 ]);
01045 DEBUG( "fob::check_error: code: " << code );
01046
01047
01048
01049 if( (code > 35) || (code < 0) ) {
01050 set_error( "fob::check_error: fob is returning corrupt data, "
01051 "please reset the flock" );
01052 return true;
01053 }
01054
01055
01056
01057
01058
01059
01060
01061
01062
01063
01064
01065
01066
01067
01068 if( code ) {
01069
01070 const error_t *err = &error_msgs[ code - 1 ];
01071 if( err->level < m_min_error_level ) {
01072
01073 std::cerr << "fob: ignoring error: " << code << ": "
01074 << error_level_str( err->level ) << ": " << err->msg << std::endl;
01075 } else {
01076
01077 set_error( "fob: %d: %s: %s\n", code,
01078 error_level_str( err->level ), err->msg );
01079 return true;
01080 }
01081 }
01082
01083
01084 return false;
01085 }
01086
01087
01088
01090 fob::fob( void ): m_error( true ), m_error_msg( "uninitialized" ),
01091 m_open( false ), m_device( -1 ), m_master( 1 ), m_fly( false ),
01092 m_group( false ), m_save( 0x00 ), m_sleep( 500000 ),
01093 m_min_error_level( fob::FATAL )
01094 {
01095
01096 pthread_mutex_init( &m_mutex, NULL );
01097
01098
01099 if( pthread_create( &m_flock_thread, NULL,
01100 get_flock_data, this ) != 0 ) {
01101
01102 set_error( "fob::fob: could not create download thread" );
01103 }
01104 }
01105
01106
01107
01109 fob::fob( const std::string& device_name, fob::hemisphere hemi,
01110 fob::port_speed speed, unsigned long sleep_ms ):
01111 m_error( true ), m_error_msg( "uninitialized" ),
01112 m_open( false ), m_device( -1 ), m_master( 1 ), m_fly( false ),
01113 m_group( false ), m_save( 0x00 ), m_sleep( sleep_ms * 1000 ),
01114 m_min_error_level( fob::FATAL )
01115 {
01116
01117 if( pthread_create( &m_flock_thread, NULL,
01118 get_flock_data, this ) != 0 ) {
01119
01120 set_error( "fob::fob: could not create download thread" );
01121 }
01122
01123
01124 pthread_mutex_init( &m_mutex, NULL );
01125
01126
01127 open( device_name, hemi, speed, sleep_ms );
01128 }
01129
01130
01131
01133 fob::~fob( void )
01134 {
01135
01136 pthread_cancel( m_flock_thread );
01137
01138
01139 pthread_mutex_destroy( &m_mutex );
01140
01141
01142 close( );
01143 }
01144
01145
01146
01148 const fob&
01149 fob::open( const std::string& device_name,
01150 fob::hemisphere hemi, fob::port_speed speed, unsigned long sleep_ms )
01151 {
01152
01153 assert( !m_open );
01154
01155
01156 m_hemisphere = hemi;
01157
01158
01159 set_sleep( sleep_ms );
01160
01161
01162 DEBUG( "fob::open: dev: '" << device_name << "'" );
01163 m_device = ::open( device_name.c_str( ), O_RDWR );
01164 if( m_device < 0 ) {
01165 set_error( "fob::open: %s", std::strerror( errno ) );
01166 return *this;
01167 }
01168
01169
01170 if( tcgetattr( m_device, &m_save_tio ) < 0 ) {
01171 set_error( "fob::open: %s", std::strerror( errno ) );
01172 return *this;
01173 }
01174
01175
01176 struct termios settings;
01177 memset( &settings, 0, sizeof( struct termios ) );
01178
01179
01180
01181
01182
01183
01184 settings.c_cflag = CS8 | CLOCAL | CREAD;
01185 if( speed == FAST ) {
01186 DEBUG( "fob::open: speed: 115200" );
01187 settings.c_cflag |= B115200;
01188 } else {
01189 DEBUG( "fob::open: speed: 38400" );
01190 settings.c_cflag |= B38400;
01191 }
01192
01193
01194 settings.c_iflag = IXOFF;
01195
01196
01197 settings.c_lflag = 0;
01198
01199
01200
01201 settings.c_cc[ VMIN ] = 0;
01202 settings.c_cc[ VTIME ] = 20;
01203
01204
01205 tcflush( m_device, TCIFLUSH );
01206 if( tcsetattr( m_device, TCSANOW, &settings ) < 0 ) {
01207 set_error( "fob::open: %s", std::strerror( errno ) );
01208 return *this;
01209 }
01210
01211
01212 clear_device( );
01213
01214
01215 if( !reset( ) ) {
01216
01217 return *this;
01218 }
01219
01220
01221 if( !auto_configure( 1 ) ) {
01222
01223 return *this;
01224 }
01225
01226
01227 clear_device( );
01228 DEBUG( "fob::open: checking addressing mode" );
01229 if( !check_address_mode( ) ) {
01230
01231 std::cerr << "fob::open: warning: addressing mode may be invalid"
01232 << std::endl;
01233 }
01234
01235
01236 clear_device( );
01237 if( !load_flock_status( ) ) {
01238
01239 return *this;
01240 }
01241
01242
01243 clear_device( );
01244 if( !auto_configure( m_birds.size( ) ) ) {
01245
01246 return *this;
01247 }
01248
01249
01250
01251 for( unsigned int i = 0; i < m_birds.size( ); ++i ) {
01252 if( m_birds[ i ]->m_sensor ) {
01253 clear_device( );
01254 if( !set_hemisphere( *m_birds[ i ], hemi ) ) {
01255
01256 return *this;
01257 }
01258 }
01259 }
01260
01261
01262 DEBUG( "fob::open: success" );
01263 m_open = true;
01264 clear_error( );
01265 return *this;
01266 }
01267
01268
01269
01271 bool
01272 fob::close( void )
01273 {
01274 DEBUG( "fob::close" );
01275
01276 if( !m_open ) return true;
01277
01278
01279 clear_device( );
01280 if( m_birds.size( ) > 0 ) {
01281 select_bird( *m_birds[ 0 ] );
01282 }
01283 clear_device( );
01284 send_cmd( POINT );
01285 clear_device( );
01286 send_cmd( SLEEP );
01287
01288
01289 cmd_sleep( );
01290 set_rts( false );
01291
01292
01293 if( tcsetattr( m_device, TCSANOW, &m_save_tio ) < 0 ) {
01294 set_error( "fob::close: %s", std::strerror( errno ) );
01295 return false;
01296 }
01297
01298
01299 if( ::close( m_device ) < 0 ) {
01300 set_error( "fob::close: %s", std::strerror( errno ) );
01301 return false;
01302 }
01303
01304
01305 m_open = false;
01306 return true;
01307 }
01308
01309
01310
01312 bool
01313 fob::fly( void )
01314 {
01315 DEBUG( "fob::fly" );
01316 lock( );
01317 if( m_fly ) {
01318
01319 unlock( );
01320 return true;
01321 }
01322 unlock( );
01323
01324
01325 DEBUG( "fob::fly: sending group command" );
01326 unsigned char options = 0x1;
01327 if( !change( GROUP, &options ) ) {
01328
01329 return false;
01330 }
01331
01332
01333 m_group = true;
01334
01335
01336 DEBUG( "fob::fly: sending stream command" );
01337 if( !send_cmd( STREAM ) ) {
01338
01339 return false;
01340 }
01341
01342
01343 lock( );
01344 m_fly = true;
01345 unlock( );
01346
01347
01348 return true;
01349 }
01350
01351
01352
01354 bool
01355 fob::update( void )
01356 {
01357
01358 lock( );
01359 if( !m_fly ) {
01360 unlock( );
01361 return true;
01362 }
01363 unlock( );
01364
01365 unsigned int read_error = 0;
01366 unsigned int phases_found = 0;
01367 unsigned char buffer[ 256 ];
01368 unsigned int i = 0;
01369
01370
01371
01372 if( m_save & 0x80 ) {
01373 buffer[ i++ ] = m_save;
01374 ++phases_found;
01375 m_save = 0x0;
01376 }
01377
01378
01379 while( (phases_found < 2) && (read_error < 5) ) {
01380
01381 if( ::read( m_device, &buffer[ i ], 1 ) == 1 ) {
01382
01383
01384 if( buffer[ i ] & 0x80 ) {
01385 ++phases_found;
01386 }
01387
01388
01389 ++i;
01390 } else {
01391 ++read_error;
01392 }
01393 }
01394
01395 if( read_error > 4 ) {
01396
01397
01398 m_save = 0x0;
01399 set_error( "fob::update: flock no longer responding" );
01400 return false;
01401 }
01402
01403
01404 m_save = buffer[ --i ];
01405
01406
01407 int address = static_cast<int>( buffer[ i - 1 ] ) - 1;
01408
01409
01410 if( (address < 0) || (address >= static_cast<int>( m_birds.size( ))) ) {
01411
01412 std::cerr << "fob::update: warning: bad bird address: "
01413 << address << " bytes read: " << i << std::endl;
01414 return true;
01415 }
01416
01417
01418
01419
01420 m_birds[ address ]->update( buffer, i - 1 );
01421
01422
01423 return true;
01424 }
01425
01426
01427
01429 extern "C" {
01430 void*
01431 get_flock_data( void *data )
01432 {
01433
01434 pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS, NULL );
01435
01436
01437 fob *flock = (fob*)data;
01438
01439
01440 while( 1 ) {
01441 flock->update( );
01442 }
01443 }
01444 }