#include "mungal4.h" #include "..\munga\controls.h" #pragma hdrstop #include "l4rio.h" #include "l4ctrl.h" #if defined(TRACE_RIO_RECEIVE_PACKET) BitTrace RIO_Receive_Packet("RIO Receive Packet"); #endif #if defined(TRACE_RIO_SEND_PACKET) BitTrace RIO_Send_Packet("RIO Send Packet); #endif #if defined(DEBUG) # define Test_Tell(n) DEBUG_STREAM << n #else # define Test_Tell(n) #endif #define default_deadband_value 0.03 static Byte RIOLengths[] = { 0, // CheckRequest 0, // VersionRequest 0, // AnalogRequest 1, // ResetRequest 2, // LampRequest 2, // CheckReply 2, // VersionReply 10, // AnalogReply 1, // ButtonPressed 1, // ButtonReleased 2, // KeyPressed 2, // KeyReleased 1 // TestModeChange }; Byte RIO::reply_check_string[] = {RIO::CheckReply, 3, 2 }; Byte RIO::reply_version_string[] = {RIO::VersionReply, 1, 23}; Byte RIO::reply_button_press_string[] = {RIO::ButtonPressed, 22}; Byte RIO::reply_button_release_string[]= {RIO::ButtonReleased, 22}; Byte RIO::reply_key_press_string[] = {RIO::KeyPressed, 0, 4}; Byte RIO::reply_key_release_string[] = {RIO::KeyReleased, 0, 4}; Byte RIO::reply_test_enter_string[] = {RIO::TestModeChange, 1}; Byte RIO::reply_test_exit_string[] = {RIO::TestModeChange, 0}; Byte RIO::reply_analog_string[] = { RIO::AnalogReply, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0 }; // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Utilities ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ int CombinePair(Byte low_value, Byte high_value) { int result; result = ((int) (low_value & 0x7F)) | (((int) high_value) << 7); if (result & 0x2000) { result |= ~0x3FFF; } Check_Fpu(); return result; } void BoardError(NotationFile *notation_file, char *type, int position) { Check(notation_file); Check_Pointer(type); char where[40]; sprintf(where, "%s@Slot=%d:Address=%d", type, position >> 3, position & 7); notation_file->AppendEntry("RIOBoardErrors", "error", where); Check_Fpu(); } //########################################################################### //############################ Joystick classes ############################# //########################################################################### const char *FilterChannel::highName = "high"; const char *FilterChannel::centerName = "center"; const char *FilterChannel::lowName = "low"; const char *FilterChannel::joystickXName = "JoystickX"; const char *FilterChannel::joystickYName = "JoystickY"; const char *FilterChannel::throttleName = "Throttle"; const char *FilterChannel::leftPedalName = "LeftPedal"; const char *FilterChannel::rightPedalName = "RightPedal"; FilterChannel::FilterChannel(): average(5,0) { valuesFromFile = False; previousValue = 0; polarity = unipolar; mode = unaligned; deadbandScalar = default_deadband_value; lowerDeadband = 0; upperDeadband = 0; Check_Fpu(); } FilterChannel::FilterChannel( NotationFile *init_file, const char *page_name, int default_min, int default_max ): average(5,0) { valuesFromFile = True; previousValue = 0; polarity = unipolar; mode = normal; deadbandScalar = default_deadband_value; pageName = page_name; min = default_min; max = default_max; //------------------------------------------- // Attempt to read calibration values from // the notation file. If the values don't // exist, then create them from the defaults. //------------------------------------------- if (init_file->GetEntry(pageName, highName, &max) == 0) { init_file->SetEntry(pageName, highName, default_max); } if (init_file->GetEntry(pageName, lowName, &min) == 0) { init_file->SetEntry(pageName, lowName, default_min); } center = (max-min)/2; Check_Fpu(); } FilterChannel::FilterChannel( NotationFile *init_file, const char *page_name, int default_min, int default_center, int default_max ): average(5,0) { valuesFromFile = True; previousValue = 0; polarity = bipolar; mode = normal; deadbandScalar = default_deadband_value; pageName = page_name; min = default_min; center = default_center; max = default_max; //------------------------------------------- // Attempt to read calibration values from // the notation file. If the values don't // exist, then create them from the defaults. //------------------------------------------- if (init_file->GetEntry(pageName, highName, &max) == 0) { init_file->SetEntry(pageName, highName, default_max); } if (init_file->GetEntry(pageName, centerName, ¢er) == 0) { init_file->SetEntry(pageName, centerName, default_center); } if (init_file->GetEntry(pageName, lowName, &min) == 0) { init_file->SetEntry(pageName, lowName, default_min); } CalculateDeadBands(); Check_Fpu(); } FilterChannel::~FilterChannel() { Check(this); Check_Fpu(); } void FilterChannel::SetPolarity(PolarMode newPolarity) { Check(this); polarity = newPolarity; // HACK - filterchannel must be realigned when changing to bipolar! Check_Fpu(); } void FilterChannel::SetDeadBand(Scalar dead_band) { Check(this); deadbandScalar = fabs(dead_band); //--------------------------------------------------------- // Recalculate deadbands and ranges if needed //--------------------------------------------------------- if (mode == normal) { CalculateDeadBands(); } Check_Fpu(); } void FilterChannel::BeginAlignment() { Check(this); //--------------------------------------------------------- // Set bogus min/max, force update //--------------------------------------------------------- mode = unaligned; min = 10000; max = -10000; Check_Fpu(); } void FilterChannel::EndAlignment(NotationFile *init_file) { Check(this); //--------------------------------------------------------- // Save the most recent value as the center //--------------------------------------------------------- center = previousValue; //------------------------------------------------------------ // If channel was never adjusted, synthesize reasonable values //------------------------------------------------------------ // I don't trust abs(): saw weirdness. int delta = max-min; if (delta < 0) { delta = -delta; } if (delta < 10) { if (polarity == bipolar) { min = center-100; max = center+100; } else { min = 0; max = 100; } } else { int setback = delta/33; // move the edges in by 3% max -= setback; min += setback; } //--------------------------------------------------------- // Save the new values //--------------------------------------------------------- if (valuesFromFile) { if (init_file != NULL) { init_file->SetEntry(pageName, highName, max); init_file->SetEntry(pageName, lowName, min); if (polarity == bipolar) { init_file->SetEntry(pageName, centerName, center); } } } //--------------------------------------------------------- // Calculate real deadband values //--------------------------------------------------------- CalculateDeadBands(); //--------------------------------------------------------- // Go to normal mode //--------------------------------------------------------- mode = normal; Check_Fpu(); } Scalar FilterChannel::Update(int value) { Check(this); Scalar result = 0.0; previousValue = value; //--------------------------------------------------------- // Generate average, use for min/max determination //--------------------------------------------------------- average.Add(value); { int the_average = average.CalculateOlympicAverage(); if (the_average < min) { min = the_average; } if (the_average > max) { max = the_average; } } //--------------------------------------------------------- // Perform position calculations //--------------------------------------------------------- switch (polarity) { case unipolar: { //--------------------------------------------------------- // Subtract 'min' from current value //--------------------------------------------------------- value -= min; //--------------------------------------------------------- // Subtract deadband value //--------------------------------------------------------- int deadband_adjustment = (int) ((max-min)*deadbandScalar); value -= deadband_adjustment; if (value > 0) { int adjusted_maximum = max-deadband_adjustment; if (adjusted_maximum > 0) { result = ((Scalar)value)/adjusted_maximum; } } } break; case bipolar: if (mode == unaligned) { //--------------------------------------------------------- // Use 1/2 (max-min) as temporary center //--------------------------------------------------------- center = (max-min) >> 1; //--------------------------------------------------------- // Set temporary deadband values //--------------------------------------------------------- upperDeadband = (int) ((max-min)*deadbandScalar); lowerDeadband= upperDeadband; } //--------------------------------------------------------- // Adjust for center //--------------------------------------------------------- value -= center; //--------------------------------------------------------- // Generate scaled results //--------------------------------------------------------- if (value < 0) { value += lowerDeadband; if (value < 0) { if (lowerRange > 0) { if (value <= -lowerRange) { result = -1.0; } else { result = ((Scalar) value)/lowerRange; } } } } else { value -= upperDeadband; if (value > 0) { if (upperRange > 0) { if (value >= upperRange) { result = 1.0; } else { result = ((Scalar) value)/upperRange; } } } } break; } //--------------------------------------------------------- // Return result //--------------------------------------------------------- Check_Fpu(); # if defined(DEBUG) DEBUG_STREAM << pageName << ":" << value << "=" << result << "\n"; # endif return result; } Logical FilterChannel::TestInstance() const { return True; } void FilterChannel::CalculateDeadBands() { Check(this); lowerDeadband = (int) ((center-min)*deadbandScalar + .5); lowerRange = center - (min+lowerDeadband); upperDeadband = (int) ((max-center)*deadbandScalar + .5); upperRange = (max-upperDeadband) - center; # if defined(DEBUG) DEBUG_STREAM << "pageName =" << pageName <<"\n"; DEBUG_STREAM << "min =" << min <<"\n"; DEBUG_STREAM << "center=" << center <<"\n"; DEBUG_STREAM << "max= " << max <<"\n"; DEBUG_STREAM << "lowerDeadband= " << lowerDeadband <<"\n"; DEBUG_STREAM << "lowerRange = " << lowerRange <<"\n"; DEBUG_STREAM << "upperDeadband= " << upperDeadband <<"\n"; DEBUG_STREAM << "upperRange = " << upperRange <<"\n"; # endif Check_Fpu(); } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Ranger ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Ranger::Ranger( const char *page_name, int hardware_min, int hardware_max, Scalar deadband ){ Check_Pointer(this); pageName = page_name; hardwareMinimum = hardware_min; hardwareMaximum = hardware_max; SetDeadBand(deadband); //------------------------------------------------------------ // We ASSUME that the control is at rest (center for joystick) //------------------------------------------------------------ ForceToZero(); Check_Fpu(); } Ranger::~Ranger() { Check(this); Check_Fpu(); } Logical Ranger::TestInstance() const { Check_Fpu(); return True; } void Ranger::SetDeadBand(Scalar dead_band) { Check(this); deadbandInteger = (int)((hardwareMaximum - hardwareMinimum) * fabs(dead_band)); Check_Fpu(); } void Ranger::ForceToZero() { Check(this); sampledInputFlag = False; Check_Fpu(); } Scalar Ranger::Update(int input) { Check(this); int range; Scalar result = ((Scalar) 0); Verify(hardwareMaximum > hardwareMinimum); //------------------------------------------------------------ // Uncentered processing: slide offset to keep value // within the proscribed range //------------------------------------------------------------ if (hardwareMinimum >= 0) // this designates an uncentered Ranger { //--------------------------------------------------------- // Sample current input for offset value //--------------------------------------------------------- if (!sampledInputFlag) { sampledInputFlag = True; offset = -input; //------------------------------------------ // Initialize to reasonable values //------------------------------------------ highestInput = (hardwareMaximum*3)/4; lowestInput = hardwareMinimum; } //------------------------------------------------------------ // Add offset //------------------------------------------------------------ input += offset; //------------------------------------------------------------ // Slide offset if needed //------------------------------------------------------------ if (input > hardwareMaximum) { offset -= input-hardwareMaximum; input = hardwareMaximum; } else if (input < hardwareMinimum) { offset -= input-hardwareMinimum; input = hardwareMinimum; } //----------------------------------------------------------------- // Keep track of limit (lowestValue will always be hardwareMinimum) //----------------------------------------------------------------- if (input > highestInput) { highestInput = input; } //------------------------------------------------------------ // Generate scaled result //------------------------------------------------------------ input -= hardwareMinimum; // normalize to zero if (input > deadbandInteger) { range = highestInput - lowestInput - deadbandInteger; if (range > 0) { result = ((Scalar)(input-deadbandInteger))/(Scalar)range; } } } //------------------------------------------------------------ // Centered processing: keep max, min of input to // determine total range //------------------------------------------------------------ else { //--------------------------------------------------------- // Sample current input for offset value //--------------------------------------------------------- if (!sampledInputFlag) { sampledInputFlag = True; //------------------------------------------ // Set offset such that this is the new zero //------------------------------------------ offset = -input; //------------------------------------------ // Initialize to reasonable values... // ...add offset to reflect true limits // that are available with this offset //------------------------------------------ // HardwareMinimum is known to be negative because of 'if' statement Verify(hardwareMaximum > 0); highestInput = (hardwareMaximum*3)/4 + offset; lowestInput = (hardwareMinimum*3)/4 + offset; } //------------------------------------------------------------ // Adjust for offset //------------------------------------------------------------ input += offset; if (input > highestInput) { highestInput = input; } if (input < lowestInput) { lowestInput = input; } //--------------------------------------- // Let's make sure before we continue... //--------------------------------------- Verify(highestInput >= lowestInput); Verify(input <= highestInput); Verify(input >= lowestInput); //------------------------------------------------------------ // Generate scaled result //------------------------------------------------------------ if (input < -deadbandInteger) { //--------------------------------------- // Generate range //--------------------------------------- range = abs(lowestInput) - deadbandInteger; //--------------------------------------- // Generate scaled result //--------------------------------------- if (range > 0) { result = ((Scalar)(input+deadbandInteger))/(Scalar)range; } } else if (input > deadbandInteger) { //--------------------------------------- // Generate range //--------------------------------------- range = abs(highestInput) - deadbandInteger; //--------------------------------------- // Generate scaled result //--------------------------------------- if (range > 0) { result = ((Scalar)(input-deadbandInteger))/(Scalar)range; } } } if (result > ((Scalar) 1.0)) { DEBUG_STREAM << "Too high!" << " input=" << input << " result=" << result << "\n" << pageName << " offset=" << offset << " lowestInput=" << lowestInput << " highestInput=" << highestInput << " deadbandInteger=" << deadbandInteger << " range=" << range << "\n"; result = ((Scalar) 1.0); //Fail("Ranger::Update above 1.0"); } else if (result < ((Scalar)-1.0)) { DEBUG_STREAM << "Too low!" << " input=" << input << " result=" << result << "\n" << pageName << " lowestInput=" << lowestInput << " highestInput=" << highestInput << " deadbandInteger=" << deadbandInteger << " range=" << range << "\n"; result = ((Scalar)-1.0); //Fail("Ranger::Update below -1.0"); } Verify(result <= ((Scalar) 1.0)); Verify(result >= ((Scalar) -1.0)); Check_Fpu(); return result; } void Ranger::Statistics(NotationFile *failure_file) { Check(this); Check(failure_file); int range = highestInput - lowestInput, hardware_range = hardwareMaximum - hardwareMinimum; Verify(hardware_range > 0); Scalar range_percentage = ((Scalar) range)/hardware_range; //--------------------------------- // Report slippage //--------------------------------- if (range_percentage > (Scalar) 1.1) // allow 10% overrange { failure_file->SetEntry(pageName, "Overrange", range_percentage); } //--------------------------------- // Report low range //--------------------------------- if (range_percentage < (Scalar) .50) { failure_file->SetEntry(pageName, "UnderRange", range_percentage); } Check_Fpu(); } //######################################################################## //############################### RIO #################################### //######################################################################## //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Constructor //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //Win32 Serial support: ADB 02/13/07 //RIO::RIO(Word port, Word intNum, Logical perform_tests): RIO::RIO(const char* port, Logical perform_tests): PCSerialPacket() { Tell("RIO initialization: variables\n"); Check_Pointer(this); // //--------------------------------------------------------------------- // Initialize values //--------------------------------------------------------------------- // TestModeActive = 0; Throttle = (Scalar) 0; LeftPedal = (Scalar) 0; RightPedal = (Scalar) 0; JoystickX = (Scalar) 0; JoystickY = (Scalar) 0; remoteRetryCount = 0; remoteAbandonCount = 0; remoteFullBufferCount = 0; lineErrorCount = 0; overrunCount = 0; abandonCount = 0; operational = True; // discardCount = 0; failureFile = NULL; failureFileOpenCount = 0; // //--------------------------------------------------------------------- // Clear error log //--------------------------------------------------------------------- // OpenFailureFile(); Check(failureFile); failureFile->DeletePage("RIOBoardErrors"); failureFile->DeletePage("RIODeadLamps"); failureFile->DeletePage("RIOErrors"); CloseFailureFile(); // //--------------------------------------------------------------------- // Read value ranges from notation file, initialize rangers // // Order of integers is: minimum, maximum, end-zone-range, deadband //--------------------------------------------------------------------- // { // NotationFile // stat_file((const char *) "RIO.INI"); leftPedalRanger = new Ranger("LeftPedal", 0, 470, .0); Register_Object(leftPedalRanger); rightPedalRanger = new Ranger("RightPedal", 0, 470, .0); Register_Object(rightPedalRanger); throttleRanger = new Ranger("Throttle", 0, 800, .05); Register_Object(throttleRanger); joystickXRanger = new Ranger("JoystickX", -96, 96, .05); Register_Object(joystickXRanger); joystickYRanger = new Ranger("JoystickY", -97, 108, .05); Register_Object(joystickYRanger); } // //--------------------------------------------------------------------- // Start the PCSerialPacket //--------------------------------------------------------------------- // //Win32 Serial support: ADB 02/13/07 //int status = PCSerialPacket::Initialize( // PCSP_9600, // port, // intNum, // (Byte *) RIOLengths, // 13, // (Byte *) RIOLengths, // 13 // ); int status = PCSerialPacket::Initialize(PCS_9600, PCS_N81, port, (BYTE*)RIOLengths, 13, (BYTE*)RIOLengths, 13); switch(status) { case PCSPAKInitOk: // silent if OK DEBUG_STREAM << "RIO successfully initialized!\n"; break; //Win32 Serial Support: ADB 02/24/2007 //case PCSPAKInitErrDPMI: // DEBUG_STREAM << "RIO::RIO DPMI error!\n"; // break; //case PCSPAKInitErrAlloc: // DEBUG_STREAM << "RIO::RIO buffer allocation error!\n"; // break; case PCSPAKWin32Err: DEBUG_STREAM << "RIO::RIO Win32 Serial Initalization error!\n"; break; default: DEBUG_STREAM << "RIO::RIO unexpected init result=" << status << "!\n"; break; } #if 0 extern Byte previousIMR, previousISR, previousIRR; extern Byte middleIMR, middleISR, middleIRR; extern Byte postIMR, postISR, postIRR; extern Byte pcspakLSR, pcspakIER, pcspakIIR; DEBUG_STREAM << hex << "previousIMR=" << (int) (previousIMR & 0xFF) << ", mid=" << (int) (middleIMR & 0xFF) << ", post=" << (int) (postIMR & 0xFF) << "\n" << "previousISR=" << (int) (previousISR & 0xFF) << ", mid=" << (int) (middleISR & 0xFF) << ", post=" << (int) (postISR & 0xFF) << "\n" << "previousIRR=" << (int) (previousIRR & 0xFF) << ", mid=" << (int) (middleIRR & 0xFF) << ", post=" << (int) (postIRR & 0xFF) << "\n" << "pcspakLSR=" << (int) (pcspakLSR & 0xFF) << ", pcspakIER=" << (int) (pcspakIER & 0xFF) << ", pcspakIIR was=" << (int) (pcspakIIR & 0xFF) << "\n" << dec; #endif MajorRevision = 0xFF; MinorRevision = 0xFF; if (perform_tests) { // //--------------------------------------------------------------------- // Reset remote I/O board //--------------------------------------------------------------------- // Time when; int bomb = 0; RIOEvent dummy_event; Tell("RIO initialization: reset board\n"); // Reset RIO board SetDTR(True); // Assert reset when = Now(); for(when += .1f; Now() < when; ); SetDTR(False); // Retract reset when = Now(); for(when += 1.0f; Now() < when; ); // //--------------------------------------------------------------------- // Wait for test mode to start (or bomb out) //--------------------------------------------------------------------- // Tell("RIO initialization: check board\n"); RequestCheck(); when = Now(); when += 5.0f; while (!TestModeActive) { if (Now() > when) { bomb = 1; DEBUG_STREAM << "RIO never came back from check request!\n"; break; } GetNextEvent(&dummy_event); } // //--------------------------------------------------------------------- // Wait for test mode to finish (or bomb out) //--------------------------------------------------------------------- // if (!bomb) { when = Now(); when += 5.0f; while (TestModeActive) { if (Now() > when) { bomb = 1; DEBUG_STREAM << "RIO never came back from test mode!\n"; break; } GetNextEvent(&dummy_event); } } // //--------------------------------------------------------------------- // Get version (or bomb out) //--------------------------------------------------------------------- // if (!bomb) { RequestVersion(); when = Now(); when += 5.0f; while (MajorRevision == 0xFF) { if (Now() > when) { DEBUG_STREAM << "RIO never came back from version request!\n"; break; } GetNextEvent(&dummy_event); } } if(!bomb) { DEBUG_STREAM<<"RIO initialization finished\n"; } else { DEBUG_STREAM<<"RIO initialization failed! Shutting Down Serial Port!\n"; ShutdownRxThread(); } } Check_Fpu(); } //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Destructor //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ extern int historyIndex; extern Byte history[]; enum { txFlag=1, rxFlag=2, eventFlag=3 }; enum { IRQ_EVENT=0, IRQ_EVENT_RX=1, IRQ_EVENT_TX=2, IRQ_EVENT_MSR=3, IRQ_EVENT_LSR=4, IRQ_EVENT_BOGUS=5, TX_EVENT_RESTART=10, TX_EVENT_ABANDON=11, TX_EVENT_DONE=12, TX_EVENT_ACK=13, TX_EVENT_NAK=14, TX_EVENT_EARLY=15, TX_EVENT_EMPTY=16, TX_EVENT_KICK=17, RX_EVENT_FULL=20, RX_EVENT_NOT_CMD=21, RX_EVENT_FULLBODY=22, RX_EVENT_NAK=23, RX_EVENT_CKSMERR=24, RX_EVENT_OK=25 }; RIO::~RIO() { Check(this); #if 0 //--------------------------------------------------------------------- // Save serial history for debugging //--------------------------------------------------------------------- // If you enable this, set KEEP_HISTORY in PCSPAK.ASM to '1' as well. // Otherwise you will be viewing nonexistent history data. const char *commandName[13] = { "CheckReq", //=0x80 "VersionReq", "AnalogReq", "ResetReq", "LampReq", "CheckReply", "VersionReply", "AnalogReply", "ButtonPressed", "ButtonReleased", "KeyPressed", "KeyReleased", "TestModeChange" }; int i, type, j; cout << flush; printf("tx\t\trx\t\tevent\n"); printf("-----\t-----\t\t---------------------\n"); for(i=0; i= 0x80) && (j <= 0x8C)) { printf("%s", commandName[j-0x80]); } else { printf("%02X", j); } printf("\n"); break; } break; case rxFlag: printf("\t\t"); switch(j) { case 0xFC: printf("ACK\n"); break; case 0xFD: printf("NAK\n"); break; case 0xFE: printf("RST\n"); break; case 0xFF: printf("IDL\n"); break; default: if ((j >= 0x80) && (j <= 0x8C)) { printf("%s", commandName[j-0x80]); } else { printf("%02X", j); } printf("\n"); break; } break; case eventFlag: printf("\t\t\t\t"); switch(j) { case IRQ_EVENT: printf("IRQ entry\n"); break; case IRQ_EVENT_RX: printf("IRQ_EVENT_RX\n"); break; case IRQ_EVENT_TX: printf("IRQ_EVENT_TX\n"); break; case IRQ_EVENT_MSR: printf("IRQ_EVENT_MSR\n"); break; case IRQ_EVENT_LSR: printf("IRQ_EVENT_LSR\n"); break; case IRQ_EVENT_BOGUS: printf("IRQ_EVENT_BOGUS\n"); break; case TX_EVENT_RESTART: printf("TX_EVENT_RESTART\n"); break; case TX_EVENT_ABANDON: printf("TX_EVENT_ABANDON\n"); break; case TX_EVENT_DONE: printf("TX_EVENT_DONE\n"); break; case TX_EVENT_ACK: printf("TX_EVENT_ACK\n"); break; case TX_EVENT_NAK: printf("TX_EVENT_NAK\n"); break; case TX_EVENT_EARLY: printf("TX_EVENT_EARLY\n"); break; case TX_EVENT_EMPTY: printf("TX_EVENT_EMPTY\n"); break; case TX_EVENT_KICK: printf("TX_EVENT_KICK\n"); break; case RX_EVENT_FULL: printf("RX_EVENT_FULL\n"); break; case RX_EVENT_NOT_CMD: printf("RX_EVENT_NOT_CMD\n"); break; case RX_EVENT_FULLBODY: printf("RX_EVENT_FULLBODY\n"); break; case RX_EVENT_NAK: printf("RX_EVENT_NAK\n"); break; case RX_EVENT_CKSMERR: printf("RX_EVENT_CKSMERR\n"); break; case RX_EVENT_OK: printf("RX_EVENT_OK\n"); break; default: printf("unknown event %02X\n", j); break; } break; } } fflush(stdout); #endif //--------------------------------------------------------------------- // Flush data to RIO //--------------------------------------------------------------------- RIOEvent dummy_event; // This odd sequence of allocation, setting, and adding is necessary: // if you try to combine them, the compiler gets confused as to which // method to invoke for 'Now()'. Time then; then = Now(); then += 5.0f; while (Now() < then) { //------------------------------------------------- // Drop out of loop when all packets have been // transmitted and the last character has been sent //------------------------------------------------- if (TransmitQueueCount() <= 0) { if (!IsActive()) { break; } } GetNextEvent(&dummy_event); } //--------------------------------------------------------------------- // Update failure log //--------------------------------------------------------------------- #if LOG_RIO_DATA OpenFailureFile(); Check(failureFile); failureFile->SetEntry("RIO","lineErrors",lineErrorCount); failureFile->SetEntry("RIO","abandonedPackets",abandonCount); failureFile->SetEntry("RIO","overruns",overrunCount); failureFile->SetEntry("RIO","remoteRetry",remoteRetryCount); failureFile->SetEntry("RIO","remoteAbandon",remoteAbandonCount); failureFile->SetEntry("RIO","remoteFullBuffer",remoteFullBufferCount); CloseFailureFile(); #endif //------------------------------------------- // Update ranger statistics, delete rangers //------------------------------------------- { // NotationFile // stat_file((const char *) "RIO.INI"); Check(leftPedalRanger); // leftPedalRanger->Statistics(&stat_file); Unregister_Object(leftPedalRanger); delete leftPedalRanger; leftPedalRanger = NULL; Check(rightPedalRanger); // rightPedalRanger->Statistics(&stat_file); Unregister_Object(rightPedalRanger); delete rightPedalRanger; rightPedalRanger = NULL; Check(throttleRanger); // throttleRanger->Statistics(&stat_file); Unregister_Object(throttleRanger); delete throttleRanger; throttleRanger = NULL; Check(joystickXRanger); // joystickXRanger->Statistics(&stat_file); Unregister_Object(joystickXRanger); delete joystickXRanger; joystickXRanger = NULL; Check(joystickYRanger); // joystickYRanger->Statistics(&stat_file); Unregister_Object(joystickYRanger); delete joystickYRanger; joystickYRanger = NULL; } Check_Fpu(); } Logical RIO::TestInstance() const { return True; } extern Byte pic_isr, pic_imr, pic_irr; extern Byte uart_iir; extern Byte pcspak_active,pcspak_rxState,pcspak_txState; extern Word pcspak_head,pcspak_tail; extern Word pcspak_tempHead,pcspak_tempTail,pcspak_count; extern "C" void PCSPAKState(PCSerialPacket *ptr); Logical RIO::GetNextEvent(RIOEvent *destination) { Check(this); Byte receive_buffer[256]; Logical reply, looping; Word errors; //PCSPAKState(this); // //cout << flush; //printf( // "RIO isr=%02X imr=%02X irr=%02X, iir=%02X, a=%1d c=%04X ts=%1d rs=%1d e=%X\n", // pic_isr, pic_imr, pic_irr, // uart_iir, // pcspak_active, // pcspak_count, // pcspak_txState, pcspak_rxState, // pcspak_tempHead,pcspak_tempTail, // Errors() //); //fflush(stdout); if (! operational) { return False; } errors = Errors(); if (errors) { if (errors & PCSerialPacket::initError) { NotationFile failure((const char *) "FAILURE.LOG"); failure.SetEntry("RIOErrors","error","initialization"); operational = False; } else { if (errors & PCSerialPacket::txAbandonPacket) { //cout << "RIO:: packet abandoned\n"; ++abandonCount; } if (errors & PCSerialPacket::overrunError) { //cout << "RIO:: overrun\n"; ++overrunCount; } if (errors & ( PCSerialPacket::parityError | PCSerialPacket::framingError | PCSerialPacket::overrunError ) ) { ++lineErrorCount; } } } do { looping = False; reply = ReceivePacket(receive_buffer); if (reply) { switch(receive_buffer[0]) { case CheckReply: switch(receive_buffer[1]) { case BoardMissing: OpenFailureFile(); BoardError(failureFile,"missing_board",(int) receive_buffer[2]); CloseFailureFile(); break; case BoardBad: OpenFailureFile(); BoardError(failureFile,"dead_board",(int) receive_buffer[2]); CloseFailureFile(); break; case LampBad: OpenFailureFile(); Check(failureFile); failureFile->AppendEntry( "RIODeadLamps", "lamp", LBE4ControlsManager::GetLampName((int) receive_buffer[2]) ); CloseFailureFile(); break; case RestartCount: remoteRetryCount += receive_buffer[2]; break; case AbandonCount: remoteAbandonCount += receive_buffer[2]; break; case FullBufferCount: remoteFullBufferCount += receive_buffer[2]; break; } looping = True; // status events not sent to host break; case VersionReply: destination->Type = RIO::VersionEvent; MajorRevision = receive_buffer[1]; MinorRevision = receive_buffer[2]; break; case AnalogReply: destination->Type = RIO::AnalogEvent; // // NOTE: no data is sent in this packet. // The application is expected to directly read // the values in the object. // //---------------------------------------- // Discard the next N analog packets // (set by ForceCenterJoystick) //---------------------------------------- // if (discardCount) // { // --discardCount; // } // else { Check(throttleRanger); Throttle = throttleRanger->Update( // Note (-): Throttle counts BACKWARDS -CombinePair(receive_buffer[1], receive_buffer[2]) ); Check(leftPedalRanger); LeftPedal = leftPedalRanger->Update( CombinePair(receive_buffer[3], receive_buffer[4]) ); Check(rightPedalRanger); RightPedal = rightPedalRanger->Update( CombinePair(receive_buffer[5], receive_buffer[6]) ); Check(joystickYRanger); JoystickY = joystickYRanger->Update( CombinePair(receive_buffer[7], receive_buffer[8]) ); Check(joystickXRanger); JoystickX = joystickXRanger->Update( CombinePair(receive_buffer[9], receive_buffer[10]) ); } break; case ButtonPressed: destination->Type = RIO::ButtonPressedEvent; destination->Data.Unit = receive_buffer[1]; break; case ButtonReleased: destination->Type = RIO::ButtonReleasedEvent; destination->Data.Unit = receive_buffer[1]; break; case KeyPressed: destination->Type = RIO::KeyEvent; destination->Data.Keyboard.Unit = receive_buffer[1]; destination->Data.Keyboard.Key = receive_buffer[2]; break; case TestModeChange: if (receive_buffer[1] != 0) { Tell("RIO entered test mode\n"); TestModeActive = 1; OpenFailureFile(); Check(failureFile); failureFile->DeletePage("RIOBoardErrors"); failureFile->DeletePage("RIODeadLamps"); } else { Tell("RIO exited test mode\n"); TestModeActive = 0; CloseFailureFile(); } looping = True; // this event not sent to host break; default: // discard unused or bogus packets looping = True; break; } } } while (looping); Check_Fpu(); return reply; } void RIO::ForceCenterJoystick() { Check(this); // ResetVerticalJoystick(); // ResetHorizontalJoystick(); //------------------------------------------- // Make sure we don't use 'old' data // (skip the next two packets) // ...why 2? Just to make sure... //------------------------------------------- // discardCount = 2; Check(joystickXRanger); joystickXRanger->ForceToZero(); Check(joystickYRanger); joystickYRanger->ForceToZero(); Check_Fpu(); } void RIO::SetJoystickDeadBand(Scalar dead_band) { Check(this); Check(joystickXRanger); joystickXRanger->SetDeadBand(dead_band); Check(joystickYRanger); joystickYRanger->SetDeadBand(dead_band); Check_Fpu(); } void RIO::SetThrottleDeadBand(Scalar dead_band) { Check(this); Check(throttleRanger); throttleRanger->SetDeadBand(dead_band); Check_Fpu(); } void RIO::SetPedalsDeadBand(Scalar dead_band) { Check(this); Check(leftPedalRanger); leftPedalRanger->SetDeadBand(dead_band); Check(rightPedalRanger); rightPedalRanger->SetDeadBand(dead_band); Check_Fpu(); } void RIO::RequestCheck() { Check(this); static Byte request_check_string[] = { RIO::CheckRequest }; if (operational && !TestModeActive) { SendPacket((Byte *) request_check_string); } Check_Fpu(); } void RIO::RequestVersion() { Check(this); static Byte request_version_string[] = { RIO::VersionRequest }; if (operational && !TestModeActive) { SendPacket((Byte *) request_version_string); } Check_Fpu(); } void RIO::RequestAnalogUpdate() { //DEBUG_STREAM << "Analog Update Requested: " << GetTickCount() << std::endl << std::flush; Check(this); static Byte request_analog_string[] = { RIO::AnalogRequest }; if (operational && !TestModeActive) { SendPacket((Byte *) request_analog_string); } Check_Fpu(); } void RIO::GeneralReset() { Check(this); static Byte request_reset_string[] = { RIO::ResetRequest, 0 }; if (operational && !TestModeActive) { SendPacket((Byte *) request_reset_string); } Check_Fpu(); } void RIO::ResetThrottle() { Check(this); static Byte request_throttle_string[] = { RIO::ResetRequest, 1 }; if (operational && !TestModeActive) { SendPacket((Byte *) request_throttle_string); } Check_Fpu(); } void RIO::ResetLeftPedal() { Check(this); static Byte request_lpedal_string[] = { RIO::ResetRequest, 2 }; if (operational && !TestModeActive) { SendPacket((Byte *) request_lpedal_string); } Check_Fpu(); } void RIO::ResetRightPedal() { Check(this); static Byte request_rpedal_string[] = { RIO::ResetRequest, 3 }; if (operational && !TestModeActive) { SendPacket((Byte *) request_rpedal_string); } Check_Fpu(); } void RIO::ResetVerticalJoystick() { Check(this); static Byte request_vstick_string[] = { RIO::ResetRequest, 4 }; if (operational && !TestModeActive) { SendPacket((Byte *) request_vstick_string); } Check_Fpu(); } void RIO::ResetHorizontalJoystick() { Check(this); static Byte request_hstick_string[] = { RIO::ResetRequest, 5 }; if (operational && !TestModeActive) { SendPacket((Byte *) request_hstick_string); } Check_Fpu(); } void RIO::SetLamp(int lampNumber, int state) { Check(this); static Byte request_lamp_string[] = { RIO::LampRequest, 0, 0 }; if (operational) { request_lamp_string[1] = (Byte) (lampNumber & 0x7F); request_lamp_string[2] = (Byte) (state & 0x7F); SendPacket((Byte *) request_lamp_string); } Check_Fpu(); } void RIO::OpenFailureFile() { Check(this); if (failureFileOpenCount == 0) { failureFile = new NotationFile("FAILURE.LOG"); Check(failureFile); Register_Object(failureFile); } ++failureFileOpenCount; Check_Fpu(); } void RIO::CloseFailureFile() { Check(this); --failureFileOpenCount; if (failureFileOpenCount <= 0) { failureFileOpenCount = 0; Check(failureFile); Unregister_Object(failureFile); delete failureFile; } Check_Fpu(); }