Components and supplies
FT232RL
ATmega328
M74HC595YTTR
AS1115
Apps and platforms
Arduino IDE
Project description
Code
Electrical Control Firmare
arduino
1/****************************************************************************************/ 2/* */ 3/* Electrical Control | ©Kantooya */ 4/* */ 5/* Author: Sam Farah */ 6/* Email: sam.farah1986@gmail.com */ 7/* Website: http://samfarah.net */ 8/* Version: 1.0 */ 9/* Description: */ 10/* The firmware for the ATMega microcontroller on board, it controls */ 11/* the circuit, and handles reading inputs and sends commands to FSX. */ 12/* */ 13/****************************************************************************************/ 14 15 16//-------------------------- Headers ---------------------------- 17#include <U8g2lib.h> 18#include <AS1115.h> 19//#include <Arduino.h> 20#include <Quadrature.h> //for rotary encoders 21//#ifdef U8X8_HAVE_HW_SPI 22//#include <SPI.h> 23//#endif 24#ifdef U8X8_HAVE_HW_I2C 25#include <WSWire.h> 26#endif 27#include <MemoryFree.h> 28#include <avr/pgmspace.h> 29//--------------------------------------------------------------- 30 31//---------------------------- Pins ----------------------------- 32// Name Arduino Pin Pin on ATMega 33// ----------- ----------- ------------- 34#define LED2_CLK PD5 35#define LED2_DS PD7 36#define LED2_LTCH PD6 37#define LED1_CLK PD3 38#define LED1_DS PD2 39#define LED1_LTCH PD4 40#define IRQ1 A0 41#define IRQ2 A1 42//--------------------------------------------------------------- 43 44 45//------------------------- Settings ---------------------------- 46#define TCAADDR 0x70 47#define SerialTimeout 1000 48#define TempDelay 3000 49#define EBaro 0 50#define ENSet 1 51//--------------------------------------------------------------- 52 53//----------------------- Prototypes ---------------------------- 54class TDisplay; 55class TEncoderData; 56class TSwitchCtrl; 57class TChannel; 58class TPowerData; 59class TInstrumentData; 60//--------------------------------------------------------------- 61 62//------------------------- Objects ----------------------------- 63AS1115 disp = AS1115(0x00); 64AS1115 *SwitchCtr1 = new AS1115(0x00), *SwitchCtr2 = new AS1115(0x00); 65TSwitchCtrl *SwitchCtrs[2]; 66U8G2_SSD1306_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE); 67 68Quadrature Encoder1(8, 9); 69Quadrature Encoder2(A2, A3); 70//--------------------------------------------------------------- 71 72//-------------------------- Enums ------------------------------ 73//enum EDispID { EBaro = 0, ENSet = 1 }; 74//--------------------------------------------------------------- 75 76//---------------------- Public Variables ----------------------- 77//unsigned long TimeOutCheck; 78//byte counter = 0; 79byte tempDigitIndex, CodeIn; 80String LED1String = ""; 81String LED2String = ""; 82 83char temp; 84TDisplay *Displays[2]; 85TPowerData *PowerData; 86TInstrumentData *InstrumentData; 87bool MasterPower = true; 88bool UpdatePowerDisp = false; 89bool UpdateInstrumentDisp = false; 90static const byte TickPositions[] PROGMEM = { 39,41,43,50,60,71,92, 102, 124 }; 91static const byte GraphOrder[] PROGMEM = { 8,9,10,11,12,13,14,15,0,1 }; 92//static const byte BaroDigits[] = { 3,4,5,6 }; 93//static const byte NSetDigits[] = { 0, 1, 2 }; 94bool SpeedSet = false; 95bool N1Set = false; 96bool Strtr1 = false; 97bool Strtr2 = false; 98uint8_t Autobreak = 0; 99uint8_t LastAddress = 7; 100int8_t R1old, R2old, R1dif, R2dif; 101//--------------------------------------------------------------- 102class TDisplay 103{ 104private: 105 byte *Index; 106 byte DigitCount; 107 //byte ID; 108 //bool TempValChange; 109 bool ShowADP; 110 //unsigned long LastTempChange; 111 112 void SendValues(byte index, char value, bool ShowDP) 113 { 114 //return; 115 tcaselect(3, true); 116 AS1115 *CurrentDriver = &disp;// index > 7 ? &DispCtrl2 : &DispCtrl1; 117 index %= 8; 118 if (CurrentDriver->digitWrite(index, value, ShowDP)) 119 { 120 // Serial.println("I2C Froze (Displays)"); 121 I2C_ClearBus(); 122 Wire.begin(); 123 } 124 } 125public: 126 String Data;// , TempData; 127 TDisplay(byte *_Index, byte _DigitCount, bool _showADP) 128 { 129 Data.reserve(4); 130 //TempData.reserve(4); 131 ShowADP = _showADP; 132 Index = _Index; 133 DigitCount = _DigitCount; 134 //ID = _ID; 135 UpdateDisplay(" "); 136 //TempValChange = false; 137 //TempData = ""; 138 } 139 void UpdateDisplay() { UpdateDisplay(Data); } 140 void UpdateDisplay(String Val) 141 { 142 uint8_t DPFound = 0; 143 for (byte i = 0; i < DigitCount + DPFound; i++) 144 { 145 if (Val[i] == '.') 146 { 147 SendValues(Index[i - 1], Val[i - 1], ShowADP); 148 DPFound++; 149 } 150 else SendValues(Index[i - DPFound], Val[i], false); 151 } 152 } 153 void ClearDisplay() { UpdateDisplay(" "); } 154 // byte GetID() { return ID; } 155 //void SetTempValChange(bool val) 156 //{ 157 // TempValChange = val; 158 // // LastTempChange = millis(); 159 //} 160 byte GetDigitCount() { return DigitCount; } 161}; 162//-------------------------------------------- 163class TPowerData 164{ 165public: 166 String BatteryVoltage; 167 String BatteryCurrent; 168 String MainBusVoltage; 169 String MainBusCurrent; 170 String APUVoltage; 171 bool APUGenActive; 172 TPowerData() 173 { 174 BatteryVoltage.reserve(4); 175 BatteryCurrent.reserve(4); 176 MainBusVoltage.reserve(4); 177 MainBusCurrent.reserve(3); 178 APUVoltage.reserve(2); 179 } 180}; 181//-------------------------------------------- 182class TInstrumentData 183{ 184public: 185 uint8_t Flaps; 186 uint8_t FlapsHandle; 187 uint8_t FlapsPoisitonCount; 188 uint8_t FuelLeft; 189 uint8_t FuelCentre; 190 uint8_t FuelRight; 191 String Autobreak; 192 TInstrumentData() { Autobreak.reserve(3); } 193 void SetFlaps(String StrFlaps) { Flaps = atoi(StrFlaps.c_str()); } 194 void SetFlapsHandle(String strFlapsHandle) { FlapsHandle = atoi(strFlapsHandle.c_str()); } 195 void SetFlapsPoisitonCount(String strFlapsPoisitonCount) { FlapsPoisitonCount = atoi(strFlapsPoisitonCount.c_str()); } 196 void SetFuelLeft(String strFuel) { FuelLeft = atoi(strFuel.c_str()); } 197 void SetFuelCentre(String strFuel) { FuelCentre = atoi(strFuel.c_str()); } 198 void SetFuelRight(String strFuel) { FuelRight = atoi(strFuel.c_str()); } 199 void SetAutoBreak(char Val) 200 { 201 switch (Val) 202 { 203 case '0':Autobreak = "RTO"; break; 204 case '1':Autobreak = "OFF"; break; 205 case '2':Autobreak = " 1 "; break; 206 case '3':Autobreak = " 2 "; break; 207 case '4':Autobreak = " 3 "; break; 208 case '5':Autobreak = "MAX"; break; 209 } 210 } 211}; 212 213class TSwitchCtrl 214{ 215private: 216 AS1115 *Chip; 217 String Data; 218 String OldData; 219public: 220 byte MuxAddress; 221 byte IRQ; 222 byte LSB, MSB; 223 TSwitchCtrl(uint8_t _IRQ, AS1115 *_Chip, uint8_t _LSB, uint8_t _MSB, uint8_t _MuxAddress) 224 { 225 Data.reserve(16); 226 OldData.reserve(16); 227 IRQ = _IRQ; 228 Chip = _Chip; 229 LSB = _LSB; 230 MSB = _MSB; 231 MuxAddress = _MuxAddress; 232 Data = ""; 233 tcaselect(MuxAddress, false); 234 Chip->begin(0x00, 0x00); 235 Chip->begin(0x01, 0x00); 236 Chip->begin(0x02, 0x00); 237 Chip->begin(0x03, 0x00); 238 } 239 void ReadSwitchs() 240 { 241 tcaselect(MuxAddress, false); 242 uint8_t ErrorCode; 243 //Serial.print("Saving "); 244 //Serial.print(Data); 245 //Serial.println(" as old"); 246 OldData = Data; 247 Data = Chip->ReadKeysMul(&ErrorCode);//potentially not needed (the Leading Zeros, already handled from library) 248 //Serial.print("new val is: "); 249 //Serial.println (Data); 250 if (ErrorCode >= 4) 251 { 252 I2C_ClearBus(); 253 Wire.begin(); 254 } 255 tcaselect(LastAddress, false); 256 } 257 String GetData() { return Data; } 258 String GetOldData() { return OldData; } 259 void EmptyBuffer() 260 { 261 tcaselect(MuxAddress, false); 262 uint8_t ErrorCode; 263 264 Chip->ReadKeysMul(&ErrorCode);//potentially not needed (the Leading Zeros, already handled from library) 265 if (ErrorCode >= 4) 266 { 267 I2C_ClearBus(); 268 Wire.begin(); 269 } 270 tcaselect(LastAddress, false); 271 } 272}; 273/* 274Frame Buffer Examples: clearBuffer/sendBuffer. Fast, but may not work with all Arduino boards because of RAM consumption 275Page Buffer Examples: firstPage/nextPage. Less RAM usage, should work with all Arduino boards. 276U8x8 Text Only Example: No RAM usage, direct communication with display controller. No graphics, 8x8 Text only. 277*/ 278 279 280void tcaselect(uint8_t i, bool SaveAddress) { 281 if (i > 7) return; 282 if (SaveAddress == true) LastAddress = i; 283 Wire.beginTransmission(TCAADDR); 284 Wire.write(1 << i); 285 Wire.endTransmission(); 286 //delay(10); 287} 288 289void u8g2_prepare(void) { 290 u8g2.setFont(u8g2_font_6x10_tf); 291 u8g2.setFontRefHeightExtendedText(); 292 u8g2.setDrawColor(1); 293 u8g2.setFontPosTop(); 294 u8g2.setFontDirection(0); 295} 296void PowerDevice() 297{ 298 if (MasterPower == 0) 299 { 300 SendLED2Data("0000000000000000"); 301 SendLED1Data("0000000000000000"); 302 Displays[EBaro]->UpdateDisplay(" "); 303 Displays[ENSet]->UpdateDisplay(" "); 304 tcaselect(6, true); 305 u8g2.clearDisplay(); 306 tcaselect(7, true); 307 u8g2.clearDisplay(); 308 309 } 310 else 311 { 312 UpdateAllDisplays(); 313 UpdateInstrumentDisplay(); 314 UpdatePowerDisplay(); 315 } 316} 317ISR(PCINT1_vect) // handle pin change interrupt for D8 to D13 here 318{ 319 interrupts(); 320 for (byte SwtchCtrlIndex = 0; SwtchCtrlIndex < 2; SwtchCtrlIndex++) 321 { 322 if (digitalRead(SwitchCtrs[SwtchCtrlIndex]->IRQ) == LOW) 323 { 324 SwitchCtrs[SwtchCtrlIndex]->ReadSwitchs(); 325 byte ChangedIndex = 0; 326 char NewValue, InverseValue; 327 for (byte i = 0; i < 16; i++) 328 { 329 330 if (SwitchCtrs[SwtchCtrlIndex]->GetData()[i] != SwitchCtrs[SwtchCtrlIndex]->GetOldData()[i]) 331 { 332 NewValue = SwitchCtrs[SwtchCtrlIndex]->GetData()[i]; 333 InverseValue = NewValue == '0' ? '1' : '0'; 334 ChangedIndex = 32 - i - SwitchCtrs[SwtchCtrlIndex]->LSB; 335 break; 336 } 337 } 338 if (!MasterPower && ChangedIndex != 31) return;//if powered off, only listen to power swtich. 339 if (NewValue == '1') //push buttons 340 { 341 switch (ChangedIndex) 342 { 343 case 1:Serial.println(F("C15")); break; 344 case 2:Serial.println(F("C14")); break; 345 case 8:Serial.println(F("E43")); Serial.println(F("E46")); break; 346 case 14:Serial.println(F("C02")); break; 347 case 15:Serial.println(F("C01")); break; 348 case 22:Serial.println(F("F31")); break; 349 case 23:Serial.println(F("B31")); break; 350 case 25:Serial.println(F("B35")); break; 351 case 27:Serial.println(F("C13")); break; 352 case 28:Serial.println(LED1String[4] == '1' ? F("C21") : F("C20")); break; 353 case 29:Serial.println(F("C04")); break; 354 case 30:Serial.println(F("C16")); break; 355 //case 26:Serial.println("F34"); break; AUTO BARO?? 356 case 32:Serial.println(F("F34")); break; 357 } 358 } 359 switch (ChangedIndex) //toggle switches 360 { 361 case 4:Serial.println(NewValue == '1' ? F("E17") : F("E18")); break; 362 case 5:Serial.println(NewValue == '1' ? F("E32") : F("E31")); break; 363 case 6:Serial.println(NewValue == '1' ? F("E30") : F("C11")); break; 364 case 7:Serial.println(NewValue == '0' ? F("E30") : F("C11")); break; 365 case 12:Serial.println(NewValue == '1' ? F("E23") : F("E24")); break; 366 case 13:Serial.println(NewValue == '1' ? F("E20") : F("E21")); break; 367 //case 13:Serial.println(F("E21")); break; 368 case 17:Autobreak = 4; SetAB(); break; 369 case 18:Autobreak = 3; SetAB(); break; 370 case 19:Autobreak = 2; SetAB(); break; 371 case 20:Autobreak = 1; SetAB(); break; 372 case 21:Autobreak = 0; SetAB(); break; 373 case 24:Autobreak = 5; SetAB(); break; 374 case 31:MasterPower = NewValue == '1'; 375 PowerDevice(); 376 break; 377 } 378 } 379 } 380} 381void setup(void) { 382 383 LED1String.reserve(16); 384 LED2String.reserve(16); 385 //BargraphStirng.reserve(10); 386 387 Serial.begin(115200); 388 pinMode(IRQ1, INPUT_PULLUP); 389 pinMode(IRQ2, INPUT_PULLUP); 390 pinMode(LED1_CLK, OUTPUT); 391 pinMode(LED1_DS, OUTPUT); 392 pinMode(LED1_LTCH, OUTPUT); 393 pinMode(LED2_CLK, OUTPUT); 394 pinMode(LED2_DS, OUTPUT); 395 pinMode(LED2_LTCH, OUTPUT); 396 397 398 SwitchCtrs[0] = new TSwitchCtrl(IRQ1, SwitchCtr1, 0, 15, 5); 399 SwitchCtrs[1] = new TSwitchCtrl(IRQ2, SwitchCtr2, 16, 31, 4); 400 401 tcaselect(3, false); 402 disp.setFont(FONT_CODEB); 403 disp.begin(0x03, 0x00); 404 disp.setIntensity(0x06); 405 406 407 Displays[EBaro] = new TDisplay(new byte[5]{ 3,4,5,6 }, 4, true); 408 Displays[ENSet] = new TDisplay(new byte[5]{ 0, 1, 2 }, 3, false); 409 410 PowerData = new TPowerData(); 411 InstrumentData = new TInstrumentData; 412 413 SwitchCtrs[0]->ReadSwitchs(); 414 SwitchCtrs[1]->ReadSwitchs(); 415 416 MasterPower = SwitchCtrs[0]->GetData()[1] == '1'; 417 PowerDevice(); 418 419 delay(50); 420 pciSetup(IRQ1); 421 pciSetup(IRQ2); 422 423 424 tcaselect(6, false); 425 u8g2.begin(); 426 tcaselect(7, false); 427 u8g2.begin(); 428 429 UpdatePowerDisp = false; 430 UpdateInstrumentDisp = false; 431 432 LED1String = "000000000000000000000000"; 433 LED2String = "000000000000000000000000"; 434 //u8g2.setFlipMode(0); 435} 436void loop(void) { 437 ENCODER(); //Check the Rotary Encoders 438 if (!Serial.available()) //Check if anything there 439 { 440 if (UpdatePowerDisp == true && MasterPower == true) UpdatePowerDisplay(); 441 if (UpdateInstrumentDisp == true && MasterPower == true) UpdateInstrumentDisplay(); 442 return; 443 } 444 445 while (Serial.available()) 446 { 447 switch (getChar()) //Get a serial read if there is. 448 { 449 case '=':EQUALS(); break; 450 case '<':LESSTHAN(); break; 451 case '?':QUESTION(); break; 452 case '#':HASHTAG(); break; 453 case '$':DOLLAR(); break; 454 default:break; // ignore floating values //while (Serial.available()) Serial.read(); break; // empty buffer 455 } 456 } 457 while (Serial.available()) Serial.read(); // empty buffer 458 UpdateAllDisplays(); 459} 460void pciSetup(byte pin) 461{ 462 *digitalPinToPCMSK(pin) |= bit(digitalPinToPCMSKbit(pin)); // enable pin 463 PCIFR |= bit(digitalPinToPCICRbit(pin)); // clear any outstanding interrupt 464 PCICR |= bit(digitalPinToPCICRbit(pin)); // enable interrupt for the group 465} 466void SetAB() 467{ 468 for (byte i = 0; i < 6; i++)Serial.println(F("Y031")); 469 for (byte i = 0; i < Autobreak; i++)Serial.println(F("Y021")); 470} 471//------------------------------------------------------------------------------------------------------------------------------------------ 472void UpdateAllDisplays() 473{ 474 if (MasterPower) { 475 //for (byte i = 0; i < 2; i++) { 476 Displays[EBaro]->UpdateDisplay(); 477 Displays[ENSet]->UpdateDisplay(); 478 //} 479 SendLED2Data(LED2String); 480 LED1String[7] = !SpeedSet && N1Set ? '1' : '0'; 481 LED1String[6] = MasterPower ? '1' : '0'; 482 LED1String[15] = Displays[EBaro]->Data == "29.92" ? '1' : '0'; 483 SendLED1Data(LED1String); 484 485 } 486} 487//------------------------------------------------------------------------------------------------------------------------------------------ 488char getChar()// Get a character from the serial buffer 489{ 490 //TimeOutCheck = millis(); 491 while (Serial.available() == 0);// if (millis() - TimeOutCheck > SerialTimeout)return '0';//time out command - prevent freezing 492 return((char)Serial.read()); 493} 494//------------------------------------------------------------------------------------------------------------------------------------------ 495void EQUALS() { 496 497 CodeIn = getChar(); 498 switch (CodeIn) { 499 case 't': LED1String[12] = getChar(); break; //auto throttle 500 case 's': SpeedSet = getChar() == '1' ? true : false; break;//airspeed 501 case 'u': N1Set = getChar() == '1' ? true : false; break;//n1set 502 } 503} 504//------------------------------------------------------------------------------------------------------------------------------------------ 505void QUESTION() { 506 CodeIn = getChar(); 507 String GenStats, GearStats; 508 switch (CodeIn) { 509 case 'k': Displays[EBaro]->Data = GetBufferValue(5); break; //Kohlsman setting Hg 510 case 'I': PowerData->BatteryVoltage = GetBufferValue(4); UpdatePowerDisp = true; break; //Battery Voltage 511 case 'J': PowerData->BatteryCurrent = GetBufferValue(4); UpdatePowerDisp = true; break; //Battery Current 512 case 'K': PowerData->MainBusVoltage = GetBufferValue(4); UpdatePowerDisp = true; break; //Main Bus Voltage 513 case 's': 514 GenStats = GetBufferValue(2); 515 LED1String[10] = GenStats[0] == '1' ? '0' : '1'; 516 LED1String[11] = GenStats[1] == '1' ? '0' : '1'; 517 break; 518 case 'Y'://gear 519 GearStats = GetBufferValue(3); 520 LED2String[2] = GearStats[2] == '1' ? '1' : '0';//right red 521 LED2String[4] = GearStats[1] == '1' ? '1' : '0';//left red 522 LED2String[6] = GearStats[0] == '1' ? '1' : '0';//nose red 523 LED2String[3] = GearStats[2] == '2' ? '1' : '0';//right grn 524 LED2String[5] = GearStats[1] == '2' ? '1' : '0';//left grn 525 LED2String[7] = GearStats[0] == '2' ? '1' : '0';//nose grn 526 break; 527 } 528} 529//------------------------------------------------------------------------------------------------------------------------------------------ 530void LESSTHAN() 531{ 532 CodeIn = getChar(); 533 switch (CodeIn) 534 { 535 case 'G': InstrumentData->SetFlaps(GetBufferValue(3)); UpdateInstrumentDisp = true; break; //Flaps 536 case 'X': InstrumentData->SetFuelLeft(GetBufferValue(3)); UpdateInstrumentDisp = true; break; //Flaps 537 case 'Y': InstrumentData->SetFuelCentre(GetBufferValue(3)); UpdateInstrumentDisp = true; break; //Flaps 538 case 'Z': InstrumentData->SetFuelRight(GetBufferValue(3)); UpdateInstrumentDisp = true; break; //Flaps 539 case 'I': LED1String[1] = getChar(); break; //Plane on Ground 540 case 'q': LED1String[5] = getChar(); break; //Parking Break 541 case 'i': LED1String[4] = getChar(); break; //Spoiler Arked 542 case 'r': LED1String[2] = getChar(); break; //Eng 1 Fuel Vales 543 case 's': LED1String[0] = getChar(); break; //Eng 2 Fuel Vales 544 case 'k': Strtr1 = (getChar() == '1' ? true : false); LED1String[3] = (Strtr1 || Strtr2) ? '1' : '0'; break; //eng starter 545 case 'l': Strtr2 = (getChar() == '1' ? true : false); LED1String[3] = (Strtr1 || Strtr2) ? '1' : '0'; break; //eng starter 546 547 } 548} 549//------------------------------------------------------------------------------------------------------------------------------------------ 550void HASHTAG() { 551 CodeIn = getChar(); 552 switch (CodeIn) 553 { 554 case 'H': Displays[ENSet]->Data = GetBufferValue(4); break; 555 case 'I': PowerData->MainBusCurrent = GetBufferValue(3); UpdatePowerDisp = true; break; //Main Bus Current 556 case 'L': InstrumentData->SetFlapsHandle(GetBufferValue(2)); UpdateInstrumentDisp = true; break; //Flaps Index 557 case 'K': InstrumentData->SetFlapsPoisitonCount(GetBufferValue(2)); UpdateInstrumentDisp = true; break; //Flaps Index 558 case 'J': InstrumentData->SetAutoBreak(getChar()); UpdateInstrumentDisp = true; break; //Flaps Index 559 case 'N': LED1String[14] = getChar(); break; //HAS G/S 560 case 'M': LED1String[13] = getChar(); break; //HAS LOC 561 } 562 563} 564//------------------------------------------------------------------------------------------------------------------------------------------ 565 566void ENCODER() { 567 568 int8_t R1 = (Encoder1.position() / 2); //The /2 is to suit the encoder 569 if (R1 != R1old) { // checks to see if it different 570 (R1dif = (R1 - R1old));// finds out the difference 571 //Serial.println(Encoder1.position()); 572 if (R1dif == 1) Serial.println(F("B43")); 573 if (R1dif == -1)Serial.println(F("B44")); 574 R1old = R1; // overwrites the old reading with the new one. 575 //Disp->SetTempValChange(true); 576 } 577 578 int8_t R2 = (Encoder2.position() / 2); //The /2 is to suit the encoder 579 if (R2 != R2old) { // checks to see if it different 580 (R2dif = (R2 - R2old));// finds out the difference 581 if (R2dif == 1) Serial.println(F("C25")); 582 if (R2dif == -1)Serial.println(F("C26")); 583 R2old = R2; // overwrites the old reading with the new one. 584 //Disp->SetTempValChange(true); 585 } 586} 587//------------------------------------------------------------------------------------------------------------------------------------------ 588void DOLLAR() { 589 CodeIn = getChar(); 590 switch (CodeIn) 591 { 592 case 'g': GETBarLED(GetBufferValue(3)); break; 593 case 'i': PowerData->APUVoltage = GetBufferValue(2); UpdatePowerDisp = true; break; //APU Voltage 594 case 'k': PowerData->APUGenActive = getChar() == '1' ? true : false; break; //APU Gen Active (considers APU RPM) 595 case 'j': LED1String[9] = getChar(); break; //APU Gen 596 } 597} 598//------------------------------------------------------------------------------------------------------------------------------------------ 599String GetBufferValue(int byteCount) 600{ 601 String buff = ""; 602 for (byte i = 0; i < byteCount; i++) 603 { 604 temp = getChar(); 605 if ((temp <= '9' && temp >= '0') || temp == '.' || temp == '-' || temp == '+')buff += temp; 606 else buff += '0'; 607 } 608 return buff; 609} 610//------------------------------------------------------------------------------------------------------------------------------------------ 611uint8_t I2C_ClearBus() { 612#if defined(TWCR) && defined(TWEN) 613 TWCR &= ~(_BV(TWEN)); //Disable the Atmel 2-Wire interface so we can control the SDA and SCL pins directly 614#endif 615 616 pinMode(SDA, INPUT_PULLUP); // Make SDA (data) and SCL (clock) pins Inputs with pullup. 617 pinMode(SCL, INPUT_PULLUP); 618 delay(20); 619 620 boolean SCL_LOW = (digitalRead(SCL) == LOW); // Check is SCL is Low. 621 if (SCL_LOW) { //If it is held low Arduno cannot become the I2C master. 622 return 1; //I2C bus error. Could not clear SCL clock line held low 623 } 624 625 boolean SDA_LOW = (digitalRead(SDA) == LOW); // vi. Check SDA input. 626 byte clockCount = 20; // > 2x9 clock 627 628 while (SDA_LOW && (clockCount > 0)) { // vii. If SDA is Low, 629 clockCount--; 630 // Note: I2C bus is open collector so do NOT drive SCL or SDA high. 631 pinMode(SCL, INPUT); // release SCL pullup so that when made output it will be LOW 632 pinMode(SCL, OUTPUT); // then clock SCL Low 633 delayMicroseconds(10); // for >5uS 634 pinMode(SCL, INPUT); // release SCL LOW 635 pinMode(SCL, INPUT_PULLUP); // turn on pullup resistors again 636 // do not force high as slave may be holding it low for clock stretching. 637 delayMicroseconds(10); // for >5uS 638 // The >5uS is so that even the slowest I2C devices are handled. 639 SCL_LOW = (digitalRead(SCL) == LOW); // Check if SCL is Low. 640 byte counter = 20; 641 while (SCL_LOW && (counter > 0)) { // loop waiting for SCL to become High only wait 2sec. 642 counter--; 643 delay(50); 644 SCL_LOW = (digitalRead(SCL) == LOW); 645 } 646 if (SCL_LOW) { // still low after 2 sec error 647 return 2; // I2C bus error. Could not clear. SCL clock line held low by slave clock stretch for >2sec 648 } 649 SDA_LOW = (digitalRead(SDA) == LOW); // and check SDA input again and loop 650 } 651 if (SDA_LOW) { // still low 652 return 3; // I2C bus error. Could not clear. SDA data line held low 653 } 654 655 // else pull SDA line low for Start or Repeated Start 656 pinMode(SDA, INPUT); // remove pullup. 657 pinMode(SDA, OUTPUT); // and then make it LOW i.e. send an I2C Start or Repeated start control. 658 // When there is only one I2C master a Start or Repeat Start has the same function as a Stop and clears the bus. 659 // A Repeat Start is a Start occurring after a Start with no intervening Stop. 660 delayMicroseconds(10); // wait >5uS 661 pinMode(SDA, INPUT); // remove output low 662 pinMode(SDA, INPUT_PULLUP); // and make SDA high i.e. send I2C STOP control. 663 delayMicroseconds(10); // x. wait >5uS 664 pinMode(SDA, INPUT); // and reset pins as tri-state inputs which is the default state on reset 665 pinMode(SCL, INPUT); 666 //Serial.println("I2C Recovered"); 667 return 0; // all ok 668} 669//------------------------------------------------------------------------------------------------------------------------------------------ 670 671 672void PulseLEN(uint8_t pin, bool StartLow) 673{ 674 if (StartLow) 675 { 676 digitalWrite(pin, LOW); 677 digitalWrite(pin, HIGH); //fix for double send 678 digitalWrite(pin, LOW); 679 } 680 else 681 { 682 digitalWrite(pin, HIGH); 683 digitalWrite(pin, LOW); 684 digitalWrite(pin, HIGH); 685 } 686} 687//------------------------------------------------------------------------------------------------------------------------------------------ 688void PulseData(uint8_t DSpin, uint8_t CLKPin, char Data) 689{ 690 digitalWrite(DSpin, (Data == '1' ? HIGH : LOW)); 691 digitalWrite(CLKPin, LOW); 692 digitalWrite(CLKPin, HIGH); 693} 694//------------------------------------------------------------------------------------------------------------------------------------------ 695void SendLED1Data(String data) 696{ 697 PulseLEN(LED1_LTCH, false); 698 for (byte i = 0; i < 16; i++)PulseData(LED1_DS, LED1_CLK, data[i]); 699 PulseLEN(LED1_LTCH, true); 700 701 /* PulseLEN(LED2_LTCH, false); 702 for (int i = 31; i >= 16; i--)PulseData(LED2_DS, LED2_CLK, data[i]); 703 PulseLEN(LED2_LTCH, true);*/ 704} 705//------------------------------------------------------------------------------------------------------------------------------------------ 706void SendLED2Data(String data) 707{ 708 PulseLEN(LED2_LTCH, false); 709 for (byte i = 0; i < 16; i++) { 710 PulseData(LED2_DS, LED2_CLK, data[i]); //delay(10); 711 } 712 PulseLEN(LED2_LTCH, true); 713 714 /* PulseLEN(LED2_LTCH, false); 715 for (int i = 31; i >= 16; i--)PulseData(LED2_DS, LED2_CLK, data[i]); 716 PulseLEN(LED2_LTCH, true);*/ 717} 718//------------------------------------------------------------------------------------------------------------------------------------------ 719void GETBarLED(String APURPMVal) 720{ 721 String BargraphStirng = ""; 722 if (APURPMVal[0] == '1') 723 { 724 BargraphStirng = "1111111111"; 725 } 726 else 727 { 728 byte val = APURPMVal[1] - '0'; 729 BargraphStirng = ""; 730 for (byte i = 0; i < val; i++) 731 BargraphStirng += '1'; 732 for (byte i = 0; i < 10 - val; i++) 733 BargraphStirng += '0'; 734 } 735 736 for (byte i = 0; i < 10; i++) 737 LED2String[pgm_read_byte(&(GraphOrder[i]))] = BargraphStirng[i]; 738} 739//------------------------------------------------------------------------------------------------------------------------------------------ 740void UpdatePowerDisplay() 741{ 742 //return; 743 tcaselect(6, true); 744 u8g2.firstPage(); 745 do 746 { 747 748 u8g2.drawHLine(0, 17, 128); 749 u8g2.drawHLine(0, 42, 128); 750 u8g2.drawVLine(64, 0, 17); 751 u8g2.drawVLine(43, 42, 22); 752 u8g2.drawVLine(86, 42, 22); 753 754 755 756 u8g2_prepare(); 757 u8g2.setFont(u8g2_font_freedoomr10_tu); 758 u8g2.drawStr(10, 0, (PowerData->BatteryVoltage + "V").c_str()); 759 u8g2.drawStr(80, 0, (PowerData->BatteryCurrent + "A").c_str()); 760 u8g2.drawStr(3, 50, (PowerData->MainBusVoltage + "V").c_str()); 761 u8g2.drawStr(51, 50, (PowerData->MainBusCurrent + "A").c_str()); 762 u8g2.drawStr(97, 50, (PowerData->APUVoltage + "V").c_str()); 763 764 if (PowerData->BatteryCurrent[0] == '-') 765 { 766 u8g2.setFont(u8g2_font_crox3hb_tf); 767 u8g2.drawStr(2, 23, "LOW BATTERY"); 768 } 769 770 u8g2.setFont(u8g2_font_6x10_tf); 771 772 } while (u8g2.nextPage()); 773 774 775 UpdatePowerDisp = false; 776 777} 778//------------------------------------------------------------------------------------------------------------------------------------------ 779void UpdateInstrumentDisplay() 780{ 781 //return; 782 uint8_t i; 783 uint8_t CentrePos; 784 uint8_t actualpos; 785 tcaselect(7, true); 786 u8g2.firstPage(); 787 u8g2_prepare(); 788 do 789 { 790 u8g2.drawVLine(34, 0, 44); 791 u8g2.drawHLine(0, 44, 128); 792 u8g2.drawVLine(42, 45, 21); 793 u8g2.drawVLine(86, 45, 21); 794 795 796 // Fuel 797 u8g2.setFont(u8g2_font_4x6_tf); 798 u8g2.drawStr(13, 47, "LEFT"); 799 u8g2.drawStr(55, 47, "CENTRE"); 800 u8g2.drawStr(100, 47, "RIGHT"); 801 u8g2.drawStr(40, 2, "FLAPS:"); 802 u8g2.setFont(u8g2_font_6x10_tf); 803 804 u8g2.drawStr(13, 56, (String(InstrumentData->FuelLeft) + "%").c_str()); 805 u8g2.drawStr(55, 56, (String(InstrumentData->FuelCentre) + "%").c_str()); 806 u8g2.drawStr(100, 56, (String(InstrumentData->FuelRight) + "%").c_str()); 807 808 // //Autobreak 809 u8g2.drawStr(8, 15, InstrumentData->Autobreak.c_str()); 810 811 // //Flaps Demo 812 u8g2.setFont(u8g2_font_micro_mn); 813 814 815 u8g2.drawStr(42, 35, "0");//save ram 816 u8g2.drawStr(40, 35, "1"); 817 //u8g2.drawStr(44, 35, "2"); 818 u8g2.drawStr(48, 35, "5"); 819 u8g2.drawStr(56, 35, "10"); 820 u8g2.drawStr(67, 35, "15"); 821 u8g2.drawStr(88, 35, "25"); 822 u8g2.drawStr(98, 35, "30"); 823 u8g2.drawStr(120, 35, "40");//save ram ends 824 825 //u8g2.setFont(u8g2_font_4x6_tf); 826 827 //u8g2.setFont(u8g2_font_6x10_tf); 828 u8g2.drawHLine(44, 30, 81); 829 830 for (i = 0; i < 9; i++)u8g2.drawVLine(pgm_read_byte(&(TickPositions[i])), 29, 3); //SAVE RAM 831 832 833 actualpos = map(InstrumentData->Flaps, 0, 100, 0, 85); 834 //u8g2.drawStr(50, 5, String(39 + actualpos).c_str()); 835 836 837 838 u8g2.drawVLine(39, 20, 7); 839 u8g2.drawBox(39, 20, actualpos, 7); 840 if (InstrumentData->FlapsPoisitonCount == 8) 841 { 842 CentrePos = pgm_read_byte(&(TickPositions[InstrumentData->FlapsHandle])); 843 u8g2.drawVLine(CentrePos, 10, 4); 844 u8g2.drawTriangle(CentrePos - 2, 14, CentrePos, 18, CentrePos + 3, 14); //tales waaayyy tooo much RAM 845 } 846 // //u8g2.drawVLine(i , 20, 8); 847 848 } while (u8g2.nextPage()); 849 UpdateInstrumentDisp = false; 850} 851//------------------------------------------------------------------------------------------------------------------------------------------
Autopilot Firmware
arduino
1/****************************************************************************************/ 2/* */ 3/* Autopilot 500-TS | ©Kantooya Inc */ 4/* */ 5/* Author: Sam Farah */ 6/* Email: sam.farah1986@gmail.com */ 7/* Website: http://samfarah.net */ 8/* Version: 1.0 */ 9/* Description: */ 10/* The firmware for the ATMega microcontroller on board, it controls */ 11/* the circuit, and handles reading inputs and sends commands to FSX. */ 12/* */ 13/****************************************************************************************/ 14 15//-------------------------- Headers ---------------------------- 16#include <AS1115.h> 17#include "WSWire.h" 18#include "math.h" 19#include "Quadrature.h" //for rotary encoders 20//--------------------------------------------------------------- 21 22//---------------------------- Pins ----------------------------- 23// Name Arduino Pin Pin on ATMega 24// ----------- ----------- ------------- 25#define LED_DS 2 // 32 26#define LED_CLK 3 // 1 27#define LED_LTCH 4 // 2 28#define ALTEnc_B 6 // 29#define ALTEnc_A 7 // 30#define VSEnc_B 8 // 31#define VSEnc_A 9 // 32#define IRQ 13 // 17 33#define SpdEnc_B 10 // 34#define SpdEnc_A 11 // 35#define HdgEnc_A A0 // 36#define HdgEnc_B A1 // 37#define CrsEnc_A A2 // 38#define CrsEnc_B A3 // 39#define SDA A4 // 40#define SCL A5 // 41//--------------------------------------------------------------- 42 43//------------------------- Settings ---------------------------- 44#define SerialTimeout 1000 45#define TempDelay 2000 46//--------------------------------------------------------------- 47 48//-------------------------- Enums ------------------------------ 49enum EDispID{ ESpeedDisp = 0, EALTDisp = 1, EVSDisp = 2, ECrsDsip = 3, EHdgDisp = 4 }; 50//--------------------------------------------------------------- 51 52//----------------------- Prototypes ---------------------------- 53int ReadSwitches(); 54void pciSetup(byte); 55void SendLEDData(String); 56void(*resetFunc) (void) = 0; //declare reset function @ address 0 57void TestLEDs(int); 58void InitLEDs(int); 59uint8_t I2C_ClearBus(); 60class SDisplayData; 61class TTestDisplayData; 62class TDisplay; 63class TEncoderData; 64class TBlinkLED; 65//--------------------------------------------------------------- 66 67//------------------------- Objects ----------------------------- 68AS1115 DispCtrl1 = AS1115(0x01); 69AS1115 DispCtrl2 = AS1115(0x02); 70AS1115 SwitchCtrl = AS1115(0x03); 71TEncoderData *SpeedCtrl, *ALTCtrl, *VSCtrl, *HdgCtrl, *CrsCtrl; 72TBlinkLED *RealDataBlink, *SpeedBlink, *AltBlink, *HdgBlink; 73//--------------------------------------------------------------- 74class SDisplayData 75{ 76public: 77 String SetMem; 78 String ReadMem; 79}; 80//---------------------- Public Variables ----------------------- 81int SwLEDList[] = { 3, 1, 2, 0, 9, 10, 11, 4, 0, 0, 14, 5, 0, 12, 8, 13 }; 82bool BlinIndexArray[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 83String FSXCommands[] = { "B09", "B04", "B10", "", "A54", "A54", "B30", "B08", "", "", "Y080", "B05", "", "B34", "B01", "B26" }; 84String LEDString = "0000000000000000"; 85String OldLEDs = "0000000000000000"; 86String BlinkLEDs = "0000000000000000"; 87int tempVal, CodeIn; 88bool TestProgram = false, ShowDP = false, ShowRealValues = false, OldShowRealValues = false; 89bool ShowZeros, Connected = false, MasterBattery; 90char navMeM, SpeedMeM, ATHRMeM; 91SDisplayData ALTData, SpdData, VSData, HdgData, CrsData; 92TDisplay *Displays[5]; 93unsigned long int HoldTime = 0, TimeOutCheck; 94//--------------------------------------------------------------- 95 96//-------------------------- Classes ---------------------------- 97class TDisplay 98{ 99private: 100 byte *Index; 101 int DigitCount; 102 EDispID ID; 103 bool TempValChange; 104 unsigned long int LastTempChange; 105 SDisplayData *Data; 106 void SendValues(byte index, char value) 107 { 108 if (index > 7) 109 { 110 if (DispCtrl2.digitWrite(index - 8, value, (TestProgram ? ShowZeros : MasterBattery))) 111 { 112 Serial.println("I2C Froze (Displays)"); 113 I2C_ClearBus(); 114 Wire.begin(); 115 DispCtrl1.begin(); 116 DispCtrl2.begin(); 117 SwitchCtrl.begin(); 118 } 119 } 120 else 121 { 122 if (DispCtrl1.digitWrite(index, value, (index == 6 || index == 1 ? ShowDP : 0))) 123 { 124 Serial.println("I2C Froze (Displays)"); 125 I2C_ClearBus(); 126 Wire.begin(); 127 DispCtrl1.begin(); 128 DispCtrl2.begin(); 129 SwitchCtrl.begin(); 130 } 131 } 132 } 133public: 134 TDisplay(byte *_Index, EDispID _ID, SDisplayData *_Data) 135 { 136 Index = _Index; 137 DigitCount = 3; 138 ID = _ID; 139 UpdateDisplay(" "); 140 TempValChange = false; 141 Data = _Data; 142 } 143 void CheckTempDisplay() 144 { 145 if (TempValChange && millis() - LastTempChange > TempDelay) 146 { 147 TempValChange = false; 148 UpdateDisplay(); 149 } 150 } 151 152 void UpdateDisplay() 153 { 154 UpdateDisplay(!ShowRealValues || TempValChange ? Data->SetMem : Data->ReadMem); 155 } 156 void UpdateDisplay(String Val) 157 { 158 159 160 bool LeadZeroFound = false; 161 bool Negative = false; 162 for (int i = 0; i < DigitCount; i++) 163 { 164 if (!MasterBattery && !TestProgram)Val[i] = ' '; 165 else 166 { 167 if (Val[i] == '-') 168 { 169 Negative = true; 170 Val[i] = ' '; 171 } 172 else if (Val[i] == '+')Val[i] = ' '; 173 else 174 if (Val[i] == '0' && !LeadZeroFound && i != DigitCount - 1 && (!TestProgram || ((Index[i] != 6 && Index[i] != 1) || LEDString[11] == '0')))Val[i] = ' '; 175 else 176 { 177 LeadZeroFound = true; 178 if (Negative) 179 { 180 if (TestProgram && (LEDString[11] == '1' && (Index[i] == 7 || Index[i] == 2))) 181 { 182 SendValues(Index[i - 1], '0'); 183 SendValues(Index[i - 2], '-'); 184 } 185 else SendValues(Index[i - 1], '-'); 186 187 Negative = false; 188 } 189 } 190 } 191 192 SendValues(Index[i], Val[i]); 193 } 194 } 195 void ClearDisplay() 196 { 197 UpdateDisplay(" "); 198 } 199 EDispID GetID(){ return ID; } 200 void SetTempValChange(bool val) 201 { 202 TempValChange = val; 203 LastTempChange = millis(); 204 } 205 206}; 207//-------------------------------------------- 208 209//-------------------------------------------- 210class TTestDisplayData 211{ 212public: 213 int Value; 214 TTestDisplayData() 215 { 216 Value = 0; 217 } 218 String toString() 219 { 220 String RetVal = String(Value); 221 String Buff = ""; 222 for (int i = 0; i < 3 - RetVal.length(); i++) 223 Buff += '0'; 224 RetVal = Buff + RetVal; 225 226 return RetVal; 227 } 228 void Inc() 229 { 230 Value++; 231 if (Value>999)Value = 0; 232 } 233 void Dec(bool AllowNegative) 234 { 235 Value--; 236 if (AllowNegative){ if (Value < -99)Value = 0; } 237 else{ if (Value < 0)Value = 0; } 238 } 239}; 240//-------------------------------------------- 241class TEncoderData 242{ 243private: 244 int R;// a variable 245 int Rold;// the old reading 246 int Rdif;// the difference since last loop 247 Quadrature *Encoder; 248 TTestDisplayData *TestData; 249 TDisplay *Disp; 250 251public: 252 TEncoderData(int _PinA, int _PinB, TDisplay *_Disp) 253 { 254 Encoder = new Quadrature(_PinA, _PinB); 255 TestData = new TTestDisplayData(); 256 Disp = _Disp; 257 } 258 void ReadEncoder(String IncCommand, String DecCommand) 259 { 260 R = (Encoder->position() / 2); //The /2 is to suit the encoder 261 if (R != Rold) { // checks to see if it different 262 (Rdif = (R - Rold));// finds out the difference 263 if (Rdif == 1) Serial.println(IncCommand); 264 if (Rdif == -1)Serial.println(DecCommand); 265 Rold = R; // overwrites the old reading with the new one. 266 Disp->SetTempValChange(true); 267 } 268 } 269 void ReadEncoder(TDisplay *Disp)//used for test program. 270 { 271 R = (Encoder->position() / 2); //The /2 is to suit the encoder 272 if (R != Rold) { // checks to see if it different 273 (Rdif = (R - Rold));// finds out the difference 274 if (Rdif == 1)TestData->Inc(); 275 if (Rdif == -1)TestData->Dec(true); 276 Rold = R; // overwrites the old reading with the new one. 277 Disp->UpdateDisplay(TestData->toString()); 278 } 279 } 280 void RefreshDisplay(TDisplay *Disp) 281 { 282 Disp->UpdateDisplay(TestData->toString()); 283 } 284}; 285//-------------------------------------------- 286class TBlinkLED 287{ 288private: 289 unsigned long BlinkDelayCounter; 290 int LEDIndex; 291 int NormalDelay; 292 int ActiveDelay; 293 bool BlinkTemp; 294public: 295 void Activate() 296 { 297 BlinkTemp = true; 298 BlinkDelayCounter = 0; 299 300 } 301 void deactivate() 302 { 303 BlinkTemp = false; 304 } 305 TBlinkLED(int _LEDIndex, int _NormalDelay, int _ActiveDelay) 306 { 307 LEDIndex = _LEDIndex; 308 NormalDelay = _NormalDelay; 309 ActiveDelay = _ActiveDelay; 310 BlinIndexArray[LEDIndex] = true; 311 } 312 void Blink(bool pressed) 313 { 314 if (millis() - BlinkDelayCounter > (pressed ? ActiveDelay : NormalDelay)) 315 { 316 BlinkLEDs = GetBlinkString(); 317 BlinkLEDs[LEDIndex] = BlinkTemp ? '1' : '0'; 318 SendLEDData(BlinkLEDs); 319 BlinkTemp = !BlinkTemp; 320 BlinkDelayCounter = millis(); 321 } 322 } 323 void DontBlink() 324 { 325 BlinkLEDs = GetBlinkString(); 326 BlinkLEDs[LEDIndex] = LEDString[LEDIndex]; 327 if (BlinkLEDs != OldLEDs) 328 { 329 SendLEDData(BlinkLEDs); 330 OldLEDs = BlinkLEDs; 331 } 332 } 333}; 334//-------------------------------------------- 335//----------------------- End of Classes ------------------------ 336String GetBlinkString() 337{ 338 String RetVal = "0000000000000000"; 339 for (int i = 0; i < 16; i++) 340 { 341 if (!BlinIndexArray[i])RetVal[i] = LEDString[i]; 342 else RetVal[i] = BlinkLEDs[i]; 343 } 344 return RetVal; 345} 346//----------------------- Interrupts ---------------------------- 347ISR(PCINT0_vect) // handle pin change interrupt for D8 to D13 here 348{ 349 interrupts(); 350 if (digitalRead(IRQ) == LOW) 351 { 352 353 tempVal = ReadSwitches(); 354 if (tempVal > 0) 355 { 356 if (TestProgram) //Execute Test Program when buttons are pressed. 357 { 358 if ((LEDString[4] != '1' || tempVal == 8) && tempVal != 1) 359 { 360 LEDString[SwLEDList[tempVal - 1]] = (LEDString[SwLEDList[tempVal - 1]] == '0' ? '1' : '0'); 361 SendLEDData(ShowRealValues ? BlinkLEDs : LEDString); 362 } 363 switch (tempVal) 364 { 365 case 1: 366 HoldTime = millis(); 367 break; 368 case 13: 369 resetFunc(); //exit test program 370 break; 371 case 5: 372 case 6: 373 case 7: 374 case 14: 375 case 15: 376 ShowZeros = (LEDString[12] == '1'); 377 ShowDP = (LEDString[11] == '1'&& LEDString[8] == '1' && LEDString[5] == '0'); 378 if (LEDString[9] == '0' && LEDString[10] == '1' && LEDString[8] == '1') 379 { 380 DispCtrl1.setFont(FONT_CODEB); 381 DispCtrl2.setFont(FONT_CODEB); 382 SpeedCtrl->RefreshDisplay(Displays[ESpeedDisp]); 383 ALTCtrl->RefreshDisplay(Displays[EALTDisp]); 384 VSCtrl->RefreshDisplay(Displays[EVSDisp]); 385 CrsCtrl->RefreshDisplay(Displays[ECrsDsip]); 386 HdgCtrl->RefreshDisplay(Displays[EHdgDisp]); 387 } 388 break; 389 case 8: 390 if (LEDString[4] == '1') 391 { 392 ShowRealValues = false; 393 LEDString = "1111111111111111"; 394 for (int i = 0; i < 8; i++)DispCtrl1.digitWrite(i, 8, (i == 6 || i == 1)); 395 for (int i = 0; i < 7; i++)DispCtrl2.digitWrite(i, 8, 1); 396 } 397 else 398 { 399 ShowDP = false; 400 LEDString = "0000000000000000"; 401 } 402 SendLEDData(LEDString); 403 break; 404 } 405 } 406 else if (Connected) //send commands to FSX 407 { 408 switch (tempVal) 409 { 410 case 1: //B/C Hold Button 411 HoldTime = millis(); 412 break; 413 case 2: //heading pressed, fixed bug where it captures real data. 414 Serial.println(LEDString[1] == '0' ? "Y111" : "Y121"); 415 break; 416 case 12:// alt pressed, fixed bug where it captures real data 417 Serial.println(LEDString[5] == '0' ? "Y091" : "Y101"); 418 break; 419 case 13://Level Button 420 Serial.println("B05"); 421 Serial.println("B05"); 422 Serial.println("B210000"); 423 break; 424 default: 425 Serial.println(FSXCommands[tempVal - 1]); 426 } 427 } 428 } 429 } 430 else if (Connected || TestProgram) 431 { 432 if (tempVal == 1) 433 { 434 if (millis() - HoldTime > 300) 435 { 436 BlinkLEDs = LEDString; 437 RealDataBlink->Activate(); 438 SpeedBlink->Activate(); 439 AltBlink->Activate(); 440 HdgBlink->deactivate(); 441 442 for (int i = 0; i < 5; i++)Displays[i]->SetTempValChange(false); 443 444 ShowRealValues = !ShowRealValues; 445 if (TestProgram){ 446 if (!ShowRealValues) 447 { 448 LEDString[3] == '0'; 449 SendLEDData(LEDString); 450 } 451 } 452 } 453 else 454 { 455 if (TestProgram) 456 { 457 LEDString[3] = LEDString[3] == '0' ? '1' : '0'; 458 SendLEDData(LEDString); 459 } 460 else 461 Serial.println("B09"); 462 } 463 } 464 } 465} 466//--------------------------------------------------------------- 467void setup() { 468 469 Serial.begin(115200); 470 pinMode(IRQ, INPUT); 471 pinMode(LED_DS, OUTPUT); 472 pinMode(LED_CLK, OUTPUT); 473 pinMode(LED_LTCH, OUTPUT); 474 475 DispCtrl1.setFont(FONT_CODEB); 476 DispCtrl2.setFont(FONT_CODEB); 477 DispCtrl1.setDecode(DECODE_ALL_FONT); 478 DispCtrl2.setDecode(DECODE_ALL_FONT); 479 480 MasterBattery = false; 481 482 Displays[ESpeedDisp] = new TDisplay(new byte[3]{3, 4, 5}, ESpeedDisp, &SpdData);; 483 Displays[EALTDisp] = new TDisplay(new byte[3]{0, 1, 2}, EALTDisp, &ALTData);; 484 Displays[EVSDisp] = new TDisplay(new byte[3]{14, 6, 7}, EVSDisp, &VSData);; 485 Displays[ECrsDsip] = new TDisplay(new byte[3]{8, 9, 10}, ECrsDsip, &CrsData);; 486 Displays[EHdgDisp] = new TDisplay(new byte[3]{11, 12, 13}, EHdgDisp, &HdgData);; 487 488 SpeedCtrl = new TEncoderData(SpdEnc_A, SpdEnc_B, Displays[ESpeedDisp]); 489 ALTCtrl = new TEncoderData(ALTEnc_A, ALTEnc_B, Displays[EALTDisp]); 490 VSCtrl = new TEncoderData(VSEnc_A, VSEnc_B, Displays[EVSDisp]); 491 HdgCtrl = new TEncoderData(HdgEnc_A, HdgEnc_B, Displays[EHdgDisp]); 492 CrsCtrl = new TEncoderData(CrsEnc_A, CrsEnc_B, Displays[ECrsDsip]); 493 494 RealDataBlink = new TBlinkLED(3, 250, 125); 495 SpeedBlink = new TBlinkLED(13, 125, 250); 496 AltBlink = new TBlinkLED(5, 130, 250); 497 HdgBlink = new TBlinkLED(1, 135, 250); 498 499 SwitchCtrl.begin(); 500 DispCtrl1.begin(); 501 DispCtrl2.begin(); 502 delay(500); 503 504 DispCtrl1.setIntensity(0x0F); 505 DispCtrl2.setIntensity(0x0F); 506 507 InitLEDs(1); 508 509 if (SwitchCtrl.ReadKeys(NULL) == 13)//go to test program 510 { 511 TestProgram = true; 512 TestLEDs(50); 513 SendLEDData("0000000000000000"); 514 } 515 pciSetup(IRQ); 516 517 if (TestProgram)InitLEDs(2); 518} 519//------------------------------------------------------------------------------------------------------------------------------------------ 520void loop() { 521 if (TestProgram) 522 { 523 if (LEDString[4] == '0') 524 { 525 if (LEDString[8] == '1') 526 { 527 if (LEDString[9] == '1') 528 { 529 for (int i = 0; i < 5; i++)Displays[i]->UpdateDisplay(String(random(0, 1000))); 530 delay(200); 531 } 532 else if (LEDString[10] == '1') 533 { 534 SpeedCtrl->ReadEncoder(Displays[ESpeedDisp]); 535 ALTCtrl->ReadEncoder(Displays[EALTDisp]); 536 VSCtrl->ReadEncoder(Displays[EVSDisp]); 537 CrsCtrl->ReadEncoder(Displays[ECrsDsip]); 538 HdgCtrl->ReadEncoder(Displays[EHdgDisp]); 539 } 540 else { 541 DispCtrl1.setFont(FONT_HEX); 542 DispCtrl2.setFont(FONT_HEX); 543 544 for (int i = 0; i < 8; i++) 545 if (DispCtrl1.digitWrite(i, i, 0) >= 4) 546 { 547 Serial.println("I2C Froze"); 548 I2C_ClearBus(); 549 Wire.begin(); 550 DispCtrl1.begin(); 551 DispCtrl2.begin(); 552 } 553 for (int i = 0; i < 7; i++) 554 if (DispCtrl2.digitWrite(i, i + 8, ShowZeros) >= 4) 555 { 556 Serial.println("I2C Froze"); 557 I2C_ClearBus(); 558 Wire.begin(); 559 DispCtrl1.begin(); 560 DispCtrl2.begin(); 561 } 562 delay(200); 563 } 564 } 565 else 566 { 567 DispCtrl1.setFont(FONT_CODEB); 568 DispCtrl2.setFont(FONT_CODEB); 569 ShowZeros = false; 570 for (int i = 0; i < 5; i++)Displays[i]->ClearDisplay(); 571 delay(200); 572 } 573 } 574 if (ShowRealValues) 575 { 576 RealDataBlink->Blink(LEDString[3] == '1'); 577 if (LEDString[13] == '1')SpeedBlink->Blink(false); 578 if (LEDString[5] == '1')AltBlink->Blink(false); 579 if (LEDString[1] == '1')HdgBlink->Blink(false); 580 } 581 } 582 else //real program 583 { 584 {ENCODER(); } //Check the Rotary Encoders 585 if (Serial.available()) 586 { //Check if anything there 587 CodeIn = getChar(); //Get a serial read if there is. 588 if (CodeIn == '=') { EQUALS(); Connected = true; } // The first identifier is "=" ,, goto void EQUALS 589 else if (CodeIn == '?') { QUESTION(); Connected = true; }// The first identifier is "?" ,, goto void QUESTION 590 else if (CodeIn == '<') { LESSTHAN(); Connected = true; }// The first identifier is "?" ,, goto void QUESTION 591 else 592 { 593 String ReadBuffer = ""; 594 while (Serial.available())ReadBuffer += char(Serial.read());// Empties the buffer use to show ReadBuffer += char(Serial.read()); 595 if (ReadBuffer.length() > 0) 596 { 597 Serial.println("--------------------------"); 598 Serial.println(ReadBuffer); 599 Serial.println("--------------------------"); 600 } 601 } 602 for (int i = 0; i < 5; i++)Displays[i]->UpdateDisplay(); 603 } 604 605 if (ShowRealValues != OldShowRealValues) 606 { 607 OldShowRealValues = ShowRealValues; 608 for (int i = 0; i < 5; i++)Displays[i]->UpdateDisplay(); 609 } 610 611 if (ShowRealValues && MasterBattery) 612 { 613 RealDataBlink->Blink(LEDString[3] == '1'); 614 615 if (LEDString[13] == '1' && SpdData.ReadMem != SpdData.SetMem)SpeedBlink->Blink(false); 616 else SpeedBlink->DontBlink(); 617 618 if (LEDString[5] == '1' && VSData.ReadMem.substring(1, 3) != "00")AltBlink->Blink(false); 619 else AltBlink->DontBlink(); 620 621 if (LEDString[1] == '1' && HdgData.ReadMem != HdgData.SetMem && !(HdgData.ReadMem == "360" && HdgData.SetMem == "000"))HdgBlink->Blink(false); 622 else HdgBlink->DontBlink(); 623 } 624 else 625 if (LEDString != OldLEDs) 626 { 627 SendLEDData(LEDString); 628 OldLEDs = LEDString; 629 } 630 631 for (int i = 0; i < 5; i++)Displays[i]->CheckTempDisplay(); 632 } 633} 634//------------------------------------------------------------------------------------------------------------------------------------------ 635char getChar()// Get a character from the serial buffer 636{ 637 TimeOutCheck = millis(); 638 while (Serial.available() == 0) 639 if (millis() - TimeOutCheck > SerialTimeout)return '0';//time out command 640 return((char)Serial.read()); 641} 642//------------------------------------------------------------------------------------------------------------------------------------------ 643void SendLEDData(String data) 644{ 645 digitalWrite(LED_LTCH, HIGH); 646 digitalWrite(LED_LTCH, LOW); 647 digitalWrite(LED_LTCH, HIGH); 648 for (int i = 15; i >= 0; i--) 649 { 650 digitalWrite(LED_DS, (data[i] == '1' ? HIGH : LOW)); 651 digitalWrite(LED_CLK, LOW); 652 digitalWrite(LED_CLK, HIGH); 653 } 654 digitalWrite(LED_LTCH, LOW); 655 digitalWrite(LED_LTCH, HIGH); //fix for double send 656 digitalWrite(LED_LTCH, LOW); 657 658} 659//------------------------------------------------------------------------------------------------------------------------------------------ 660void pciSetup(byte pin) 661{ 662 *digitalPinToPCMSK(pin) |= bit(digitalPinToPCMSKbit(pin)); // enable pin 663 PCIFR |= bit(digitalPinToPCICRbit(pin)); // clear any outstanding interrupt 664 PCICR |= bit(digitalPinToPCICRbit(pin)); // enable interrupt for the group 665} 666//------------------------------------------------------------------------------------------------------------------------------------------ 667int ReadSwitches() 668{ 669 uint8_t ErrorCode; 670 int val = SwitchCtrl.ReadKeys(&ErrorCode); 671 if (ErrorCode >= 4) 672 { 673 Serial.println("I2C Froze (Switches)"); 674 I2C_ClearBus(); 675 Wire.begin(); 676 DispCtrl1.begin(); 677 DispCtrl2.begin(); 678 SwitchCtrl.begin(); 679 } 680 if (val > 0 && val < 255) 681 return val; 682 return 0; 683} 684//------------------------------------------------------------------------------------------------------------------------------------------ 685void TestLEDs(int D) 686{ 687 for (int i = 1; i < 15; i++) 688 { 689 if (i == 6 || i == 7 || i == 15 || i == 0)continue; 690 String temp = ""; 691 for (int j = 0; j < 16; j++) temp += (j == i ? "1" : "0"); 692 SendLEDData(temp); 693 delay(D); 694 } 695 for (int i = 13; i >= 2; i--) 696 { 697 if (i == 6 || i == 7 || i == 15 || i == 0)continue; 698 String temp = ""; 699 for (int j = 0; j < 15; j++) temp += (j == i ? "1" : "0"); 700 SendLEDData(temp); 701 delay(D); 702 } 703} 704//------------------------------------------------------------------------------------------------------------------------------------------ 705void InitLEDs(int count) 706{ 707 int _Delay = 300; 708 for (int i = 1; i <= count; i++) 709 { 710 SendLEDData("1111111111111111"); 711 delay(_Delay); 712 SendLEDData("0000000000000000"); 713 delay(_Delay); 714 } 715} 716//------------------------------------------------------------------------------------------------------------------------------------------ 717void EQUALS(){ 718 CodeIn = getChar(); 719 switch (CodeIn) { 720 case 'a': LEDString[8] = getChar(); break; //Master AP 721 case 'k': LEDString[5] = getChar(); break; //Altitude Hold 722 case 'm': LEDString[4] = getChar(); break; //App hold 723 case 'o': LEDString[2] = getChar(); break; //Loc (Nav) Hold 724 case 'n': LEDString[3] = getChar(); break; //B/C hold 725 case 'j': LEDString[1] = getChar(); break; //Heading Hold 726 case 'q': LEDString[11] = getChar(); break; //Flight Director 727 case 'v': LEDString[14] = getChar(); break; //Take-Off Power 728 case 'b': ALTData.SetMem = GetBufferValue(5); break; //ALT Set 729 case 'f': SpdData.SetMem = GetBufferValue(3); break; //Speed Set 730 case 'c': VSData.SetMem = GetBufferValue(5); break; //Vertical Speed Set 731 case 'd': HdgData.SetMem = GetBufferValue(3); break; //Heading Set 732 case 'e': CrsData.SetMem = GetBufferValue(3); CrsData.ReadMem = CrsData.SetMem; break; //Course Set 733 case 't': //ATHR 734 ATHRMeM = getChar(); 735 if (MasterBattery)LEDString[12] = ATHRMeM; 736 break; 737 case 'l': //GPS-NAV 738 navMeM = getChar(); 739 if (MasterBattery) 740 { 741 LEDString[9] = navMeM; 742 LEDString[10] = (LEDString[9] == '0' ? '1' : '0'); 743 } 744 break; 745 case 's': //Speed Hold 746 SpeedMeM = getChar(); 747 if (MasterBattery)LEDString[13] = SpeedMeM; 748 break; 749 } 750} 751//------------------------------------------------------------------------------------------------------------------------------------------ 752void QUESTION(){ // The first identifier was "?" 753 CodeIn = getChar(); 754 switch (CodeIn) { 755 case 'U': // Bus Voltage 756 String buff = GetBufferValue(2); 757 getChar(); 758 getChar(); 759 if (buff.toInt() == 0)//plain's turned off 760 { 761 MasterBattery = false; 762 LEDString[9] = '0'; 763 LEDString[10] = '0'; 764 LEDString[12] = '0'; 765 LEDString[13] = '0'; 766 for (int i = 0; i < 5; i++)Displays[i]->UpdateDisplay("000"); 767 } 768 else 769 { 770 MasterBattery = true; 771 LEDString[9] = navMeM; 772 LEDString[10] = (LEDString[9] == '0' ? '1' : '0'); 773 LEDString[12] = ATHRMeM; 774 LEDString[13] = SpeedMeM; 775 for (int i = 0; i < 5; i++)Displays[i]->UpdateDisplay(); 776 } 777 } 778} 779void LESSTHAN() 780{ 781 CodeIn = getChar(); 782 switch (CodeIn) 783 { 784 case 'D': ALTData.ReadMem = GetBufferValue(5); break; //ALT Read 785 case 'P': SpdData.ReadMem = GetBufferValue(3); break; //Speed Read 786 case 'J': HdgData.ReadMem = GetBufferValue(3); break; //Heading Read 787 case 'L': //Vertical Speed Read 788 VSData.ReadMem = GetBufferValue(6); 789 VSData.ReadMem = VSData.ReadMem[0] + VSData.ReadMem.substring(2, 6); 790 break; 791 } 792} 793//------------------------------------------------------------------------------------------------------------------------------------------ 794void ENCODER(){ 795 796 SpeedCtrl->ReadEncoder("B15", "B16"); 797 ALTCtrl->ReadEncoder("B11", "B12"); 798 VSCtrl->ReadEncoder("B13", "B14"); 799 HdgCtrl->ReadEncoder("A57", "A58"); 800 CrsCtrl->ReadEncoder("A56", "A55"); 801} 802//------------------------------------------------------------------------------------------------------------------------------------------ 803String GetBufferValue(int byteCount) 804{ 805 String buff = ""; 806 char temp; 807 for (int i = 0; i < byteCount; i++) 808 { 809 temp = getChar(); 810 if ((temp <= '9' && temp >= '0') || temp == '-' || temp == '+' || temp == '.') 811 buff += temp; 812 else 813 buff += '0'; 814 } 815 816 //Serial.println(buff); 817 818 return buff; 819} 820//------------------------------------------------------------------------------------------------------------------------------------------ 821uint8_t I2C_ClearBus() { 822#if defined(TWCR) && defined(TWEN) 823 TWCR &= ~(_BV(TWEN)); //Disable the Atmel 2-Wire interface so we can control the SDA and SCL pins directly 824#endif 825 826 pinMode(SDA, INPUT_PULLUP); // Make SDA (data) and SCL (clock) pins Inputs with pullup. 827 pinMode(SCL, INPUT_PULLUP); 828 delay(200); 829 830 boolean SCL_LOW = (digitalRead(SCL) == LOW); // Check is SCL is Low. 831 if (SCL_LOW) { //If it is held low Arduno cannot become the I2C master. 832 return 1; //I2C bus error. Could not clear SCL clock line held low 833 } 834 835 boolean SDA_LOW = (digitalRead(SDA) == LOW); // vi. Check SDA input. 836 int clockCount = 20; // > 2x9 clock 837 838 while (SDA_LOW && (clockCount > 0)) { // vii. If SDA is Low, 839 clockCount--; 840 // Note: I2C bus is open collector so do NOT drive SCL or SDA high. 841 pinMode(SCL, INPUT); // release SCL pullup so that when made output it will be LOW 842 pinMode(SCL, OUTPUT); // then clock SCL Low 843 delayMicroseconds(10); // for >5uS 844 pinMode(SCL, INPUT); // release SCL LOW 845 pinMode(SCL, INPUT_PULLUP); // turn on pullup resistors again 846 // do not force high as slave may be holding it low for clock stretching. 847 delayMicroseconds(10); // for >5uS 848 // The >5uS is so that even the slowest I2C devices are handled. 849 SCL_LOW = (digitalRead(SCL) == LOW); // Check if SCL is Low. 850 int counter = 20; 851 while (SCL_LOW && (counter > 0)) { // loop waiting for SCL to become High only wait 2sec. 852 counter--; 853 delay(100); 854 SCL_LOW = (digitalRead(SCL) == LOW); 855 } 856 if (SCL_LOW) { // still low after 2 sec error 857 return 2; // I2C bus error. Could not clear. SCL clock line held low by slave clock stretch for >2sec 858 } 859 SDA_LOW = (digitalRead(SDA) == LOW); // and check SDA input again and loop 860 } 861 if (SDA_LOW) { // still low 862 return 3; // I2C bus error. Could not clear. SDA data line held low 863 } 864 865 // else pull SDA line low for Start or Repeated Start 866 pinMode(SDA, INPUT); // remove pullup. 867 pinMode(SDA, OUTPUT); // and then make it LOW i.e. send an I2C Start or Repeated start control. 868 // When there is only one I2C master a Start or Repeat Start has the same function as a Stop and clears the bus. 869 /// A Repeat Start is a Start occurring after a Start with no intervening Stop. 870 delayMicroseconds(10); // wait >5uS 871 pinMode(SDA, INPUT); // remove output low 872 pinMode(SDA, INPUT_PULLUP); // and make SDA high i.e. send I2C STOP control. 873 delayMicroseconds(10); // x. wait >5uS 874 pinMode(SDA, INPUT); // and reset pins as tri-state inputs which is the default state on reset 875 pinMode(SCL, INPUT); 876 Serial.println("I2C Recovered"); 877 return 0; // all ok 878} 879//------------------------------------------------------------------------------------------------------------------------------------------
GPS firmware
arduino
1/****************************************************************************************/ 2/* */ 3/* GPS | �Kantooya */ 4/* */ 5/* Author: Sam Farah */ 6/* Email: sam.farah1986@gmail.com */ 7/* Website: http://samfarah.net */ 8/* Version: 1.0 */ 9/* Description: */ 10/* The firmware for the ATMega microcontroller on board, it controls */ 11/* the circuit, and handles reading inputs and sends commands to FSX. */ 12/* */ 13/****************************************************************************************/ 14 15//-------------------------- Headers ---------------------------- 16#include <Quadrature.h> 17#include <AS1115.h> 18#include <WSWire.h> 19//--------------------------------------------------------------- 20 21//---------------------------- Pins ----------------------------- 22// Name Arduino Pin Pin on ATMega 23// ----------- ----------- ------------- 24#define IRQ1 A0 // 25#define Encoder1A A3 // 26#define Encoder1B A2 // 27#define Encoder2A 8 // 28#define Encoder2B 9 // 29//--------------------------------------------------------------- 30 31//------------------------ SETTINGS ----------------------------- 32#define HoldDelay 700 33//--------------------------------------------------------------- 34 35//----------------------- Prototypes ---------------------------- 36class TSwitchCtrl; 37uint8_t I2C_ClearBus(); 38//--------------------------------------------------------------- 39 40//------------------------- Objects ----------------------------- 41Quadrature Encoder1(Encoder1A, Encoder1B); 42Quadrature Encoder2(Encoder2A, Encoder2B); 43TSwitchCtrl *SwitchCtr; 44AS1115 *SwitchCtr1; 45//--------------------------------------------------------------- 46 47//---------------------- Public Variables ----------------------- 48int R1old; 49int R2old; 50int R1dif; 51int R2dif; 52unsigned long int HoldTime = 0; 53bool ClearPressed = false; 54//--------------------------------------------------------------- 55 56//-------------------------- Classes ---------------------------- 57class TSwitchCtrl 58{ 59private: 60 AS1115 * Chip; 61 String Data; 62 String OldData; 63public: 64 byte IRQ; 65 byte LSB, MSB; 66 TSwitchCtrl(uint8_t _IRQ, AS1115 *_Chip, uint8_t _LSB, uint8_t _MSB) 67 { 68 IRQ = _IRQ; 69 Chip = _Chip; 70 LSB = _LSB; 71 MSB = _MSB; 72 Data = ""; 73 Chip->begin(0x03,0x00); 74 } 75 void ReadSwitchs() 76 { 77 uint8_t ErrorCode; 78 OldData = Data; 79 Data = Chip->ReadKeysMul(&ErrorCode);// GetLeadingZeros(, 16);//potentially not needed (the Leading Zeros, already handled from library) 80 if (ErrorCode >= 4) 81 { 82 I2C_ClearBus(); 83 Wire.begin(); 84 } 85 } 86 String GetData() { return Data; } 87 String GetOldData() { return OldData; } 88}; 89//--------------------------------------------------------------- 90 91//------------------------ Functions ----------------------------- 92String GetLeadingZeros(String Bin, short digits) 93{ 94 String Padding = ""; 95 for (int i = 0; i < digits - Bin.length(); i++)Padding += "0"; 96 return Padding + Bin; 97} 98//--------------------------------------------------------------- 99 100//----------------------- Interrupt ---------------------------- 101ISR(PCINT1_vect) // handle pin change interrupt for D8 to D13 here 102{ 103 interrupts(); 104 if (digitalRead(SwitchCtr->IRQ) == LOW) 105 { 106 107 SwitchCtr->ReadSwitchs(); 108 byte ChangedIndex = 0; 109 char NewValue, InverseValue; 110 for (byte i = 0; i < 16; i++) 111 if (SwitchCtr->GetData()[i] != SwitchCtr->GetOldData()[i]) 112 { 113 NewValue = SwitchCtr->GetData()[i]; 114 InverseValue = NewValue == '0' ? '1' : '0'; 115 ChangedIndex = i; 116 } 117 //Serial.println(ChangedIndex); 118 //if (!MasterPower && ChangedIndex != 20) return;//if powered off, only listen to power swtich. 119 if (NewValue == '1') //push buttons 120 { 121 switch (ChangedIndex) 122 { 123 case 1: Serial.println("G11"); break; 124 case 2: Serial.println("G10"); break; 125 case 3: Serial.println("G12"); break; 126 case 4: Serial.println("G13"); break; 127 case 5: HoldTime = millis(); ClearPressed = true; break; 128 case 6: Serial.println("G18"); break; 129 case 7: Serial.println("G19"); break; 130 case 9: Serial.println("G02"); break; 131 case 10: Serial.println("G03"); break; 132 case 11: Serial.println("G04"); break; 133 case 12: Serial.println("G07"); break; 134 case 13: Serial.println("G08"); break; 135 case 14: Serial.println("G09"); break; 136 } 137 } 138 else 139 { 140 if (ChangedIndex == 5) 141 { 142 ClearPressed = false; 143 if (millis() - HoldTime < HoldDelay)Serial.println("G14"); 144 } 145 } 146 } 147} 148 149//****************************************************************************************************************************************** 150void setup() { 151 pinMode(IRQ1, INPUT_PULLUP); 152 Serial.begin(115200); 153 SwitchCtr1 = new AS1115(0x00); 154 SwitchCtr = new TSwitchCtrl(IRQ1, SwitchCtr1, 0, 15); 155 delay(50); 156 pciSetup(IRQ1); 157 delay(50); 158 SwitchCtr->ReadSwitchs(); 159 SwitchCtr->GetData(); 160} 161 162void loop() { 163 ENCODER(); 164 if (ClearPressed == true && millis() - HoldTime >= HoldDelay) 165 { 166 Serial.println("G15"); 167 ClearPressed = false; 168 } 169} 170//****************************************************************************************************************************************** 171 172//------------------------------------------------------------------------------------------------------------------------------------------ 173void pciSetup(byte pin) 174{ 175 *digitalPinToPCMSK(pin) |= bit(digitalPinToPCMSKbit(pin)); // enable pin 176 PCIFR |= bit(digitalPinToPCICRbit(pin)); // clear any outstanding interrupt 177 PCICR |= bit(digitalPinToPCICRbit(pin)); // enable interrupt for the group 178} 179//------------------------------------------------------------------------------------------------------------------------------------------ 180void ENCODER() { 181 int R1 = (Encoder1.position()); //The /2 is to suit the encoder 182 if (R1 != R1old) { // checks to see if it different 183 (R1dif = (R1 - R1old));// finds out the difference 184 //Serial.println(Encoder1.position()); 185 if (R1dif == 1) Serial.println("G22"); 186 if (R1dif == -1)Serial.println("G23"); 187 R1old = R1; // overwrites the old reading with the new one. 188 //Disp->SetTempValChange(true); 189 } 190 int R2 = (Encoder2.position()); //The /2 is to suit the encoder 191 if (R2 != R2old) { // checks to see if it different 192 (R2dif = (R2 - R2old));// finds out the difference 193 if (R2dif == 1) Serial.println("G20"); 194 if (R2dif == -1)Serial.println("G21"); 195 R2old = R2; // overwrites the old reading with the new one. 196 //Disp->SetTempValChange(true); 197 } 198 199} 200//------------------------------------------------------------------------------------------------------------------------------------------ 201uint8_t I2C_ClearBus() { 202#if defined(TWCR) && defined(TWEN) 203 TWCR &= ~(_BV(TWEN)); //Disable the Atmel 2-Wire interface so we can control the SDA and SCL pins directly 204#endif 205 206 pinMode(SDA, INPUT_PULLUP); // Make SDA (data) and SCL (clock) pins Inputs with pullup. 207 pinMode(SCL, INPUT_PULLUP); 208 delay(20); 209 210 boolean SCL_LOW = (digitalRead(SCL) == LOW); // Check is SCL is Low. 211 if (SCL_LOW) { //If it is held low Arduno cannot become the I2C master. 212 return 1; //I2C bus error. Could not clear SCL clock line held low 213 } 214 215 boolean SDA_LOW = (digitalRead(SDA) == LOW); // vi. Check SDA input. 216 int clockCount = 20; // > 2x9 clock 217 218 while (SDA_LOW && (clockCount > 0)) { // vii. If SDA is Low, 219 clockCount--; 220 // Note: I2C bus is open collector so do NOT drive SCL or SDA high. 221 pinMode(SCL, INPUT); // release SCL pullup so that when made output it will be LOW 222 pinMode(SCL, OUTPUT); // then clock SCL Low 223 delayMicroseconds(10); // for >5uS 224 pinMode(SCL, INPUT); // release SCL LOW 225 pinMode(SCL, INPUT_PULLUP); // turn on pullup resistors again 226 // do not force high as slave may be holding it low for clock stretching. 227 delayMicroseconds(10); // for >5uS 228 // The >5uS is so that even the slowest I2C devices are handled. 229 SCL_LOW = (digitalRead(SCL) == LOW); // Check if SCL is Low. 230 int counter = 20; 231 while (SCL_LOW && (counter > 0)) { // loop waiting for SCL to become High only wait 2sec. 232 counter--; 233 delay(50); 234 SCL_LOW = (digitalRead(SCL) == LOW); 235 } 236 if (SCL_LOW) { // still low after 2 sec error 237 return 2; // I2C bus error. Could not clear. SCL clock line held low by slave clock stretch for >2sec 238 } 239 SDA_LOW = (digitalRead(SDA) == LOW); // and check SDA input again and loop 240 } 241 if (SDA_LOW) { // still low 242 return 3; // I2C bus error. Could not clear. SDA data line held low 243 } 244 245 // else pull SDA line low for Start or Repeated Start 246 pinMode(SDA, INPUT); // remove pullup. 247 pinMode(SDA, OUTPUT); // and then make it LOW i.e. send an I2C Start or Repeated start control. 248 // When there is only one I2C master a Start or Repeat Start has the same function as a Stop and clears the bus. 249 // A Repeat Start is a Start occurring after a Start with no intervening Stop. 250 delayMicroseconds(10); // wait >5uS 251 pinMode(SDA, INPUT); // remove output low 252 pinMode(SDA, INPUT_PULLUP); // and make SDA high i.e. send I2C STOP control. 253 delayMicroseconds(10); // x. wait >5uS 254 pinMode(SDA, INPUT); // and reset pins as tri-state inputs which is the default state on reset 255 pinMode(SCL, INPUT); 256 //Serial.println("I2C Recovered"); 257 return 0; // all ok 258} 259//------------------------------------------------------------------------------------------------------------------------------------------ 260
Radio Stack Firmware
arduino
1/****************************************************************************************/ 2/* */ 3/* Radiostack 125-PB | ©Kantooya */ 4/* */ 5/* Author: Sam Farah */ 6/* Email: sam.farah1986@gmail.com */ 7/* Website: http://samfarah.net */ 8/* Version: 1.0 */ 9/* Description: */ 10/* The firmware for the ATMega microcontroller on board, it controls */ 11/* the circuit, and handles reading inputs and sends commands to FSX. */ 12/* */ 13/****************************************************************************************/ 14 15//-------------------------- Headers ---------------------------- 16#include <AS1115.h> 17#include "WSWire.h" 18#include "math.h" 19#include "Quadrature.h" //for rotary encoders 20#include <MemoryFree.h> 21#include <avr/pgmspace.h> 22//--------------------------------------------------------------- 23 24//---------------------------- Pins ----------------------------- 25// Name Arduino Pin Pin on ATMega 26// ----------- ----------- ------------- 27#define LED1_DS 2 // PD2 28#define LED1_CLK 3 // PD3 29#define LED1_LTCH 4 // PD4 30#define LED2_DS 5 // PD5 31#define LED2_CLK 6 // PD6 32#define LED2_LTCH 7 // PD7 33#define FrqEnc_A 8 // 34#define FrqEnc_B 9 // 35#define IRQ1 11 // 36#define IRQ2 12 // 37#define IRQ3 13 // 38#define SDA A4 // 39#define SCL A5 // 40//--------------------------------------------------------------- 41 42//------------------------- Settings ---------------------------- 43#define SerialTimeout 1000 44#define TempDelay 3000 45#define TWI_FREQ 50L 46//--------------------------------------------------------------- 47 48//-------------------------- Enums ------------------------------ 49enum EDispID{ EActiveDisp = 0, EStdByDisp = 1, EATCDisp = 2 }; 50enum EChannel{ COM1 = 0, COM2 = 1, NAV1 = 2, NAV2 = 3, ADF = 4 }; 51//--------------------------------------------------------------- 52 53//----------------------- Prototypes ---------------------------- 54class SDisplayData; 55class TDisplay; 56class TEncoderData; 57class TSwitchCtrl; 58class TChannel; 59//--------------------------------------------------------------- 60 61//------------------------- Objects ----------------------------- 62AS1115 DispCtrl1 = AS1115(0x01), DispCtrl2 = AS1115(0x02); 63AS1115 *SwitchCtr1 = new AS1115(0x03), *SwitchCtr2 = &DispCtrl2, *SwitchCtr3 = new AS1115(0x00); 64TEncoderData *FreqCtrl; 65TChannel *Channel[5]; 66//--------------------------------------------------------------- 67 68//---------------------- Public Variables ----------------------- 69String LEDString = ""; 70TDisplay *Displays[3]; 71TSwitchCtrl *SwitchCtrs[3]; 72byte tempDigitIndex, CodeIn; 73unsigned long TimeOutCheck; 74bool MHz = true, MasterPower = false; 75uint8_t SelectedMode; 76bool ATCMode; 77char temp; 78short mul; 79//--------------------------------------------------------------- 80 81//-------------------------- Classes ---------------------------- 82class TChannel 83{ 84public: 85 char MHzIncCommand[4]; 86 char MHzDecCommand[4]; 87 char KHzIncCommand[4]; 88 char KHzDecCommand[4]; 89 char SwapCommand[4]; 90 char CallCommand[4]; 91 String Active; 92 String Standby; 93 uint8_t Status; 94 uint8_t LEDIndex; 95 96 TChannel(char MHzUp[], char MHzDown[], char KHzUp[], char KHzDown[], char Swap[], char call[], uint8_t LED, uint8_t StatLED) 97 { 98 strcpy(MHzIncCommand, strcat(MHzUp, "\\0")); 99 strcpy(MHzDecCommand, strcat(MHzDown, "\\0")); 100 strcpy(KHzIncCommand, strcat(KHzUp, "\\0")); 101 strcpy(KHzDecCommand, strcat(KHzDown, "\\0")); 102 strcpy(SwapCommand, strcat(Swap, "\\0")); 103 strcpy(CallCommand, strcat(call, "\\0")); 104 105 Status = StatLED; 106 LEDIndex = LED; 107 } 108}; 109//--------------------------------------------------------------- 110class TDisplay 111{ 112private: 113 byte *Index; 114 byte DigitCount; 115 EDispID ID; 116 bool TempValChange; 117 unsigned long LastTempChange; 118 119 void SendValues(byte index, char value, bool ShowDP) 120 { 121 AS1115 *CurrentDriver = index > 7 ? &DispCtrl2 : &DispCtrl1; 122 index %= 8; 123 if (CurrentDriver->digitWrite(index, value, ShowDP)) 124 { 125 // Serial.println("I2C Froze (Displays)"); 126 I2C_ClearBus(); 127 Wire.begin(); 128 } 129 } 130public: 131 String Data, TempData; 132 TDisplay(byte *_Index, EDispID _ID, byte _DigitCount) 133 { 134 Index = _Index; 135 DigitCount = _DigitCount; 136 ID = _ID; 137 UpdateDisplay(" "); 138 TempValChange = false; 139 TempData = ""; 140 } 141 void CheckTempDisplay() 142 { 143 if (TempValChange && millis() - LastTempChange > TempDelay) 144 { 145 TempValChange = false; 146 UpdateDisplay(); 147 tempDigitIndex = 0; 148 } 149 } 150 void UpdateDisplay(){ UpdateDisplay(TempValChange ? TempData : Data); } 151 void UpdateDisplay(String Val) 152 { 153 uint8_t DPFound = 0; 154 for (byte i = 0; i < DigitCount + DPFound; i++) 155 { 156 if (Val[i] == '.') 157 { 158 SendValues(Index[i - 1], Val[i - 1], true); 159 DPFound++; 160 } 161 else SendValues(Index[i - DPFound], Val[i], false); 162 } 163 } 164 void ClearDisplay(){ UpdateDisplay(" "); } 165 EDispID GetID(){ return ID; } 166 void SetTempValChange(bool val) 167 { 168 TempValChange = val; 169 LastTempChange = millis(); 170 } 171}; 172//-------------------------------------------- 173class TEncoderData 174{ 175private: 176 int R;// a variable 177 int Rold;// the old reading 178 int Rdif;// the difference since last loop 179 Quadrature *Encoder; 180 TDisplay *Disp; 181 182public: 183 TEncoderData(uint8_t _PinA, uint8_t _PinB, TDisplay *_Disp) 184 { 185 pinMode(_PinA, INPUT); 186 pinMode(_PinB, INPUT); 187 Encoder = new Quadrature(_PinA, _PinB); 188 Disp = _Disp; 189 } 190 void ReadEncoder(String IncCommand, String DecCommand) 191 { 192 R = (Encoder->position() / 2); //The /2 is to suit the encoder 193 if (R != Rold) { // checks to see if it different 194 (Rdif = (R - Rold));// finds out the difference 195 if (Rdif == 1) Serial.println(IncCommand); 196 if (Rdif == -1)Serial.println(DecCommand); 197 Rold = R; // overwrites the old reading with the new one. 198 } 199 } 200 void ReadEncoder() 201 { 202 R = (Encoder->position() / 2); //The /2 is to suit the encoder 203 if (R != Rold) { // checks to see if it different 204 (Rdif = (R - Rold));// finds out the difference 205 if (Rdif == 1) 206 { 207 switch (mul) 208 { 209 case 0:Serial.println("A28"); break; 210 case 1:Serial.println("A27"); break; 211 case 2:Serial.println("A26"); break; 212 case 3:Serial.println("A25"); break; 213 } 214 } 215 if (Rdif == -1) 216 { 217 switch (mul) 218 { 219 case 0:Serial.println("A32"); break; 220 case 1:Serial.println("A31"); break; 221 case 2:Serial.println("A30"); break; 222 case 3:Serial.println("A29"); break; 223 } 224 } 225 Rold = R; // overwrites the old reading with the new one. 226 } 227 } 228}; 229//-------------------------------------------- 230class TSwitchCtrl 231{ 232private: 233 AS1115 *Chip; 234 String Data; 235 String OldData; 236public: 237 byte IRQ; 238 byte LSB, MSB; 239 TSwitchCtrl(uint8_t _IRQ, AS1115 *_Chip, uint8_t _LSB, uint8_t _MSB) 240 { 241 IRQ = _IRQ; 242 Chip = _Chip; 243 LSB = _LSB; 244 MSB = _MSB; 245 Data = ""; 246 Chip->begin(); 247 } 248 void ReadSwitchs() 249 { 250 uint8_t ErrorCode; 251 OldData = Data; 252 Data = GetLeadingZeros(Chip->ReadKeysMul(&ErrorCode), 16);//potentially not needed (the Leading Zeros, already handled from library) 253 if (ErrorCode >= 4) 254 { 255 I2C_ClearBus(); 256 Wire.begin(); 257 } 258 } 259 String GetData(){ return Data; } 260 String GetOldData(){ return OldData; } 261}; 262//-------------------------------------------- 263void pciSetup(byte pin) 264{ 265 *digitalPinToPCMSK(pin) |= bit(digitalPinToPCMSKbit(pin)); // enable pin 266 PCIFR |= bit(digitalPinToPCICRbit(pin)); // clear any outstanding interrupt 267 PCICR |= bit(digitalPinToPCICRbit(pin)); // enable interrupt for the group 268} 269//----------------------- Interrupt ---------------------------- 270ISR(PCINT0_vect) // handle pin change interrupt for D8 to D13 here 271{ 272 interrupts(); 273 for (byte SwtchCtrlIndex = 0; SwtchCtrlIndex < 3; SwtchCtrlIndex++) 274 if (digitalRead(SwitchCtrs[SwtchCtrlIndex]->IRQ) == LOW) 275 { 276 SwitchCtrs[SwtchCtrlIndex]->ReadSwitchs(); 277 byte ChangedIndex = 0; 278 char NewValue, InverseValue; 279 for (byte i = 0; i < 16; i++) 280 if (SwitchCtrs[SwtchCtrlIndex]->GetData()[i] != SwitchCtrs[SwtchCtrlIndex]->GetOldData()[i]) 281 { 282 NewValue = SwitchCtrs[SwtchCtrlIndex]->GetData()[i]; 283 InverseValue = NewValue == '0' ? '1' : '0'; 284 //Serial.println(String(48 - i - SwitchCtrs[SwtchCtrlIndex]->LSB) + " to " + NewValue); 285 ChangedIndex = 48 - i - SwitchCtrs[SwtchCtrlIndex]->LSB; 286 if (ChangedIndex == 33 || ChangedIndex == 34)break;//priortize Pitot heat, due to HW design error 287 } 288 if (!MasterPower && ChangedIndex != 20) return;//if powered off, only listen to power swtich. 289 if (NewValue == '1') //push buttons 290 { 291 switch (ChangedIndex) 292 { 293 case 33://Pitot Heat 294 case 34: 295 if (LEDString[28] == '0')Serial.println("C05"); 296 else Serial.println("C06"); 297 break; 298 case 8:ChangeMode(COM1); break; //COM1 Mode 299 case 16:ChangeMode(COM2); break; //COM2 Mode 300 case 18:ChangeMode(NAV1); break; //NAV1 Mode 301 case 23:ChangeMode(NAV2); break; //NAV2 Mode 302 case 22:ChangeMode(ADF); mul = 0; break; //ADF Mode 303 case 19: //Range Change 304 if (SelectedMode == ADF) 305 { 306 mul += 1; 307 mul %= 4; 308 } 309 else 310 { 311 MHz = !MHz; 312 LEDString[9] = LEDString[9] == '1' ? '0' : '1'; 313 LEDString[8] = LEDString[9] == '1' ? '0' : '1'; 314 315 } 316 SendLEDData(LEDString); 317 break; 318 case 40:Serial.println(Channel[SelectedMode]->CallCommand); break; //Call 319 case 1: //ATC Mode 320 ATCMode = !ATCMode; 321 if (ATCMode)Displays[EATCDisp]->UpdateDisplay("----"); 322 else Displays[EATCDisp]->UpdateDisplay(); 323 break; 324 case 7: KeypadPress("Y131", '1'); break; //Keypad 1 325 case 15:KeypadPress("Y141", '2'); break; //Keypad 2 326 case 6: KeypadPress("Y151", '3'); break; //Keypad 3 327 case 14:KeypadPress("Y181", '4'); break; //Keypad 4 328 case 5: KeypadPress("Y191", '5'); break; //Keypad 5 329 case 13:KeypadPress("Y201", '6'); break; //Keypad 6 330 case 4: KeypadPress("Y211", '7'); break; //Keypad 7 331 case 12:KeypadPress("Y241", '0'); break; //Keypad 0 332 case 3:UpdateTempDigits('8'); break; //potenial problem //Keypad CLR 333 case 11: //Keypad [8] 334 if (ATCMode)Serial.println("Y221"); 335 else 336 { 337 char c[5]; 338 sprintf(c, "%04d", freeMemory()); 339 Displays[EATCDisp]->TempData = String(c); 340 Displays[EATCDisp]->SetTempValChange(true); 341 Displays[EATCDisp]->UpdateDisplay(); 342 }; 343 break; 344 case 2: if (ATCMode)Serial.println("Y231"); //Keypad [9] 345 else Serial.println("Y131"); 346 break; 347 } 348 } 349 switch (ChangedIndex) //toggle switches 350 { 351 case 20: //Master Power 352 353 if (NewValue == '1')PowerUp(); 354 else Shutdown(); 355 356 break; 357 case 36:Serial.print("C43"); Serial.println(InverseValue); break; 358 case 44:Serial.print("C44"); Serial.println(InverseValue); break; 359 case 35: 360 Serial.print("C49"); Serial.println(InverseValue); 361 Serial.print("C48"); Serial.println(InverseValue); 362 break; 363 case 43:Serial.print("C45"); Serial.println(InverseValue); break; 364 case 37: 365 Serial.print("C47"); Serial.println(InverseValue); 366 Serial.print("C41"); Serial.println(InverseValue); 367 break; 368 case 45:Serial.print("C42"); Serial.println(InverseValue); break; 369 case 38:Serial.print("C46"); Serial.println(InverseValue); break; 370 case 46: 371 Serial.print("C50"); Serial.println(InverseValue); 372 373 break; 374 case 39:Serial.println("Y171"); break; 375 case 47:Serial.println("Y161"); break; 376 case 48:Serial.println("F12"); break; 377 case 21:Serial.println(Channel[SelectedMode]->SwapCommand); 378 MHz = true; 379 LEDString[9] = '1'; 380 LEDString[8] = '0'; 381 SendLEDData(LEDString); 382 break; 383 } 384 break;//potenial problem 385 } 386} 387 388//****************************************************************************************************************************************** 389void setup() { 390 Serial.begin(115200); 391 for (int i = 0; i < 32; i++)LEDString += "0"; 392 ATCMode = false; 393 //PinModes 394 pinMode(IRQ1, INPUT); 395 pinMode(IRQ2, INPUT); 396 pinMode(IRQ3, INPUT); 397 pinMode(LED1_DS, OUTPUT); 398 pinMode(LED1_CLK, OUTPUT); 399 pinMode(LED1_LTCH, OUTPUT); 400 pinMode(LED2_DS, OUTPUT); 401 pinMode(LED2_CLK, OUTPUT); 402 pinMode(LED2_LTCH, OUTPUT); 403 //Display Controlers Settings 404 DispCtrl1.setFont(FONT_CODEB); 405 DispCtrl2.setFont(FONT_CODEB); 406 407 DispCtrl1.begin(); 408 409 //Switch Controlers 410 SwitchCtrs[0] = new TSwitchCtrl(IRQ1, SwitchCtr1, 32, 47); 411 SwitchCtrs[1] = new TSwitchCtrl(IRQ2, SwitchCtr2, 16, 31); 412 SwitchCtrs[2] = new TSwitchCtrl(IRQ3, SwitchCtr3, 0, 15); 413 414 DispCtrl1.setIntensity(0x06); 415 DispCtrl2.setIntensity(0x06); 416 //Display definitions 417 Displays[EActiveDisp] = new TDisplay(new byte[5]{0, 1, 2, 3, 4}, EActiveDisp, 5); 418 Displays[EStdByDisp] = new TDisplay(new byte[5]{5, 6, 7, 8, 9}, EStdByDisp, 5); 419 Displays[EATCDisp] = new TDisplay(new byte[4]{13, 12, 11, 10}, EATCDisp, 4); 420 //Rotary Encoder Definition 421 FreqCtrl = new TEncoderData(FrqEnc_A, FrqEnc_B, Displays[EStdByDisp]); 422 //Modes / Channels 423 Channel[0] = new TChannel("A02", "A01", "A04", "A03", "A06", "A45", 7, 3); 424 Channel[1] = new TChannel("A08", "A07", "A10", "A09", "A12", "A46", 6, 2); 425 Channel[2] = new TChannel("A14", "A13", "A16", "A15", "A18", "A48", 5, 1); 426 Channel[3] = new TChannel("A20", "A19", "A22", "A21", "A24", "A49", 4, 0); 427 Channel[4] = new TChannel("A26", "A30", "A27", "A31", "", "A52", 12, 13); 428 429 delay(50); 430 431 for (byte i = 0; i < 3; i++)SwitchCtrs[i]->ReadSwitchs();//initialize switches - TODO: apply changes to sim accordingly 432 SendLEDData(LEDString);//turn off all LEDS 433 //Setup interrupt pins 434 pciSetup(IRQ1); 435 pciSetup(IRQ2); 436 pciSetup(IRQ3); 437 438 ChangeMode(SelectedMode); 439 if (SwitchCtrs[1]->GetData()[12] == '0')Shutdown(); 440 else PowerUp(); 441 442 443} 444//------------------------------------------------------------------------------------------------------------------------------------------ 445void loop() { 446 ENCODER(); //Check the Rotary Encoders 447 Displays[EATCDisp]->CheckTempDisplay();//Check if ATC display showing tmep data. 448 if (!Serial.available())return;//Check if anything there 449 switch (getChar()) //Get a serial read if there is. 450 { 451 case '=':EQUALS(); break; 452 case '<':LESSTHAN(); break; 453 default:while (Serial.available())Serial.read(); break; 454 } 455 UpdateAllDisplays(); //only if data was available. 456} 457//****************************************************************************************************************************************** 458 459//------------------------------------------------------------------------------------------------------------------------------------------ 460String GetLeadingZeros(String Bin, short digits) 461{ 462 String Padding = ""; 463 for (int i = 0; i < digits - Bin.length(); i++)Padding += "0"; 464 return Padding + Bin; 465} 466//------------------------------------------------------------------------------------------------------------------------------------------ 467void UpdateAllDisplays() 468{ 469 Displays[EActiveDisp]->Data = Channel[SelectedMode]->Active; 470 Displays[EStdByDisp]->Data = Channel[SelectedMode]->Standby; 471 if (MasterPower){ 472 for (int i = 0; i < 3; i++){ 473 if (i == 2 && ATCMode)continue;//to skip updating SQWAK display if in ATC Mode 474 Displays[i]->UpdateDisplay(); 475 } 476 SendLEDData(LEDString); 477 } 478} 479//------------------------------------------------------------------------------------------------------------------------------------------ 480void ChangeMode(uint8_t Mode) 481{ 482 SelectedMode = Mode; 483 for (uint8_t i = 0; i < 5; i++)LEDString[Channel[i]->LEDIndex] = i == Mode ? '1' : '0'; 484 LEDString[11] = LEDString[Channel[SelectedMode]->Status]; 485 UpdateAllDisplays(); 486} 487//------------------------------------------------------------------------------------------------------------------------------------------ 488void UpdateTempDigits(char val) 489{ 490 if (val == '8')Displays[EATCDisp]->TempData = "1200"; 491 else 492 { 493 if (tempDigitIndex == 0)Displays[EATCDisp]->TempData = " "; 494 Displays[EATCDisp]->TempData[tempDigitIndex] = val; 495 tempDigitIndex++; 496 Displays[EATCDisp]->SetTempValChange(true); 497 Displays[EATCDisp]->UpdateDisplay(); 498 } 499 if (tempDigitIndex > 3 || val == '8') 500 { 501 Serial.println("A42" + Displays[EATCDisp]->TempData); 502 Displays[EATCDisp]->SetTempValChange(false); 503 if (tempDigitIndex > 0 && tempDigitIndex < 4) 504 { 505 Displays[EATCDisp]->Data = "1200"; 506 Displays[EATCDisp]->UpdateDisplay(); 507 } 508 tempDigitIndex = 0; 509 } 510} 511//------------------------------------------------------------------------------------------------------------------------------------------ 512void KeypadPress(String ATCCommand, char KeypadValue) 513{ 514 if (ATCMode)Serial.println(ATCCommand); 515 else UpdateTempDigits(KeypadValue); 516} 517//------------------------------------------------------------------------------------------------------------------------------------------ 518void Shutdown() 519{ 520 LEDString[10] = '0'; 521 SendLEDData("0000000000000000"); 522 for (byte i = 0; i < 3; i++)Displays[i]->ClearDisplay(); 523 MasterPower = false; 524 Serial.println("A430"); 525} 526void PowerUp() 527{ 528 LEDString[10] = '1'; 529 LEDString[9] = MHz ? '1' : '0'; 530 LEDString[8] = LEDString[9] == '1' ? '0' : '1'; 531 SendLEDData(LEDString); 532 for (byte i = 0; i < 3; i++)Displays[i]->UpdateDisplay(); 533 MasterPower = true; 534 Serial.println("A431"); 535} 536void TestLEDs(int D) 537{ 538 String temp = ""; 539 for (int j = 0; j < 32; j++)temp += (random(0, 2) == 1 ? "1" : "0"); 540 SendLEDData(temp); 541 delay(D); 542} 543//------------------------------------------------------------------------------------------------------------------------------------------ 544int ReadSwitches() 545{ 546 uint8_t ErrorCode; 547 int val = SwitchCtr1->ReadKeys(&ErrorCode); 548 if (ErrorCode >= 4) 549 { 550 I2C_ClearBus(); 551 Wire.begin(); 552 } 553 if (val > 0 && val < 255)return val; 554 return 0; 555} 556//------------------------------------------------------------------------------------------------------------------------------------------ 557char getChar()// Get a character from the serial buffer 558{ 559 TimeOutCheck = millis(); 560 while (Serial.available() == 0)if (millis() - TimeOutCheck > SerialTimeout)return '0';//time out command - prevent freezing 561 return((char)Serial.read()); 562} 563//------------------------------------------------------------------------------------------------------------------------------------------ 564void EQUALS(){ 565 CodeIn = getChar(); 566 switch (CodeIn) { 567 case 'M':LEDString[3] = getChar(); break; //COM1 Active 568 case 'N':LEDString[2] = getChar(); break; //COM2 Active 569 case 'P':LEDString[1] = getChar(); break; //NAV1 Active 570 case 'Q':LEDString[0] = getChar(); break; //NAV2 Active 571 case 'S':LEDString[13] = getChar(); break; //ADF Active 572 case 'A':Channel[COM1]->Active = GetBufferValue(7); break; //COM1 Active 573 case 'B':Channel[COM1]->Standby = GetBufferValue(7); break; //COM1 Stby 574 case 'C':Channel[COM2]->Active = GetBufferValue(7); break; //COM2 Active 575 case 'D':Channel[COM2]->Standby = GetBufferValue(7); break; //COM2 Stby 576 case 'E':Channel[NAV1]->Active = GetBufferValue(6); break; //NAV1 Active 577 case 'F':Channel[NAV1]->Standby = GetBufferValue(6); break; //NAV1 Stby 578 case 'G':Channel[NAV2]->Active = GetBufferValue(6); break; //NAV2 Active 579 case 'H':Channel[NAV2]->Standby = GetBufferValue(6); break; //NAV2 Stby 580 case 'I':Channel[ADF]->Standby = GetBufferValue(6); Channel[4]->Active = " "; break; //ADF 581 case 'J':Displays[EATCDisp]->Data = GetBufferValue(4); break; //SQUAK Set 582 } 583 LEDString[11] = LEDString[Channel[SelectedMode]->Status];//update Call Stats LED 584} 585//------------------------------------------------------------------------------------------------------------------------------------------ 586void LESSTHAN() 587{ 588 CodeIn = getChar(); 589 switch (CodeIn) 590 { 591 case 'd': LEDString[26] = getChar(); break; 592 case 'e': LEDString[27] = getChar(); break; 593 case 'b': LEDString[28] = getChar(); break; 594 case 'c': LEDString[29] = getChar(); break; 595 case 'g': //Avionics Power 596 temp = getChar(); 597 if (temp == '0' && MasterPower)Serial.println("A431"); 598 else if (temp == '1' && !MasterPower)Serial.println("A430");//force sim to follow phyical switch 599 break; 600 case 'f'://LED Status 601 String LightState = GetBufferValue(10); 602 LEDString[18] = LightState[2]; 603 LEDString[19] = LightState[3]; 604 LEDString[20] = LightState[8]; 605 LEDString[21] = LightState[4]; 606 LEDString[22] = LightState[6]; 607 LEDString[23] = LightState[1]; 608 LEDString[17] = LightState[5]; 609 LEDString[16] = LightState[9]; 610 break; 611 } 612} 613//------------------------------------------------------------------------------------------------------------------------------------------ 614void ENCODER(){ 615 616 if (SelectedMode == ADF) 617 { 618 FreqCtrl->ReadEncoder(); 619 620 } 621 else 622 { 623 if (MHz)FreqCtrl->ReadEncoder(Channel[SelectedMode]->MHzIncCommand, Channel[SelectedMode]->MHzDecCommand); 624 else FreqCtrl->ReadEncoder(Channel[SelectedMode]->KHzIncCommand, Channel[SelectedMode]->KHzDecCommand); 625 } 626} 627//------------------------------------------------------------------------------------------------------------------------------------------ 628String GetBufferValue(int byteCount) 629{ 630 String buff = ""; 631 for (int i = 0; i < byteCount; i++) 632 { 633 temp = getChar(); 634 if ((temp <= '9' && temp >= '0') || temp == '.')buff += temp; 635 else buff += '0'; 636 } 637 return buff; 638} 639//------------------------------------------------------------------------------------------------------------------------------------------ 640uint8_t I2C_ClearBus() { 641#if defined(TWCR) && defined(TWEN) 642 TWCR &= ~(_BV(TWEN)); //Disable the Atmel 2-Wire interface so we can control the SDA and SCL pins directly 643#endif 644 645 pinMode(SDA, INPUT_PULLUP); // Make SDA (data) and SCL (clock) pins Inputs with pullup. 646 pinMode(SCL, INPUT_PULLUP); 647 delay(20); 648 649 boolean SCL_LOW = (digitalRead(SCL) == LOW); // Check is SCL is Low. 650 if (SCL_LOW) { //If it is held low Arduno cannot become the I2C master. 651 return 1; //I2C bus error. Could not clear SCL clock line held low 652 } 653 654 boolean SDA_LOW = (digitalRead(SDA) == LOW); // vi. Check SDA input. 655 int clockCount = 20; // > 2x9 clock 656 657 while (SDA_LOW && (clockCount > 0)) { // vii. If SDA is Low, 658 clockCount--; 659 // Note: I2C bus is open collector so do NOT drive SCL or SDA high. 660 pinMode(SCL, INPUT); // release SCL pullup so that when made output it will be LOW 661 pinMode(SCL, OUTPUT); // then clock SCL Low 662 delayMicroseconds(10); // for >5uS 663 pinMode(SCL, INPUT); // release SCL LOW 664 pinMode(SCL, INPUT_PULLUP); // turn on pullup resistors again 665 // do not force high as slave may be holding it low for clock stretching. 666 delayMicroseconds(10); // for >5uS 667 // The >5uS is so that even the slowest I2C devices are handled. 668 SCL_LOW = (digitalRead(SCL) == LOW); // Check if SCL is Low. 669 int counter = 20; 670 while (SCL_LOW && (counter > 0)) { // loop waiting for SCL to become High only wait 2sec. 671 counter--; 672 delay(50); 673 SCL_LOW = (digitalRead(SCL) == LOW); 674 } 675 if (SCL_LOW) { // still low after 2 sec error 676 return 2; // I2C bus error. Could not clear. SCL clock line held low by slave clock stretch for >2sec 677 } 678 SDA_LOW = (digitalRead(SDA) == LOW); // and check SDA input again and loop 679 } 680 if (SDA_LOW) { // still low 681 return 3; // I2C bus error. Could not clear. SDA data line held low 682 } 683 684 // else pull SDA line low for Start or Repeated Start 685 pinMode(SDA, INPUT); // remove pullup. 686 pinMode(SDA, OUTPUT); // and then make it LOW i.e. send an I2C Start or Repeated start control. 687 // When there is only one I2C master a Start or Repeat Start has the same function as a Stop and clears the bus. 688 // A Repeat Start is a Start occurring after a Start with no intervening Stop. 689 delayMicroseconds(10); // wait >5uS 690 pinMode(SDA, INPUT); // remove output low 691 pinMode(SDA, INPUT_PULLUP); // and make SDA high i.e. send I2C STOP control. 692 delayMicroseconds(10); // x. wait >5uS 693 pinMode(SDA, INPUT); // and reset pins as tri-state inputs which is the default state on reset 694 pinMode(SCL, INPUT); 695 //Serial.println("I2C Recovered"); 696 return 0; // all ok 697} 698//------------------------------------------------------------------------------------------------------------------------------------------ 699void PulseLEN(uint8_t pin, bool StartLow) 700{ 701 if (StartLow) 702 { 703 digitalWrite(pin, LOW); 704 digitalWrite(pin, HIGH); //fix for double send 705 digitalWrite(pin, LOW); 706 } 707 else 708 { 709 digitalWrite(pin, HIGH); 710 digitalWrite(pin, LOW); 711 digitalWrite(pin, HIGH); 712 } 713} 714//------------------------------------------------------------------------------------------------------------------------------------------ 715void PulseData(uint8_t DSpin, uint8_t CLKPin, char Data) 716{ 717 digitalWrite(DSpin, (Data == '1' ? HIGH : LOW)); 718 digitalWrite(CLKPin, LOW); 719 digitalWrite(CLKPin, HIGH); 720} 721//------------------------------------------------------------------------------------------------------------------------------------------ 722void SendLEDData(String data) 723{ 724 PulseLEN(LED1_LTCH, false); 725 for (int i = 15; i >= 0; i--)PulseData(LED1_DS, LED1_CLK, data[i]); 726 PulseLEN(LED1_LTCH, true); 727 728 PulseLEN(LED2_LTCH, false); 729 for (int i = 31; i >= 16; i--)PulseData(LED2_DS, LED2_CLK, data[i]); 730 PulseLEN(LED2_LTCH, true); 731} 732//------------------------------------------------------------------------------------------------------------------------------------------
Electrical Control Firmare
arduino
1/****************************************************************************************/ 2/* */ 3/* Electrical Control | ©Kantooya */ 4/* */ 5/* Author: Sam Farah */ 6/* Email: sam.farah1986@gmail.com */ 7/* Website: http://samfarah.net */ 8/* Version: 1.0 */ 9/* Description: */ 10/* The firmware for the ATMega microcontroller on board, it controls */ 11/* the circuit, and handles reading inputs and sends commands to FSX. */ 12/* */ 13/****************************************************************************************/ 14 15 16//-------------------------- Headers ---------------------------- 17#include <U8g2lib.h> 18#include <AS1115.h> 19//#include <Arduino.h> 20#include <Quadrature.h> //for rotary encoders 21//#ifdef U8X8_HAVE_HW_SPI 22//#include <SPI.h> 23//#endif 24#ifdef U8X8_HAVE_HW_I2C 25#include <WSWire.h> 26#endif 27#include <MemoryFree.h> 28#include <avr/pgmspace.h> 29//--------------------------------------------------------------- 30 31//---------------------------- Pins ----------------------------- 32// Name Arduino Pin Pin on ATMega 33// ----------- ----------- ------------- 34#define LED2_CLK PD5 35#define LED2_DS PD7 36#define LED2_LTCH PD6 37#define LED1_CLK PD3 38#define LED1_DS PD2 39#define LED1_LTCH PD4 40#define IRQ1 A0 41#define IRQ2 A1 42//--------------------------------------------------------------- 43 44 45//------------------------- Settings ---------------------------- 46#define TCAADDR 0x70 47#define SerialTimeout 1000 48#define TempDelay 3000 49#define EBaro 0 50#define ENSet 1 51//--------------------------------------------------------------- 52 53//----------------------- Prototypes ---------------------------- 54class TDisplay; 55class TEncoderData; 56class TSwitchCtrl; 57class TChannel; 58class TPowerData; 59class TInstrumentData; 60//--------------------------------------------------------------- 61 62//------------------------- Objects ----------------------------- 63AS1115 disp = AS1115(0x00); 64AS1115 *SwitchCtr1 = new AS1115(0x00), *SwitchCtr2 = new AS1115(0x00); 65TSwitchCtrl *SwitchCtrs[2]; 66U8G2_SSD1306_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE); 67 68Quadrature Encoder1(8, 9); 69Quadrature Encoder2(A2, A3); 70//--------------------------------------------------------------- 71 72//-------------------------- Enums ------------------------------ 73//enum EDispID { EBaro = 0, ENSet = 1 }; 74//--------------------------------------------------------------- 75 76//---------------------- Public Variables ----------------------- 77//unsigned long TimeOutCheck; 78//byte counter = 0; 79byte tempDigitIndex, CodeIn; 80String LED1String = ""; 81String LED2String = ""; 82 83char temp; 84TDisplay *Displays[2]; 85TPowerData *PowerData; 86TInstrumentData *InstrumentData; 87bool MasterPower = true; 88bool UpdatePowerDisp = false; 89bool UpdateInstrumentDisp = false; 90static const byte TickPositions[] PROGMEM = { 39,41,43,50,60,71,92, 102, 124 }; 91static const byte GraphOrder[] PROGMEM = { 8,9,10,11,12,13,14,15,0,1 }; 92//static const byte BaroDigits[] = { 3,4,5,6 }; 93//static const byte NSetDigits[] = { 0, 1, 2 }; 94bool SpeedSet = false; 95bool N1Set = false; 96bool Strtr1 = false; 97bool Strtr2 = false; 98uint8_t Autobreak = 0; 99uint8_t LastAddress = 7; 100int8_t R1old, R2old, R1dif, R2dif; 101//--------------------------------------------------------------- 102class TDisplay 103{ 104private: 105 byte *Index; 106 byte DigitCount; 107 //byte ID; 108 //bool TempValChange; 109 bool ShowADP; 110 //unsigned long LastTempChange; 111 112 void SendValues(byte index, char value, bool ShowDP) 113 { 114 //return; 115 tcaselect(3, true); 116 AS1115 *CurrentDriver = &disp;// index > 7 ? &DispCtrl2 : &DispCtrl1; 117 index %= 8; 118 if (CurrentDriver->digitWrite(index, value, ShowDP)) 119 { 120 // Serial.println("I2C Froze (Displays)"); 121 I2C_ClearBus(); 122 Wire.begin(); 123 } 124 } 125public: 126 String Data;// , TempData; 127 TDisplay(byte *_Index, byte _DigitCount, bool _showADP) 128 { 129 Data.reserve(4); 130 //TempData.reserve(4); 131 ShowADP = _showADP; 132 Index = _Index; 133 DigitCount = _DigitCount; 134 //ID = _ID; 135 UpdateDisplay(" "); 136 //TempValChange = false; 137 //TempData = ""; 138 } 139 void UpdateDisplay() { UpdateDisplay(Data); } 140 void UpdateDisplay(String Val) 141 { 142 uint8_t DPFound = 0; 143 for (byte i = 0; i < DigitCount + DPFound; i++) 144 { 145 if (Val[i] == '.') 146 { 147 SendValues(Index[i - 1], Val[i - 1], ShowADP); 148 DPFound++; 149 } 150 else SendValues(Index[i - DPFound], Val[i], false); 151 } 152 } 153 void ClearDisplay() { UpdateDisplay(" "); } 154 // byte GetID() { return ID; } 155 //void SetTempValChange(bool val) 156 //{ 157 // TempValChange = val; 158 // // LastTempChange = millis(); 159 //} 160 byte GetDigitCount() { return DigitCount; } 161}; 162//-------------------------------------------- 163class TPowerData 164{ 165public: 166 String BatteryVoltage; 167 String BatteryCurrent; 168 String MainBusVoltage; 169 String MainBusCurrent; 170 String APUVoltage; 171 bool APUGenActive; 172 TPowerData() 173 { 174 BatteryVoltage.reserve(4); 175 BatteryCurrent.reserve(4); 176 MainBusVoltage.reserve(4); 177 MainBusCurrent.reserve(3); 178 APUVoltage.reserve(2); 179 } 180}; 181//-------------------------------------------- 182class TInstrumentData 183{ 184public: 185 uint8_t Flaps; 186 uint8_t FlapsHandle; 187 uint8_t FlapsPoisitonCount; 188 uint8_t FuelLeft; 189 uint8_t FuelCentre; 190 uint8_t FuelRight; 191 String Autobreak; 192 TInstrumentData() { Autobreak.reserve(3); } 193 void SetFlaps(String StrFlaps) { Flaps = atoi(StrFlaps.c_str()); } 194 void SetFlapsHandle(String strFlapsHandle) { FlapsHandle = atoi(strFlapsHandle.c_str()); } 195 void SetFlapsPoisitonCount(String strFlapsPoisitonCount) { FlapsPoisitonCount = atoi(strFlapsPoisitonCount.c_str()); } 196 void SetFuelLeft(String strFuel) { FuelLeft = atoi(strFuel.c_str()); } 197 void SetFuelCentre(String strFuel) { FuelCentre = atoi(strFuel.c_str()); } 198 void SetFuelRight(String strFuel) { FuelRight = atoi(strFuel.c_str()); } 199 void SetAutoBreak(char Val) 200 { 201 switch (Val) 202 { 203 case '0':Autobreak = "RTO"; break; 204 case '1':Autobreak = "OFF"; break; 205 case '2':Autobreak = " 1 "; break; 206 case '3':Autobreak = " 2 "; break; 207 case '4':Autobreak = " 3 "; break; 208 case '5':Autobreak = "MAX"; break; 209 } 210 } 211}; 212 213class TSwitchCtrl 214{ 215private: 216 AS1115 *Chip; 217 String Data; 218 String OldData; 219public: 220 byte MuxAddress; 221 byte IRQ; 222 byte LSB, MSB; 223 TSwitchCtrl(uint8_t _IRQ, AS1115 *_Chip, uint8_t _LSB, uint8_t _MSB, uint8_t _MuxAddress) 224 { 225 Data.reserve(16); 226 OldData.reserve(16); 227 IRQ = _IRQ; 228 Chip = _Chip; 229 LSB = _LSB; 230 MSB = _MSB; 231 MuxAddress = _MuxAddress; 232 Data = ""; 233 tcaselect(MuxAddress, false); 234 Chip->begin(0x00, 0x00); 235 Chip->begin(0x01, 0x00); 236 Chip->begin(0x02, 0x00); 237 Chip->begin(0x03, 0x00); 238 } 239 void ReadSwitchs() 240 { 241 tcaselect(MuxAddress, false); 242 uint8_t ErrorCode; 243 //Serial.print("Saving "); 244 //Serial.print(Data); 245 //Serial.println(" as old"); 246 OldData = Data; 247 Data = Chip->ReadKeysMul(&ErrorCode);//potentially not needed (the Leading Zeros, already handled from library) 248 //Serial.print("new val is: "); 249 //Serial.println (Data); 250 if (ErrorCode >= 4) 251 { 252 I2C_ClearBus(); 253 Wire.begin(); 254 } 255 tcaselect(LastAddress, false); 256 } 257 String GetData() { return Data; } 258 String GetOldData() { return OldData; } 259 void EmptyBuffer() 260 { 261 tcaselect(MuxAddress, false); 262 uint8_t ErrorCode; 263 264 Chip->ReadKeysMul(&ErrorCode);//potentially not needed (the Leading Zeros, already handled from library) 265 if (ErrorCode >= 4) 266 { 267 I2C_ClearBus(); 268 Wire.begin(); 269 } 270 tcaselect(LastAddress, false); 271 } 272}; 273/* 274Frame Buffer Examples: clearBuffer/sendBuffer. Fast, but may not work with all Arduino boards because of RAM consumption 275Page Buffer Examples: firstPage/nextPage. Less RAM usage, should work with all Arduino boards. 276U8x8 Text Only Example: No RAM usage, direct communication with display controller. No graphics, 8x8 Text only. 277*/ 278 279 280void tcaselect(uint8_t i, bool SaveAddress) { 281 if (i > 7) return; 282 if (SaveAddress == true) LastAddress = i; 283 Wire.beginTransmission(TCAADDR); 284 Wire.write(1 << i); 285 Wire.endTransmission(); 286 //delay(10); 287} 288 289void u8g2_prepare(void) { 290 u8g2.setFont(u8g2_font_6x10_tf); 291 u8g2.setFontRefHeightExtendedText(); 292 u8g2.setDrawColor(1); 293 u8g2.setFontPosTop(); 294 u8g2.setFontDirection(0); 295} 296void PowerDevice() 297{ 298 if (MasterPower == 0) 299 { 300 SendLED2Data("0000000000000000"); 301 SendLED1Data("0000000000000000"); 302 Displays[EBaro]->UpdateDisplay(" "); 303 Displays[ENSet]->UpdateDisplay(" "); 304 tcaselect(6, true); 305 u8g2.clearDisplay(); 306 tcaselect(7, true); 307 u8g2.clearDisplay(); 308 309 } 310 else 311 { 312 UpdateAllDisplays(); 313 UpdateInstrumentDisplay(); 314 UpdatePowerDisplay(); 315 } 316} 317ISR(PCINT1_vect) // handle pin change interrupt for D8 to D13 here 318{ 319 interrupts(); 320 for (byte SwtchCtrlIndex = 0; SwtchCtrlIndex < 2; SwtchCtrlIndex++) 321 { 322 if (digitalRead(SwitchCtrs[SwtchCtrlIndex]->IRQ) == LOW) 323 { 324 SwitchCtrs[SwtchCtrlIndex]->ReadSwitchs(); 325 byte ChangedIndex = 0; 326 char NewValue, InverseValue; 327 for (byte i = 0; i < 16; i++) 328 { 329 330 if (SwitchCtrs[SwtchCtrlIndex]->GetData()[i] != SwitchCtrs[SwtchCtrlIndex]->GetOldData()[i]) 331 { 332 NewValue = SwitchCtrs[SwtchCtrlIndex]->GetData()[i]; 333 InverseValue = NewValue == '0' ? '1' : '0'; 334 ChangedIndex = 32 - i - SwitchCtrs[SwtchCtrlIndex]->LSB; 335 break; 336 } 337 } 338 if (!MasterPower && ChangedIndex != 31) return;//if powered off, only listen to power swtich. 339 if (NewValue == '1') //push buttons 340 { 341 switch (ChangedIndex) 342 { 343 case 1:Serial.println(F("C15")); break; 344 case 2:Serial.println(F("C14")); break; 345 case 8:Serial.println(F("E43")); Serial.println(F("E46")); break; 346 case 14:Serial.println(F("C02")); break; 347 case 15:Serial.println(F("C01")); break; 348 case 22:Serial.println(F("F31")); break; 349 case 23:Serial.println(F("B31")); break; 350 case 25:Serial.println(F("B35")); break; 351 case 27:Serial.println(F("C13")); break; 352 case 28:Serial.println(LED1String[4] == '1' ? F("C21") : F("C20")); break; 353 case 29:Serial.println(F("C04")); break; 354 case 30:Serial.println(F("C16")); break; 355 //case 26:Serial.println("F34"); break; AUTO BARO?? 356 case 32:Serial.println(F("F34")); break; 357 } 358 } 359 switch (ChangedIndex) //toggle switches 360 { 361 case 4:Serial.println(NewValue == '1' ? F("E17") : F("E18")); break; 362 case 5:Serial.println(NewValue == '1' ? F("E32") : F("E31")); break; 363 case 6:Serial.println(NewValue == '1' ? F("E30") : F("C11")); break; 364 case 7:Serial.println(NewValue == '0' ? F("E30") : F("C11")); break; 365 case 12:Serial.println(NewValue == '1' ? F("E23") : F("E24")); break; 366 case 13:Serial.println(NewValue == '1' ? F("E20") : F("E21")); break; 367 //case 13:Serial.println(F("E21")); break; 368 case 17:Autobreak = 4; SetAB(); break; 369 case 18:Autobreak = 3; SetAB(); break; 370 case 19:Autobreak = 2; SetAB(); break; 371 case 20:Autobreak = 1; SetAB(); break; 372 case 21:Autobreak = 0; SetAB(); break; 373 case 24:Autobreak = 5; SetAB(); break; 374 case 31:MasterPower = NewValue == '1'; 375 PowerDevice(); 376 break; 377 } 378 } 379 } 380} 381void setup(void) { 382 383 LED1String.reserve(16); 384 LED2String.reserve(16); 385 //BargraphStirng.reserve(10); 386 387 Serial.begin(115200); 388 pinMode(IRQ1, INPUT_PULLUP); 389 pinMode(IRQ2, INPUT_PULLUP); 390 pinMode(LED1_CLK, OUTPUT); 391 pinMode(LED1_DS, OUTPUT); 392 pinMode(LED1_LTCH, OUTPUT); 393 pinMode(LED2_CLK, OUTPUT); 394 pinMode(LED2_DS, OUTPUT); 395 pinMode(LED2_LTCH, OUTPUT); 396 397 398 SwitchCtrs[0] = new TSwitchCtrl(IRQ1, SwitchCtr1, 0, 15, 5); 399 SwitchCtrs[1] = new TSwitchCtrl(IRQ2, SwitchCtr2, 16, 31, 4); 400 401 tcaselect(3, false); 402 disp.setFont(FONT_CODEB); 403 disp.begin(0x03, 0x00); 404 disp.setIntensity(0x06); 405 406 407 Displays[EBaro] = new TDisplay(new byte[5]{ 3,4,5,6 }, 4, true); 408 Displays[ENSet] = new TDisplay(new byte[5]{ 0, 1, 2 }, 3, false); 409 410 PowerData = new TPowerData(); 411 InstrumentData = new TInstrumentData; 412 413 SwitchCtrs[0]->ReadSwitchs(); 414 SwitchCtrs[1]->ReadSwitchs(); 415 416 MasterPower = SwitchCtrs[0]->GetData()[1] == '1'; 417 PowerDevice(); 418 419 delay(50); 420 pciSetup(IRQ1); 421 pciSetup(IRQ2); 422 423 424 tcaselect(6, false); 425 u8g2.begin(); 426 tcaselect(7, false); 427 u8g2.begin(); 428 429 UpdatePowerDisp = false; 430 UpdateInstrumentDisp = false; 431 432 LED1String = "000000000000000000000000"; 433 LED2String = "000000000000000000000000"; 434 //u8g2.setFlipMode(0); 435} 436void loop(void) { 437 ENCODER(); //Check the Rotary Encoders 438 if (!Serial.available()) //Check if anything there 439 { 440 if (UpdatePowerDisp == true && MasterPower == true) UpdatePowerDisplay(); 441 if (UpdateInstrumentDisp == true && MasterPower == true) UpdateInstrumentDisplay(); 442 return; 443 } 444 445 while (Serial.available()) 446 { 447 switch (getChar()) //Get a serial read if there is. 448 { 449 case '=':EQUALS(); break; 450 case '<':LESSTHAN(); break; 451 case '?':QUESTION(); break; 452 case '#':HASHTAG(); break; 453 case '$':DOLLAR(); break; 454 default:break; // ignore floating values //while (Serial.available()) Serial.read(); break; // empty buffer 455 } 456 } 457 while (Serial.available()) Serial.read(); // empty buffer 458 UpdateAllDisplays(); 459} 460void pciSetup(byte pin) 461{ 462 *digitalPinToPCMSK(pin) |= bit(digitalPinToPCMSKbit(pin)); // enable pin 463 PCIFR |= bit(digitalPinToPCICRbit(pin)); // clear any outstanding interrupt 464 PCICR |= bit(digitalPinToPCICRbit(pin)); // enable interrupt for the group 465} 466void SetAB() 467{ 468 for (byte i = 0; i < 6; i++)Serial.println(F("Y031")); 469 for (byte i = 0; i < Autobreak; i++)Serial.println(F("Y021")); 470} 471//------------------------------------------------------------------------------------------------------------------------------------------ 472void UpdateAllDisplays() 473{ 474 if (MasterPower) { 475 //for (byte i = 0; i < 2; i++) { 476 Displays[EBaro]->UpdateDisplay(); 477 Displays[ENSet]->UpdateDisplay(); 478 //} 479 SendLED2Data(LED2String); 480 LED1String[7] = !SpeedSet && N1Set ? '1' : '0'; 481 LED1String[6] = MasterPower ? '1' : '0'; 482 LED1String[15] = Displays[EBaro]->Data == "29.92" ? '1' : '0'; 483 SendLED1Data(LED1String); 484 485 } 486} 487//------------------------------------------------------------------------------------------------------------------------------------------ 488char getChar()// Get a character from the serial buffer 489{ 490 //TimeOutCheck = millis(); 491 while (Serial.available() == 0);// if (millis() - TimeOutCheck > SerialTimeout)return '0';//time out command - prevent freezing 492 return((char)Serial.read()); 493} 494//------------------------------------------------------------------------------------------------------------------------------------------ 495void EQUALS() { 496 497 CodeIn = getChar(); 498 switch (CodeIn) { 499 case 't': LED1String[12] = getChar(); break; //auto throttle 500 case 's': SpeedSet = getChar() == '1' ? true : false; break;//airspeed 501 case 'u': N1Set = getChar() == '1' ? true : false; break;//n1set 502 } 503} 504//------------------------------------------------------------------------------------------------------------------------------------------ 505void QUESTION() { 506 CodeIn = getChar(); 507 String GenStats, GearStats; 508 switch (CodeIn) { 509 case 'k': Displays[EBaro]->Data = GetBufferValue(5); break; //Kohlsman setting Hg 510 case 'I': PowerData->BatteryVoltage = GetBufferValue(4); UpdatePowerDisp = true; break; //Battery Voltage 511 case 'J': PowerData->BatteryCurrent = GetBufferValue(4); UpdatePowerDisp = true; break; //Battery Current 512 case 'K': PowerData->MainBusVoltage = GetBufferValue(4); UpdatePowerDisp = true; break; //Main Bus Voltage 513 case 's': 514 GenStats = GetBufferValue(2); 515 LED1String[10] = GenStats[0] == '1' ? '0' : '1'; 516 LED1String[11] = GenStats[1] == '1' ? '0' : '1'; 517 break; 518 case 'Y'://gear 519 GearStats = GetBufferValue(3); 520 LED2String[2] = GearStats[2] == '1' ? '1' : '0';//right red 521 LED2String[4] = GearStats[1] == '1' ? '1' : '0';//left red 522 LED2String[6] = GearStats[0] == '1' ? '1' : '0';//nose red 523 LED2String[3] = GearStats[2] == '2' ? '1' : '0';//right grn 524 LED2String[5] = GearStats[1] == '2' ? '1' : '0';//left grn 525 LED2String[7] = GearStats[0] == '2' ? '1' : '0';//nose grn 526 break; 527 } 528} 529//------------------------------------------------------------------------------------------------------------------------------------------ 530void LESSTHAN() 531{ 532 CodeIn = getChar(); 533 switch (CodeIn) 534 { 535 case 'G': InstrumentData->SetFlaps(GetBufferValue(3)); UpdateInstrumentDisp = true; break; //Flaps 536 case 'X': InstrumentData->SetFuelLeft(GetBufferValue(3)); UpdateInstrumentDisp = true; break; //Flaps 537 case 'Y': InstrumentData->SetFuelCentre(GetBufferValue(3)); UpdateInstrumentDisp = true; break; //Flaps 538 case 'Z': InstrumentData->SetFuelRight(GetBufferValue(3)); UpdateInstrumentDisp = true; break; //Flaps 539 case 'I': LED1String[1] = getChar(); break; //Plane on Ground 540 case 'q': LED1String[5] = getChar(); break; //Parking Break 541 case 'i': LED1String[4] = getChar(); break; //Spoiler Arked 542 case 'r': LED1String[2] = getChar(); break; //Eng 1 Fuel Vales 543 case 's': LED1String[0] = getChar(); break; //Eng 2 Fuel Vales 544 case 'k': Strtr1 = (getChar() == '1' ? true : false); LED1String[3] = (Strtr1 || Strtr2) ? '1' : '0'; break; //eng starter 545 case 'l': Strtr2 = (getChar() == '1' ? true : false); LED1String[3] = (Strtr1 || Strtr2) ? '1' : '0'; break; //eng starter 546 547 } 548} 549//------------------------------------------------------------------------------------------------------------------------------------------ 550void HASHTAG() { 551 CodeIn = getChar(); 552 switch (CodeIn) 553 { 554 case 'H': Displays[ENSet]->Data = GetBufferValue(4); break; 555 case 'I': PowerData->MainBusCurrent = GetBufferValue(3); UpdatePowerDisp = true; break; //Main Bus Current 556 case 'L': InstrumentData->SetFlapsHandle(GetBufferValue(2)); UpdateInstrumentDisp = true; break; //Flaps Index 557 case 'K': InstrumentData->SetFlapsPoisitonCount(GetBufferValue(2)); UpdateInstrumentDisp = true; break; //Flaps Index 558 case 'J': InstrumentData->SetAutoBreak(getChar()); UpdateInstrumentDisp = true; break; //Flaps Index 559 case 'N': LED1String[14] = getChar(); break; //HAS G/S 560 case 'M': LED1String[13] = getChar(); break; //HAS LOC 561 } 562 563} 564//------------------------------------------------------------------------------------------------------------------------------------------ 565 566void ENCODER() { 567 568 int8_t R1 = (Encoder1.position() / 2); //The /2 is to suit the encoder 569 if (R1 != R1old) { // checks to see if it different 570 (R1dif = (R1 - R1old));// finds out the difference 571 //Serial.println(Encoder1.position()); 572 if (R1dif == 1) Serial.println(F("B43")); 573 if (R1dif == -1)Serial.println(F("B44")); 574 R1old = R1; // overwrites the old reading with the new one. 575 //Disp->SetTempValChange(true); 576 } 577 578 int8_t R2 = (Encoder2.position() / 2); //The /2 is to suit the encoder 579 if (R2 != R2old) { // checks to see if it different 580 (R2dif = (R2 - R2old));// finds out the difference 581 if (R2dif == 1) Serial.println(F("C25")); 582 if (R2dif == -1)Serial.println(F("C26")); 583 R2old = R2; // overwrites the old reading with the new one. 584 //Disp->SetTempValChange(true); 585 } 586} 587//------------------------------------------------------------------------------------------------------------------------------------------ 588void DOLLAR() { 589 CodeIn = getChar(); 590 switch (CodeIn) 591 { 592 case 'g': GETBarLED(GetBufferValue(3)); break; 593 case 'i': PowerData->APUVoltage = GetBufferValue(2); UpdatePowerDisp = true; break; //APU Voltage 594 case 'k': PowerData->APUGenActive = getChar() == '1' ? true : false; break; //APU Gen Active (considers APU RPM) 595 case 'j': LED1String[9] = getChar(); break; //APU Gen 596 } 597} 598//------------------------------------------------------------------------------------------------------------------------------------------ 599String GetBufferValue(int byteCount) 600{ 601 String buff = ""; 602 for (byte i = 0; i < byteCount; i++) 603 { 604 temp = getChar(); 605 if ((temp <= '9' && temp >= '0') || temp == '.' || temp == '-' || temp == '+')buff += temp; 606 else buff += '0'; 607 } 608 return buff; 609} 610//------------------------------------------------------------------------------------------------------------------------------------------ 611uint8_t I2C_ClearBus() { 612#if defined(TWCR) && defined(TWEN) 613 TWCR &= ~(_BV(TWEN)); //Disable the Atmel 2-Wire interface so we can control the SDA and SCL pins directly 614#endif 615 616 pinMode(SDA, INPUT_PULLUP); // Make SDA (data) and SCL (clock) pins Inputs with pullup. 617 pinMode(SCL, INPUT_PULLUP); 618 delay(20); 619 620 boolean SCL_LOW = (digitalRead(SCL) == LOW); // Check is SCL is Low. 621 if (SCL_LOW) { //If it is held low Arduno cannot become the I2C master. 622 return 1; //I2C bus error. Could not clear SCL clock line held low 623 } 624 625 boolean SDA_LOW = (digitalRead(SDA) == LOW); // vi. Check SDA input. 626 byte clockCount = 20; // > 2x9 clock 627 628 while (SDA_LOW && (clockCount > 0)) { // vii. If SDA is Low, 629 clockCount--; 630 // Note: I2C bus is open collector so do NOT drive SCL or SDA high. 631 pinMode(SCL, INPUT); // release SCL pullup so that when made output it will be LOW 632 pinMode(SCL, OUTPUT); // then clock SCL Low 633 delayMicroseconds(10); // for >5uS 634 pinMode(SCL, INPUT); // release SCL LOW 635 pinMode(SCL, INPUT_PULLUP); // turn on pullup resistors again 636 // do not force high as slave may be holding it low for clock stretching. 637 delayMicroseconds(10); // for >5uS 638 // The >5uS is so that even the slowest I2C devices are handled. 639 SCL_LOW = (digitalRead(SCL) == LOW); // Check if SCL is Low. 640 byte counter = 20; 641 while (SCL_LOW && (counter > 0)) { // loop waiting for SCL to become High only wait 2sec. 642 counter--; 643 delay(50); 644 SCL_LOW = (digitalRead(SCL) == LOW); 645 } 646 if (SCL_LOW) { // still low after 2 sec error 647 return 2; // I2C bus error. Could not clear. SCL clock line held low by slave clock stretch for >2sec 648 } 649 SDA_LOW = (digitalRead(SDA) == LOW); // and check SDA input again and loop 650 } 651 if (SDA_LOW) { // still low 652 return 3; // I2C bus error. Could not clear. SDA data line held low 653 } 654 655 // else pull SDA line low for Start or Repeated Start 656 pinMode(SDA, INPUT); // remove pullup. 657 pinMode(SDA, OUTPUT); // and then make it LOW i.e. send an I2C Start or Repeated start control. 658 // When there is only one I2C master a Start or Repeat Start has the same function as a Stop and clears the bus. 659 // A Repeat Start is a Start occurring after a Start with no intervening Stop. 660 delayMicroseconds(10); // wait >5uS 661 pinMode(SDA, INPUT); // remove output low 662 pinMode(SDA, INPUT_PULLUP); // and make SDA high i.e. send I2C STOP control. 663 delayMicroseconds(10); // x. wait >5uS 664 pinMode(SDA, INPUT); // and reset pins as tri-state inputs which is the default state on reset 665 pinMode(SCL, INPUT); 666 //Serial.println("I2C Recovered"); 667 return 0; // all ok 668} 669//------------------------------------------------------------------------------------------------------------------------------------------ 670 671 672void PulseLEN(uint8_t pin, bool StartLow) 673{ 674 if (StartLow) 675 { 676 digitalWrite(pin, LOW); 677 digitalWrite(pin, HIGH); //fix for double send 678 digitalWrite(pin, LOW); 679 } 680 else 681 { 682 digitalWrite(pin, HIGH); 683 digitalWrite(pin, LOW); 684 digitalWrite(pin, HIGH); 685 } 686} 687//------------------------------------------------------------------------------------------------------------------------------------------ 688void PulseData(uint8_t DSpin, uint8_t CLKPin, char Data) 689{ 690 digitalWrite(DSpin, (Data == '1' ? HIGH : LOW)); 691 digitalWrite(CLKPin, LOW); 692 digitalWrite(CLKPin, HIGH); 693} 694//------------------------------------------------------------------------------------------------------------------------------------------ 695void SendLED1Data(String data) 696{ 697 PulseLEN(LED1_LTCH, false); 698 for (byte i = 0; i < 16; i++)PulseData(LED1_DS, LED1_CLK, data[i]); 699 PulseLEN(LED1_LTCH, true); 700 701 /* PulseLEN(LED2_LTCH, false); 702 for (int i = 31; i >= 16; i--)PulseData(LED2_DS, LED2_CLK, data[i]); 703 PulseLEN(LED2_LTCH, true);*/ 704} 705//------------------------------------------------------------------------------------------------------------------------------------------ 706void SendLED2Data(String data) 707{ 708 PulseLEN(LED2_LTCH, false); 709 for (byte i = 0; i < 16; i++) { 710 PulseData(LED2_DS, LED2_CLK, data[i]); //delay(10); 711 } 712 PulseLEN(LED2_LTCH, true); 713 714 /* PulseLEN(LED2_LTCH, false); 715 for (int i = 31; i >= 16; i--)PulseData(LED2_DS, LED2_CLK, data[i]); 716 PulseLEN(LED2_LTCH, true);*/ 717} 718//------------------------------------------------------------------------------------------------------------------------------------------ 719void GETBarLED(String APURPMVal) 720{ 721 String BargraphStirng = ""; 722 if (APURPMVal[0] == '1') 723 { 724 BargraphStirng = "1111111111"; 725 } 726 else 727 { 728 byte val = APURPMVal[1] - '0'; 729 BargraphStirng = ""; 730 for (byte i = 0; i < val; i++) 731 BargraphStirng += '1'; 732 for (byte i = 0; i < 10 - val; i++) 733 BargraphStirng += '0'; 734 } 735 736 for (byte i = 0; i < 10; i++) 737 LED2String[pgm_read_byte(&(GraphOrder[i]))] = BargraphStirng[i]; 738} 739//------------------------------------------------------------------------------------------------------------------------------------------ 740void UpdatePowerDisplay() 741{ 742 //return; 743 tcaselect(6, true); 744 u8g2.firstPage(); 745 do 746 { 747 748 u8g2.drawHLine(0, 17, 128); 749 u8g2.drawHLine(0, 42, 128); 750 u8g2.drawVLine(64, 0, 17); 751 u8g2.drawVLine(43, 42, 22); 752 u8g2.drawVLine(86, 42, 22); 753 754 755 756 u8g2_prepare(); 757 u8g2.setFont(u8g2_font_freedoomr10_tu); 758 u8g2.drawStr(10, 0, (PowerData->BatteryVoltage + "V").c_str()); 759 u8g2.drawStr(80, 0, (PowerData->BatteryCurrent + "A").c_str()); 760 u8g2.drawStr(3, 50, (PowerData->MainBusVoltage + "V").c_str()); 761 u8g2.drawStr(51, 50, (PowerData->MainBusCurrent + "A").c_str()); 762 u8g2.drawStr(97, 50, (PowerData->APUVoltage + "V").c_str()); 763 764 if (PowerData->BatteryCurrent[0] == '-') 765 { 766 u8g2.setFont(u8g2_font_crox3hb_tf); 767 u8g2.drawStr(2, 23, "LOW BATTERY"); 768 } 769 770 u8g2.setFont(u8g2_font_6x10_tf); 771 772 } while (u8g2.nextPage()); 773 774 775 UpdatePowerDisp = false; 776 777} 778//------------------------------------------------------------------------------------------------------------------------------------------ 779void UpdateInstrumentDisplay() 780{ 781 //return; 782 uint8_t i; 783 uint8_t CentrePos; 784 uint8_t actualpos; 785 tcaselect(7, true); 786 u8g2.firstPage(); 787 u8g2_prepare(); 788 do 789 { 790 u8g2.drawVLine(34, 0, 44); 791 u8g2.drawHLine(0, 44, 128); 792 u8g2.drawVLine(42, 45, 21); 793 u8g2.drawVLine(86, 45, 21); 794 795 796 // Fuel 797 u8g2.setFont(u8g2_font_4x6_tf); 798 u8g2.drawStr(13, 47, "LEFT"); 799 u8g2.drawStr(55, 47, "CENTRE"); 800 u8g2.drawStr(100, 47, "RIGHT"); 801 u8g2.drawStr(40, 2, "FLAPS:"); 802 u8g2.setFont(u8g2_font_6x10_tf); 803 804 u8g2.drawStr(13, 56, (String(InstrumentData->FuelLeft) + "%").c_str()); 805 u8g2.drawStr(55, 56, (String(InstrumentData->FuelCentre) + "%").c_str()); 806 u8g2.drawStr(100, 56, (String(InstrumentData->FuelRight) + "%").c_str()); 807 808 // //Autobreak 809 u8g2.drawStr(8, 15, InstrumentData->Autobreak.c_str()); 810 811 // //Flaps Demo 812 u8g2.setFont(u8g2_font_micro_mn); 813 814 815 u8g2.drawStr(42, 35, "0");//save ram 816 u8g2.drawStr(40, 35, "1"); 817 //u8g2.drawStr(44, 35, "2"); 818 u8g2.drawStr(48, 35, "5"); 819 u8g2.drawStr(56, 35, "10"); 820 u8g2.drawStr(67, 35, "15"); 821 u8g2.drawStr(88, 35, "25"); 822 u8g2.drawStr(98, 35, "30"); 823 u8g2.drawStr(120, 35, "40");//save ram ends 824 825 //u8g2.setFont(u8g2_font_4x6_tf); 826 827 //u8g2.setFont(u8g2_font_6x10_tf); 828 u8g2.drawHLine(44, 30, 81); 829 830 for (i = 0; i < 9; i++)u8g2.drawVLine(pgm_read_byte(&(TickPositions[i])), 29, 3); //SAVE RAM 831 832 833 actualpos = map(InstrumentData->Flaps, 0, 100, 0, 85); 834 //u8g2.drawStr(50, 5, String(39 + actualpos).c_str()); 835 836 837 838 u8g2.drawVLine(39, 20, 7); 839 u8g2.drawBox(39, 20, actualpos, 7); 840 if (InstrumentData->FlapsPoisitonCount == 8) 841 { 842 CentrePos = pgm_read_byte(&(TickPositions[InstrumentData->FlapsHandle])); 843 u8g2.drawVLine(CentrePos, 10, 4); 844 u8g2.drawTriangle(CentrePos - 2, 14, CentrePos, 18, CentrePos + 3, 14); //tales waaayyy tooo much RAM 845 } 846 // //u8g2.drawVLine(i , 20, 8); 847 848 } while (u8g2.nextPage()); 849 UpdateInstrumentDisp = false; 850} 851//------------------------------------------------------------------------------------------------------------------------------------------
Autopilot Firmware
arduino
1/****************************************************************************************/ 2/* */ 3/* Autopilot 500-TS | ©Kantooya Inc */ 4/* */ 5/* Author: Sam Farah */ 6/* Email: sam.farah1986@gmail.com */ 7/* Website: http://samfarah.net */ 8/* Version: 1.0 */ 9/* Description: */ 10/* The firmware for the ATMega microcontroller on board, it controls */ 11/* the circuit, and handles reading inputs and sends commands to FSX. */ 12/* */ 13/****************************************************************************************/ 14 15//-------------------------- Headers ---------------------------- 16#include <AS1115.h> 17#include "WSWire.h" 18#include "math.h" 19#include "Quadrature.h" //for rotary encoders 20//--------------------------------------------------------------- 21 22//---------------------------- Pins ----------------------------- 23// Name Arduino Pin Pin on ATMega 24// ----------- ----------- ------------- 25#define LED_DS 2 // 32 26#define LED_CLK 3 // 1 27#define LED_LTCH 4 // 2 28#define ALTEnc_B 6 // 29#define ALTEnc_A 7 // 30#define VSEnc_B 8 // 31#define VSEnc_A 9 // 32#define IRQ 13 // 17 33#define SpdEnc_B 10 // 34#define SpdEnc_A 11 // 35#define HdgEnc_A A0 // 36#define HdgEnc_B A1 // 37#define CrsEnc_A A2 // 38#define CrsEnc_B A3 // 39#define SDA A4 // 40#define SCL A5 // 41//--------------------------------------------------------------- 42 43//------------------------- Settings ---------------------------- 44#define SerialTimeout 1000 45#define TempDelay 2000 46//--------------------------------------------------------------- 47 48//-------------------------- Enums ------------------------------ 49enum EDispID{ ESpeedDisp = 0, EALTDisp = 1, EVSDisp = 2, ECrsDsip = 3, EHdgDisp = 4 }; 50//--------------------------------------------------------------- 51 52//----------------------- Prototypes ---------------------------- 53int ReadSwitches(); 54void pciSetup(byte); 55void SendLEDData(String); 56void(*resetFunc) (void) = 0; //declare reset function @ address 0 57void TestLEDs(int); 58void InitLEDs(int); 59uint8_t I2C_ClearBus(); 60class SDisplayData; 61class TTestDisplayData; 62class TDisplay; 63class TEncoderData; 64class TBlinkLED; 65//--------------------------------------------------------------- 66 67//------------------------- Objects ----------------------------- 68AS1115 DispCtrl1 = AS1115(0x01); 69AS1115 DispCtrl2 = AS1115(0x02); 70AS1115 SwitchCtrl = AS1115(0x03); 71TEncoderData *SpeedCtrl, *ALTCtrl, *VSCtrl, *HdgCtrl, *CrsCtrl; 72TBlinkLED *RealDataBlink, *SpeedBlink, *AltBlink, *HdgBlink; 73//--------------------------------------------------------------- 74class SDisplayData 75{ 76public: 77 String SetMem; 78 String ReadMem; 79}; 80//---------------------- Public Variables ----------------------- 81int SwLEDList[] = { 3, 1, 2, 0, 9, 10, 11, 4, 0, 0, 14, 5, 0, 12, 8, 13 }; 82bool BlinIndexArray[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 83String FSXCommands[] = { "B09", "B04", "B10", "", "A54", "A54", "B30", "B08", "", "", "Y080", "B05", "", "B34", "B01", "B26" }; 84String LEDString = "0000000000000000"; 85String OldLEDs = "0000000000000000"; 86String BlinkLEDs = "0000000000000000"; 87int tempVal, CodeIn; 88bool TestProgram = false, ShowDP = false, ShowRealValues = false, OldShowRealValues = false; 89bool ShowZeros, Connected = false, MasterBattery; 90char navMeM, SpeedMeM, ATHRMeM; 91SDisplayData ALTData, SpdData, VSData, HdgData, CrsData; 92TDisplay *Displays[5]; 93unsigned long int HoldTime = 0, TimeOutCheck; 94//--------------------------------------------------------------- 95 96//-------------------------- Classes ---------------------------- 97class TDisplay 98{ 99private: 100 byte *Index; 101 int DigitCount; 102 EDispID ID; 103 bool TempValChange; 104 unsigned long int LastTempChange; 105 SDisplayData *Data; 106 void SendValues(byte index, char value) 107 { 108 if (index > 7) 109 { 110 if (DispCtrl2.digitWrite(index - 8, value, (TestProgram ? ShowZeros : MasterBattery))) 111 { 112 Serial.println("I2C Froze (Displays)"); 113 I2C_ClearBus(); 114 Wire.begin(); 115 DispCtrl1.begin(); 116 DispCtrl2.begin(); 117 SwitchCtrl.begin(); 118 } 119 } 120 else 121 { 122 if (DispCtrl1.digitWrite(index, value, (index == 6 || index == 1 ? ShowDP : 0))) 123 { 124 Serial.println("I2C Froze (Displays)"); 125 I2C_ClearBus(); 126 Wire.begin(); 127 DispCtrl1.begin(); 128 DispCtrl2.begin(); 129 SwitchCtrl.begin(); 130 } 131 } 132 } 133public: 134 TDisplay(byte *_Index, EDispID _ID, SDisplayData *_Data) 135 { 136 Index = _Index; 137 DigitCount = 3; 138 ID = _ID; 139 UpdateDisplay(" "); 140 TempValChange = false; 141 Data = _Data; 142 } 143 void CheckTempDisplay() 144 { 145 if (TempValChange && millis() - LastTempChange > TempDelay) 146 { 147 TempValChange = false; 148 UpdateDisplay(); 149 } 150 } 151 152 void UpdateDisplay() 153 { 154 UpdateDisplay(!ShowRealValues || TempValChange ? Data->SetMem : Data->ReadMem); 155 } 156 void UpdateDisplay(String Val) 157 { 158 159 160 bool LeadZeroFound = false; 161 bool Negative = false; 162 for (int i = 0; i < DigitCount; i++) 163 { 164 if (!MasterBattery && !TestProgram)Val[i] = ' '; 165 else 166 { 167 if (Val[i] == '-') 168 { 169 Negative = true; 170 Val[i] = ' '; 171 } 172 else if (Val[i] == '+')Val[i] = ' '; 173 else 174 if (Val[i] == '0' && !LeadZeroFound && i != DigitCount - 1 && (!TestProgram || ((Index[i] != 6 && Index[i] != 1) || LEDString[11] == '0')))Val[i] = ' '; 175 else 176 { 177 LeadZeroFound = true; 178 if (Negative) 179 { 180 if (TestProgram && (LEDString[11] == '1' && (Index[i] == 7 || Index[i] == 2))) 181 { 182 SendValues(Index[i - 1], '0'); 183 SendValues(Index[i - 2], '-'); 184 } 185 else SendValues(Index[i - 1], '-'); 186 187 Negative = false; 188 } 189 } 190 } 191 192 SendValues(Index[i], Val[i]); 193 } 194 } 195 void ClearDisplay() 196 { 197 UpdateDisplay(" "); 198 } 199 EDispID GetID(){ return ID; } 200 void SetTempValChange(bool val) 201 { 202 TempValChange = val; 203 LastTempChange = millis(); 204 } 205 206}; 207//-------------------------------------------- 208 209//-------------------------------------------- 210class TTestDisplayData 211{ 212public: 213 int Value; 214 TTestDisplayData() 215 { 216 Value = 0; 217 } 218 String toString() 219 { 220 String RetVal = String(Value); 221 String Buff = ""; 222 for (int i = 0; i < 3 - RetVal.length(); i++) 223 Buff += '0'; 224 RetVal = Buff + RetVal; 225 226 return RetVal; 227 } 228 void Inc() 229 { 230 Value++; 231 if (Value>999)Value = 0; 232 } 233 void Dec(bool AllowNegative) 234 { 235 Value--; 236 if (AllowNegative){ if (Value < -99)Value = 0; } 237 else{ if (Value < 0)Value = 0; } 238 } 239}; 240//-------------------------------------------- 241class TEncoderData 242{ 243private: 244 int R;// a variable 245 int Rold;// the old reading 246 int Rdif;// the difference since last loop 247 Quadrature *Encoder; 248 TTestDisplayData *TestData; 249 TDisplay *Disp; 250 251public: 252 TEncoderData(int _PinA, int _PinB, TDisplay *_Disp) 253 { 254 Encoder = new Quadrature(_PinA, _PinB); 255 TestData = new TTestDisplayData(); 256 Disp = _Disp; 257 } 258 void ReadEncoder(String IncCommand, String DecCommand) 259 { 260 R = (Encoder->position() / 2); //The /2 is to suit the encoder 261 if (R != Rold) { // checks to see if it different 262 (Rdif = (R - Rold));// finds out the difference 263 if (Rdif == 1) Serial.println(IncCommand); 264 if (Rdif == -1)Serial.println(DecCommand); 265 Rold = R; // overwrites the old reading with the new one. 266 Disp->SetTempValChange(true); 267 } 268 } 269 void ReadEncoder(TDisplay *Disp)//used for test program. 270 { 271 R = (Encoder->position() / 2); //The /2 is to suit the encoder 272 if (R != Rold) { // checks to see if it different 273 (Rdif = (R - Rold));// finds out the difference 274 if (Rdif == 1)TestData->Inc(); 275 if (Rdif == -1)TestData->Dec(true); 276 Rold = R; // overwrites the old reading with the new one. 277 Disp->UpdateDisplay(TestData->toString()); 278 } 279 } 280 void RefreshDisplay(TDisplay *Disp) 281 { 282 Disp->UpdateDisplay(TestData->toString()); 283 } 284}; 285//-------------------------------------------- 286class TBlinkLED 287{ 288private: 289 unsigned long BlinkDelayCounter; 290 int LEDIndex; 291 int NormalDelay; 292 int ActiveDelay; 293 bool BlinkTemp; 294public: 295 void Activate() 296 { 297 BlinkTemp = true; 298 BlinkDelayCounter = 0; 299 300 } 301 void deactivate() 302 { 303 BlinkTemp = false; 304 } 305 TBlinkLED(int _LEDIndex, int _NormalDelay, int _ActiveDelay) 306 { 307 LEDIndex = _LEDIndex; 308 NormalDelay = _NormalDelay; 309 ActiveDelay = _ActiveDelay; 310 BlinIndexArray[LEDIndex] = true; 311 } 312 void Blink(bool pressed) 313 { 314 if (millis() - BlinkDelayCounter > (pressed ? ActiveDelay : NormalDelay)) 315 { 316 BlinkLEDs = GetBlinkString(); 317 BlinkLEDs[LEDIndex] = BlinkTemp ? '1' : '0'; 318 SendLEDData(BlinkLEDs); 319 BlinkTemp = !BlinkTemp; 320 BlinkDelayCounter = millis(); 321 } 322 } 323 void DontBlink() 324 { 325 BlinkLEDs = GetBlinkString(); 326 BlinkLEDs[LEDIndex] = LEDString[LEDIndex]; 327 if (BlinkLEDs != OldLEDs) 328 { 329 SendLEDData(BlinkLEDs); 330 OldLEDs = BlinkLEDs; 331 } 332 } 333}; 334//-------------------------------------------- 335//----------------------- End of Classes ------------------------ 336String GetBlinkString() 337{ 338 String RetVal = "0000000000000000"; 339 for (int i = 0; i < 16; i++) 340 { 341 if (!BlinIndexArray[i])RetVal[i] = LEDString[i]; 342 else RetVal[i] = BlinkLEDs[i]; 343 } 344 return RetVal; 345} 346//----------------------- Interrupts ---------------------------- 347ISR(PCINT0_vect) // handle pin change interrupt for D8 to D13 here 348{ 349 interrupts(); 350 if (digitalRead(IRQ) == LOW) 351 { 352 353 tempVal = ReadSwitches(); 354 if (tempVal > 0) 355 { 356 if (TestProgram) //Execute Test Program when buttons are pressed. 357 { 358 if ((LEDString[4] != '1' || tempVal == 8) && tempVal != 1) 359 { 360 LEDString[SwLEDList[tempVal - 1]] = (LEDString[SwLEDList[tempVal - 1]] == '0' ? '1' : '0'); 361 SendLEDData(ShowRealValues ? BlinkLEDs : LEDString); 362 } 363 switch (tempVal) 364 { 365 case 1: 366 HoldTime = millis(); 367 break; 368 case 13: 369 resetFunc(); //exit test program 370 break; 371 case 5: 372 case 6: 373 case 7: 374 case 14: 375 case 15: 376 ShowZeros = (LEDString[12] == '1'); 377 ShowDP = (LEDString[11] == '1'&& LEDString[8] == '1' && LEDString[5] == '0'); 378 if (LEDString[9] == '0' && LEDString[10] == '1' && LEDString[8] == '1') 379 { 380 DispCtrl1.setFont(FONT_CODEB); 381 DispCtrl2.setFont(FONT_CODEB); 382 SpeedCtrl->RefreshDisplay(Displays[ESpeedDisp]); 383 ALTCtrl->RefreshDisplay(Displays[EALTDisp]); 384 VSCtrl->RefreshDisplay(Displays[EVSDisp]); 385 CrsCtrl->RefreshDisplay(Displays[ECrsDsip]); 386 HdgCtrl->RefreshDisplay(Displays[EHdgDisp]); 387 } 388 break; 389 case 8: 390 if (LEDString[4] == '1') 391 { 392 ShowRealValues = false; 393 LEDString = "1111111111111111"; 394 for (int i = 0; i < 8; i++)DispCtrl1.digitWrite(i, 8, (i == 6 || i == 1)); 395 for (int i = 0; i < 7; i++)DispCtrl2.digitWrite(i, 8, 1); 396 } 397 else 398 { 399 ShowDP = false; 400 LEDString = "0000000000000000"; 401 } 402 SendLEDData(LEDString); 403 break; 404 } 405 } 406 else if (Connected) //send commands to FSX 407 { 408 switch (tempVal) 409 { 410 case 1: //B/C Hold Button 411 HoldTime = millis(); 412 break; 413 case 2: //heading pressed, fixed bug where it captures real data. 414 Serial.println(LEDString[1] == '0' ? "Y111" : "Y121"); 415 break; 416 case 12:// alt pressed, fixed bug where it captures real data 417 Serial.println(LEDString[5] == '0' ? "Y091" : "Y101"); 418 break; 419 case 13://Level Button 420 Serial.println("B05"); 421 Serial.println("B05"); 422 Serial.println("B210000"); 423 break; 424 default: 425 Serial.println(FSXCommands[tempVal - 1]); 426 } 427 } 428 } 429 } 430 else if (Connected || TestProgram) 431 { 432 if (tempVal == 1) 433 { 434 if (millis() - HoldTime > 300) 435 { 436 BlinkLEDs = LEDString; 437 RealDataBlink->Activate(); 438 SpeedBlink->Activate(); 439 AltBlink->Activate(); 440 HdgBlink->deactivate(); 441 442 for (int i = 0; i < 5; i++)Displays[i]->SetTempValChange(false); 443 444 ShowRealValues = !ShowRealValues; 445 if (TestProgram){ 446 if (!ShowRealValues) 447 { 448 LEDString[3] == '0'; 449 SendLEDData(LEDString); 450 } 451 } 452 } 453 else 454 { 455 if (TestProgram) 456 { 457 LEDString[3] = LEDString[3] == '0' ? '1' : '0'; 458 SendLEDData(LEDString); 459 } 460 else 461 Serial.println("B09"); 462 } 463 } 464 } 465} 466//--------------------------------------------------------------- 467void setup() { 468 469 Serial.begin(115200); 470 pinMode(IRQ, INPUT); 471 pinMode(LED_DS, OUTPUT); 472 pinMode(LED_CLK, OUTPUT); 473 pinMode(LED_LTCH, OUTPUT); 474 475 DispCtrl1.setFont(FONT_CODEB); 476 DispCtrl2.setFont(FONT_CODEB); 477 DispCtrl1.setDecode(DECODE_ALL_FONT); 478 DispCtrl2.setDecode(DECODE_ALL_FONT); 479 480 MasterBattery = false; 481 482 Displays[ESpeedDisp] = new TDisplay(new byte[3]{3, 4, 5}, ESpeedDisp, &SpdData);; 483 Displays[EALTDisp] = new TDisplay(new byte[3]{0, 1, 2}, EALTDisp, &ALTData);; 484 Displays[EVSDisp] = new TDisplay(new byte[3]{14, 6, 7}, EVSDisp, &VSData);; 485 Displays[ECrsDsip] = new TDisplay(new byte[3]{8, 9, 10}, ECrsDsip, &CrsData);; 486 Displays[EHdgDisp] = new TDisplay(new byte[3]{11, 12, 13}, EHdgDisp, &HdgData);; 487 488 SpeedCtrl = new TEncoderData(SpdEnc_A, SpdEnc_B, Displays[ESpeedDisp]); 489 ALTCtrl = new TEncoderData(ALTEnc_A, ALTEnc_B, Displays[EALTDisp]); 490 VSCtrl = new TEncoderData(VSEnc_A, VSEnc_B, Displays[EVSDisp]); 491 HdgCtrl = new TEncoderData(HdgEnc_A, HdgEnc_B, Displays[EHdgDisp]); 492 CrsCtrl = new TEncoderData(CrsEnc_A, CrsEnc_B, Displays[ECrsDsip]); 493 494 RealDataBlink = new TBlinkLED(3, 250, 125); 495 SpeedBlink = new TBlinkLED(13, 125, 250); 496 AltBlink = new TBlinkLED(5, 130, 250); 497 HdgBlink = new TBlinkLED(1, 135, 250); 498 499 SwitchCtrl.begin(); 500 DispCtrl1.begin(); 501 DispCtrl2.begin(); 502 delay(500); 503 504 DispCtrl1.setIntensity(0x0F); 505 DispCtrl2.setIntensity(0x0F); 506 507 InitLEDs(1); 508 509 if (SwitchCtrl.ReadKeys(NULL) == 13)//go to test program 510 { 511 TestProgram = true; 512 TestLEDs(50); 513 SendLEDData("0000000000000000"); 514 } 515 pciSetup(IRQ); 516 517 if (TestProgram)InitLEDs(2); 518} 519//------------------------------------------------------------------------------------------------------------------------------------------ 520void loop() { 521 if (TestProgram) 522 { 523 if (LEDString[4] == '0') 524 { 525 if (LEDString[8] == '1') 526 { 527 if (LEDString[9] == '1') 528 { 529 for (int i = 0; i < 5; i++)Displays[i]->UpdateDisplay(String(random(0, 1000))); 530 delay(200); 531 } 532 else if (LEDString[10] == '1') 533 { 534 SpeedCtrl->ReadEncoder(Displays[ESpeedDisp]); 535 ALTCtrl->ReadEncoder(Displays[EALTDisp]); 536 VSCtrl->ReadEncoder(Displays[EVSDisp]); 537 CrsCtrl->ReadEncoder(Displays[ECrsDsip]); 538 HdgCtrl->ReadEncoder(Displays[EHdgDisp]); 539 } 540 else { 541 DispCtrl1.setFont(FONT_HEX); 542 DispCtrl2.setFont(FONT_HEX); 543 544 for (int i = 0; i < 8; i++) 545 if (DispCtrl1.digitWrite(i, i, 0) >= 4) 546 { 547 Serial.println("I2C Froze"); 548 I2C_ClearBus(); 549 Wire.begin(); 550 DispCtrl1.begin(); 551 DispCtrl2.begin(); 552 } 553 for (int i = 0; i < 7; i++) 554 if (DispCtrl2.digitWrite(i, i + 8, ShowZeros) >= 4) 555 { 556 Serial.println("I2C Froze"); 557 I2C_ClearBus(); 558 Wire.begin(); 559 DispCtrl1.begin(); 560 DispCtrl2.begin(); 561 } 562 delay(200); 563 } 564 } 565 else 566 { 567 DispCtrl1.setFont(FONT_CODEB); 568 DispCtrl2.setFont(FONT_CODEB); 569 ShowZeros = false; 570 for (int i = 0; i < 5; i++)Displays[i]->ClearDisplay(); 571 delay(200); 572 } 573 } 574 if (ShowRealValues) 575 { 576 RealDataBlink->Blink(LEDString[3] == '1'); 577 if (LEDString[13] == '1')SpeedBlink->Blink(false); 578 if (LEDString[5] == '1')AltBlink->Blink(false); 579 if (LEDString[1] == '1')HdgBlink->Blink(false); 580 } 581 } 582 else //real program 583 { 584 {ENCODER(); } //Check the Rotary Encoders 585 if (Serial.available()) 586 { //Check if anything there 587 CodeIn = getChar(); //Get a serial read if there is. 588 if (CodeIn == '=') { EQUALS(); Connected = true; } // The first identifier is "=" ,, goto void EQUALS 589 else if (CodeIn == '?') { QUESTION(); Connected = true; }// The first identifier is "?" ,, goto void QUESTION 590 else if (CodeIn == '<') { LESSTHAN(); Connected = true; }// The first identifier is "?" ,, goto void QUESTION 591 else 592 { 593 String ReadBuffer = ""; 594 while (Serial.available())ReadBuffer += char(Serial.read());// Empties the buffer use to show ReadBuffer += char(Serial.read()); 595 if (ReadBuffer.length() > 0) 596 { 597 Serial.println("--------------------------"); 598 Serial.println(ReadBuffer); 599 Serial.println("--------------------------"); 600 } 601 } 602 for (int i = 0; i < 5; i++)Displays[i]->UpdateDisplay(); 603 } 604 605 if (ShowRealValues != OldShowRealValues) 606 { 607 OldShowRealValues = ShowRealValues; 608 for (int i = 0; i < 5; i++)Displays[i]->UpdateDisplay(); 609 } 610 611 if (ShowRealValues && MasterBattery) 612 { 613 RealDataBlink->Blink(LEDString[3] == '1'); 614 615 if (LEDString[13] == '1' && SpdData.ReadMem != SpdData.SetMem)SpeedBlink->Blink(false); 616 else SpeedBlink->DontBlink(); 617 618 if (LEDString[5] == '1' && VSData.ReadMem.substring(1, 3) != "00")AltBlink->Blink(false); 619 else AltBlink->DontBlink(); 620 621 if (LEDString[1] == '1' && HdgData.ReadMem != HdgData.SetMem && !(HdgData.ReadMem == "360" && HdgData.SetMem == "000"))HdgBlink->Blink(false); 622 else HdgBlink->DontBlink(); 623 } 624 else 625 if (LEDString != OldLEDs) 626 { 627 SendLEDData(LEDString); 628 OldLEDs = LEDString; 629 } 630 631 for (int i = 0; i < 5; i++)Displays[i]->CheckTempDisplay(); 632 } 633} 634//------------------------------------------------------------------------------------------------------------------------------------------ 635char getChar()// Get a character from the serial buffer 636{ 637 TimeOutCheck = millis(); 638 while (Serial.available() == 0) 639 if (millis() - TimeOutCheck > SerialTimeout)return '0';//time out command 640 return((char)Serial.read()); 641} 642//------------------------------------------------------------------------------------------------------------------------------------------ 643void SendLEDData(String data) 644{ 645 digitalWrite(LED_LTCH, HIGH); 646 digitalWrite(LED_LTCH, LOW); 647 digitalWrite(LED_LTCH, HIGH); 648 for (int i = 15; i >= 0; i--) 649 { 650 digitalWrite(LED_DS, (data[i] == '1' ? HIGH : LOW)); 651 digitalWrite(LED_CLK, LOW); 652 digitalWrite(LED_CLK, HIGH); 653 } 654 digitalWrite(LED_LTCH, LOW); 655 digitalWrite(LED_LTCH, HIGH); //fix for double send 656 digitalWrite(LED_LTCH, LOW); 657 658} 659//------------------------------------------------------------------------------------------------------------------------------------------ 660void pciSetup(byte pin) 661{ 662 *digitalPinToPCMSK(pin) |= bit(digitalPinToPCMSKbit(pin)); // enable pin 663 PCIFR |= bit(digitalPinToPCICRbit(pin)); // clear any outstanding interrupt 664 PCICR |= bit(digitalPinToPCICRbit(pin)); // enable interrupt for the group 665} 666//------------------------------------------------------------------------------------------------------------------------------------------ 667int ReadSwitches() 668{ 669 uint8_t ErrorCode; 670 int val = SwitchCtrl.ReadKeys(&ErrorCode); 671 if (ErrorCode >= 4) 672 { 673 Serial.println("I2C Froze (Switches)"); 674 I2C_ClearBus(); 675 Wire.begin(); 676 DispCtrl1.begin(); 677 DispCtrl2.begin(); 678 SwitchCtrl.begin(); 679 } 680 if (val > 0 && val < 255) 681 return val; 682 return 0; 683} 684//------------------------------------------------------------------------------------------------------------------------------------------ 685void TestLEDs(int D) 686{ 687 for (int i = 1; i < 15; i++) 688 { 689 if (i == 6 || i == 7 || i == 15 || i == 0)continue; 690 String temp = ""; 691 for (int j = 0; j < 16; j++) temp += (j == i ? "1" : "0"); 692 SendLEDData(temp); 693 delay(D); 694 } 695 for (int i = 13; i >= 2; i--) 696 { 697 if (i == 6 || i == 7 || i == 15 || i == 0)continue; 698 String temp = ""; 699 for (int j = 0; j < 15; j++) temp += (j == i ? "1" : "0"); 700 SendLEDData(temp); 701 delay(D); 702 } 703} 704//------------------------------------------------------------------------------------------------------------------------------------------ 705void InitLEDs(int count) 706{ 707 int _Delay = 300; 708 for (int i = 1; i <= count; i++) 709 { 710 SendLEDData("1111111111111111"); 711 delay(_Delay); 712 SendLEDData("0000000000000000"); 713 delay(_Delay); 714 } 715} 716//------------------------------------------------------------------------------------------------------------------------------------------ 717void EQUALS(){ 718 CodeIn = getChar(); 719 switch (CodeIn) { 720 case 'a': LEDString[8] = getChar(); break; //Master AP 721 case 'k': LEDString[5] = getChar(); break; //Altitude Hold 722 case 'm': LEDString[4] = getChar(); break; //App hold 723 case 'o': LEDString[2] = getChar(); break; //Loc (Nav) Hold 724 case 'n': LEDString[3] = getChar(); break; //B/C hold 725 case 'j': LEDString[1] = getChar(); break; //Heading Hold 726 case 'q': LEDString[11] = getChar(); break; //Flight Director 727 case 'v': LEDString[14] = getChar(); break; //Take-Off Power 728 case 'b': ALTData.SetMem = GetBufferValue(5); break; //ALT Set 729 case 'f': SpdData.SetMem = GetBufferValue(3); break; //Speed Set 730 case 'c': VSData.SetMem = GetBufferValue(5); break; //Vertical Speed Set 731 case 'd': HdgData.SetMem = GetBufferValue(3); break; //Heading Set 732 case 'e': CrsData.SetMem = GetBufferValue(3); CrsData.ReadMem = CrsData.SetMem; break; //Course Set 733 case 't': //ATHR 734 ATHRMeM = getChar(); 735 if (MasterBattery)LEDString[12] = ATHRMeM; 736 break; 737 case 'l': //GPS-NAV 738 navMeM = getChar(); 739 if (MasterBattery) 740 { 741 LEDString[9] = navMeM; 742 LEDString[10] = (LEDString[9] == '0' ? '1' : '0'); 743 } 744 break; 745 case 's': //Speed Hold 746 SpeedMeM = getChar(); 747 if (MasterBattery)LEDString[13] = SpeedMeM; 748 break; 749 } 750} 751//------------------------------------------------------------------------------------------------------------------------------------------ 752void QUESTION(){ // The first identifier was "?" 753 CodeIn = getChar(); 754 switch (CodeIn) { 755 case 'U': // Bus Voltage 756 String buff = GetBufferValue(2); 757 getChar(); 758 getChar(); 759 if (buff.toInt() == 0)//plain's turned off 760 { 761 MasterBattery = false; 762 LEDString[9] = '0'; 763 LEDString[10] = '0'; 764 LEDString[12] = '0'; 765 LEDString[13] = '0'; 766 for (int i = 0; i < 5; i++)Displays[i]->UpdateDisplay("000"); 767 } 768 else 769 { 770 MasterBattery = true; 771 LEDString[9] = navMeM; 772 LEDString[10] = (LEDString[9] == '0' ? '1' : '0'); 773 LEDString[12] = ATHRMeM; 774 LEDString[13] = SpeedMeM; 775 for (int i = 0; i < 5; i++)Displays[i]->UpdateDisplay(); 776 } 777 } 778} 779void LESSTHAN() 780{ 781 CodeIn = getChar(); 782 switch (CodeIn) 783 { 784 case 'D': ALTData.ReadMem = GetBufferValue(5); break; //ALT Read 785 case 'P': SpdData.ReadMem = GetBufferValue(3); break; //Speed Read 786 case 'J': HdgData.ReadMem = GetBufferValue(3); break; //Heading Read 787 case 'L': //Vertical Speed Read 788 VSData.ReadMem = GetBufferValue(6); 789 VSData.ReadMem = VSData.ReadMem[0] + VSData.ReadMem.substring(2, 6); 790 break; 791 } 792} 793//------------------------------------------------------------------------------------------------------------------------------------------ 794void ENCODER(){ 795 796 SpeedCtrl->ReadEncoder("B15", "B16"); 797 ALTCtrl->ReadEncoder("B11", "B12"); 798 VSCtrl->ReadEncoder("B13", "B14"); 799 HdgCtrl->ReadEncoder("A57", "A58"); 800 CrsCtrl->ReadEncoder("A56", "A55"); 801} 802//------------------------------------------------------------------------------------------------------------------------------------------ 803String GetBufferValue(int byteCount) 804{ 805 String buff = ""; 806 char temp; 807 for (int i = 0; i < byteCount; i++) 808 { 809 temp = getChar(); 810 if ((temp <= '9' && temp >= '0') || temp == '-' || temp == '+' || temp == '.') 811 buff += temp; 812 else 813 buff += '0'; 814 } 815 816 //Serial.println(buff); 817 818 return buff; 819} 820//------------------------------------------------------------------------------------------------------------------------------------------ 821uint8_t I2C_ClearBus() { 822#if defined(TWCR) && defined(TWEN) 823 TWCR &= ~(_BV(TWEN)); //Disable the Atmel 2-Wire interface so we can control the SDA and SCL pins directly 824#endif 825 826 pinMode(SDA, INPUT_PULLUP); // Make SDA (data) and SCL (clock) pins Inputs with pullup. 827 pinMode(SCL, INPUT_PULLUP); 828 delay(200); 829 830 boolean SCL_LOW = (digitalRead(SCL) == LOW); // Check is SCL is Low. 831 if (SCL_LOW) { //If it is held low Arduno cannot become the I2C master. 832 return 1; //I2C bus error. Could not clear SCL clock line held low 833 } 834 835 boolean SDA_LOW = (digitalRead(SDA) == LOW); // vi. Check SDA input. 836 int clockCount = 20; // > 2x9 clock 837 838 while (SDA_LOW && (clockCount > 0)) { // vii. If SDA is Low, 839 clockCount--; 840 // Note: I2C bus is open collector so do NOT drive SCL or SDA high. 841 pinMode(SCL, INPUT); // release SCL pullup so that when made output it will be LOW 842 pinMode(SCL, OUTPUT); // then clock SCL Low 843 delayMicroseconds(10); // for >5uS 844 pinMode(SCL, INPUT); // release SCL LOW 845 pinMode(SCL, INPUT_PULLUP); // turn on pullup resistors again 846 // do not force high as slave may be holding it low for clock stretching. 847 delayMicroseconds(10); // for >5uS 848 // The >5uS is so that even the slowest I2C devices are handled. 849 SCL_LOW = (digitalRead(SCL) == LOW); // Check if SCL is Low. 850 int counter = 20; 851 while (SCL_LOW && (counter > 0)) { // loop waiting for SCL to become High only wait 2sec. 852 counter--; 853 delay(100); 854 SCL_LOW = (digitalRead(SCL) == LOW); 855 } 856 if (SCL_LOW) { // still low after 2 sec error 857 return 2; // I2C bus error. Could not clear. SCL clock line held low by slave clock stretch for >2sec 858 } 859 SDA_LOW = (digitalRead(SDA) == LOW); // and check SDA input again and loop 860 } 861 if (SDA_LOW) { // still low 862 return 3; // I2C bus error. Could not clear. SDA data line held low 863 } 864 865 // else pull SDA line low for Start or Repeated Start 866 pinMode(SDA, INPUT); // remove pullup. 867 pinMode(SDA, OUTPUT); // and then make it LOW i.e. send an I2C Start or Repeated start control. 868 // When there is only one I2C master a Start or Repeat Start has the same function as a Stop and clears the bus. 869 /// A Repeat Start is a Start occurring after a Start with no intervening Stop. 870 delayMicroseconds(10); // wait >5uS 871 pinMode(SDA, INPUT); // remove output low 872 pinMode(SDA, INPUT_PULLUP); // and make SDA high i.e. send I2C STOP control. 873 delayMicroseconds(10); // x. wait >5uS 874 pinMode(SDA, INPUT); // and reset pins as tri-state inputs which is the default state on reset 875 pinMode(SCL, INPUT); 876 Serial.println("I2C Recovered"); 877 return 0; // all ok 878} 879//------------------------------------------------------------------------------------------------------------------------------------------
GPS firmware
arduino
1/****************************************************************************************/ 2/* */ 3/* GPS | �Kantooya */ 4/* */ 5/* Author: Sam Farah */ 6/* Email: sam.farah1986@gmail.com */ 7/* Website: http://samfarah.net */ 8/* Version: 1.0 */ 9/* Description: */ 10/* The firmware for the ATMega microcontroller on board, it controls */ 11/* the circuit, and handles reading inputs and sends commands to FSX. */ 12/* */ 13/****************************************************************************************/ 14 15//-------------------------- Headers ---------------------------- 16#include <Quadrature.h> 17#include <AS1115.h> 18#include <WSWire.h> 19//--------------------------------------------------------------- 20 21//---------------------------- Pins ----------------------------- 22// Name Arduino Pin Pin on ATMega 23// ----------- ----------- ------------- 24#define IRQ1 A0 // 25#define Encoder1A A3 // 26#define Encoder1B A2 // 27#define Encoder2A 8 // 28#define Encoder2B 9 // 29//--------------------------------------------------------------- 30 31//------------------------ SETTINGS ----------------------------- 32#define HoldDelay 700 33//--------------------------------------------------------------- 34 35//----------------------- Prototypes ---------------------------- 36class TSwitchCtrl; 37uint8_t I2C_ClearBus(); 38//--------------------------------------------------------------- 39 40//------------------------- Objects ----------------------------- 41Quadrature Encoder1(Encoder1A, Encoder1B); 42Quadrature Encoder2(Encoder2A, Encoder2B); 43TSwitchCtrl *SwitchCtr; 44AS1115 *SwitchCtr1; 45//--------------------------------------------------------------- 46 47//---------------------- Public Variables ----------------------- 48int R1old; 49int R2old; 50int R1dif; 51int R2dif; 52unsigned long int HoldTime = 0; 53bool ClearPressed = false; 54//--------------------------------------------------------------- 55 56//-------------------------- Classes ---------------------------- 57class TSwitchCtrl 58{ 59private: 60 AS1115 * Chip; 61 String Data; 62 String OldData; 63public: 64 byte IRQ; 65 byte LSB, MSB; 66 TSwitchCtrl(uint8_t _IRQ, AS1115 *_Chip, uint8_t _LSB, uint8_t _MSB) 67 { 68 IRQ = _IRQ; 69 Chip = _Chip; 70 LSB = _LSB; 71 MSB = _MSB; 72 Data = ""; 73 Chip->begin(0x03,0x00); 74 } 75 void ReadSwitchs() 76 { 77 uint8_t ErrorCode; 78 OldData = Data; 79 Data = Chip->ReadKeysMul(&ErrorCode);// GetLeadingZeros(, 16);//potentially not needed (the Leading Zeros, already handled from library) 80 if (ErrorCode >= 4) 81 { 82 I2C_ClearBus(); 83 Wire.begin(); 84 } 85 } 86 String GetData() { return Data; } 87 String GetOldData() { return OldData; } 88}; 89//--------------------------------------------------------------- 90 91//------------------------ Functions ----------------------------- 92String GetLeadingZeros(String Bin, short digits) 93{ 94 String Padding = ""; 95 for (int i = 0; i < digits - Bin.length(); i++)Padding += "0"; 96 return Padding + Bin; 97} 98//--------------------------------------------------------------- 99 100//----------------------- Interrupt ---------------------------- 101ISR(PCINT1_vect) // handle pin change interrupt for D8 to D13 here 102{ 103 interrupts(); 104 if (digitalRead(SwitchCtr->IRQ) == LOW) 105 { 106 107 SwitchCtr->ReadSwitchs(); 108 byte ChangedIndex = 0; 109 char NewValue, InverseValue; 110 for (byte i = 0; i < 16; i++) 111 if (SwitchCtr->GetData()[i] != SwitchCtr->GetOldData()[i]) 112 { 113 NewValue = SwitchCtr->GetData()[i]; 114 InverseValue = NewValue == '0' ? '1' : '0'; 115 ChangedIndex = i; 116 } 117 //Serial.println(ChangedIndex); 118 //if (!MasterPower && ChangedIndex != 20) return;//if powered off, only listen to power swtich. 119 if (NewValue == '1') //push buttons 120 { 121 switch (ChangedIndex) 122 { 123 case 1: Serial.println("G11"); break; 124 case 2: Serial.println("G10"); break; 125 case 3: Serial.println("G12"); break; 126 case 4: Serial.println("G13"); break; 127 case 5: HoldTime = millis(); ClearPressed = true; break; 128 case 6: Serial.println("G18"); break; 129 case 7: Serial.println("G19"); break; 130 case 9: Serial.println("G02"); break; 131 case 10: Serial.println("G03"); break; 132 case 11: Serial.println("G04"); break; 133 case 12: Serial.println("G07"); break; 134 case 13: Serial.println("G08"); break; 135 case 14: Serial.println("G09"); break; 136 } 137 } 138 else 139 { 140 if (ChangedIndex == 5) 141 { 142 ClearPressed = false; 143 if (millis() - HoldTime < HoldDelay)Serial.println("G14"); 144 } 145 } 146 } 147} 148 149//****************************************************************************************************************************************** 150void setup() { 151 pinMode(IRQ1, INPUT_PULLUP); 152 Serial.begin(115200); 153 SwitchCtr1 = new AS1115(0x00); 154 SwitchCtr = new TSwitchCtrl(IRQ1, SwitchCtr1, 0, 15); 155 delay(50); 156 pciSetup(IRQ1); 157 delay(50); 158 SwitchCtr->ReadSwitchs(); 159 SwitchCtr->GetData(); 160} 161 162void loop() { 163 ENCODER(); 164 if (ClearPressed == true && millis() - HoldTime >= HoldDelay) 165 { 166 Serial.println("G15"); 167 ClearPressed = false; 168 } 169} 170//****************************************************************************************************************************************** 171 172//------------------------------------------------------------------------------------------------------------------------------------------ 173void pciSetup(byte pin) 174{ 175 *digitalPinToPCMSK(pin) |= bit(digitalPinToPCMSKbit(pin)); // enable pin 176 PCIFR |= bit(digitalPinToPCICRbit(pin)); // clear any outstanding interrupt 177 PCICR |= bit(digitalPinToPCICRbit(pin)); // enable interrupt for the group 178} 179//------------------------------------------------------------------------------------------------------------------------------------------ 180void ENCODER() { 181 int R1 = (Encoder1.position()); //The /2 is to suit the encoder 182 if (R1 != R1old) { // checks to see if it different 183 (R1dif = (R1 - R1old));// finds out the difference 184 //Serial.println(Encoder1.position()); 185 if (R1dif == 1) Serial.println("G22"); 186 if (R1dif == -1)Serial.println("G23"); 187 R1old = R1; // overwrites the old reading with the new one. 188 //Disp->SetTempValChange(true); 189 } 190 int R2 = (Encoder2.position()); //The /2 is to suit the encoder 191 if (R2 != R2old) { // checks to see if it different 192 (R2dif = (R2 - R2old));// finds out the difference 193 if (R2dif == 1) Serial.println("G20"); 194 if (R2dif == -1)Serial.println("G21"); 195 R2old = R2; // overwrites the old reading with the new one. 196 //Disp->SetTempValChange(true); 197 } 198 199} 200//------------------------------------------------------------------------------------------------------------------------------------------ 201uint8_t I2C_ClearBus() { 202#if defined(TWCR) && defined(TWEN) 203 TWCR &= ~(_BV(TWEN)); //Disable the Atmel 2-Wire interface so we can control the SDA and SCL pins directly 204#endif 205 206 pinMode(SDA, INPUT_PULLUP); // Make SDA (data) and SCL (clock) pins Inputs with pullup. 207 pinMode(SCL, INPUT_PULLUP); 208 delay(20); 209 210 boolean SCL_LOW = (digitalRead(SCL) == LOW); // Check is SCL is Low. 211 if (SCL_LOW) { //If it is held low Arduno cannot become the I2C master. 212 return 1; //I2C bus error. Could not clear SCL clock line held low 213 } 214 215 boolean SDA_LOW = (digitalRead(SDA) == LOW); // vi. Check SDA input. 216 int clockCount = 20; // > 2x9 clock 217 218 while (SDA_LOW && (clockCount > 0)) { // vii. If SDA is Low, 219 clockCount--; 220 // Note: I2C bus is open collector so do NOT drive SCL or SDA high. 221 pinMode(SCL, INPUT); // release SCL pullup so that when made output it will be LOW 222 pinMode(SCL, OUTPUT); // then clock SCL Low 223 delayMicroseconds(10); // for >5uS 224 pinMode(SCL, INPUT); // release SCL LOW 225 pinMode(SCL, INPUT_PULLUP); // turn on pullup resistors again 226 // do not force high as slave may be holding it low for clock stretching. 227 delayMicroseconds(10); // for >5uS 228 // The >5uS is so that even the slowest I2C devices are handled. 229 SCL_LOW = (digitalRead(SCL) == LOW); // Check if SCL is Low. 230 int counter = 20; 231 while (SCL_LOW && (counter > 0)) { // loop waiting for SCL to become High only wait 2sec. 232 counter--; 233 delay(50); 234 SCL_LOW = (digitalRead(SCL) == LOW); 235 } 236 if (SCL_LOW) { // still low after 2 sec error 237 return 2; // I2C bus error. Could not clear. SCL clock line held low by slave clock stretch for >2sec 238 } 239 SDA_LOW = (digitalRead(SDA) == LOW); // and check SDA input again and loop 240 } 241 if (SDA_LOW) { // still low 242 return 3; // I2C bus error. Could not clear. SDA data line held low 243 } 244 245 // else pull SDA line low for Start or Repeated Start 246 pinMode(SDA, INPUT); // remove pullup. 247 pinMode(SDA, OUTPUT); // and then make it LOW i.e. send an I2C Start or Repeated start control. 248 // When there is only one I2C master a Start or Repeat Start has the same function as a Stop and clears the bus. 249 // A Repeat Start is a Start occurring after a Start with no intervening Stop. 250 delayMicroseconds(10); // wait >5uS 251 pinMode(SDA, INPUT); // remove output low 252 pinMode(SDA, INPUT_PULLUP); // and make SDA high i.e. send I2C STOP control. 253 delayMicroseconds(10); // x. wait >5uS 254 pinMode(SDA, INPUT); // and reset pins as tri-state inputs which is the default state on reset 255 pinMode(SCL, INPUT); 256 //Serial.println("I2C Recovered"); 257 return 0; // all ok 258} 259//------------------------------------------------------------------------------------------------------------------------------------------ 260
Comments
Only logged in users can leave comments