28#include <simgear/compiler.h>
30#if defined( unix ) || defined( __CYGWIN__ )
31# include <sys/types.h>
45#include <simgear/debug/logstream.hxx>
46#include <simgear/misc/sg_path.hxx>
47#include <simgear/props/props_io.hxx>
62 ignore_flight_controls(NULL),
63 ignore_pedal_controls(NULL),
69 config = _config_file;
75#if defined( unix ) || defined( __CYGWIN__ )
77 lseek( fd, 0, SEEK_SET );
81 SG_LOG( SG_IO, SG_ALERT,
"Read failed" );
90#if defined( unix ) || defined( __CYGWIN__ )
92 lseek( fd, 0, SEEK_SET );
96 SG_LOG( SG_IO, SG_ALERT,
"Read failed" );
105#if defined( unix ) || defined( __CYGWIN__ )
107 lseek( fd, 0, SEEK_SET );
111 SG_LOG( SG_IO, SG_ALERT,
"Read failed" );
118void FGATCInput::init_config() {
119#if defined( unix ) || defined( __CYGWIN__ )
120 if ( !config.isAbsolute() ) {
122 SGPath tmp = SGPath::home();
123 tmp.append(
".atcflightsim" );
124 tmp.append( config.utf8Str() );
134 SG_LOG( SG_IO, SG_ALERT,
"This board is already open for input! "
142 SG_LOG( SG_IO, SG_ALERT,
143 "Initializing ATC input hardware, please wait ..." );
145 snprintf( analog_in_file, 256,
146 "/proc/atcflightsim/board%d/analog_in", board );
147 snprintf( radios_file, 256,
148 "/proc/atcflightsim/board%d/radios", board );
149 snprintf( switches_file, 256,
150 "/proc/atcflightsim/board%d/switches", board );
152#if defined( unix ) || defined( __CYGWIN__ )
158 analog_in_fd =
::open( analog_in_file, O_RDONLY );
159 if ( analog_in_fd == -1 ) {
160 SG_LOG( SG_IO, SG_ALERT,
"errno = " << errno );
162 snprintf( msg, 300,
"Error opening %s", analog_in_file );
167 radios_fd =
::open( radios_file, O_RDWR );
168 if ( radios_fd == -1 ) {
169 SG_LOG( SG_IO, SG_ALERT,
"errno = " << errno );
171 snprintf( msg, 300,
"Error opening %s", radios_file );
176 switches_fd =
::open( switches_file, O_RDONLY );
177 if ( switches_fd == -1 ) {
178 SG_LOG( SG_IO, SG_ALERT,
"errno = " << errno );
180 snprintf( msg, 300,
"Error opening %s", switches_file );
191 SG_LOG( SG_IO, SG_ALERT,
192 "Done initializing ATC input hardware." );
200 ignore_flight_controls
201 =
fgGetNode(
"/input/atcsim/ignore-flight-controls",
true );
202 ignore_pedal_controls
203 =
fgGetNode(
"/input/atcsim/ignore-pedal-controls",
true );
207 snprintf( base_name, 256,
"/input/atc-board[%d]/analog-in", board );
210 snprintf( base_name, 256,
"/input/atc-board[%d]/radio-switches", board );
213 snprintf( base_name, 256,
"/input/atc-board[%d]/switches", board );
227static double scale(
int center,
int deadband,
int min,
int max,
int value ) {
232 if ( value <= (center - deadband) ) {
233 range = (center - deadband) -
min;
234 result = (value - (center - deadband)) / range;
235 }
else if ( value >= (center + deadband) ) {
236 range = max - (center + deadband);
237 result = (value - (center + deadband)) / range;
242 if ( result < -1.0 ) result = -1.0;
243 if ( result > 1.0 ) result = 1.0;
252static double scale(
int min,
int max,
int value ) {
258 result = (value -
min) / range;
260 if ( result < 0.0 ) result = 0.0;
261 if ( result > 1.0 ) result = 1.0;
269static double clamp(
double min,
double max,
double value ) {
270 double result = value;
272 if ( result <
min ) result =
min;
273 if ( result > max ) result = max;
287 if ( obs[2] >= 68 && obs[2] < 480 ) {
289 }
else if ( obs[2] >= 480 ) {
294 }
else if ( obs[1] < 68 ) {
297 }
else if ( obs[2] < 30 ) {
298 if ( obs[1] >= 68 && obs[1] < 480 ) {
302 }
else if ( obs[1] >= 480 ) {
304 if ( obs[0] < obs[1] ) {
312 }
else if ( obs[1] > 980 ) {
313 if ( obs[2] <= 956 && obs[2] > 480 ) {
315 }
else if ( obs[2] <= 480 ) {
320 }
else if ( obs[1] > 956 ) {
323 }
else if ( obs[2] > 980 ) {
324 if ( obs[1] <= 956 && obs[1] > 480 ) {
328 }
else if ( obs[1] <= 480 ) {
330 if ( obs[0] > obs[1] ) {
339 if ( obs[1] < 480 && obs[2] > 480 ) {
341 if ( obs[0] < obs[1] ) {
345 }
else if ( obs[1] > 480 && obs[2] < 480 ) {
347 if ( obs[0] > obs[1] ) {
351 }
else if ( obs[0] > 480 && obs[1] < 480 && obs[2] < 480 ) {
353 if ( obs[1] > obs[2] ) {
357 }
else if ( obs[0] < 480 && obs[1] > 480 && obs[2] > 480 ) {
359 if ( obs[1] < obs[2] ) {
364 result = obs[1] - obs[2];
365 if ( abs(result) > 400 ) {
374 if ( result < -500 ) { result += 1024; }
375 if ( result > 500 ) { result -= 1024; }
382 if ( fabs(ave - val) < 400 || fabs(val) < fabs(ave) ) {
383 return 0.5 * ave + 0.5 * val;
390bool FGATCInput::do_analog_in() {
396 unsigned char hi = analog_in_bytes[2 * channel] & 0x03;
397 unsigned char lo = analog_in_bytes[2 * channel + 1];
398 analog_in_data[channel] = hi * 256 + lo;
405 if ( analog_in_node != NULL ) {
406 for (
int i = 0;
i < analog_in_node->nChildren(); ++
i ) {
409 SGPropertyNode *child = analog_in_node->getChild(
i);
410 string cname = child->getNameString();
411 int index = child->getIndex();
415 vector <SGPropertyNode *> output_nodes;
423 if ( cname ==
"channel" ) {
424 SGPropertyNode *prop;
425 prop = child->getChild(
"name" );
426 if ( prop != NULL ) {
427 name = prop->getStringValue();
429 prop = child->getChild(
"type", 0 );
430 if ( prop != NULL ) {
431 type = prop->getStringValue();
433 prop = child->getChild(
"type", 1 );
434 if ( prop != NULL ) {
435 subtype = prop->getStringValue();
438 while ( (prop = child->getChild(
"prop", j)) != NULL ) {
440 =
fgGetNode( prop->getStringValue(),
true );
441 output_nodes.push_back( tmp );
444 prop = child->getChild(
"center" );
445 if ( prop != NULL ) {
446 center = prop->getIntValue();
448 prop = child->getChild(
"min" );
449 if ( prop != NULL ) {
450 min = prop->getIntValue();
452 prop = child->getChild(
"max" );
453 if ( prop != NULL ) {
454 max = prop->getIntValue();
456 prop = child->getChild(
"deadband" );
457 if ( prop != NULL ) {
458 deadband = prop->getIntValue();
460 prop = child->getChild(
"hysteresis" );
461 if ( prop != NULL ) {
462 hysteresis = prop->getIntValue();
464 prop = child->getChild(
"offset" );
465 if ( prop != NULL ) {
466 offset = prop->getFloatValue();
468 prop = child->getChild(
"factor" );
469 if ( prop != NULL ) {
470 factor = prop->getFloatValue();
475 int raw_value = analog_in_data[index];
479 if ( type ==
"flight"
480 && !ignore_flight_controls->getBoolValue() )
482 if ( subtype !=
"pedals" ||
483 ( subtype ==
"pedals"
484 && !ignore_pedal_controls->getBoolValue() ) )
487 float scaled_value = 0.0f;
489 if ( hysteresis > 0 ) {
490 int last_raw_value = 0;
491 prop = child->getChild(
"last-raw-value", 0,
true );
492 last_raw_value = prop->getIntValue();
494 if (
abs(raw_value - last_raw_value) < hysteresis )
497 raw_value = last_raw_value;
500 prop->setIntValue( raw_value );
505 scaled_value =
scale( center, deadband,
506 min, max, raw_value );
508 scaled_value =
scale(
min, max, raw_value );
510 scaled_value *= factor;
511 scaled_value += offset;
515 scaled_value =
clamp( -1.0, 1.0, scaled_value );
517 scaled_value =
clamp( 0.0, 1.0, scaled_value );
521 for ( j = 0; j < (int)output_nodes.size(); ++j ) {
522 output_nodes[j]->setDoubleValue( scaled_value );
525 }
else if ( type ==
"avionics-simple" ) {
527 float scaled_value = 0.0f;
529 scaled_value =
scale( center, deadband,
530 min, max, raw_value );
532 scaled_value =
scale(
min, max, raw_value );
534 scaled_value *= factor;
535 scaled_value += offset;
539 scaled_value =
clamp( -1.0, 1.0, scaled_value );
541 scaled_value =
clamp( 0.0, 1.0, scaled_value );
545 for ( j = 0; j < (int)output_nodes.size(); ++j ) {
546 output_nodes[j]->setDoubleValue( scaled_value );
548 }
else if ( type ==
"avionics-resolver" ) {
557 bool do_init =
false;
558 float scaled_value = 0.0f;
562 prop = child->getChild(
"is-inited", 0 );
563 if ( prop == NULL ) {
565 prop = child->getChild(
"is-inited", 0,
true );
566 prop->setBoolValue(
true );
570 for ( j = 0; j < 3; ++j ) {
571 prop = child->getChild(
"raw", j,
true );
573 raw[j] = analog_in_data[index];
575 raw[j] = prop->getIntValue();
582 int diff =
tony_magic( analog_in_data[index], raw );
586 for ( j = 0; j < 3; ++j ) {
587 prop = child->getChild(
"raw", j,
true );
588 prop->setIntValue( raw[j] );
592 prop = child->getChild(
"diff-average", 0,
true );
593 double diff_ave = prop->getDoubleValue();
595 prop->setDoubleValue( diff_ave );
598 scaled_value = diff_ave * factor;
601 for ( j = 0; j < (int)output_nodes.size(); ++j ) {
602 float value = output_nodes[j]->getDoubleValue();
603 value += scaled_value;
605 prop = child->getChild(
"min-clamp" );
606 if ( prop != NULL ) {
607 double min = prop->getDoubleValue();
608 if ( value <
min ) { value =
min; }
611 prop = child->getChild(
"max-clamp" );
612 if ( prop != NULL ) {
613 double max = prop->getDoubleValue();
614 if ( value > max ) { value = max; }
617 prop = child->getChild(
"compass-heading" );
618 if ( prop != NULL ) {
619 bool compass = prop->getBoolValue();
621 while ( value >= 360.0 ) { value -= 360.0; }
622 while ( value < 0.0 ) { value += 360.0; }
626 output_nodes[j]->setDoubleValue( value );
630 SG_LOG( SG_IO, SG_DEBUG,
"Invalid channel type = "
634 SG_LOG( SG_IO, SG_DEBUG,
635 "Input config error, expecting 'channel' but found "
656 unsigned char switches = switch_data[row];
658 for(
int column = 0; column <
ATC_NUM_COLS; ++column ) {
660 switch_matrix[board][column][row] = switches & 1;
662 switch_matrix[board][row-8][8+column] = switches & 1;
664 switches = switches >> 1;
669bool FGATCInput::do_switches() {
678 if ( switches_node != NULL ) {
679 for (
int i = 0;
i < switches_node->nChildren(); ++
i ) {
682 SGPropertyNode *child = switches_node->getChild(
i);
683 string cname = child->getNameString();
686 vector <SGPropertyNode *> output_nodes;
691 float scaled_value = 0.0f;
696 SGPropertyNode *prop;
697 prop = child->getChild(
"name" );
698 if ( prop != NULL ) {
699 name = prop->getStringValue();
701 prop = child->getChild(
"type" );
702 if ( prop != NULL ) {
703 type = prop->getStringValue();
706 while ( (prop = child->getChild(
"prop", j)) != NULL ) {
708 =
fgGetNode( prop->getStringValue(),
true );
709 output_nodes.push_back( tmp );
712 prop = child->getChild(
"factor" );
713 if ( prop != NULL ) {
714 factor = prop->getFloatValue();
716 prop = child->getChild(
"invert" );
717 if ( prop != NULL ) {
718 invert = prop->getBoolValue();
720 prop = child->getChild(
"steady-state-filter" );
721 if ( prop != NULL ) {
722 filter = prop->getIntValue();
727 if ( cname ==
"switch" ) {
728 prop = child->getChild(
"row" );
729 if ( prop != NULL ) {
730 row = prop->getIntValue();
732 prop = child->getChild(
"col" );
733 if ( prop != NULL ) {
734 col = prop->getIntValue();
738 int raw_value = switch_matrix[board][row][col];
742 raw_value = !raw_value;
746 scaled_value = (float)raw_value * factor;
748 }
else if ( cname ==
"combo-switch" ) {
749 float combo_value = 0.0f;
753 while ( (pos = child->getChild(
"position", k++)) != NULL ) {
756 prop = pos->getChild(
"row" );
757 if ( prop != NULL ) {
758 row = prop->getIntValue();
760 prop = pos->getChild(
"col" );
761 if ( prop != NULL ) {
762 col = prop->getIntValue();
764 prop = pos->getChild(
"value" );
765 if ( prop != NULL ) {
766 combo_value = prop->getFloatValue();
770 int raw_value = switch_matrix[board][row][col];
777 scaled_value = combo_value;
783 scaled_value *= factor;
784 }
else if ( cname ==
"additive-switch" ) {
785 float additive_value = 0.0f;
786 float increment = 0.0f;
790 while ( (pos = child->getChild(
"position", k++)) != NULL ) {
793 prop = pos->getChild(
"row" );
794 if ( prop != NULL ) {
795 row = prop->getIntValue();
797 prop = pos->getChild(
"col" );
798 if ( prop != NULL ) {
799 col = prop->getIntValue();
801 prop = pos->getChild(
"value" );
802 if ( prop != NULL ) {
803 increment = prop->getFloatValue();
807 int raw_value = switch_matrix[board][row][col];
814 additive_value += increment;
819 scaled_value = additive_value * factor;
826 bool update_prop =
true;
829 SGPropertyNode *fv = child->getChild(
"filter-value", 0,
true );
830 float filter_value = fv->getFloatValue();
831 SGPropertyNode *fc = child->getChild(
"filter-count", 0,
true );
832 int filter_count = fc->getIntValue();
834 if ( fabs(scaled_value - filter_value) < 0.0001 ) {
840 if ( filter_count < filter ) {
844 fv->setFloatValue( scaled_value );
845 fc->setIntValue( filter_count );
849 if ( type ==
"engine" || type ==
"flight" ) {
850 if ( ! ignore_flight_controls->getBoolValue() ) {
852 for ( j = 0; j < (int)output_nodes.size(); ++j ) {
853 output_nodes[j]->setDoubleValue( scaled_value );
856 }
else if ( type ==
"avionics" ) {
858 for ( j = 0; j < (int)output_nodes.size(); ++j ) {
859 output_nodes[j]->setDoubleValue( scaled_value );
874bool FGATCInput::do_radio_switches() {
879 if ( radio_in_node != NULL ) {
880 for (
int i = 0;
i < radio_in_node->nChildren(); ++
i ) {
883 SGPropertyNode *child = radio_in_node->getChild(
i);
884 string cname = child->getNameString();
886 if ( cname ==
"switch" ) {
889 vector <SGPropertyNode *> output_nodes;
896 int scaled_value = 0;
899 SGPropertyNode *prop;
900 prop = child->getChild(
"name" );
901 if ( prop != NULL ) {
902 name = prop->getStringValue();
904 prop = child->getChild(
"type" );
905 if ( prop != NULL ) {
906 type = prop->getStringValue();
909 while ( (prop = child->getChild(
"prop", j)) != NULL ) {
911 =
fgGetNode( prop->getStringValue(),
true );
912 output_nodes.push_back( tmp );
915 prop = child->getChild(
"byte" );
916 if ( prop != NULL ) {
917 byte_num = prop->getIntValue();
919 prop = child->getChild(
"right-shift" );
920 if ( prop != NULL ) {
921 right_shift = prop->getIntValue();
923 prop = child->getChild(
"mask" );
924 if ( prop != NULL ) {
925 mask = prop->getIntValue();
927 prop = child->getChild(
"factor" );
928 if ( prop != NULL ) {
929 factor = prop->getIntValue();
931 prop = child->getChild(
"offset" );
932 if ( prop != NULL ) {
933 offset = prop->getIntValue();
935 prop = child->getChild(
"invert" );
936 if ( prop != NULL ) {
937 invert = prop->getBoolValue();
942 = (radio_switch_data[byte_num] >> right_shift) & mask;
946 raw_value = !raw_value;
948 scaled_value = raw_value * factor + offset;
951 for ( j = 0; j < (int)output_nodes.size(); ++j ) {
952 output_nodes[j]->setIntValue( scaled_value );
966 SG_LOG( SG_IO, SG_ALERT,
"This board has not been opened for input! "
981#if defined( unix ) || defined( __CYGWIN__ )
989 result =
::close( analog_in_fd );
990 if ( result == -1 ) {
991 SG_LOG( SG_IO, SG_ALERT,
"errno = " << errno );
993 snprintf( msg, 300,
"Error closing %s", analog_in_file );
999 if ( result == -1 ) {
1000 SG_LOG( SG_IO, SG_ALERT,
"errno = " << errno );
1002 snprintf( msg, 300,
"Error closing %s", radios_file );
1007 result =
::close( switches_fd );
1008 if ( result == -1 ) {
1009 SG_LOG( SG_IO, SG_ALERT,
"errno = " << errno );
1011 snprintf( msg, 300,
"Error closing %s", switches_file );
SGPropertyNode * get_props()
SGPropertyNode * fgGetNode(const char *path, bool create)
Get a property node.