├── COPYING.txt ├── OpenPanzerTCB ├── Battle.ino ├── ButtonsAndSwitches.ino ├── Driving.ino ├── IO.ino ├── LVC.ino ├── Lights.ino ├── ObjectSetup.ino ├── OpenPanzerTCB.ino ├── Radio.ino ├── ServoSetup.ino ├── SimpleTimerStuff.ino ├── Smoker.ino ├── Sound.ino ├── SpecFunctions.ino ├── UserTest.ino ├── Utilities.ino └── src │ ├── EEPROMex │ ├── EEPROMVar.h │ ├── EEPROMex.cpp │ ├── EEPROMex.h │ ├── LICENSE.md │ ├── README.md │ └── keywords.txt │ ├── LedHandler │ ├── LedHandler.cpp │ └── LedHandler.h │ ├── OP_Button │ ├── OP_Button.cpp │ ├── OP_Button.h │ ├── ReadMe.txt │ └── keywords.txt │ ├── OP_Devices │ └── OP_Devices.h │ ├── OP_Driver │ ├── OP_Driver.cpp │ ├── OP_Driver.h │ └── keywords.txt │ ├── OP_EEPROM │ ├── OP_EEPROM.cpp │ ├── OP_EEPROM.h │ ├── OP_EEPROM_Struct.h │ ├── OP_EEPROM_VarInfo.h │ ├── OP_EEPROM_Vars.xls │ └── keywords.txt │ ├── OP_FT │ ├── OP_FunctionsTriggers.h │ └── keywords.txt │ ├── OP_IBusDecode │ ├── OP_iBusDecode.cpp │ ├── OP_iBusDecode.h │ └── keywords.txt │ ├── OP_IO │ ├── OP_IO.h │ └── keywords.txt │ ├── OP_IRLib │ ├── OP_IRLib.cpp │ ├── OP_IRLib.h │ ├── OP_IRLibMatch.h │ └── keywords.txt │ ├── OP_Motors │ ├── OP_Motors.cpp │ ├── OP_Motors.h │ └── keywords.txt │ ├── OP_PCComm │ ├── OP_PCComm.cpp │ ├── OP_PCComm.h │ └── keywords.txt │ ├── OP_PPMDecode │ ├── OP_PPMDecode.cpp │ ├── OP_PPMDecode.h │ └── keywords.txt │ ├── OP_PololuQik │ ├── OP_PololuQik.cpp │ ├── OP_PololuQik.h │ └── keywords.txt │ ├── OP_Radio │ ├── OP_Radio.cpp │ ├── OP_Radio.h │ ├── OP_RadioDefines.h │ └── keywords.txt │ ├── OP_SBusDecode │ ├── OP_SBusDecode.cpp │ ├── OP_SBusDecode.h │ └── keywords.txt │ ├── OP_Sabertooth │ ├── OP_Sabertooth.cpp │ ├── OP_Sabertooth.h │ └── keywords.txt │ ├── OP_Scout │ ├── Examples │ │ └── ScoutControl │ │ │ └── ScoutControl.ino │ ├── OP_Scout.cpp │ ├── OP_Scout.h │ └── keywords.txt │ ├── OP_Servo │ ├── OP_Servo.cpp │ ├── OP_Servo.h │ └── keywords.txt │ ├── OP_Settings │ ├── OP_Settings.h │ └── keywords.txt │ ├── OP_SimpleTimer │ ├── OP_SimpleTimer.cpp │ ├── OP_SimpleTimer.h │ └── keywords.txt │ ├── OP_Smoker │ ├── OP_Smoker.cpp │ ├── OP_Smoker.h │ └── keywords.txt │ ├── OP_Sound │ ├── OP_Sound.cpp │ ├── OP_Sound.h │ ├── OP_SoundCard.cpp │ ├── OP_TaigenSound.cpp │ └── keywords.txt │ ├── OP_TBS │ ├── OP_TBS.cpp │ ├── OP_TBS.h │ └── keywords.txt │ ├── OP_Tank │ ├── OP_BattleTimes.h │ ├── OP_Tank.cpp │ ├── OP_Tank.h │ └── keywords.txt │ └── elapsedMillis │ ├── LICENSE │ ├── README.md │ ├── elapsedMillis.h │ ├── keywords.txt │ ├── library.json │ └── library.properties └── README.md /OpenPanzerTCB/ButtonsAndSwitches.ino: -------------------------------------------------------------------------------- 1 | 2 | // RETURN SETTINGS FROM BOARD SWITCHES 3 | // --------------------------------------------------------------------------------------------------------------------------------------------------> 4 | 5 | 6 | // FIGHT/REPAIR SWITCH: Is this tank a repair tank? 7 | // --------------------------------------------------------------------------------------------------------------------------------------------------> 8 | boolean GetIsRepair(void) 9 | { // Repair tank setting. If LOW (held to ground), tank is fighter. If HIGH (through input pullup), tank is repair. 10 | // But the actual pin read is done in the OP_Tank class. 11 | return Tank.isRepairTank(); 12 | } 13 | 14 | // DIPSWITCH 1 & 2: TANK WEIGHT CLASS 15 | // --------------------------------------------------------------------------------------------------------------------------------------------------> 16 | char GetWeightClass(void) 17 | { 18 | // Weight classes are selected by dipswitches 1 & 2 19 | // Both on: CUSTOM - set by user 20 | // 1 on, 2 off: Light 21 | // 1 off, 2 on: Medium 22 | // Both off: Heavy 23 | 24 | if (DipSwitchOn(1) && DipSwitchOn(2)) return WC_CUSTOM; 25 | else if (DipSwitchOn(1) && DipSwitchOff(2)) return WC_LIGHT; 26 | else if (DipSwitchOff(1) && DipSwitchOn(2)) return WC_MEDIUM; 27 | else if (DipSwitchOff(1) && DipSwitchOff(2)) return WC_HEAVY; 28 | } 29 | 30 | // DIPSWITCH 3-4: MENU SELECTION 31 | // --------------------------------------------------------------------------------------------------------------------------------------------------> 32 | // Four menus can be selected by dip-switches. After setting the dipswitch, enter the menu by pressing the input button for 2 seconds. 33 | uint8_t GetMenuNumber(void) 34 | { 35 | if (DipSwitchOn(3) && DipSwitchOn(4)) return 1; // Barrel elevation pan servo setup 36 | else if (DipSwitchOn(3) && DipSwitchOff(4)) return 2; // Steering servo for cars/halftracks 37 | else if (DipSwitchOff(3) && DipSwitchOn(4)) return 3; // Turret rotation servo setup 38 | else if (DipSwitchOff(3) && DipSwitchOff(4)) return 4; // Recoil servo setup 39 | } 40 | 41 | // DIPSWITCH 5 - PC Communication Serial Port 42 | // --------------------------------------------------------------------------------------------------------------------------------------------------> 43 | // If dipswitch 5 is ON, communication with the PC will be through the USB port. If it is OFF, communication will be through Aux Serial (Serial 1). 44 | // We can attach a Bluetooth module to Serial 1 and therefore update settings from OP Config wirelessly. 45 | // NOTE: This port is only used for reading/writing settings. It is NOT used for *flashing* new firmware to the board - that always goes through the USB port. 46 | // NOTE: Remember that the USB port and Aux Serial will show up as different COM ports on your computer. 47 | // NOTE: The baud rate for the Aux Serial port defaults to 115,200 but you can change it on the Misc tab of OP Config. Baud rate for USB will always be 115200. 48 | boolean UseAuxSerialForPCComm(void) 49 | { 50 | return DipSwitchOff(5); 51 | } 52 | 53 | void SetActiveCommPort() 54 | { 55 | static uint8_t useAlternate = 0xAA; 56 | static uint32_t lastTime = millis(); 57 | 58 | // The local static variable useAlternate keeps track of the current setting. 59 | // But when we call this function, we check the current setting against the actual position of Dipswitch #5. 60 | // If the current setting doesn't match, the user made a change, so update the current setting, and 61 | // adjust the pointer to the serial port for both Debug output and the PCComm class. 62 | 63 | // We haven't yet initialized - do so now. This will only get run once 64 | if (useAlternate == 0xAA) 65 | { 66 | if (UseAuxSerialForPCComm()) 67 | { 68 | PCComm.switchToAltSerial(); // Use Serial 1 for PC comm 69 | DebugSerial = &Serial1; // Use Serial 1 for debugging messages 70 | useAlternate = 0xFF; 71 | } 72 | else 73 | { 74 | PCComm.revertToDefaultSerial(); // Use Serial 0 for PC comm 75 | DebugSerial = &Serial; // Use Serial 0 for debugging messages 76 | useAlternate = 0x00; 77 | } 78 | } 79 | 80 | // This will get run every other time this function is called, which will be once per loop 81 | // It will only change the serial port of the switch has changed since last time, and only 82 | // if a certain amount of time has passed since the last check (switch debounce) 83 | if (millis() - lastTime > 50) // 50ms debounce 84 | { 85 | lastTime = millis(); 86 | if (UseAuxSerialForPCComm() && useAlternate == 0x00) 87 | { 88 | PCComm.switchToAltSerial(); // Use Serial 1 for PC comm 89 | DebugSerial = &Serial1; // Use Serial 1 for debugging messages 90 | if (DEBUG) DebugSerial->println(F("Comms changed to Serial 1")); 91 | useAlternate = 0xFF; 92 | } 93 | else if (!UseAuxSerialForPCComm() && useAlternate == 0xFF) 94 | { 95 | PCComm.revertToDefaultSerial(); // Use Serial 0 for PC comm 96 | DebugSerial = &Serial; // Use Serial 0 for debugging messages 97 | if (DEBUG) DebugSerial->println(F("Comms changed to USB")); 98 | useAlternate = 0x00; 99 | } 100 | } 101 | } 102 | 103 | // BASIC DIPSWITCH UTILITIES 104 | // --------------------------------------------------------------------------------------------------------------------------------------------------> 105 | // The dipswitches are held to ground when "ON" 106 | // Physically these are left floating when "OFF", but we have input pullups turned on, so they are actually high. 107 | // In short, low is ON and high is OFF. 108 | boolean DipSwitchOn(uint8_t switchNum) 109 | { 110 | return !DipSwitchOff(switchNum); // If it's off, it's not on 111 | } 112 | 113 | boolean DipSwitchOff(uint8_t switchNum) 114 | { 115 | switch (switchNum) 116 | { 117 | case 1: return digitalRead(pin_Dip1); break; 118 | case 2: return digitalRead(pin_Dip2); break; 119 | case 3: return digitalRead(pin_Dip3); break; 120 | case 4: return digitalRead(pin_Dip4); break; 121 | case 5: return digitalRead(pin_Dip5); break; 122 | default: return false; 123 | } 124 | } 125 | 126 | -------------------------------------------------------------------------------- /OpenPanzerTCB/IO.ino: -------------------------------------------------------------------------------- 1 | 2 | // IO Ports 3 | // -------------------------------------------------------------------------------------------------------------------------------->> 4 | // Not very sophisticated. But there are only two of them, and the functionality is basic. No need for a whole class 5 | 6 | void SetActiveInputFlag(void) 7 | { 8 | // It is wise to set these to inputs if we are not going to use them, because it is less likely you will accidentally fry a pin that way. 9 | // But just because they are set to inputs, doesn't mean we are using them. We are only using them if the input is set as a trigger to some 10 | // function. So let's run through the function triggers and see if any match. 11 | 12 | for (int i=0; i= (trigger_id_multiplier_ports * (i + 1)) && 20 | eeprom.ramcopy.SF_Trigger[t].TriggerID < (trigger_id_multiplier_ports * (i + 2))) 21 | { 22 | IO_Pin[i].inputActive = true; // Ok, this is an input, and it is assigned to a function. Set Active to true 23 | break; 24 | } 25 | } 26 | } 27 | } 28 | //DebugSerial->print(F("A Active Input: ")); 29 | //PrintLnYesNo(IO_Pin[0].inputActive); 30 | //DebugSerial->print(F("B Active Input: ")); 31 | //PrintLnYesNo(IO_Pin[1].inputActive); 32 | } 33 | 34 | void ReadIOPorts() 35 | { 36 | // No point doing analog reads every loop if these are not set as inputs to some function, 37 | // so we do the inputActive check first 38 | if (IO_Pin[IOA].inputActive) PortA_ReadValue(); 39 | if (IO_Pin[IOB].inputActive) PortB_ReadValue(); 40 | } 41 | 42 | // PORT A - OUTPUT FUNCTIONS (On, Off, Toggle, Pulse, Blink) 43 | boolean isPortA_Output(void) 44 | { // If this statement is true, PortA is set to Output 45 | // If false, it is an input 46 | return (IO_port & _BV(IO_A_bit)); 47 | } 48 | void PortA_On() 49 | { // For safety, we only do anything if this has been set to output 50 | if (isPortA_Output()) 51 | { 52 | if (DEBUG && !IO_Output[IOA].isOn()) { DebugSerial->println(F("IO Port A Output - On")); } 53 | IO_Output[IOA].on(); 54 | } 55 | } 56 | void PortA_Off() 57 | { // For safety, we only do anything if this has been set to output 58 | if (isPortA_Output()) 59 | { 60 | if (DEBUG && (IO_Output[IOA].isOn() || IO_Output[IOA].isBlinking())) { DebugSerial->println(F("IO Port A Output - Off")); } 61 | IO_Output[IOA].off(); 62 | } 63 | } 64 | void PortA_Toggle() 65 | { 66 | // Normally we would use IO_Output[IOA].toggle(); but we want to show the debugging messages so we do it this way instead 67 | IO_Output[IOA].isOn() ? PortA_Off() : PortA_On(); 68 | } 69 | void PortA_Pulse() 70 | { 71 | // This function briefly holds the pin in the opposite direction of its default state. 72 | // For example if the default is high, the pin is held low briefly. This can be used to 73 | // emulate a "button push" to external devices that can accept a logic signal. 74 | if (IO_Pin[IOA].Settings.dataType) 75 | { 76 | IO_Output[IOA].off(); // Go in the opposite direction (dataType == true means default high, so go low) 77 | timer.setTimeout(eeprom.ramcopy.IOPulseOnTime_mS, PortA_On); // Wait briefly then revert to default high 78 | } 79 | else 80 | { 81 | IO_Output[IOA].on(); // Go in the opposite direction (dataType == false means default low, so go high) 82 | timer.setTimeout(eeprom.ramcopy.IOPulseOnTime_mS, PortA_Off); // Wait briefly then revert to default low 83 | } 84 | if (DEBUG) { DebugSerial->println(F("IO Port A - Pulsed")); } 85 | } 86 | void PortA_Blink() 87 | { 88 | IO_Output[IOA].startBlinking(eeprom.ramcopy.IOBlinkOnTime_mS, eeprom.ramcopy.IOBlinkOffTime_mS); 89 | if (DEBUG) { DebugSerial->println(F("IO Port A - Start Blinking")); } 90 | } 91 | 92 | // PORT A - INPUT FUNCTION 93 | void PortA_ReadValue(void) 94 | { int oldVal; 95 | if (isPortA_Output()==false) 96 | { 97 | oldVal = IO_Pin[IOA].inputValue; 98 | if (IO_Pin[IOA].Settings.dataType) 99 | { // If the user set this to "digital" input (dataType = 1), anything over 1/2 counts as 0 (because we have pullups turned on), 100 | // and anything below counts as 1. In other words, the input will automatically be off (high). The user has to 101 | // specifically tie the input to ground to set the input on (low). 102 | analogRead(pin_IO_A) > 512 ? IO_Pin[IOA].inputValue = 0 : IO_Pin[IOA].inputValue = 1; 103 | } 104 | else 105 | { // In this case we want to save the actual analog reading. 106 | // We may want to filter this (take an average) to eliminate noise, but that is not yet implemented. 107 | IO_Pin[IOA].inputValue = analogRead(pin_IO_A); 108 | } 109 | // Only set the updated flag if the value has changed. 110 | IO_Pin[IOA].inputValue == oldVal ? IO_Pin[IOA].updated = false : IO_Pin[IOA].updated = true; 111 | } 112 | } 113 | 114 | 115 | // PORT B - OUTPUT FUNCTIONS (On, Off, Toggle, Pulse, Blink) 116 | boolean isPortB_Output(void) 117 | { // If this statement is true, PortB is set to Output 118 | // If false, it is an input 119 | return (IO_port & _BV(IO_B_bit)); 120 | } 121 | void PortB_On() 122 | { // For safety, we only do anything if this has been set to output 123 | if (isPortB_Output()) 124 | { 125 | if (DEBUG && !IO_Output[IOB].isOn()) { DebugSerial->println(F("IO Port B Output - On")); } 126 | IO_Output[IOB].on(); 127 | } 128 | } 129 | void PortB_Off() 130 | { // For safety, we only do anything if this has been set to output 131 | if (isPortB_Output()) 132 | { 133 | if (DEBUG && (IO_Output[IOB].isOn() || IO_Output[IOB].isBlinking())) { DebugSerial->println(F("IO Port B Output - Off")); } 134 | IO_Output[IOB].off(); 135 | } 136 | } 137 | void PortB_Toggle() 138 | { 139 | // Normally we would use IO_Output[IOB].toggle(); but we want to show the debugging messages so we do it this way instead 140 | IO_Output[IOB].isOn() ? PortB_Off() : PortB_On(); 141 | } 142 | void PortB_Pulse() 143 | { 144 | // This function briefly holds the pin in the opposite direction of its default state. 145 | // For example if the default is high, the pin is held low briefly. This can be used to 146 | // emulate a "button push" to external devices that can accept a logic signal. 147 | if (IO_Pin[IOB].Settings.dataType) 148 | { 149 | IO_Output[IOB].off(); // Go in the opposite direction (dataType == true means default high, so go low) 150 | timer.setTimeout(eeprom.ramcopy.IOPulseOnTime_mS, PortB_On); // Wait briefly then revert to default high 151 | } 152 | else 153 | { 154 | IO_Output[IOB].on(); // Go in the opposite direction (dataType == false means default low, so go high) 155 | timer.setTimeout(eeprom.ramcopy.IOPulseOnTime_mS, PortB_Off); // Wait briefly then revert to default low 156 | } 157 | if (DEBUG) { DebugSerial->println(F("IO Port B - Pulsed")); } 158 | } 159 | void PortB_Blink() 160 | { 161 | IO_Output[IOB].startBlinking(eeprom.ramcopy.IOBlinkOnTime_mS, eeprom.ramcopy.IOBlinkOffTime_mS); 162 | if (DEBUG) { DebugSerial->println(F("IO Port B - Start Blinking")); } 163 | } 164 | 165 | // PORT B - INPUT FUNCTION 166 | void PortB_ReadValue(void) 167 | { int oldVal; 168 | if (isPortB_Output()==false) // In other words, do this only if PortB is set to Input 169 | { 170 | oldVal = IO_Pin[IOB].inputValue; 171 | if (IO_Pin[IOB].Settings.dataType) 172 | { // If the user set this to "digital" input (dataType = 1), anything over 1/2 counts as 0 (because we have pullups turned on), 173 | // and anything below counts as 1. In other words, the input will automatically be off (high). The user has to 174 | // specifically tie the input to ground to set the input on (low). 175 | analogRead(pin_IO_B) > 512 ? IO_Pin[IOB].inputValue = 0 : IO_Pin[IOB].inputValue = 1; 176 | } 177 | else 178 | { // In this case we want to save the actual analog reading. 179 | // We may want to filter this (take an average) to eliminate noise, but that is not yet implemented. 180 | IO_Pin[IOB].inputValue = analogRead(pin_IO_B); 181 | } 182 | // Only set the updated flag if the value has changed. 183 | IO_Pin[IOB].inputValue == oldVal ? IO_Pin[IOB].updated = false : IO_Pin[IOB].updated = true; 184 | } 185 | } 186 | 187 | 188 | -------------------------------------------------------------------------------- /OpenPanzerTCB/LVC.ino: -------------------------------------------------------------------------------- 1 | 2 | // LOW VOLTAGE CUTOFF 3 | // --------------------------------------------------------------------------------------------------------------------------------------------------> 4 | void CheckVoltage(void) 5 | { 6 | // LOW VOLTAGE CUTOFF & BATTERY UNPLUGGED 7 | // ------------------------------------------------------------------------------------------------------------------------------------------------> 8 | // The program starts with BatteryUnplugged set to true. We only do this check until the battery is first detected. Once it is, we don't check again. 9 | // Even if the user later unplugs the battery, it will be considered an LVC condition. 10 | if (BatteryUnplugged) 11 | { 12 | if (!IsBatteryUnplugged()) 13 | { 14 | // Ok, battery has been detected 15 | BatteryUnplugged = false; 16 | HavePower = true; // True for now, we will do an LVC check next to make sure the battery has enough voltage 17 | } 18 | } 19 | else 20 | { // In this case, we know the battery is (or was) plugged in. 21 | // Now check the voltage level 22 | if (BatteryBelowCutoff() && !LVC) // The battery has just dropped below the cutoff level. 23 | { 24 | LVC = true; 25 | HavePower = false; 26 | if (DEBUG) 27 | { 28 | DebugSerial->print(F("LVC threshold reached! (")); 29 | DumpLVC_Voltage(); 30 | DebugSerial->println(F("v)")); 31 | } 32 | StopEverything(); 33 | LVC_BlinkHandler(); // Start the special blinker to indicate LVC 34 | } 35 | else if (LVC && !BatteryBelowCutoff()) 36 | { // In this case we were in LVC, but now the battery has gone back up above the cutoff 37 | // Restore power 38 | LVC = false; 39 | HavePower = true; 40 | if (DEBUG) DebugSerial->println(F("LVC Exit - Voltage Restored")); 41 | } 42 | } 43 | } 44 | 45 | void EnableRoutineVoltageCheck(void) 46 | { 47 | LVC_TimerID = timer.setInterval(2000, CheckVoltage); 48 | } 49 | 50 | void DisableRoutineVoltageCheck(void) 51 | { 52 | if (timer.isEnabled(LVC_TimerID)) timer.deleteTimer(LVC_TimerID); 53 | } 54 | 55 | boolean IsBatteryUnplugged(void) 56 | { 57 | // If the voltage reading is really low, the issue probably isn't a dead battery, but more likely the 58 | // user is running from USB power alone. That is fine, but we still want to know about it. 59 | if (ReadVoltage() < 2.0) // We consider anything below 2 volts to be unplugged 60 | { 61 | return true; 62 | } 63 | else 64 | { 65 | return false; 66 | } 67 | } 68 | 69 | boolean BatteryBelowCutoff(void) 70 | { 71 | uint16_t milliVolts; 72 | 73 | // Read voltage, convert it to millivolts since that's what we're actually going to use to compare to the cutoff 74 | milliVolts = static_cast(ReadVoltage() * 1000.0); 75 | 76 | // Check voltage against cutoff. 77 | if (milliVolts < eeprom.ramcopy.LVC_Cutoff_mV) 78 | { 79 | return true; 80 | } 81 | else 82 | { 83 | return false; 84 | } 85 | } 86 | 87 | float ReadVoltage(void) 88 | { 89 | int voltSense; // What we read on the analog pin 90 | float unFilteredVoltage; // Converted to voltage on pin 91 | static float filteredVoltage; // Voltage on pin after being run through a simple low-pass filter 92 | float Voltage; // Pin voltage converted to battery voltage 93 | static boolean firstPass = true; 94 | 95 | // We are using this voltage divider: 96 | // 97 | // GND |-----/\/\/\-----------------/\/\/\-------> +V Batt 98 | // 4.7k | 10k 99 | // | 100 | // Measure 101 | 102 | // The voltage we measure on the pin isn't the actual outside voltage of the battery, it is the battery voltage divided by some number 103 | //multiplier = (4.7 + 10) / 4.7 = 3.1277 104 | const float multiplier = 3.1277; // Multiply this by our measured voltage and we will have battery voltage 105 | 106 | // But wait! Our input polarity protection diode also drops at least 0.3 volts, and up to 0.5 volts at 5A draw (max 0.7 volts but we shouldn't be running that much current through it). 107 | // (These are specs for the Vishay V12P10-M3/86A) 108 | // Most of the time we will probably be at the low end of that scale, and that is also more conservative for LVC purposes. 109 | const float vAdj = 0.3; // Our adjustment factor 110 | 111 | // To reduce the effect of noise, we run our voltage through a low-pass filter. 112 | // With an alpha of 0.9, it is like giving the voltage reading a weight of 10%, and past readings a weight of 90% 113 | const float alpha = 0.9; 114 | 115 | // Ok, here we go: first take an analog reading (will give us a number between 0-1023) 116 | voltSense = analogRead(pin_BattVoltage); 117 | //Convert the reading to actual voltage read (0 - 5 Vdc) 118 | unFilteredVoltage = (voltSense / 1024.0) * 5.0; 119 | // Now run it through low-pass filter 120 | if (firstPass) { filteredVoltage = unFilteredVoltage; firstPass = false; } 121 | filteredVoltage = alpha * filteredVoltage + (1.0 - alpha) * unFilteredVoltage; 122 | // Now convert the measured voltage to the external battery voltage by accounting for our voltage divider 123 | Voltage = filteredVoltage * multiplier; 124 | // Now also add our adjustment factor to account for the voltage drop on the input polarity diode 125 | Voltage += vAdj; 126 | 127 | // In testing this results in a pretty accurate reading 128 | // Takes about 700 microSeconds (0.7 mS = 0.0007 seconds) 129 | //DebugSerial->print("Voltage: "); 130 | //DebugSerial->println(Voltage,2); 131 | 132 | return Voltage; 133 | } 134 | 135 | 136 | -------------------------------------------------------------------------------- /OpenPanzerTCB/Radio.ino: -------------------------------------------------------------------------------- 1 | 2 | 3 | void StartFailsafe() 4 | { 5 | if (!Failsafe) 6 | { 7 | StopEverything(); // Stop every physical movement 8 | Failsafe = true; // Set the failsafe flag 9 | StartFailsafeLights(); // Start the failsafe blinking effect 10 | if (DEBUG) { DebugSerial->println(F("RADIO FAILSAFE")); } 11 | } 12 | } 13 | 14 | void EndFailsafe() 15 | { 16 | if (Failsafe) 17 | { 18 | Failsafe = false; 19 | StopFailsafeLights(); 20 | ForceTriggersOnFirstPass = true; // Force a re-execution of all function triggers 21 | if (SAVE_DEBUG) 22 | { 23 | DebugSerial->print(F("Radio Ready - ")); 24 | DebugSerial->println(RadioProtocol(Radio.getProtocol())); 25 | } 26 | } 27 | } 28 | 29 | 30 | -------------------------------------------------------------------------------- /OpenPanzerTCB/SimpleTimerStuff.ino: -------------------------------------------------------------------------------- 1 | 2 | // This gets called each time through the main loop. If we have 3 | // anything that needs to be continuously polled, put it here. 4 | void PerLoopUpdates(void) 5 | { 6 | InputButton.read(); // Read the input button 7 | SetActiveCommPort(); // Check Dipswitch #5 and set the communication port to USB (switch On) or Serial 1 (switch Off) 8 | UpdateSimpleTimers(); // Update timers 9 | } 10 | 11 | void UpdateSimpleTimers() 12 | { 13 | timer.run(); // Our simple timer object, used all over the place including by various libraries. 14 | Radio.Update(); // Radio update (polls SBus and iBus) 15 | UpdateEngineStatusDelayTimer(); // Engine status delay timer, prevents engine changing states quickly if user has specified a delay 16 | Tank.Update(); // Polled updates for the tank object 17 | 18 | // Now we also update the four motor objects. The motor update() routines will only do something if the motor type is a serial controller. 19 | // We can use this to force serial commands be sent at set intervals even if the command hasn't changed; this keeps us from tripping the serial 20 | // watchdog that for example the Scout ESC implements. 21 | switch (eeprom.ramcopy.DriveType) 22 | { 23 | case DT_TANK: { RightTread->update(); LeftTread->update(); } break; 24 | case DT_HALFTRACK: { RightTread->update(); LeftTread->update(); } break; 25 | case DT_CAR: { DriveMotor->update(); } break; 26 | case DT_DKLM: // Fall through 27 | case DT_DMD: { DriveMotor->update(); SteeringMotor->update(); } break; 28 | default: break; 29 | } 30 | 31 | TurretRotation->update(); 32 | TurretElevation->update(); 33 | 34 | // We also update the smoker object because it can have special effects that require polling, 35 | // or serial watchdog that requires re-sending the current speed at regular intervals 36 | Smoker->update(TransmissionEngaged); 37 | 38 | // Update IO A/B if outputs 39 | for (int i=0; i> 3 | // SMOKER STUFF 4 | // --------------------------------------------------------------------------------------------->> 5 | 6 | // Typically the user will want the smoker to be controlled automatically by the TCB and set to 7 | // whatever the engine speed is. However we do give the user the option of controlling the smoker 8 | // manually with an analog input. The functions below are used by the main sketch to set the 9 | // smoker speed automatically, but they all check for the the SmokerControlAuto flag, and only 10 | // perform the action if it is enabled. 11 | 12 | // In other words, we use these functions instead of direct calls to the Smoker object so we 13 | // can implement the auto check. 14 | 15 | // In some cases we also check if the user has the SmokerEnable flag set to true. 16 | // This flag can be controlled by the user on-the-fly if they want to temporarily disable the smoker 17 | // from the transmitter. 18 | 19 | void EnableSmoker() 20 | { 21 | if (!SmokerEnabled) 22 | { 23 | SmokerEnabled = true; 24 | if (DEBUG) { DebugSerial->println(F("Smoker enabled")); } 25 | 26 | // Also, if they enable while the engine is running, we need to auto-turn it on 27 | if (EngineRunning) 28 | { 29 | TransmissionEngaged ? SetSmoker_Idle() : SetSmoker_FastIdle(); 30 | } 31 | } 32 | } 33 | 34 | void DisableSmoker() 35 | { 36 | if (SmokerEnabled) 37 | { 38 | // If they disable while the engine is running, we need to auto turn it off 39 | if (EngineRunning) ShutdownSmoker(TransmissionEngaged); 40 | 41 | // Disable smoker 42 | SmokerEnabled = false; 43 | if (DEBUG) { DebugSerial->println(F("Smoker disabled")); } 44 | } 45 | } 46 | 47 | void ToggleSmoker() 48 | { 49 | if (SmokerEnabled) DisableSmoker(); 50 | else EnableSmoker(); 51 | } 52 | 53 | void StopSmoker(void) 54 | { 55 | if (eeprom.ramcopy.SmokerControlAuto) 56 | { 57 | Smoker->stop(); 58 | } 59 | } 60 | void StartSmoker(boolean engaged) 61 | { 62 | if (eeprom.ramcopy.SmokerControlAuto && SmokerEnabled) 63 | { 64 | Smoker->Startup(engaged); 65 | } 66 | } 67 | void ShutdownSmoker(boolean engaged) 68 | { 69 | if (eeprom.ramcopy.SmokerControlAuto) 70 | { 71 | Smoker->Shutdown(engaged); 72 | } 73 | } 74 | void SetSmoker_Idle(void) 75 | { 76 | if (eeprom.ramcopy.SmokerControlAuto && SmokerEnabled) 77 | { 78 | Smoker->setIdle(); 79 | } 80 | } 81 | void SetSmoker_FastIdle(void) 82 | { 83 | if (eeprom.ramcopy.SmokerControlAuto && SmokerEnabled) 84 | { 85 | Smoker->setFastIdle(); 86 | } 87 | } 88 | void SetSmoker_Speed(int smoker_speed) 89 | { 90 | if (eeprom.ramcopy.SmokerControlAuto && SmokerEnabled) 91 | { 92 | Smoker->setSpeed(smoker_speed); 93 | } 94 | } 95 | void Smoker_RestoreSpeed(void) 96 | { 97 | if (eeprom.ramcopy.SmokerControlAuto && SmokerEnabled) 98 | { 99 | Smoker->restore_Speed(); 100 | } 101 | } 102 | void Smoker_SetDestroyedSpeed() 103 | { 104 | if (eeprom.ramcopy.SmokerControlAuto && SmokerEnabled && eeprom.ramcopy.SmokerDestroyedSpeed > 0) 105 | { 106 | Smoker->restore_Speed(); // The speed range may have been diminished during battle, we want to restore the full range 107 | Smoker->setSpeed(eeprom.ramcopy.SmokerDestroyedSpeed); // Now apply the user's smoker speed setting for when the tank is destroyed 108 | } 109 | } 110 | 111 | // These functions are called if the user wants to control the smoker output manually. Any motor could be attached to the output and run 112 | // in a single direction at variable speed with an analog input (or dim a high-current light) 113 | void Smoker_ManualControl(uint16_t level) 114 | { 115 | // This should be prevented from other sanity checking, but just in case, don't allow this function to do anything 116 | // if the smoker is being auto-controlled by the engine speed. 117 | if (eeprom.ramcopy.SmokerControlAuto == false) 118 | { // Recall, all analog special functions will receive values from 0-1023. 119 | // But the Smoker speed is a value from 0 to MOTOR_MAX_FWDSPEED, so we need to use the map function: 120 | Smoker->setSpeed(map(level, ANALOG_SPECFUNCTION_MIN_VAL, ANALOG_SPECFUNCTION_MAX_VAL, 0, MOTOR_MAX_FWDSPEED)); 121 | } 122 | } 123 | 124 | void Smoker_PreheatEnable() 125 | { 126 | // Restore our active preheat seconds setting to the saved version in the eeprom.ramcopy 127 | if (SmokerPreHeat_Sec == 0 && eeprom.ramcopy.SmokerPreHeat_Sec != 0) 128 | { 129 | SmokerPreHeat_Sec = eeprom.ramcopy.SmokerPreHeat_Sec; 130 | if (DEBUG) 131 | { 132 | DebugSerial->print("Smoker preheat delay enabled ("); 133 | DebugSerial->print(eeprom.ramcopy.SmokerPreHeat_Sec); 134 | DebugSerial->println(" seconds)"); 135 | } 136 | } 137 | } 138 | void Smoker_PreheatDisable() 139 | { 140 | // By setting our active preheat seconds setting to 0 we disable the preheat functionality 141 | if (SmokerPreHeat_Sec != 0) 142 | { 143 | SmokerPreHeat_Sec = 0; 144 | if (DEBUG) DebugSerial->println("Smoker preheat delay disabled"); 145 | } 146 | } 147 | void Smoker_PreheatToggle() 148 | { 149 | static boolean isEnabled = (bool)eeprom.ramcopy.SmokerPreHeat_Sec; 150 | if (isEnabled) 151 | { 152 | Smoker_PreheatDisable(); 153 | isEnabled = false; 154 | } 155 | else 156 | { 157 | Smoker_PreheatEnable(); 158 | isEnabled = true; 159 | } 160 | } 161 | 162 | void Smoker_ManualOn() 163 | { 164 | if (eeprom.ramcopy.SmokerControlAuto == false) 165 | { 166 | Smoker->setSpeed(MOTOR_MAX_FWDSPEED); 167 | } 168 | } 169 | 170 | void Smoker_ManualOff() 171 | { 172 | if (eeprom.ramcopy.SmokerControlAuto == false) 173 | { 174 | Smoker->setSpeed(0); 175 | } 176 | } 177 | 178 | void Smoker_ManualToggle() 179 | { 180 | if (eeprom.ramcopy.SmokerControlAuto == false) 181 | { 182 | if (Smoker->getSpeed() > 0) Smoker->setSpeed(0); 183 | else Smoker->setSpeed(MOTOR_MAX_FWDSPEED); 184 | } 185 | } 186 | 187 | 188 | -------------------------------------------------------------------------------- /OpenPanzerTCB/Sound.ino: -------------------------------------------------------------------------------- 1 | 2 | void InstantiateSoundObject(void) 3 | { 4 | // Sanity check - make sure Sound Device is valid 5 | if (eeprom.ramcopy.SoundDevice < SD_FIRST_SD || eeprom.ramcopy.SoundDevice > SD_LAST_SD) 6 | { // Default to TBS Mini if we have some invalid value, and update EEPROM too 7 | eeprom.ramcopy.SoundDevice = SD_BENEDINI_TBSMINI; 8 | EEPROM.updateInt(offsetof(_eeprom_data, SoundDevice), SD_BENEDINI_TBSMINI); 9 | } 10 | 11 | switch (eeprom.ramcopy.SoundDevice) 12 | { 13 | case SD_BENEDINI_TBSMINI: 14 | TankSound = new BenediniTBS(&timer, false); // false means "not the Micro" but instead this is the Mini 15 | RCOutput6_Available = false; // The Benedini Mini requires all three of these RC outputs, so they are not available for other uses 16 | RCOutput7_Available = false; 17 | RCOutput8_Available = false; 18 | break; 19 | 20 | case SD_BENEDINI_TBSMICRO: 21 | TankSound = new BenediniTBS(&timer, true); // true means "Micro" (not Mini) 22 | RCOutput6_Available = true; // The Benedini Micro will only use Prop 1 and 2 (RC Outputs 8 and 7), Prop 3 is open for the user, he could program some fancy switches in the Tx and pass them through. 23 | RCOutput7_Available = false; 24 | RCOutput8_Available = false; 25 | break; 26 | 27 | case SD_OP_SOUND_CARD: 28 | TankSound = new OP_SoundCard(&MotorSerial); // We communicate on the same serial port as we use for serial motor controllers 29 | RCOutput6_Available = true; // Because the OP Sound Card communicates over serial, we have all three of these RC outputs free for general use 30 | RCOutput7_Available = true; 31 | RCOutput8_Available = true; 32 | break; 33 | 34 | case SD_TAIGEN_SOUND: 35 | TankSound = new OP_TaigenSound(); 36 | TankServos.detach(PROP1); // We will be using this output for the Taigen sound card, so make sure it is detached as a servo output (should already be anyway) 37 | RCOutput6_Available = true; // Taigen needs the Prop1 output (Servo 8). But RC outputs 6 and 7 are free for general use. 38 | RCOutput7_Available = true; 39 | RCOutput8_Available = false; // This one reserved for Taigen comms. 40 | break; 41 | 42 | case SD_BEIER_USMRC2: 43 | // Not available yet 44 | RCOutput6_Available = false; // Don't know about these but keep them reserved for now. 45 | RCOutput7_Available = false; 46 | RCOutput8_Available = false; 47 | break; 48 | 49 | case SD_ONBOARD: // No onboard sound for the MkI TCB - fallthrough to default 50 | default: 51 | // We shouldn't end up here but in case we do, we need to define something or else the program will croak at runtime. 52 | // We set it to TBS Mini and save it to EEPROM so we don't end up here again next time 53 | eeprom.ramcopy.SoundDevice = SD_BENEDINI_TBSMINI; 54 | EEPROM.updateInt(offsetof(_eeprom_data, SoundDevice), SD_BENEDINI_TBSMINI); 55 | TankSound = new BenediniTBS(&timer, false); // false meaning Mini, not Micro 56 | RCOutput6_Available = false; // The Benedini requires all three of these RC outputs, so they are not available for other uses 57 | RCOutput7_Available = false; 58 | RCOutput8_Available = false; 59 | } 60 | 61 | // Now initialize 62 | TankSound->begin(); 63 | 64 | } 65 | 66 | // We need local functions here in the sketch so we can assign these to our 67 | // special function callbacks in LoadFunctionTriggers() in the ObjectSetup tab 68 | void SetVolume(uint16_t unmapped_level) 69 | { 70 | static uint8_t lastLevel = 0; 71 | 72 | // TankSound volume adjustment function expects a uint8_t value from 0-100 73 | uint8_t level = map(unmapped_level, ANALOG_SPECFUNCTION_MIN_VAL, ANALOG_SPECFUNCTION_MAX_VAL, 0, 100); 74 | 75 | // Only update if changed by some small amount - this hysterisis prevents us from constantly spamming 76 | // the serial port as a consequence of a jittery signal. 77 | if (abs(level - lastLevel) > 2) // Apply changes greater than 2 percent 78 | { 79 | if (level < 3) level = 0; // This helps ensure we can always get an actual Off position 80 | if (level > 97) level = 100; // And this that we can always reliably achieve On 81 | TankSound->SetVolume(level); 82 | lastLevel = level; 83 | if (DEBUG) { DebugSerial->print(F("Set volume: ")); PrintLnPct(level); } 84 | } 85 | } 86 | 87 | void IncreaseVolume(void) 88 | { 89 | TankSound->IncreaseVolume(); 90 | } 91 | void DecreaseVolume(void) 92 | { 93 | TankSound->DecreaseVolume(); 94 | } 95 | void StopVolume(void) 96 | { 97 | TankSound->StopVolume(); 98 | } 99 | 100 | void EnableTrackOverlaySounds() 101 | { 102 | TankSound->EnableTrackOverlay(true); 103 | } 104 | void DisableTrackOverlaySounds() 105 | { 106 | TankSound->EnableTrackOverlay(false); 107 | } 108 | 109 | void TriggerUserSound(uint8_t s) 110 | { 111 | TankSound->UserSound_Play(s); 112 | if (DEBUG) { PrintUserSound(); DebugSerial->println(s); } 113 | } 114 | void UserSound_Repeat(uint8_t s) 115 | { 116 | TankSound->UserSound_Repeat(s); 117 | if (DEBUG) { PrintUserSound(); DebugSerial->print(s); DebugSerial->println(F(" - Start Repeating")); } 118 | } 119 | void UserSound_Stop(uint8_t s) 120 | { 121 | TankSound->UserSound_Stop(s); 122 | if (DEBUG) { PrintUserSound(); DebugSerial->print(s); DebugSerial->println(F(" - Stop")); } 123 | } 124 | void UserSound_StopAll() 125 | { 126 | TankSound->UserSound_StopAll(); 127 | if (DEBUG) { DebugSerial->println(F("Stop All User Sounds")); } 128 | } 129 | 130 | void PrintUserSound() 131 | { 132 | DebugSerial->print(F("User Sound ")); 133 | } 134 | 135 | void SoundBank(soundbank sb, switch_action a) 136 | { 137 | TankSound->SoundBank(sb, a); // Send the sound bank command 138 | if (DEBUG) 139 | { 140 | PrintSoundBank(sb); 141 | switch (a) 142 | { 143 | case ACTION_ONSTART: DebugSerial->println(F("Play/Stop")); break; 144 | case ACTION_PLAYNEXT: DebugSerial->println(F("Play Next")); break; 145 | case ACTION_PLAYPREV: DebugSerial->println(F("Play Previous")); break; 146 | case ACTION_PLAYRANDOM: DebugSerial->println(F("Play Random")); break; 147 | default: break; 148 | } 149 | } 150 | } 151 | 152 | void PrintSoundBank(soundbank sb) 153 | { 154 | DebugSerial->print(F("Sound Bank ")); 155 | switch (sb) 156 | { 157 | case SOUNDBANK_A: DebugSerial->print(F("A - ")); break; 158 | case SOUNDBANK_B: DebugSerial->print(F("B - ")); break; 159 | default: break; 160 | } 161 | } 162 | 163 | // This routine is only needed for testing during development of compatibility with Benedini TBS Flash v3. // 164 | /* 165 | void TBSTest(void) 166 | { 167 | OP_TBS * TBS; 168 | TBS = new OP_TBS (&timer); 169 | 170 | // Ok, before we run this test, stop everything. 171 | StopEverything(); 172 | 173 | // Turn the Red LED on for the duration of setup 174 | GreenLedOff(); 175 | RedLedOn(); 176 | 177 | // 178 | DebugSerial->println(); 179 | PrintDebugLine(); 180 | DebugSerial->println(F("Start TBS Prop3 Test")); 181 | PrintDebugLine(); 182 | delay(2000); 183 | 184 | // Initialize TBS outputs 185 | TBS->InitializeOutputs(); // Set all outputs to defaults 186 | 187 | // Run the test 188 | TBS->testProp3(); 189 | 190 | // Ok, we're done 191 | PrintDebugLine(); 192 | DebugSerial->println(F("End TBS Prop3 Test")); 193 | PrintDebugLine(); 194 | DebugSerial->println(); 195 | 196 | // Blink the Green LED 3 times quickly, then turn all leds off. 197 | GreenBlinkFast(3); 198 | RedLedOff(); 199 | } 200 | */ 201 | 202 | 203 | -------------------------------------------------------------------------------- /OpenPanzerTCB/UserTest.ino: -------------------------------------------------------------------------------- 1 | 2 | // These are generic special functions that the user can fill in to control whatever they want. 3 | 4 | // Here are two "digital" functions - meaning they can only be triggered by a digital trigger, and they have no paramaters 5 | // ------------------------------------------------------------------------------------------------------------------------------------->> 6 | void UserFunction1(void) 7 | { 8 | // Do something here 9 | 10 | if (DEBUG) DebugSerial->println(F("User Function 1")); 11 | } 12 | 13 | 14 | void UserFunction2(void) 15 | { 16 | // Do something here 17 | 18 | if (DEBUG) DebugSerial->println(F("User Function 2")); 19 | } 20 | 21 | 22 | 23 | // Here are two "analog" functions - meaning they can only be triggered by an analog input, and the parameter "level" 24 | // will be a number from 0-1023 (or ANALOG_SPECFUNCTION_MIN_VAL to ANALOG_SPECFUNCTION_MAX_VAL) representing the 25 | // position of the analog input 26 | // ------------------------------------------------------------------------------------------------------------------------------------->> 27 | void User_Analog_Function1(uint16_t level) 28 | { 29 | static uint16_t lastLevel; 30 | 31 | if (lastLevel != level) 32 | { 33 | lastLevel = level; 34 | 35 | // Do something here with "level" 36 | 37 | if (DEBUG) { DebugSerial->print(F("Analog User Function 1 - ")); DebugSerial->println(level); } 38 | } 39 | } 40 | 41 | void User_Analog_Function2(uint16_t level) 42 | { 43 | static uint16_t lastLevel; 44 | 45 | if (lastLevel != level) 46 | { 47 | lastLevel = level; 48 | 49 | // Do something here with "level" 50 | 51 | if (DEBUG) { DebugSerial->print(F("Analog User Function 2 - ")); DebugSerial->println(level); } 52 | } 53 | } 54 | 55 | 56 | 57 | -------------------------------------------------------------------------------- /OpenPanzerTCB/src/EEPROMex/EEPROMVar.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* 4 | EEPROMvar.h - EEPROM variable library 5 | Copyright (c) 2012 Thijs Elenbaas. All right reserved. 6 | 7 | based on class by AlphaBeta 8 | 9 | This library is free software; you can redistribute it and/or 10 | modify it under the terms of the GNU Lesser General Public 11 | License as published by the Free Software Foundation; either 12 | version 2.1 of the License, or (at your option) any later version. 13 | 14 | This library is distributed in the hope that it will be useful, 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | Lesser General Public License for more details. 18 | 19 | You should have received a copy of the GNU Lesser General Public 20 | License along with this library; if not, write to the Free Software 21 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 22 | */ 23 | 24 | template class EEPROMVar 25 | { 26 | public: 27 | EEPROMVar(T init) { 28 | address = EEPROM.getAddress(sizeof(T)); 29 | var = init; 30 | } 31 | operator T () { 32 | return var; 33 | } 34 | EEPROMVar &operator=(T val) { 35 | var = val; 36 | return *this; 37 | } 38 | 39 | void operator+=(T val) { 40 | var += T(val); 41 | } 42 | void operator-=(T val) { 43 | var -= T(val); 44 | } 45 | void operator++(int) { 46 | var += T(1); 47 | } 48 | void operator--(int) { 49 | var -= T(1); 50 | } 51 | void operator++() { 52 | var += T(1); 53 | } 54 | void operator--() { 55 | var -= T(1); 56 | } 57 | template 58 | void operator /= (V divisor) { 59 | var = var / divisor; 60 | } 61 | template 62 | void operator *= (V multiplicator) { 63 | var = var * multiplicator; 64 | } 65 | void save(){ 66 | EEPROM.writeBlock(address, var); 67 | } 68 | 69 | void update(){ 70 | EEPROM.updateBlock(address, var); 71 | } 72 | 73 | int getAddress(){ 74 | return address; 75 | } 76 | 77 | void restore(){ 78 | EEPROM.readBlock(address, var); 79 | } 80 | protected: 81 | T var; 82 | int address; 83 | }; -------------------------------------------------------------------------------- /OpenPanzerTCB/src/EEPROMex/EEPROMex.h: -------------------------------------------------------------------------------- 1 | /* 2 | EEPROMEx.h - Extended EEPROM library 3 | Copyright (c) 2012 Thijs Elenbaas. All right reserved. 4 | 5 | This library is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU Lesser General Public 7 | License as published by the Free Software Foundation; either 8 | version 2.1 of the License, or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 | Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public 16 | License along with this library; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 | */ 19 | 20 | #ifndef EEPROMEX_h 21 | #define EEPROMEX_h 22 | 23 | #if ARDUINO >= 100 24 | #include 25 | #else 26 | #include 27 | #endif 28 | #include 29 | #include 30 | 31 | 32 | #define EEPROMSizeATmega168 512 33 | #define EEPROMSizeATmega328 1024 34 | #define EEPROMSizeATmega1280 4096 35 | #define EEPROMSizeATmega32u4 1024 36 | #define EEPROMSizeAT90USB1286 4096 37 | #define EEPROMSizeMK20DX128 2048 38 | #define EEPROMSizeMK20DX256 2048 39 | #define EEPROMSizeATSAMD21G18 16384 40 | 41 | #define EEPROMSizeUno EEPROMSizeATmega328 42 | #define EEPROMSizeUnoSMD EEPROMSizeATmega328 43 | #define EEPROMSizeLilypad EEPROMSizeATmega328 44 | #define EEPROMSizeDuemilanove EEPROMSizeATmega328 45 | #define EEPROMSizePro EEPROMSizeATmega328 46 | #define EEPROMSizeFio EEPROMSizeATmega328 47 | #define EEPROMSizeMega EEPROMSizeATmega1280 48 | #define EEPROMSizeDiecimila EEPROMSizeATmega168 49 | #define EEPROMSizeNano EEPROMSizeATmega168 50 | #define EEPROMSizeTeensy2 EEPROMSizeATmega32u4 51 | #define EEPROMSizeLeonardo EEPROMSizeATmega32u4 52 | #define EEPROMSizeMicro EEPROMSizeATmega32u4 53 | #define EEPROMSizeEsplora EEPROMSizeATmega32u4 54 | #define EEPROMSizeYun EEPROMSizeATmega32u4 55 | #define EEPROMSizeTre EEPROMSizeATmega32u4 56 | #define EEPROMSizeZero EEPROMSizeATSAMD21G18 57 | #define EEPROMSizeTeensy2pp EEPROMSizeAT90USB1286 58 | #define EEPROMSizeTeensy3 EEPROMSizeMK20DX128 59 | #define EEPROMSizeTeensy31 EEPROMSizeMK20DX256 60 | class EEPROMClassEx 61 | { 62 | 63 | public: 64 | EEPROMClassEx(); 65 | bool isReady(); 66 | int writtenBytes(); 67 | void setMemPool(int base, int memSize); 68 | void setMaxAllowedWrites(int allowedWrites); 69 | int getAddress(int noOfBytes); 70 | 71 | uint8_t read(int); 72 | bool readBit(int, byte); 73 | uint8_t readByte(int); 74 | uint16_t readInt(int); 75 | uint32_t readLong(int); 76 | float readFloat(int); 77 | double readDouble(int); 78 | 79 | bool write(int, uint8_t); 80 | bool writeBit(int , uint8_t, bool); 81 | bool writeByte(int, uint8_t); 82 | bool writeInt(int, uint16_t); 83 | bool writeLong(int, uint32_t); 84 | bool writeFloat(int, float); 85 | bool writeDouble(int, double); 86 | 87 | bool update(int, uint8_t); 88 | bool updateBit(int , uint8_t, bool); 89 | bool updateByte(int, uint8_t); 90 | bool updateInt(int, uint16_t); 91 | bool updateLong(int, uint32_t); 92 | bool updateFloat(int, float); 93 | bool updateDouble(int, double); 94 | 95 | 96 | // Use template for other data formats 97 | 98 | /** 99 | * Template function to read multiple items of any type of variable, such as structs 100 | */ 101 | template int readBlock(int address, const T value[], int items) 102 | { 103 | unsigned int i; 104 | for (i = 0; i < (unsigned int)items; i++) 105 | readBlock(address+(i*sizeof(T)),value[i]); 106 | return i; 107 | } 108 | 109 | /** 110 | * Template function to read any type of variable, such as structs 111 | */ 112 | template int readBlock(int address, const T& value) 113 | { 114 | eeprom_read_block((void*)&value, (const void*)address, sizeof(value)); 115 | return sizeof(value); 116 | } 117 | 118 | /** 119 | * Template function to write multiple items of any type of variable, such as structs 120 | */ 121 | template int writeBlock(int address, const T value[], int items) 122 | { 123 | if (!isWriteOk(address+items*sizeof(T))) return 0; 124 | unsigned int i; 125 | for (i = 0; i < (unsigned int)items; i++) 126 | writeBlock(address+(i*sizeof(T)),value[i]); 127 | return i; 128 | } 129 | 130 | /** 131 | * Template function to write any type of variable, such as structs 132 | */ 133 | template int writeBlock(int address, const T& value) 134 | { 135 | if (!isWriteOk(address+sizeof(value))) return 0; 136 | eeprom_write_block((void*)&value, (void*)address, sizeof(value)); 137 | return sizeof(value); 138 | } 139 | 140 | /** 141 | * Template function to update multiple items of any type of variable, such as structs 142 | * The EEPROM will only be overwritten if different. This will reduce wear. 143 | */ 144 | template int updateBlock(int address, const T value[], int items) 145 | { 146 | int writeCount=0; 147 | if (!isWriteOk(address+items*sizeof(T))) return 0; 148 | unsigned int i; 149 | for (i = 0; i < (unsigned int)items; i++) 150 | writeCount+= updateBlock(address+(i*sizeof(T)),value[i]); 151 | return writeCount; 152 | } 153 | 154 | /** 155 | * Template function to update any type of variable, such as structs 156 | * The EEPROM will only be overwritten if different. This will reduce wear. 157 | */ 158 | template int updateBlock(int address, const T& value) 159 | { 160 | int writeCount=0; 161 | if (!isWriteOk(address+sizeof(value))) return 0; 162 | const byte* bytePointer = (const byte*)(const void*)&value; 163 | for (unsigned int i = 0; i < (unsigned int)sizeof(value); i++) { 164 | if (read(address)!=*bytePointer) { 165 | write(address, *bytePointer); 166 | writeCount++; 167 | } 168 | address++; 169 | bytePointer++; 170 | } 171 | return writeCount; 172 | } 173 | 174 | 175 | 176 | private: 177 | //Private variables 178 | static int _base; 179 | static int _memSize; 180 | static int _nextAvailableaddress; 181 | static int _writeCounts; 182 | int _allowedWrites; 183 | bool checkWrite(int base,int noOfBytes); 184 | bool isWriteOk(int address); 185 | bool isReadOk(int address); 186 | }; 187 | 188 | extern EEPROMClassEx EEPROM; 189 | 190 | #endif 191 | 192 | -------------------------------------------------------------------------------- /OpenPanzerTCB/src/EEPROMex/LICENSE.md: -------------------------------------------------------------------------------- 1 | # LGPL License 2 | -------------- 3 | Copyright (c) 2012 4 | Thijs Elenbaas 5 | 6 | This library is free software; you can redistribute it and/or 7 | modify it under the terms of the GNU Lesser General Public 8 | License as published by the Free Software Foundation; either 9 | version 2.1 of the License, or (at your option) any later version. 10 | 11 | This library is distributed in the hope that it will be useful, 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 | Lesser General Public License for more details. 15 | 16 | You should have received a copy of the GNU Lesser General Public 17 | License along with this library; if not, write to the Free Software 18 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -------------------------------------------------------------------------------- /OpenPanzerTCB/src/EEPROMex/README.md: -------------------------------------------------------------------------------- 1 | # Arduino EEPROMEx library 2 | 3 | The EEPROMex library is an extension of the standard Arduino EEPROM library. It extends the functionality of the original Arduino EEPROM library with: 4 | 5 | * Reading, writing to basic types. This includes bytes, longs, ints, floats and doubles. 6 | * Reading, writing to single bits. This helps efficient usage of the limited EEPROM memory. 7 | * Reading, writing of any data format. This can be for example structs, strings, etc. 8 | * Reading, writing of arrays of any format. By storing, for example, arrays of structs one can create a database like structure. 9 | * Update functions. The function similar to write functions, but only update changed bytes. If structures have only changed partly, updating instead of writing can save a lot EEPROM wear and significantly increase speed. 10 | * Basic memory allocation functionality. This is basically a counter of the first unallocated byte, and helps giving unique addresses to variables. 11 | * Enabling write limitation: In theory one can burn out a memory cell in a few minutes: a write/erase cycle takes approximately 4 ms, so writing 100.000 times to a single cell takes 6 1/2 min. Limiting the number of writes during the debug phase helps prevent this. 12 | * Debugging of writing out of memory range. 13 | 14 | 15 | And find detailed explanation and samples of the functionality here: 16 | [http://thijs.elenbaas.net/2012/07/extended-eeprom-library-for-arduino](http://thijs.elenbaas.net/2012/07/extended-eeprom-library-for-arduino) 17 | 18 | ## Downloading 19 | 20 | This package can be downloaded in different manners 21 | 22 | 23 | - The Arduino Library Manager: [see here how to use it](http://www.arduino.cc/en/guide/libraries#toc3). 24 | - The PlatformIO package manager: [see here how to use it](http://www.ikravets.com/computer-life/platformio/2014/10/07/integration-of-platformio-library-manager-to-arduino-and-energia-ides). 25 | - By directly loading fetching the Archive from GitHub: 26 | 1. Go to [https://github.com/thijse/Arduino-EEPROMEx](https://github.com/thijse/Arduino-EEPROMEx) 27 | 2. Click the DOWNLOAD ZIP button in the panel on the 28 | 3. Rename the uncompressed folder **Arduino-EEPROMEx-master** to **EEPROMEx**. 29 | 4. You may need to create the libraries subfolder if its your first library. 30 | 5. Place the **EEPROMEx** library folder in your **arduinosketchfolder/libraries/** folder. 31 | 5. Restart the IDE. 32 | 6. For more information, [read this extended manual](http://thijs.elenbaas.net/2012/07/installing-an-arduino-library/) 33 | - If you want to have a package that includes all referenced libraries, use the pre-packaged library 34 | 1. Download the package as a zipfile [here](https://github.com/thijse/Zipballs/blob/master/EEPROMEx/EEPROMEx.zip?raw=true) or as a tarball [here ](https://github.com/thijse/Zipballs/blob/master/EEPROMEx/EEPROMEx.tar.gz?raw=true). 35 | 2. Copy the folders inside the **libraries** folder to you your **arduinosketchfolder/libraries/** folder. 36 | 3. Restart the IDE. 37 | 3. For more information, [read this extended manual](http://thijs.elenbaas.net/2012/07/installing-an-arduino-library/) 38 | 39 | 40 | 41 | ### Using different data formats 42 | 43 | The aim of the library is to also support other standard data types: it currently implements writing and reading to int, long, float and double. 44 | 45 | ### For reading: 46 | ``` 47 | uint8_t read(int address); 48 | bool readBit(int address, byte bit) 49 | uint8_t readByte(int address); 50 | uint16_t readInt(int address); 51 | uint32_t readLong(int address); 52 | float readFloat(int address); 53 | double readDouble(int address); 54 | ``` 55 | 56 | Where address is the starting position in EEPROM, and the return value the value read from EEPROM. 57 | 58 | ### For writing: 59 | ``` 60 | bool write(int address, uint8_t value); 61 | bool writeByte(int address, uint8_t value); 62 | bool writeInt(int address, uint16_t value); 63 | bool writeLong(int address, uint32_t value); 64 | bool writeFloat(int address, float value); 65 | bool writeDouble(int address, double value); 66 | ``` 67 | The update functions are different from the write functions: they will check per byte if the current value differs and only update the the cell with a different value. This will not only reduce wear, and can also significantly reduce write time. 68 | 69 | ``` 70 | bool update(int address, uint8_t value); 71 | bool updateByte(int address, uint8_t value); 72 | bool updateInt(int address, uint16_t value); 73 | bool updateLong(int address, uint32_t value); 74 | bool updateFloat(int address, float value); 75 | bool updateDouble(int address, double); 76 | ``` 77 | 78 | ### Manipulating Single bits 79 | 80 | The following functions implements reading and writing single bits: 81 | 82 | ``` 83 | bool readBit(int address, byte bit) 84 | ``` 85 | Where bit is the write position in the byte, ranging from [0..7], with bit 0 being the right-most. The return value is the read bit. 86 | 87 | ``` 88 | bool writeBit(int address, uint8_t bit, bool value) 89 | bool updateBit(int address, uint8_t bit, bool value) 90 | ``` 91 | 92 | ### Data blocks 93 | 94 | Using the block functions any data can be read, written and updated: 95 | 96 | ``` 97 | int readBlock(int address, const T& value) 98 | int writeBlock(int address, const T& value) 99 | int updateBlock(int address, const T& value) 100 | ``` 101 | 102 | where T is the type of the data to read/write/update. This can be a basic type, but also a more complex type like a struct. The return value gives the number of bytes that have been read, written or updated. 103 | 104 | One can also read/write arrays of data-blocks: 105 | 106 | ``` 107 | int readBlock(int address, const T[]; value, int items) 108 | int writeBlock(int address, const T[]; value, int items) 109 | int updateBlock(int address, const T[]; value, int items) 110 | ``` 111 | 112 | ### Debugging EEPROM applications 113 | 114 | It is easy to burn out a memory cell in few minutes, so during debugging it would be very useful to limit the number of allowed writes. It is easy to put a bracket at the wrong location, and placing an EEPROM write inside of a loop, rather than outside, and introduce extensive writing causing wear. The following function helps limit the number of writes. 115 | 116 | ``` 117 | setMaxAllowedWrites(int allowedWrites); 118 | ``` 119 | 120 | More writes than allowed will be refused and result in an error message. You can also set the address range used by the library: 121 | 122 | ``` 123 | setMemPool(int base, int memSize); 124 | ``` 125 | 126 | The lower value is used by the getAddress function, the upper value is used for setting the EEPROM size. Writing outside the maximum size will result in an error message. The following EEPROM sizes are predefined 127 | 128 | Based on processor: 129 | ``` 130 | *EEPROMSizeATmega168 131 | *EEPROMSizeATmega328 132 | *EEPROMSizeATmega1280 133 | *EEPROMSizeATmega32u4 134 | *EEPROMSizeAT90USB1286 135 | *EEPROMSizeMK20DX128 136 | ``` 137 | Based on board: 138 | ``` 139 | *EEPROMSizeUno 140 | *EEPROMSizeUnoSMD 141 | *EEPROMSizeLilypad 142 | *EEPROMSizeDuemilanove 143 | *EEPROMSizeMega 144 | *EEPROMSizeDiecimila 145 | *EEPROMSizeNano 146 | *EEPROMSizeTeensy2 147 | *EEPROMSizeLeonardo 148 | *EEPROMSizeMicro 149 | *EEPROMSizeYun 150 | *EEPROMSizeTeensy2pp 151 | *EEPROMSizeTeensy3 152 | ``` 153 | 154 | ### EEPROM performance 155 | 156 | All of the read/write functions make sure the EEPROM is ready to be accessed. Since this may cause a delay of max 4ms, time-critical applications should first poll the EEPROM e. g. using the isReady function before attempting any actual I/O: 157 | 158 | ``` 159 | bool isReady(); 160 | ``` 161 | 162 | ## On using and modifying libraries 163 | 164 | - [http://www.arduino.cc/en/Main/Libraries](http://www.arduino.cc/en/Main/Libraries) 165 | - [http://www.arduino.cc/en/Reference/Libraries](http://www.arduino.cc/en/Reference/Libraries) 166 | 167 | 168 | ## Copyright 169 | 170 | EEPROMEx is provided Copyright © 2013,2014,2015 under LGPL License. 171 | -------------------------------------------------------------------------------- /OpenPanzerTCB/src/EEPROMex/keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map For EEPROMEx 3 | ####################################### 4 | 5 | ####################################### 6 | # Methods and Functions EEPROMEx (KEYWORD2) 7 | ####################################### 8 | 9 | isReady KEYWORD2 10 | setMemPool KEYWORD2 11 | setMaxAllowedWrites KEYWORD2 12 | getAddress KEYWORD2 13 | 14 | read KEYWORD2 15 | readByte KEYWORD2 16 | readInt KEYWORD2 17 | readLong KEYWORD2 18 | readFloat KEYWORD2 19 | readDouble KEYWORD2 20 | readBlock KEYWORD2 21 | 22 | write KEYWORD2 23 | writeByte KEYWORD2 24 | writeInt KEYWORD2 25 | writeLong KEYWORD2 26 | writeFloat KEYWORD2 27 | writeDouble KEYWORD2 28 | writeBlock KEYWORD2 29 | 30 | update KEYWORD2 31 | updateByte KEYWORD2 32 | updateInt KEYWORD2 33 | updateLong KEYWORD2 34 | updateFloat KEYWORD2 35 | updateDouble KEYWORD2 36 | updateBlock KEYWORD2 37 | 38 | ####################################### 39 | # Instances (KEYWORD2) 40 | ####################################### 41 | 42 | EEPROMEx KEYWORD2 43 | 44 | ####################################### 45 | # Constants (LITERAL1) 46 | ####################################### 47 | 48 | -------------------------------------------------------------------------------- /OpenPanzerTCB/src/LedHandler/LedHandler.h: -------------------------------------------------------------------------------- 1 | /* OP_LedHandler.h Open Panzer Led Handler - class for handling LEDs including blink effects, requires use of elapsedMillis 2 | * Source: openpanzer.org 3 | * Authors: Luke Middleton 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | */ 19 | 20 | #ifndef LedHandler_h 21 | #define LedHandler_h 22 | 23 | #include 24 | #include "../OP_Settings/OP_Settings.h" 25 | #include "../elapsedMillis/elapsedMillis.h" 26 | 27 | #define FADE_IN 1 28 | #define FADE_OUT 2 29 | #define NUM_FADE_UPDATES 100 30 | 31 | #define DEFAULT_BLINK_INTERVAL 200 32 | #define MAX_STREAM_STEPS 10 // A stream consists of a pattern of on/off blinks separated by user-specified lengths of time. A single blink (on/off) takes 2 steps. 33 | typedef struct // This struct holds an array of blink patterns, and a flag to indicate if it should repeat or not 34 | { 35 | uint16_t interval[MAX_STREAM_STEPS]; 36 | boolean repeat; 37 | } BlinkStream; 38 | 39 | class LedHandler 40 | { public: 41 | LedHandler() {}; 42 | 43 | void begin (byte p, boolean i=false); 44 | void on(void); 45 | boolean isOn(void); 46 | void off(void); 47 | void toggle(void); 48 | void update(void); // Update blinking effect 49 | boolean isBlinking(void); 50 | boolean isFading(void); 51 | void ExpireIn(uint16_t); 52 | void Blink(uint16_t interval=DEFAULT_BLINK_INTERVAL); // Blinks once at set interval 53 | void Blink(uint8_t times, uint16_t interval=DEFAULT_BLINK_INTERVAL); // Overload - Blinks N times at set interval 54 | void startBlinking(uint16_t on_interval=DEFAULT_BLINK_INTERVAL, uint16_t off_interval=DEFAULT_BLINK_INTERVAL); // Starts a continuous blink at the set intervals, to stop call stopBlinking() or Off() 55 | void stopBlinking(void); 56 | void DoubleTap(boolean repeat=false); 57 | void TripleTap(boolean repeat=false); 58 | void QuadTap(boolean repeat=false); 59 | void StreamBlink(BlinkStream bs, uint8_t numSteps); 60 | void Fade(uint8_t fade_in, uint16_t span, boolean AddBlinkEffect); 61 | void stopFading(void); 62 | 63 | private: 64 | void ClearBlinker(void); 65 | void ClearFader(void); 66 | void pinOn(void); 67 | void pinOff(void); 68 | elapsedMillis _time; 69 | elapsedMillis _expireMe; 70 | uint16_t _expireTime; 71 | byte _pin; 72 | boolean _invert; 73 | boolean _isBlinking; 74 | uint8_t _isFading; 75 | uint16_t _curStep; 76 | uint16_t _numSteps; 77 | uint16_t _nextWait; 78 | boolean _fixedInterval; 79 | BlinkStream _blinkStream; 80 | float _fadeStart; 81 | boolean _fadeBlinkEffect; 82 | uint16_t _fadeInterval; 83 | 84 | }; 85 | 86 | 87 | #endif 88 | -------------------------------------------------------------------------------- /OpenPanzerTCB/src/OP_Button/OP_Button.cpp: -------------------------------------------------------------------------------- 1 | /* OP_Button.h Button - a library for reading button inputs 2 | * Source: https://github.com/JChristensen/Button 3 | * Authors: Jack Christensen 4 | * 5 | * This library is an unmodified copy of Jack Christensen's button library. 6 | * It has been renamed to OP_Button for consistency with other Open Panzer 7 | * libraries and also to avoid conflicts with any of the other numerous 8 | * Arduino button libraries you may have already installed. 9 | * 10 | * All credit goes to Jack Christensen. For more info, see: 11 | * https://github.com/JChristensen/Button 12 | * 13 | * Mr. Christensen's original copyright is reprinted below: 14 | * 15 | *----------------------------------------------------------------------* 16 | * Arduino Button Library v1.0 * 17 | * Jack Christensen May 2011, published Mar 2012 * 18 | * * 19 | * Library for reading momentary contact switches like tactile button * 20 | * switches. Intended for use in state machine constructs. * 21 | * Use the read() function to read all buttons in the main loop, * 22 | * which should execute as fast as possible. * 23 | * * 24 | * This work is licensed under the Creative Commons Attribution- * 25 | * ShareAlike 3.0 Unported License. To view a copy of this license, * 26 | * visit http://creativecommons.org/licenses/by-sa/3.0/ or send a * 27 | * letter to Creative Commons, 171 Second Street, Suite 300, * 28 | * San Francisco, California, 94105, USA. * 29 | *----------------------------------------------------------------------*/ 30 | 31 | #include "OP_Button.h" 32 | 33 | /*----------------------------------------------------------------------* 34 | * Button(pin, puEnable, invert, dbTime) instantiates a button object. * 35 | * pin Is the Arduino pin the button is connected to. * 36 | * puEnable Enables the AVR internal pullup resistor if != 0 (can also * 37 | * use true or false). * 38 | * invert If invert == 0, interprets a high state as pressed, low as * 39 | * released. If invert != 0, interprets a high state as * 40 | * released, low as pressed (can also use true or false). * 41 | * dbTime Is the debounce time in milliseconds. * 42 | * * 43 | * (Note that invert cannot be implied from puEnable since an external * 44 | * pullup could be used.) * 45 | *----------------------------------------------------------------------*/ 46 | OP_Button::OP_Button(uint8_t pin, uint8_t puEnable, uint8_t invert, uint32_t dbTime) 47 | { 48 | _pin = pin; 49 | _puEnable = puEnable; 50 | _invert = invert; 51 | _dbTime = dbTime; 52 | pinMode(_pin, INPUT); 53 | if (_puEnable != 0) 54 | digitalWrite(_pin, HIGH); //enable pullup resistor 55 | _state = digitalRead(_pin); 56 | if (_invert != 0) _state = !_state; 57 | _time = millis(); 58 | _lastState = _state; 59 | _changed = 0; 60 | _lastChange = _time; 61 | } 62 | 63 | /*----------------------------------------------------------------------* 64 | * read() returns the state of the button, 1==pressed, 0==released, * 65 | * does debouncing, captures and maintains times, previous states, etc. * 66 | *----------------------------------------------------------------------*/ 67 | uint8_t OP_Button::read(void) 68 | { 69 | static uint32_t ms; 70 | static uint8_t pinVal; 71 | 72 | ms = millis(); 73 | pinVal = digitalRead(_pin); 74 | if (_invert != 0) pinVal = !pinVal; 75 | if (ms - _lastChange < _dbTime) { 76 | _time = ms; 77 | _changed = 0; 78 | return _state; 79 | } 80 | else { 81 | _lastState = _state; 82 | _state = pinVal; 83 | _time = ms; 84 | if (_state != _lastState) { 85 | _lastChange = ms; 86 | _changed = 1; 87 | } 88 | else { 89 | _changed = 0; 90 | } 91 | return _state; 92 | } 93 | } 94 | 95 | /*----------------------------------------------------------------------* 96 | * isPressed() and isReleased() check the button state when it was last * 97 | * read, and return false (0) or true (!=0) accordingly. * 98 | * These functions do not cause the button to be read. * 99 | *----------------------------------------------------------------------*/ 100 | uint8_t OP_Button::isPressed(void) 101 | { 102 | return _state == 0 ? 0 : 1; 103 | } 104 | 105 | uint8_t OP_Button::isReleased(void) 106 | { 107 | return _state == 0 ? 1 : 0; 108 | } 109 | 110 | /*----------------------------------------------------------------------* 111 | * wasPressed() and wasReleased() check the button state to see if it * 112 | * changed between the last two reads and return false (0) or * 113 | * true (!=0) accordingly. * 114 | * These functions do not cause the button to be read. * 115 | *----------------------------------------------------------------------*/ 116 | uint8_t OP_Button::wasPressed(void) 117 | { 118 | return _state && _changed; 119 | } 120 | 121 | uint8_t OP_Button::wasReleased(void) 122 | { 123 | return !_state && _changed; 124 | } 125 | 126 | /*----------------------------------------------------------------------* 127 | * pressedFor(ms) and releasedFor(ms) check to see if the button is * 128 | * pressed (or released), and has been in that state for the specified * 129 | * time in milliseconds. Returns false (0) or true (1) accordingly. * 130 | * These functions do not cause the button to be read. * 131 | *----------------------------------------------------------------------*/ 132 | uint8_t OP_Button::pressedFor(uint32_t ms) 133 | { 134 | return (_state == 1 && _time - _lastChange >= ms) ? 1 : 0; 135 | } 136 | 137 | uint8_t OP_Button::releasedFor(uint32_t ms) 138 | { 139 | return (_state == 0 && _time - _lastChange >= ms) ? 1 : 0; 140 | } 141 | 142 | /*----------------------------------------------------------------------* 143 | * lastChange() returns the time the button last changed state, * 144 | * in milliseconds. * 145 | *----------------------------------------------------------------------*/ 146 | uint32_t OP_Button::lastChange(void) 147 | { 148 | return _lastChange; 149 | } 150 | -------------------------------------------------------------------------------- /OpenPanzerTCB/src/OP_Button/OP_Button.h: -------------------------------------------------------------------------------- 1 | /* OP_Button.h Button - a library for reading button inputs 2 | * Source: https://github.com/JChristensen/Button 3 | * Authors: Jack Christensen 4 | * 5 | * This library is an unmodified copy of Jack Christensen's button library. 6 | * It has been renamed to OP_Button for consistency with other Open Panzer 7 | * libraries and also to avoid conflicts with any of the other numerous 8 | * Arduino button libraries you may have already installed. 9 | * 10 | * All credit goes to Jack Christensen. For more info, see: 11 | * https://github.com/JChristensen/Button 12 | * 13 | * Mr. Christensen's original copyright is reprinted below: 14 | * 15 | *----------------------------------------------------------------------* 16 | * Arduino Button Library v1.0 * 17 | * Jack Christensen Mar 2012 * 18 | * * 19 | * This work is licensed under the Creative Commons Attribution- * 20 | * ShareAlike 3.0 Unported License. To view a copy of this license, * 21 | * visit http://creativecommons.org/licenses/by-sa/3.0/ or send a * 22 | * letter to Creative Commons, 171 Second Street, Suite 300, * 23 | * San Francisco, California, 94105, USA. * 24 | *----------------------------------------------------------------------*/ 25 | 26 | #ifndef OP_BUTTON_H 27 | #define OP_BUTTON_H 28 | 29 | #include 30 | 31 | 32 | class OP_Button 33 | { 34 | public: 35 | OP_Button(uint8_t pin, uint8_t puEnable, uint8_t invert, uint32_t dbTime); 36 | uint8_t read(); 37 | uint8_t isPressed(); 38 | uint8_t isReleased(); 39 | uint8_t wasPressed(); 40 | uint8_t wasReleased(); 41 | uint8_t pressedFor(uint32_t ms); 42 | uint8_t releasedFor(uint32_t ms); 43 | uint32_t lastChange(); 44 | 45 | private: 46 | uint8_t _pin; //arduino pin number 47 | uint8_t _puEnable; //internal pullup resistor enabled 48 | uint8_t _invert; //if 0, interpret high state as pressed, else interpret low state as pressed 49 | uint8_t _state; //current button state 50 | uint8_t _lastState; //previous button state 51 | uint8_t _changed; //state changed since last read 52 | uint32_t _time; //time of current state (all times are in ms) 53 | uint32_t _lastChange; //time of last state change 54 | uint32_t _dbTime; //debounce time 55 | }; 56 | #endif -------------------------------------------------------------------------------- /OpenPanzerTCB/src/OP_Button/ReadMe.txt: -------------------------------------------------------------------------------- 1 | THIS LIBRARY IS UNCHANGED FROM JCHRISTENSEN'S ORIGINAL. 2 | IT HAS SIMPLY BEEN RENAMED TO "OP_BUTTON" SO AS NOT TO INTERFERE 3 | WITH ANY OTHER BUTTON LIBRARIES YOU MAY BE USING. 4 | 5 | 6 | ReadMe file for Arduino Button Library v1.0 7 | https://github.com/JChristensen/Button 8 | Jack Christensen Mar 2012 9 | 10 | This work is licensed under the Creative Commons Attribution-ShareAlike 3.0 11 | Unported License. To view a copy of this license, visit 12 | http://creativecommons.org/licenses/by-sa/3.0/ or send a letter to Creative 13 | Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. 14 | 15 | -------------------------------------------------------------------------------- 16 | Arduino library for debouncing and reading momentary contact switches like 17 | tactile button switches. "Long presses" of arbitrary length can be detected. 18 | Works well in state machine constructs. Use the read() function to read each 19 | button in the main loop, which should execute as fast as possible. 20 | 21 | -------------------------------------------------------------------------------- 22 | To use the library: 23 | (1) Go to https://github.com/JChristensen/Button and click the ZIP button to 24 | download the repository as a ZIP file to a convenient location on your PC. 25 | (2) Uncompress the downloaded file. This will result in a folder containing all 26 | the files for the library, that has a name that includes the branch name, 27 | for example "Button-master". 28 | (3) Rename the folder to just "Button". 29 | (4) Copy the renamed folder to the Arduino sketchbook\libraries folder. 30 | 31 | -------------------------------------------------------------------------------- 32 | The following example sketches are included with the Button library: 33 | 34 | SimpleOnOff: Just turns the Arduino's pin 13 LED on and off. 35 | 36 | LongPress: Demonstrates detecting long and short button presses. 37 | 38 | UpDown: Counts up or down, one number at a time or rapidly by holding the button 39 | down. 40 | 41 | -------------------------------------------------------------------------------- 42 | Declare button objects as follows. 43 | 44 | Button(pin, puEnable, invert, dbTime) instantiates a button object. 45 | 46 | Where: 47 | pin -- Is the Arduino pin the button is connected to, 48 | 49 | puEnable -- Enables the AVR internal pullup resistor if != 0 (can also use true 50 | or false), 51 | 52 | invert -- If invert == 0, a high state is interpreted as pressed, low as 53 | released. If invert != 0, a high state is interpreted as released, low as 54 | pressed (can also use true or false), and 55 | 56 | dbTime Is the debounce time in milliseconds. 57 | 58 | Example. Wire a normally-open tactile button switch between Arduino pin 2 and 59 | ground. We will use the internal pullup resistor, so the pin will be high when 60 | the button is not pressed, and low when the button is pressed. Therefore we 61 | should use invert == true to invert the logic: 62 | 63 | Button myButton = Button(2, true, true, 25); 64 | 65 | -------------------------------------------------------------------------------- 66 | The read() method reads the button and returns a boolean value (true or false) 67 | to indicate whether the button is pressed. The read() function needs to execute 68 | very frequently in order for the sketch to be responsive. A good place for 69 | read() is at the top of loop(). I don't normally use the return value from 70 | read(), because I use the other functions. 71 | 72 | Example: myButton.read(); 73 | 74 | -------------------------------------------------------------------------------- 75 | The isPressed() and isReleased() functions check the button state when it was 76 | last read, and return false or true accordingly. These functions DO NOT cause 77 | the button to be read. 78 | 79 | Example: if ( myButton.isPressed ) { 80 | //do some stuff 81 | } 82 | else { 83 | //do some different stuff 84 | } 85 | 86 | -------------------------------------------------------------------------------- 87 | The wasPressed() and wasReleased() functions check the button state to see if it 88 | changed between the last two reads and return false or true accordingly. These 89 | functions DO NOT cause the button to be read. Note that these functions may be 90 | more useful than isPressed() and isReleased() since they actually detect a 91 | CHANGE in the state of the button, which is usually what we want in order to 92 | cause some action. 93 | 94 | Example: if ( myButton.wasPressed() ) { ... 95 | 96 | -------------------------------------------------------------------------------- 97 | The pressedFor(ms) and releasedFor(ms) functions check to see if the button is 98 | pressed (or released), and has been in that state for the specified time in 99 | milliseconds. Returns false or true accordingly. These functions are useful to 100 | detect "long presses". Note that these functions DO NOT cause the button to be 101 | read. 102 | 103 | Example: if ( myButton.pressedFor(1000) ) { //has button been pressed 104 | //for one second? 105 | 106 | -------------------------------------------------------------------------------- 107 | Under certain circumstances, it may be useful to know when a button last changed 108 | state. lastChange() returns the time the button last changed state, in 109 | mlliseconds (the value is from the Arduino millis() function). 110 | 111 | Example: unsigned long lastChange = myButton.lastChange(); 112 | 113 | -------------------------------------------------------------------------------- 114 | -------------------------------------------------------------------------------- /OpenPanzerTCB/src/OP_Button/keywords.txt: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------- 2 | # Syntax Coloring Map 3 | # Words separated by TAB, not SPACE 4 | #------------------------------------------------------------- 5 | 6 | 7 | #------------------------------------------------------------- 8 | # KEYWORD1 - Classes 9 | #------------------------------------------------------------- 10 | OP_Button KEYWORD1 11 | 12 | 13 | 14 | #------------------------------------------------------------- 15 | # KEYWORD2 - Methods, functions, members 16 | #------------------------------------------------------------- 17 | read KEYWORD2 18 | 19 | isPressed KEYWORD2 20 | 21 | isReleased KEYWORD2 22 | 23 | wasPressed KEYWORD2 24 | 25 | wasReleased KEYWORD2 26 | 27 | pressedFor KEYWORD2 28 | 29 | releasedFor KEYWORD2 30 | 31 | lastChange KEYWORD2 32 | 33 | 34 | 35 | #------------------------------------------------------------- 36 | # LITERAL1 - Constants & Defines 37 | #------------------------------------------------------------- 38 | 39 | -------------------------------------------------------------------------------- /OpenPanzerTCB/src/OP_Devices/OP_Devices.h: -------------------------------------------------------------------------------- 1 | /* OP_Devices.h Open Panzer Devices */ 2 | 3 | 4 | #ifndef OP_DEVICES_H 5 | #define OP_DEVICES_H 6 | 7 | // ------------------------------------------------------------------------------------------------------------------------------------------------------->> 8 | // OPEN PANZER DEVICES 9 | // ------------------------------------------------------------------------------------------------------------------------------------------------------->> 10 | typedef unsigned char DEVICE; 11 | #define DEVICE_UNKNOWN 0 12 | #define DEVICE_TCB_MKI 1 13 | #define DEVICE_TCB_MKII 2 14 | #define DEVICE_TCB_DIY 3 // DIY version of the TCB firmware, moves a few pins around for compatibility with stock Arduino MEGA boards 15 | #define DEVICE_SCOUT 4 // Scout board versions R11 and later 16 | #define DEVICE_SCOUT_R10 5 // Scout board versions R10 and earlier 17 | #define DEVICE_TEENSYSOUND 6 18 | #define DEVICE_ATMEGA328 7 19 | #define DEVICE_TEENSY32 8 20 | #define DEVICE_AT_MKI 9 21 | #define DEVICE_HECLO_SHIELD 10 22 | #define DEVICE_ATMEGA2560 11 23 | 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /OpenPanzerTCB/src/OP_Driver/keywords.txt: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------- 2 | # Syntax Coloring Map 3 | # Words separated by TAB, not SPACE 4 | #------------------------------------------------------------- 5 | 6 | 7 | #------------------------------------------------------------- 8 | # KEYWORD1 - Classes 9 | #------------------------------------------------------------- 10 | 11 | OP_Driver KEYWORD1 12 | 13 | 14 | #------------------------------------------------------------- 15 | # KEYWORD2 - Methods, functions, members 16 | #------------------------------------------------------------- 17 | begin KEYWORD2 18 | setDrivingProfileSettings KEYWORD2 19 | GetBrakeFlag KEYWORD2 20 | GetDriveMode KEYWORD2 21 | isAccelRampEnabled KEYWORD2 22 | isDecelRampEnabled KEYWORD2 23 | setAccelRampFrequency KEYWORD2 24 | getAccelRampFrequency KEYWORD2 25 | setDecelRampFrequency KEYWORD2 26 | getDecelRampFrequency KEYWORD2 27 | setTurnMode KEYWORD2 28 | getTurnMode KEYWORD2 29 | setNeutralTurnAllowed KEYWORD2 30 | getNeutralTurnAllowed KEYWORD2 31 | GetDriveSpeed KEYWORD2 32 | GetThrottleSpeed KEYWORD2 33 | ScaleTurnCommand KEYWORD2 34 | MixSteering KEYWORD2 35 | 36 | 37 | #------------------------------------------------------------- 38 | # LITERAL1 - Constants & Defines 39 | #------------------------------------------------------------- 40 | 41 | DT_UNKNOWN LITERAL1 42 | DT_TANK LITERAL1 43 | DT_HALFTRACK LITERAL1 44 | DT_CAR LITERAL1 45 | DT_DKLM LITERAL1 46 | LAST_DT LITERAL1 47 | UNKNOWN LITERAL1 48 | STOP LITERAL1 49 | FORWARD LITERAL1 50 | REVERSE LITERAL1 51 | NEUTRALTURN LITERAL1 52 | LAST_MODE LITERAL1 53 | GEAR_NA LITERAL1 54 | GEAR_NEUTRAL LITERAL1 55 | GEAR_FORWARD LITERAL1 56 | GEAR_REVERSE LITERAL1 57 | ADP_NONE LITERAL1 58 | ADP_EXP_1 LITERAL1 59 | ADP_EXP_2 LITERAL1 60 | ADP_EXP_3 LITERAL1 61 | NUM_ACCEL_PRESETS LITERAL1 62 | DDP_NONE LITERAL1 63 | DDP_EXP_1 LITERAL1 64 | DDP_EXP_2 LITERAL1 65 | DDP_EXP_3 LITERAL1 66 | NUM_DECEL_PRESETS LITERAL1 67 | NUM_TURN_MODES LITERAL1 68 | MAX_SKIP_NUM LITERAL1 69 | DRIVE_RAMP_STEP_DEFAULT LITERAL1 70 | ACCEL_RAMP_STEP_DEFAULT LITERAL1 71 | DECEL_RAMP_STEP_DEFAULT LITERAL1 72 | COMPLETE_STOP_NEARLIMIT LITERAL1 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /OpenPanzerTCB/src/OP_EEPROM/OP_EEPROM.h: -------------------------------------------------------------------------------- 1 | /* OP_EEPROM.h Open Panzer EEPROM - a library functions related to EEPROM usage 2 | * Source: openpanzer.org 3 | * Authors: Luke Middleton 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | */ 19 | 20 | #ifndef OP_EEPROM_H 21 | #define OP_EEPROM_H 22 | 23 | #include 24 | // This one has meta-data about every variable stored in a progrmem array 25 | #include "OP_EEPROM_VarInfo.h" 26 | // The order we include these is important. OP_EEPROM_Struct will need these defined first 27 | #include "../OP_FT/OP_FunctionsTriggers.h" 28 | #include "../OP_IO/OP_IO.h" 29 | #include "../OP_IRLib/OP_IRLib.h" 30 | #include "../OP_Tank/OP_Tank.h" 31 | #include "../OP_Radio/OP_RadioDefines.h" 32 | #include "../OP_Sound/OP_Sound.h" 33 | #include "../OP_Motors/OP_Motors.h" 34 | #include "../OP_Smoker/OP_Smoker.h" 35 | #include "../OP_Driver/OP_Driver.h" 36 | #include "../OP_Settings/OP_Settings.h" 37 | #include "../EEPROMex/EEPROMex.h" // We use the extended version, not Arduino's built-in EEPROM library. 38 | // This one is important. It has the definition of our eeprom struct 39 | #include "OP_EEPROM_Struct.h" 40 | 41 | 42 | //--------------------------------------------------------------------------------------------------------------------------------------->> 43 | //=======================================================================================================================================>> 44 | // VERY IMPORTANT ! 45 | //=======================================================================================================================================>> 46 | // If any changes are made to the _eeprom_data struct in OP_EEPROM_Struct.h, the EEPROM_INIT definition below must be changed to a new number. 47 | // This will force the sketch to re-initialize the EEPROM and all old data will be lost - in other words, you will have to redo 48 | // radio setup, etc... (unless you wisely saved an OPZ file in OP Config first). This is an inconvenient but not as bad as if you don't reinitalize. 49 | // In that case EEPROM data corruption WILL occur and the sketch will exhibit unstable behavior! 50 | // 51 | 52 | #define EEPROM_INIT 0xCACC // Modified with 00.93.75 on 05/21/2023 53 | // 54 | // 55 | //=======================================================================================================================================>> 56 | //--------------------------------------------------------------------------------------------------------------------------------------->> 57 | 58 | 59 | #define EEPROM_START_ADDRESS 0 60 | 61 | 62 | 63 | // Class OP_EEPROM 64 | class OP_EEPROM 65 | { public: 66 | OP_EEPROM(void); // Constructor 67 | static boolean begin(void); // This function will initialize EEPROM to default values if it hasn't been before. 68 | // After initialization, the EEPROM_INIT number above will be written to EEPROM, so 69 | // next time we'll know it's been done. This prevents us from writing to the EEPROM over and over 70 | // every time we turn on the Arduino. 71 | // Vars 72 | static _eeprom_data ramcopy; // This is the complete eeprom struct that we will store in RAM 73 | 74 | // Functions 75 | static void loadRAMcopy(void); // This will load the eeprom data from eeprom into our ramcopy struct in RAM 76 | 77 | static boolean readSerialEEPROM_byID(uint16_t ID, char * chrArray, uint8_t bufflen, uint8_t &stringlength); 78 | static boolean updateEEPROM_byID(uint16_t ID, uint32_t Value); // This will update the variable of "ID" with "Value" in EEPROM 79 | 80 | static void factoryReset(void); // This will force a call to Initialize_EEPROM(). All eeprom vars will be rest to default values. 81 | 82 | protected: 83 | 84 | // Functions 85 | static void Initialize_RAMcopy(void); // Called by Initilize_EEPROM. It sets all the RAM variables to default values. 86 | static void Initialize_EEPROM(void); // This copies all variables (at default values) from RAM into eeprom. 87 | 88 | static uint16_t findStorageVarInfo(_storage_var_info &svi, uint16_t findID); // When we know the var ID but not the position in the array it occupies 89 | static boolean getStorageVarInfo(_storage_var_info &svi, uint16_t arrayPos); // For when we already know the array element we want 90 | 91 | // Vars 92 | 93 | }; 94 | 95 | 96 | 97 | 98 | #endif 99 | -------------------------------------------------------------------------------- /OpenPanzerTCB/src/OP_EEPROM/OP_EEPROM_Vars.xls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenPanzerProject/TCB/ce5072abda55802016c98b4bb13d49a97d5e44d5/OpenPanzerTCB/src/OP_EEPROM/OP_EEPROM_Vars.xls -------------------------------------------------------------------------------- /OpenPanzerTCB/src/OP_EEPROM/keywords.txt: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------- 2 | # Syntax Coloring Map 3 | # Words separated by TAB, not SPACE 4 | #------------------------------------------------------------- 5 | 6 | 7 | #------------------------------------------------------------- 8 | # KEYWORD1 - Classes 9 | #------------------------------------------------------------- 10 | 11 | OP_EEPROM KEYWORD1 12 | 13 | 14 | #------------------------------------------------------------- 15 | # KEYWORD2 - Methods, functions, members 16 | #------------------------------------------------------------- 17 | begin KEYWORD2 18 | 19 | ramcopy KEYWORD2 20 | 21 | loadRAMcopy KEYWORD2 22 | 23 | readSerialEEPROM_byID KEYWORD2 24 | 25 | updateEEPROM_byID KEYWORD2 26 | 27 | factoryReset KEYWORD2 28 | _eeprom_data KEYWORD2 29 | _vartype KEYWORD2 30 | _storage_var_info KEYWORD2 31 | 32 | 33 | #------------------------------------------------------------- 34 | # LITERAL1 - Constants & Defines 35 | #------------------------------------------------------------- 36 | 37 | NUM_STORED_VARS LITERAL1 38 | varNULL LITERAL1 39 | varBOOL LITERAL1 40 | varCHAR LITERAL1 41 | varINT8 LITERAL1 42 | varUINT8 LITERAL1 43 | varINT16 LITERAL1 44 | varUINT16 LITERAL1 45 | varINT32 LITERAL1 46 | varUINT32 LITERAL1 -------------------------------------------------------------------------------- /OpenPanzerTCB/src/OP_FT/keywords.txt: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------- 2 | # Syntax Coloring Map 3 | # Words separated by TAB, not SPACE 4 | #------------------------------------------------------------- 5 | 6 | 7 | #------------------------------------------------------------- 8 | # KEYWORD1 - Classes 9 | #------------------------------------------------------------- 10 | 11 | 12 | 13 | #------------------------------------------------------------- 14 | # KEYWORD2 - Methods, functions, members 15 | #------------------------------------------------------------- 16 | 17 | 18 | 19 | #------------------------------------------------------------- 20 | # LITERAL1 - Constants & Defines 21 | #------------------------------------------------------------- 22 | trigger_id_multiplier_auxchannel LITERAL1 23 | trigger_id_multiplier_ports LITERAL1 24 | switch_pos_multiplier LITERAL1 25 | ANALOG_SPECFUNCTION_MAX_VAL LITERAL1 26 | ANALOG_SPECFUNCTION_CENTER_VAL LITERAL1 27 | ANALOG_SPECFUNCTION_MIN_VAL LITERAL1 28 | COUNT_SPECFUNCTIONS LITERAL1 29 | MAX_FUNCTION_TRIGGERS LITERAL1 30 | _functionTrigger LITERAL1 31 | _trigger_source LITERAL1 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /OpenPanzerTCB/src/OP_IBusDecode/keywords.txt: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------- 2 | # Syntax Coloring Map 3 | # Words separated by TAB, not SPACE 4 | #------------------------------------------------------------- 5 | 6 | 7 | #------------------------------------------------------------- 8 | # KEYWORD1 - Classes 9 | #------------------------------------------------------------- 10 | 11 | iBusDecode KEYWORD1 12 | 13 | 14 | #------------------------------------------------------------- 15 | # KEYWORD2 - Methods, functions, members 16 | #------------------------------------------------------------- 17 | begin KEYWORD2 18 | shutdown KEYWORD2 19 | getState KEYWORD2 20 | getChanCount KEYWORD2 21 | GetiBus_Frame KEYWORD2 22 | NewFrame KEYWORD2 23 | update KEYWORD2 24 | 25 | 26 | #------------------------------------------------------------- 27 | # LITERAL1 - Constants & Defines 28 | #------------------------------------------------------------- 29 | 30 | UBBR_iBus LITERAL1 31 | iBus_CHANNELS LITERAL1 32 | iBus_STARTBYTE LITERAL1 33 | iBus_CMDBYTE LITERAL1 34 | iBus_FRAME_BYTES LITERAL1 35 | iBus_ACQUISITION_COUNT LITERAL1 36 | DISCARD_FRAMES LITERAL1 37 | 38 | -------------------------------------------------------------------------------- /OpenPanzerTCB/src/OP_IO/OP_IO.h: -------------------------------------------------------------------------------- 1 | /* OP_IO.h Open Panzer IO - defines and structs related to the two general purpose i/o ports on the TCB board 2 | * Source: openpanzer.org 3 | * Authors: Luke Middleton 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | */ 19 | 20 | #ifndef OP_IO_H 21 | #define OP_IO_H 22 | 23 | 24 | //-------------------------------------------------------------------------------------------------------------------------------------------------------------->> 25 | // GENERAL PURPOSE I/O 26 | //-------------------------------------------------------------------------------------------------------------------------------------------------------------->> 27 | 28 | #define NUM_IO_PORTS 2 29 | 30 | typedef struct external_io_settings{ 31 | uint8_t dataDirection; // 1 = output, 0 = input 32 | uint8_t dataType; // If input, 1 = "digital" (on/off only), 0 = analog (variable), default to digital. If Output, 1 = normally high, 0 = normally low, default normally high. 33 | }; 34 | 35 | typedef struct external_io{ 36 | boolean inputActive; // If input, hast his been assigned as a trigger to any function? 37 | uint16_t inputValue; // If input, what is the analog reading (0-1023 if analog) or digital reading (0/1 if digital) 38 | boolean updated; // If input, has the input value changed since last time? 39 | external_io_settings Settings; // Settings 40 | }; 41 | 42 | 43 | 44 | 45 | 46 | #endif 47 | -------------------------------------------------------------------------------- /OpenPanzerTCB/src/OP_IO/keywords.txt: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------- 2 | # Syntax Coloring Map 3 | # Words separated by TAB, not SPACE 4 | #------------------------------------------------------------- 5 | 6 | 7 | #------------------------------------------------------------- 8 | # KEYWORD1 - Classes 9 | #------------------------------------------------------------- 10 | 11 | 12 | 13 | #------------------------------------------------------------- 14 | # KEYWORD2 - Methods, functions, members 15 | #------------------------------------------------------------- 16 | 17 | 18 | 19 | #------------------------------------------------------------- 20 | # LITERAL1 - Constants & Defines 21 | #------------------------------------------------------------- 22 | NUM_IO_PORTS LITERAL1 23 | external_io_settings LITERAL1 24 | external_io LITERAL1 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /OpenPanzerTCB/src/OP_IRLib/OP_IRLib.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenPanzerProject/TCB/ce5072abda55802016c98b4bb13d49a97d5e44d5/OpenPanzerTCB/src/OP_IRLib/OP_IRLib.cpp -------------------------------------------------------------------------------- /OpenPanzerTCB/src/OP_IRLib/OP_IRLib.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenPanzerProject/TCB/ce5072abda55802016c98b4bb13d49a97d5e44d5/OpenPanzerTCB/src/OP_IRLib/OP_IRLib.h -------------------------------------------------------------------------------- /OpenPanzerTCB/src/OP_IRLib/OP_IRLibMatch.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenPanzerProject/TCB/ce5072abda55802016c98b4bb13d49a97d5e44d5/OpenPanzerTCB/src/OP_IRLib/OP_IRLibMatch.h -------------------------------------------------------------------------------- /OpenPanzerTCB/src/OP_IRLib/keywords.txt: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------- 2 | # Syntax Coloring Map 3 | # Words separated by TAB, not SPACE 4 | #------------------------------------------------------------- 5 | 6 | 7 | #------------------------------------------------------------- 8 | # KEYWORD1 - Classes 9 | #------------------------------------------------------------- 10 | 11 | IRdecodeBase KEYWORD1 12 | IRdecodeTamiya KEYWORD1 13 | IRdecodeTamiya_2Shot KEYWORD1 14 | IRdecodeTamiya35 KEYWORD1 15 | IRdecodeHengLong KEYWORD1 16 | IRdecodeTaigen KEYWORD1 17 | IRdecodeFOV KEYWORD1 18 | IRdecodeVsTank KEYWORD1 19 | IRdecodeWalterson72 KEYWORD1 20 | IRdecodeOpenPanzer KEYWORD1 21 | IRdecodeClark_Repair KEYWORD1 22 | IRdecodeIBU_Repair KEYWORD1 23 | IRdecodeRCTA_Repair KEYWORD1 24 | IRdecodeClark_MG KEYWORD1 25 | IRdecodeRCTA_MG KEYWORD1 26 | IRdecodeSony KEYWORD1 27 | IRdecode KEYWORD1 28 | 29 | IRsendBase KEYWORD1 30 | IRsendTamiya KEYWORD1 31 | IRsendTamiya_2Shot KEYWORD1 32 | IRsendTamiya35 KEYWORD1 33 | IRsendHengLong KEYWORD1 34 | IRsendTaigen KEYWORD1 35 | IRsendFOV KEYWORD1 36 | IRsendVsTank KEYWORD1 37 | IRsendWalterson72 KEYWORD1 38 | IRsendOpenPanzer KEYWORD1 39 | IRsendClark_Repair KEYWORD1 40 | IRsendIBU_Repair KEYWORD1 41 | IRsendRCTA_Repair KEYWORD1 42 | IRsendClark_MG KEYWORD1 43 | IRsendRCTA_MG KEYWORD1 44 | IRsendSony KEYWORD1 45 | IRsendRaw KEYWORD1 46 | 47 | IRrecvBase KEYWORD1 48 | IRrecvPCI KEYWORD1 49 | 50 | 51 | #------------------------------------------------------------- 52 | # KEYWORD2 - Methods, functions, members 53 | #------------------------------------------------------------- 54 | ReverseByte KEYWORD2 55 | IRTYPES KEYWORD2 56 | IRTEAMS KEYWORD2 57 | decode KEYWORD2 58 | decode_type KEYWORD2 59 | value KEYWORD2 60 | bits KEYWORD2 61 | rawbuf KEYWORD2 62 | rawlen KEYWORD2 63 | IgnoreHeader KEYWORD2 64 | Reset KEYWORD2 65 | decodeGeneric KEYWORD2 66 | DumpResults KEYWORD2 67 | UseExtnBuf KEYWORD2 68 | copyBuf KEYWORD2 69 | convertValueToSonyNumbers KEYWORD2 70 | SonyDeviceID KEYWORD2 71 | SonyCommand KEYWORD2 72 | sendGeneric KEYWORD2 73 | send KEYWORD2 74 | sendTeam2 KEYWORD2 75 | sendTeam3 KEYWORD2 76 | sendTeam4 KEYWORD2 77 | sendTeamA KEYWORD2 78 | sendTeamB KEYWORD2 79 | sendDeviceIDCommand KEYWORD2 80 | No_Output KEYWORD2 81 | setBlinkingOnReceive KEYWORD2 82 | GetResults KEYWORD2 83 | enableIRIn KEYWORD2 84 | resume KEYWORD2 85 | getPinNum KEYWORD2 86 | Mark_Excess KEYWORD2 87 | Pin_from_Intr KEYWORD2 88 | PERCENT_LOW KEYWORD2 89 | PERCENT_HIGH KEYWORD2 90 | ABS_MATCH KEYWORD2 91 | PERC_MATCH KEYWORD2 92 | MATCH KEYWORD2 93 | MATCH_MARK KEYWORD2 94 | MATCH_SPACE KEYWORD2 95 | 96 | 97 | #------------------------------------------------------------- 98 | # LITERAL1 - Constants & Defines 99 | #------------------------------------------------------------- 100 | 101 | IR_UNKNOWN LITERAL1 102 | IR_DISABLED LITERAL1 103 | IR_TAMIYA LITERAL1 104 | IR_TAMIYA_2SHOT LITERAL1 105 | IR_TAMIYA_35 LITERAL1 106 | IR_HENGLONG LITERAL1 107 | IR_TAIGEN LITERAL1 108 | IR_WALTERSON_72 LITERAL1 109 | IR_FOV LITERAL1 110 | IR_VSTANK LITERAL1 111 | IR_OPENPANZER LITERAL1 112 | IR_RPR_CLARK LITERAL1 113 | IR_RPR_IBU LITERAL1 114 | IR_RPR_RCTA LITERAL1 115 | IR_MG_CLARK LITERAL1 116 | IR_MG_RCTA LITERAL1 117 | IR_SONY LITERAL1 118 | IR_TEAM_NONE LITERAL1 119 | IR_TEAM_FOV_2 LITERAL1 120 | IR_TEAM_FOV_3 LITERAL1 121 | IR_TEAM_FOV_4 LITERAL1 122 | IR_TEAM_WALTERSON72_A LITERAL1 123 | IR_TEAM_WALTERSON72_B LITERAL1 124 | Tamiya_BITS LITERAL1 125 | Tamiya_GAP LITERAL1 126 | Tamiya_TIMESTOSEND LITERAL1 127 | Taigen_MARK LITERAL1 128 | Taigen_SPACE LITERAL1 129 | Taigen_BITS LITERAL1 130 | HengLong_HDR_MARK LITERAL1 131 | HengLong_SHORT_BIT LITERAL1 132 | HengLong_LONG_BIT LITERAL1 133 | HengLong_GAP LITERAL1 134 | HengLong_BITS LITERAL1 135 | HengLong_TIMESTOSEND LITERAL1 136 | FOV_HDR_MARK LITERAL1 137 | FOV_SPACE LITERAL1 138 | FOV_ONE_MARK LITERAL1 139 | FOV_ZERO_MARK LITERAL1 140 | FOV_GAP LITERAL1 141 | FOV_BITS LITERAL1 142 | FOV_TIMESTOSEND LITERAL1 143 | FOV_TEAM_1_VALUE LITERAL1 144 | FOV_TEAM_2_VALUE LITERAL1 145 | FOV_TEAM_3_VALUE LITERAL1 146 | FOV_TEAM_4_VALUE LITERAL1 147 | VsTank_HDR_MARK LITERAL1 148 | VsTank_SPACE_SHORT LITERAL1 149 | VsTank_SPACE_LONG LITERAL1 150 | VsTank_ONE_MARK LITERAL1 151 | VsTank_ZERO_MARK LITERAL1 152 | VsTank_BITS LITERAL1 153 | VsTank_TIMESTOSEND LITERAL1 154 | WALTERSON72_TEAM_A_VALUE LITERAL1 155 | WALTERSON72_TEAM_B_VALUE LITERAL1 156 | Clark_REPAIR_CODE LITERAL1 157 | Clark_REPAIR_TIMESTOSEND LITERAL1 158 | Clark_REPAIR_GAP LITERAL1 159 | Clark_MG_CODE LITERAL1 160 | Clark_MG_GAP LITERAL1 161 | RCTA_BITS LITERAL1 162 | RCTA_REPAIR_TIMESTOSEND LITERAL1 163 | MAX_SONY_DEVICE_ID LITERAL1 164 | MAX_SONY_COMMAND LITERAL1 165 | MG_REPEAT_TIME_mS LITERAL1 166 | GAP LITERAL1 167 | MARK_EXCESS_DEFAULT LITERAL1 168 | OP_IRLib_USE_PERCENT LITERAL1 169 | USECPERTICK LITERAL1 170 | PERCENT_TOLERANCE LITERAL1 171 | DEFAULT_ABS_TOLERANCE LITERAL1 172 | 173 | -------------------------------------------------------------------------------- /OpenPanzerTCB/src/OP_Motors/keywords.txt: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------- 2 | # Syntax Coloring Map 3 | # Words separated by TAB, not SPACE 4 | #------------------------------------------------------------- 5 | 6 | 7 | #------------------------------------------------------------- 8 | # KEYWORD1 - Classes 9 | #------------------------------------------------------------- 10 | 11 | Motor KEYWORD1 12 | Sabertooth_SerialESC KEYWORD1 13 | Pololu_SerialESC KEYWORD1 14 | OPScout_SerialESC KEYWORD1 15 | Onboard_ESC KEYWORD1 16 | Servo_ESC KEYWORD1 17 | Servo_PAN KEYWORD1 18 | Servo_RECOIL KEYWORD1 19 | Null_Motor KEYWORD1 20 | 21 | 22 | #------------------------------------------------------------- 23 | # KEYWORD2 - Methods, functions, members 24 | #------------------------------------------------------------- 25 | ESC_POS_t KEYWORD2 26 | Drive_t KEYWORD2 KEYWORD2 27 | set_ExternalRange KEYWORD2 28 | set_InternalRange KEYWORD2 29 | set_DefaultInternalRange KEYWORD2 30 | restore_Speed KEYWORD2 31 | set_Reversed KEYWORD2 32 | isReversed KEYWORD2 33 | cut_SpeedPct KEYWORD2 34 | set_MaxSpeedPct KEYWORD2 35 | cut_PosSpeedPct KEYWORD2 36 | cut_NegSpeedPct KEYWORD2 37 | map_Range KEYWORD2 38 | getSpeed KEYWORD2 39 | setSpeed KEYWORD2 40 | begin KEYWORD2 41 | stop KEYWORD2 42 | setPos KEYWORD2 43 | setLimits KEYWORD2 44 | PulseWidth KEYWORD2 45 | Recoil KEYWORD2 46 | 47 | 48 | #------------------------------------------------------------- 49 | # LITERAL1 - Constants & Defines 50 | #------------------------------------------------------------- 51 | 52 | SERVO_8 LITERAL1 53 | SERVO_7 LITERAL1 54 | SERVO_6 LITERAL1 55 | SERVO_5 LITERAL1 56 | SERVO_4 LITERAL1 57 | SERVO_3 LITERAL1 58 | SERVO_2 LITERAL1 59 | SERVO_1 LITERAL1 60 | SIDEA LITERAL1 61 | SIDEB LITERAL1 62 | SERVO8 LITERAL1 63 | SERVO7 LITERAL1 64 | SERVO6 LITERAL1 65 | SERVO5 LITERAL1 66 | SERVO4 LITERAL1 67 | SERVO3 LITERAL1 68 | SERVO2 LITERAL1 69 | SERVO1 LITERAL1 70 | POLOLU LITERAL1 71 | SABERTOOTH LITERAL1 72 | OP_SCOUT LITERAL1 73 | ONBOARD LITERAL1 74 | SERVO_ESC LITERAL1 75 | SERVO_PAN LITERAL1 76 | SERVO_RECOIL LITERAL1 77 | DRIVE_DETACHED LITERAL1 78 | 79 | -------------------------------------------------------------------------------- /OpenPanzerTCB/src/OP_PCComm/keywords.txt: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------- 2 | # Syntax Coloring Map 3 | # Words separated by TAB, not SPACE 4 | #------------------------------------------------------------- 5 | 6 | 7 | #------------------------------------------------------------- 8 | # KEYWORD1 - Classes 9 | #------------------------------------------------------------- 10 | 11 | OP_PCComm KEYWORD1 12 | 13 | 14 | #------------------------------------------------------------- 15 | # KEYWORD2 - Methods, functions, members 16 | #------------------------------------------------------------- 17 | SentencePrefix KEYWORD2 18 | DataSentence KEYWORD2 19 | begin KEYWORD2 20 | CheckPC KEYWORD2 21 | ListenToPC KEYWORD2 22 | switchToAltSerial KEYWORD2 23 | revertToDefaultSerial KEYWORD2 24 | skipCRC KEYWORD2 25 | requireCRC KEYWORD2 26 | 27 | 28 | #------------------------------------------------------------- 29 | # LITERAL1 - Constants & Defines 30 | #------------------------------------------------------------- 31 | 32 | DELIMITER LITERAL1 33 | NEWLINE LITERAL1 34 | INIT_STRING LITERAL1 35 | PCCMD_SABERTOOTH_BAUD LITERAL1 36 | PCCMD_CONFPOLOLU_DRIVE LITERAL1 37 | PCCMD_CONFPOLOLU_TURRET LITERAL1 38 | PCCMD_NUM_CHANNELS LITERAL1 39 | PCCMD_STARTSTREAM_RADIO LITERAL1 40 | PCCMD_STOPSTREAM_RADIO LITERAL1 41 | PCCMD_UPDATE_EEPROM LITERAL1 42 | PCCMD_READ_EEPROM LITERAL1 43 | PCCMD_READ_VERSION LITERAL1 44 | PCCMD_STAY_AWAKE LITERAL1 45 | PCCMD_DISCONNECT LITERAL1 46 | DVCMD_RADIO_NOTREADY LITERAL1 47 | DVCMD_NEXT_SENTENCE LITERAL1 48 | DVCMD_REPEAT_SENTENCE LITERAL1 49 | DVCMD_RETURN_VALUE LITERAL1 50 | DVCMD_NOSUCH_VALUE LITERAL1 51 | DVCMD_GOODBYE LITERAL1 52 | MIN_EEPROM_ID LITERAL1 53 | SERIAL_COMM_TIMEOUT LITERAL1 54 | MAX_COMM_ERRORCOUNT LITERAL1 55 | DEFAULT_SERIAL_PORT LITERAL1 56 | ALT_SERIAL_PORT LITERAL1 57 | VALUE_BUFF LITERAL1 58 | SENTENCE_BUFF LITERAL1 59 | 60 | -------------------------------------------------------------------------------- /OpenPanzerTCB/src/OP_PPMDecode/OP_PPMDecode.h: -------------------------------------------------------------------------------- 1 | /* OP_PPMDecode.h Open Panzer PPM Decode - a library for decoding typical RC PPM streams into individual channel pulse widths 2 | * Source: openpanzer.org 3 | * Authors: Michael Margolis, Luke Middleton 4 | * 5 | * This library is based on the ServoDecode library written by Michael Margolis (Arduino Forum user "MEM"). 6 | * His original work can be found on the Arduino forum under the title "Decoding Radio Control signal pulses": 7 | * http://forum.arduino.cc/index.php?topic=22140.0 8 | * 9 | * However, some changes have been made. The PPM signal now is assigned to an External Interrupt pin, in this case: 10 | * Arduino Pin 3, External INT1, or in terms of the Atmega chip itself, 11 | * Atmega Pin 7, External INT5 12 | * 13 | * The only interrupt we are now monitoring is the external pin interrupt. We don't do any timer overflows since we are not resetting TCNT1 ever. 14 | * This has also required some changes to MEM's failsafe code. 15 | * 16 | * 17 | * This program is free software: you can redistribute it and/or modify 18 | * it under the terms of the GNU General Public License as published by 19 | * the Free Software Foundation, either version 3 of the License, or 20 | * (at your option) any later version. 21 | * 22 | * This program is distributed in the hope that it will be useful, 23 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 24 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25 | * GNU General Public License for more details. 26 | * 27 | * You should have received a copy of the GNU General Public License 28 | * along with this program. If not, see . 29 | * 30 | */ 31 | 32 | #ifndef OP_PPMDecode_H 33 | #define OP_PPMDecode_H 34 | 35 | #include 36 | #include 37 | #include 38 | #include "../OP_Settings/OP_Settings.h" 39 | #include "../OP_Radio/OP_RadioDefines.h" 40 | 41 | 42 | #define PPM_PIN 3 // Input Pin in ARDUINO format. This is actually Atmega pin 7. 43 | // This is also Atmega External Interrupt 5 44 | // In Arduino, that would be External Interrupt 1 45 | 46 | #define PPM_MODE RISING // Arduino defines these: 47 | // #define FALLING 2 (10) 48 | // #define RISING 3 (11) 49 | 50 | #define MIN_PPM_CHANNELS 4 // We don't accept anything less than 4 channels, even if the signal is valid 51 | #define MAX_PPM_CHANNELS 8 // maximum number of channels in PPM stream we can store. This is not the same as the 52 | // the number of channels the main sketch actually uses (see COUNT_OP_CHANNELS in OP_Radio.h) 53 | // If your radio spits out more than 8 channels of PPM data, the extra channels will be ignored. 54 | 55 | #define PPM_ACQUISITION_COUNT 6 // Must have this many consecutive valid frames to transition to the ready state. 56 | 57 | 58 | // PPM_TICKS_PER_uS is defined in OP_Settings.h 59 | #define MIN_PPM_TICKLEN (MIN_POSSIBLE_PULSE * PPM_TICKS_PER_uS) // Minimum valid pulse width, converted to timer ticks 60 | #define MAX_PPM_TICKLEN (MAX_POSSIBLE_PULSE * PPM_TICKS_PER_uS) // Maximum valid pulse width, converted to timer ticks 61 | #define SYNC_GAP_TICKLEN (3000 * PPM_TICKS_PER_uS) // we assume a space at least 3000uS is sync. Some use longer, but this would be the minimum (it exceeds the maximum possible pulse) 62 | 63 | 64 | class PPMDecode 65 | { 66 | public: 67 | PPMDecode(); //Constructor 68 | void begin(); 69 | void shutdown(); // Disable the PPM receiver 70 | void clearTicks(); 71 | decodeState_t getState(); // Get state Function 72 | void GetPPM_Frame(int16_t pulseArray[], int16_t chanCount); // Get a full, complete frame of pulses. 73 | uint8_t getChanCount(); // Returns the number of channels in a full frame 74 | static void INT5_PPM_ISR(void); // The actual ISR will call this public member function, in order that it can access class variables 75 | static volatile boolean NewFrame; // Has an unread frame of data arrived? 76 | 77 | private: 78 | static volatile uint16_t Ticks[MAX_PPM_CHANNELS + 1]; // Array holding the channel tick count. We have +1 since 0 will be our sync pulse, rest are channels 79 | static volatile uint8_t Channel; // number of channels detected so far in the frame (first channel is 1) 80 | static volatile uint8_t stateCount; // Counts the number of times this state has been repeated 81 | static volatile decodeState_t State; // The current state 82 | static volatile uint8_t NbrChannels; // the total number of channels detected in a complete frame 83 | static volatile uint16_t tickStamp; 84 | }; 85 | 86 | 87 | #endif 88 | 89 | -------------------------------------------------------------------------------- /OpenPanzerTCB/src/OP_PPMDecode/keywords.txt: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------- 2 | # Syntax Coloring Map 3 | # Words separated by TAB, not SPACE 4 | #------------------------------------------------------------- 5 | 6 | 7 | #------------------------------------------------------------- 8 | # KEYWORD1 - Classes 9 | #------------------------------------------------------------- 10 | 11 | PPMDecode KEYWORD1 12 | 13 | 14 | #------------------------------------------------------------- 15 | # KEYWORD2 - Methods, functions, members 16 | #------------------------------------------------------------- 17 | begin KEYWORD2 18 | shutdown KEYWORD2 19 | clearTicks KEYWORD2 20 | getState KEYWORD2 21 | GetPPM_Frame KEYWORD2 22 | getChanCount KEYWORD2 23 | INT5_PPM_ISR KEYWORD2 24 | NewFrame KEYWORD2 25 | 26 | 27 | #------------------------------------------------------------- 28 | # LITERAL1 - Constants & Defines 29 | #------------------------------------------------------------- 30 | 31 | PPM_PIN LITERAL1 32 | PPM_MODE LITERAL1 33 | MIN_PPM_CHANNELS LITERAL1 34 | MAX_PPM_CHANNELS LITERAL1 35 | PPM_ACQUISITION_COUNT LITERAL1 36 | MIN_PPM_TICKLEN LITERAL1 37 | MAX_PPM_TICKLEN LITERAL1 38 | SYNC_GAP_TICKLEN LITERAL1 39 | -------------------------------------------------------------------------------- /OpenPanzerTCB/src/OP_PololuQik/OP_PololuQik.h: -------------------------------------------------------------------------------- 1 | /* OP_PololuQik.h Open Panzer PololuQik library - functions for communicating with Pololu's Qik dual-serial motor controllers, 2 | * such as the 2s12v10 and the 2s9v1 running the full Pololu Protocol in 7-bit mode. 3 | * Source: http://www.Pololu.com 4 | * Authors: Pololu 5 | * 6 | * This library is a modification of the Pololu "qik-arduino" library, and should only be used with the Open Panzer project. 7 | * For the original library, see Pololu's github page: https://github.com/pololu/qik-arduino 8 | * 9 | * The original Pololu copyright is listed below: 10 | * 11 | * Copyright (c) 2012 Pololu Corporation. For more information, see 12 | * http://www.pololu.com/ 13 | * 14 | * Permission is hereby granted, free of charge, to any person 15 | * obtaining a copy of this software and associated documentation 16 | * files (the "Software"), to deal in the Software without 17 | * restriction, including without limitation the rights to use, 18 | * copy, modify, merge, publish, distribute, sublicense, and/or sell 19 | * copies of the Software, and to permit persons to whom the 20 | * Software is furnished to do so, subject to the following 21 | * conditions: 22 | * 23 | * The above copyright notice and this permission notice shall be 24 | * included in all copies or substantial portions of the Software. 25 | * 26 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 27 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 28 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 29 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 30 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 31 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 32 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 33 | * OTHER DEALINGS IN THE SOFTWARE. 34 | * 35 | */ 36 | 37 | #ifndef OP_PololuQik_h 38 | #define OP_PololuQik_h 39 | 40 | #include 41 | #include "../OP_Settings/OP_Settings.h" 42 | 43 | 44 | // We are using the full Pololu Protocol (not the compact protocol) 45 | 46 | // Commands 47 | #define QIK_INIT_COMMAND 0xAA 48 | #define QIK_GET_ERROR_BYTE 0x82 49 | #define QIK_GET_CONFIGURATION_PARAMETER 0x83 50 | #define QIK_SET_CONFIGURATION_PARAMETER 0x84 51 | 52 | #define QIK_PARAM_NUM_DEVICE_ID 0 53 | #define QIK_PARAM_NUM_PWM 1 54 | #define QIK_PARAM_NUM_SHTDN_ERR 2 55 | #define QIK_PARAM_NUM_SER_TIMEOUT 3 56 | #define QIK_PARAM_NUM_M0_ACCEL 4 57 | #define QIK_PARAM_NUM_M1_ACCEL 5 58 | #define QIK_PARAM_NUM_M0_BRAKE 6 59 | #define QIK_PARAM_NUM_M1_BRAKE 7 60 | #define QIK_PARAM_NUM_M0_CURLIMIT 8 61 | #define QIK_PARAM_NUM_M1_CURLIMIT 9 62 | #define QIK_PARAM_NUM_M0_CURRESPONSE 10 63 | #define QIK_PARAM_NUM_M1_CURRESPONSE 11 64 | 65 | 66 | // 7-bit speed commands, we are not using the 8 bit option in Open Panzer 67 | #define QIK_MOTOR_M0_FORWARD 0x08 68 | #define QIK_MOTOR_M0_REVERSE 0x0A 69 | #define QIK_MOTOR_M1_FORWARD 0x0C 70 | #define QIK_MOTOR_M1_REVERSE 0x0E 71 | #define QIK_MOTOR_M0_BRAKE 0x06 72 | #define QIK_MOTOR_M1_BRAKE 0x07 73 | #define QIK_MOTOR_BRAKE_LEVEL 0x7F // Maximum = 127 74 | 75 | // CRC7 lookup table, takes up 256 bytes, stick it in PROGMEM 76 | const unsigned char CRC7Table[256] PROGMEM_FAR = 77 | { 78 | 0x00, 79 | 0x41,0x13,0x52,0x26,0x67,0x35,0x74,0x4C,0x0D,0x5F,0x1E,0x6A,0x2B,0x79,0x38, 80 | 0x09,0x48,0x1A,0x5B,0x2F,0x6E,0x3C,0x7D,0x45,0x04,0x56,0x17,0x63,0x22,0x70, 81 | 0x31,0x12,0x53,0x01,0x40,0x34,0x75,0x27,0x66,0x5E,0x1F,0x4D,0x0C,0x78,0x39, 82 | 0x6B,0x2A,0x1B,0x5A,0x08,0x49,0x3D,0x7C,0x2E,0x6F,0x57,0x16,0x44,0x05,0x71, 83 | 0x30,0x62,0x23,0x24,0x65,0x37,0x76,0x02,0x43,0x11,0x50,0x68,0x29,0x7B,0x3A, 84 | 0x4E,0x0F,0x5D,0x1C,0x2D,0x6C,0x3E,0x7F,0x0B,0x4A,0x18,0x59,0x61,0x20,0x72, 85 | 0x33,0x47,0x06,0x54,0x15,0x36,0x77,0x25,0x64,0x10,0x51,0x03,0x42,0x7A,0x3B, 86 | 0x69,0x28,0x5C,0x1D,0x4F,0x0E,0x3F,0x7E,0x2C,0x6D,0x19,0x58,0x0A,0x4B,0x73, 87 | 0x32,0x60,0x21,0x55,0x14,0x46,0x07,0x48,0x09,0x5B,0x1A,0x6E,0x2F,0x7D,0x3C, 88 | 0x04,0x45,0x17,0x56,0x22,0x63,0x31,0x70,0x41,0x00,0x52,0x13,0x67,0x26,0x74, 89 | 0x35,0x0D,0x4C,0x1E,0x5F,0x2B,0x6A,0x38,0x79,0x5A,0x1B,0x49,0x08,0x7C,0x3D, 90 | 0x6F,0x2E,0x16,0x57,0x05,0x44,0x30,0x71,0x23,0x62,0x53,0x12,0x40,0x01,0x75, 91 | 0x34,0x66,0x27,0x1F,0x5E,0x0C,0x4D,0x39,0x78,0x2A,0x6B,0x6C,0x2D,0x7F,0x3E, 92 | 0x4A,0x0B,0x59,0x18,0x20,0x61,0x33,0x72,0x06,0x47,0x15,0x54,0x65,0x24,0x76, 93 | 0x37,0x43,0x02,0x50,0x11,0x29,0x68,0x3A,0x7B,0x0F,0x4E,0x1C,0x5D,0x7E,0x3F, 94 | 0x6D,0x2C,0x58,0x19,0x4B,0x0A,0x32,0x73,0x21,0x60,0x14,0x55,0x07,0x46,0x77, 95 | 0x36,0x64,0x25,0x51,0x10,0x42,0x03,0x3B,0x7A,0x28,0x69,0x1D,0x5C,0x0E,0x4F 96 | }; 97 | #define GetCRC(i) pgm_read_byte_far(pgm_get_far_address(CRC7Table) + i) 98 | 99 | class OP_PololuQik 100 | { 101 | public: 102 | /*! 103 | Initializes a new instance of the PololuQik class. 104 | The device ID is set to the value given, and the specified serial port is used. 105 | \param deviceID The device ID to use. 106 | \param port The port to use. 107 | */ 108 | OP_PololuQik(byte deviceID, HardwareSerial *port); 109 | 110 | public: 111 | /*! 112 | Gets the device number. 113 | \return The device number. 114 | */ 115 | inline byte deviceID() const { return _deviceID; } 116 | 117 | /*! 118 | Gets the serial port. 119 | \return The serial port. 120 | */ 121 | inline HardwareSerial* port() const { return _port; } 122 | 123 | /*! 124 | Sends the autobaud character. 125 | \param dontWait If false, a delay is added to give the driver time to start up. 126 | */ 127 | void autobaud(boolean dontWait = false) const; 128 | 129 | /*! 130 | Sends the autobaud character. 131 | \param port The port to use. 132 | \param dontWait If false, a delay is added to give the driver time to start up. 133 | */ 134 | void autobaud(HardwareSerial *port, boolean dontWait = false); 135 | 136 | /*! 137 | Sends a packet serial command to the motor driver. 138 | \param command The number of the command. 139 | \param value The command's value. 140 | */ 141 | void command(byte command, byte value) const; 142 | 143 | public: 144 | /*! 145 | Sets the speed of the specified motor. 146 | \param motor The motor number, 1 or 2. 147 | \param speed The speed, between -127 and 127. 148 | */ 149 | void motor(byte motor, int speed) const; 150 | 151 | /*! 152 | Stops. 153 | */ 154 | void allStop() const; 155 | 156 | /*! 157 | Configures the device for use with the TCB. 158 | \param SetDeviceID = what device ID to set the unit to (0-127) 159 | \returns true if configuration was successful, false if not. 160 | \routine can take 161 | */ 162 | boolean configurePololu(byte SetDeviceID); 163 | 164 | 165 | private: 166 | void sendMessage(unsigned char message[], unsigned int length); // Sends a message of any length, including CRC 167 | 168 | void motorCommand(byte command, int speed) const; 169 | 170 | void clearError(void); 171 | 172 | //byte getConfigurationParameter(byte parameter); // Presently we are only transmitting, not receiving. 173 | byte setConfigurationParameter(byte parameter, byte value); 174 | 175 | private: 176 | const byte _deviceID; 177 | HardwareSerial *_port; 178 | }; 179 | 180 | 181 | #endif -------------------------------------------------------------------------------- /OpenPanzerTCB/src/OP_PololuQik/keywords.txt: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------- 2 | # Syntax Coloring Map 3 | # Words separated by TAB, not SPACE 4 | #------------------------------------------------------------- 5 | 6 | 7 | #------------------------------------------------------------- 8 | # KEYWORD1 - Classes 9 | #------------------------------------------------------------- 10 | 11 | OP_PololuQik KEYWORD1 12 | 13 | 14 | #------------------------------------------------------------- 15 | # KEYWORD2 - Methods, functions, members 16 | #------------------------------------------------------------- 17 | deviceID KEYWORD2 18 | port KEYWORD2 19 | autobaud KEYWORD2 20 | command KEYWORD2 21 | motor KEYWORD2 22 | allStop KEYWORD2 23 | configurePololu KEYWORD2 24 | 25 | 26 | 27 | #------------------------------------------------------------- 28 | # LITERAL1 - Constants & Defines 29 | #------------------------------------------------------------- 30 | 31 | QIK_INIT_COMMAND LITERAL1 32 | QIK_MOTOR_M0_FORWARD LITERAL1 33 | QIK_MOTOR_M0_REVERSE LITERAL1 34 | QIK_MOTOR_M1_FORWARD LITERAL1 35 | QIK_MOTOR_M1_REVERSE LITERAL1 -------------------------------------------------------------------------------- /OpenPanzerTCB/src/OP_Radio/keywords.txt: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------- 2 | # Syntax Coloring Map 3 | # Words separated by TAB, not SPACE 4 | #------------------------------------------------------------- 5 | 6 | 7 | #------------------------------------------------------------- 8 | # KEYWORD1 - Classes and types 9 | #------------------------------------------------------------- 10 | 11 | OP_Radio KEYWORD1 12 | RADIO_PROTOCOL KEYWORD1 13 | stick_channel_settings KEYWORD1 14 | stick_channel KEYWORD1 15 | stick_channels KEYWORD1 16 | aux_channel_settings KEYWORD1 17 | aux_channels KEYWORD1 18 | common_channel_settings KEYWORD1 19 | sf_channel KEYWORD1 20 | decodeState_t KEYWORD1 21 | 22 | 23 | #------------------------------------------------------------- 24 | # KEYWORD2 - Methods, functions, members 25 | #------------------------------------------------------------- 26 | saveTimer KEYWORD2 27 | detect KEYWORD2 28 | begin KEYWORD2 29 | hasBegun KEYWORD2 30 | GetCommands KEYWORD2 31 | getProtocol KEYWORD2 32 | Status KEYWORD2 33 | NewFrame KEYWORD2 34 | getChannelCount KEYWORD2 35 | ChannelsUtilized KEYWORD2 36 | UsingSpecialPositions KEYWORD2 37 | AdjustTurretStickEndPoints KEYWORD2 38 | InFailsafe KEYWORD2 39 | Sticks KEYWORD2 40 | SpecialStick KEYWORD2 41 | AuxChannel KEYWORD2 42 | Update KEYWORD2 43 | GetStringFrame KEYWORD2 44 | 45 | 46 | #------------------------------------------------------------- 47 | # LITERAL1 - Constants & Defines 48 | #------------------------------------------------------------- 49 | 50 | COUNT_OP_CHANNELS LITERAL1 51 | STICKCHANNELS LITERAL1 52 | AUXCHANNELS LITERAL1 53 | switch_positions LITERAL1 54 | SPECIALPOSITIONS LITERAL1 55 | TURRETSTICK_PULSESUBTRACT LITERAL1 56 | turretStick_Positions LITERAL1 57 | border_vals LITERAL1 58 | 59 | 60 | -------------------------------------------------------------------------------- /OpenPanzerTCB/src/OP_SBusDecode/OP_SBusDecode.h: -------------------------------------------------------------------------------- 1 | /* OP_SBusDecode.h Open Panzer SBus Decoder - a library for decoding FrSky/Futaba S.Bus serial radio data 2 | * Source: openpanzer.org 3 | * Authors: Luke Middleton 4 | * 5 | * This library owes much to the work of three other individuals: 6 | * Mike Blandford (MikeB) SBusToPPM: http://openrcforums.com/forum/viewtopic.php?f=91&t=5476&start=30 (04-Mar-2015) 7 | * Michel (mstrens) CPPM_SBUS: http://openrcforums.com/forum/viewtopic.php?f=84&t=6361&start=30#p92825 (09-Feb-2015) 8 | * Uwe Gartmann SBUS-Library: https://developer.mbed.org/users/Digixx/notebook/futaba-s-bus-controlled-by-mbed/ (09-Mar-2012) 9 | * 10 | * This library reads the 25 byte SBus protocol and converts the data into 16 analog channels. An additional 2 digital (on/off) channels are specified in the 11 | * protocol and could be implemented but presently are ignored. 12 | * 13 | * The SBus protocol is 100,000 baud inverted serial. After undoing the inversion in hardware, we can read the data stream using a common serial port. 14 | * Ironically because Arduino appropriates the hardware serial interrupt ISR(USART3_RX_vect), this library needs to be polled in order to update 15 | * (unlike the PPM decoder library that is based entirely on interrupts and updates itself as data comes in). The one offseting advantage is 16 | * that the Arduino hardware serial library implements a convenient 64 byte buffer. We could probably make a better implementation of this library if we 17 | * appropriated the ISR ourselves (specifically see Uwe Gartmann's library above, the other two implement polling like this one). But, we would like to keep 18 | * this compatible with Arduino, and this approach seems to work ok but does require some extra work in the OP_Radio class. 19 | * 20 | * 21 | * This program is free software: you can redistribute it and/or modify 22 | * it under the terms of the GNU General Public License as published by 23 | * the Free Software Foundation, either version 3 of the License, or 24 | * (at your option) any later version. 25 | * 26 | * This program is distributed in the hope that it will be useful, 27 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 28 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 29 | * GNU General Public License for more details. 30 | * 31 | * You should have received a copy of the GNU General Public License 32 | * along with this program. If not, see . 33 | * 34 | */ 35 | 36 | #ifndef OP_SBusDecode_H 37 | #define OP_SBusDecode_H 38 | 39 | #include 40 | #include "../OP_Settings/OP_Settings.h" 41 | #include "../OP_Radio/OP_RadioDefines.h" 42 | 43 | 44 | // Uncomment only ONE of the below, to indicate which hardware serial the SBus will receive data on. 45 | //#define SBUS_SERIAL_0 0 46 | //#define SBUS_SERIAL_1 1 47 | //#define SBUS_SERIAL_2 2 48 | #define SBUS_SERIAL_3 3 49 | 50 | // Now we will save the appropriate registers for the selected serial port 51 | // THIS IS ONLY GUARANTEED TO WORK FOR THE ATmega2560! 52 | #if defined (SBUS_SERIAL_0) 53 | #define SBUS_UBRRH UBRR0H 54 | #define SBUS_UBRRL UBRR0L 55 | #define SBUS_UCSRA UCSR0A 56 | #define SBUS_UCSRB UCSR0B 57 | #define SBUS_UCSRC UCSR0C 58 | #define SBUS_UDR UDR0 59 | #define SBUS_SERIAL Serial0 60 | #define SBUS_PRUSART PRUSART0 61 | #define SBUS_RXEN RXEN0 62 | #define SBUS_RXC RXC0 63 | #define SBUS_RXCIE RXCIE0 64 | #define SBUS_PORT PORTE 65 | #define SBUS_DDR DDRE 66 | #define SBUS_RXPIN PE0 67 | #elif defined (SBUS_SERIAL_1) 68 | #define SBUS_UBRRH UBRR1H 69 | #define SBUS_UBRRL UBRR1L 70 | #define SBUS_UCSRA UCSR1A 71 | #define SBUS_UCSRB UCSR1B 72 | #define SBUS_UCSRC UCSR1C 73 | #define SBUS_UDR UDR1 74 | #define SBUS_SERIAL Serial1 75 | #define SBUS_PRUSART PRUSART1 76 | #define SBUS_RXEN RXEN1 77 | #define SBUS_RXC RXC1 78 | #define SBUS_RXCIE RXCIE1 79 | #define SBUS_PORT PORTD 80 | #define SBUS_DDR DDRD 81 | #define SBUS_RXPIN PD2 82 | #elif defined (SBUS_SERIAL_2) 83 | #define SBUS_UBRRH UBRR2H 84 | #define SBUS_UBRRL UBRR2L 85 | #define SBUS_UCSRA UCSR2A 86 | #define SBUS_UCSRB UCSR2B 87 | #define SBUS_UCSRC UCSR2C 88 | #define SBUS_UDR UDR2 89 | #define SBUS_SERIAL Serial2 90 | #define SBUS_PRUSART PRUSART2 91 | #define SBUS_RXEN RXEN2 92 | #define SBUS_RXC RXC2 93 | #define SBUS_RXCIE RXCIE2 94 | #define SBUS_PORT PORTH 95 | #define SBUS_DDR DDRH 96 | #define SBUS_RXPIN PH0 97 | #else defined (SBUS_SERIAL_3) 98 | #define SBUS_UBRRH UBRR3H 99 | #define SBUS_UBRRL UBRR3L 100 | #define SBUS_UCSRA UCSR3A 101 | #define SBUS_UCSRB UCSR3B 102 | #define SBUS_UCSRC UCSR3C 103 | #define SBUS_UDR UDR3 104 | #define SBUS_SERIAL Serial3 105 | #define SBUS_PRUSART PRUSART3 106 | #define SBUS_RXEN RXEN3 107 | #define SBUS_RXC RXC3 108 | #define SBUS_RXCIE RXCIE3 109 | #define SBUS_PORT PORTJ 110 | #define SBUS_DDR DDRJ 111 | #define SBUS_RXPIN PJ0 112 | #endif 113 | 114 | // SBus is 100k baud. Pre-calculate the UBBRn setting that will give us this baud rate. 115 | #define UBRR_SBUS 9 // We can get a perfect match: 116 | // (F_CPU / (16*BAUD) ) -1 = (16,000,000 / (16 * 100,000) ) - 1 = 9 117 | // Note this is in Normal Speed Mode, so make sure you set U2Xn = 0! (See the .cpp file) 118 | 119 | #define SBUS_STARTBYTE 0x0F // First byte of an SBus frame should always be 0x0F 120 | #define SBUS_ENDBYTE 0x00 // Last byte of an SBus frame should always be 0 121 | 122 | #define SBUS_DIGI_CHAN1_BIT 0x01 // Bit masks for reading the two digital channel values in byte 24 of an SBus sentence 123 | #define SBUS_DIGI_CHAN2_BIT 0x02 // Presently we are ignoring these two channels 124 | 125 | #define SBUS_CHANNELS 16 // Number of SBus analog channels (SBus also has 2 digital channels, which we ignore) 126 | #define SBUS_FRAME_BYTES 25 // There are 25 bytes in an SBus frame 127 | 128 | #define SBUS_ACQUISITION_COUNT 4 // Must have this many consecutive valid frames to transition to the ready state. 129 | 130 | #define SBUS_DEFAULT_DISCARD_FRAMES 1 // If you want to only keep every N frames, set this to some number greater than 0. If 1, it will keep every other frame. 131 | #define SBUS_PCCOMM_DISCARD_FRAMES 1 // FrSky SBus data is sent every 9mS which is a refresh rate of 111 Hz. There is some indication FrSky may 132 | // only update the data every other frame anyway (US firmware). Even half the refresh rate (55 Hz) is more than fast enough, 133 | // although we do introduce some latency by skipping frames. But this is tank, not a racing quad. 9/1000ths-of-a-second latency is acceptable. 134 | // The second setting (SBUS_PCCOMM_DISCARD_FRAMES) is an optionally slower level for streaming to the PC during the Radio Setup routine. 135 | // If we try to send even 8 channels of data every 9mS and it takes 5mS to send the packet and we need 3mS to read the next incoming 136 | // sentence, timing becomes very tight and in testing I couldn't maintain stable comms without skipping every other. 137 | // However for now it doesn't seem necessary to slow it down more than the default so we can leave it at 1 as well. 138 | 139 | // SBUS_TICKS_PER_uS is defined in OP_Settings.h 140 | #define SBUS_MIN_TICKS_BEFORE_START (3000 * SBUS_TICKS_PER_uS) // Min time between end of frame and beginning of next start byte is 3 mS (3000 uS) 141 | //#define SBUS_MAX_TICKS_BETWEEN_CHARS (150 * SBUS_TICKS_PER_uS) // NOT USED. Max time between subsequent bytes is 150 uS. We would need to write our own interrupt-based 142 | // serial receiver, instead of using Arduino's, to implement the time-between-char check. 143 | class SBusDecode 144 | { 145 | public: 146 | SBusDecode(); //Constructor 147 | void begin(); 148 | void shutdown(void); // Turn the receiver off 149 | decodeState_t getState(void); 150 | uint8_t getChanCount(void); // Channel count - will always return SBUS_CHANNELS 151 | void GetSBus_Frame(int16_t pulseArray[], int16_t chanCount); // Copy a complete frame of pulses 152 | static boolean NewFrame; // Has an unread frame of data arrived? 153 | void update(void); 154 | void slowDownForPCComm(void); // Adjust on the fly how many frames we choose to discard, this will set it to SBUS_PCCOMM_DISCARD_FRAMES 155 | void defaultSpeed(void); // Revert to the default number of discarded frames SBUS_DEFAULT_DISCARD_FRAMES 156 | 157 | private: 158 | static void ConvertSBus_to_PWM(void); // Convert a frame of SBus data to pulse-widths 159 | 160 | static HardwareSerial *_serial; // Hardware serial pointer 161 | static uint8_t SBusData[SBUS_FRAME_BYTES]; // Array to hold SBus frame bytes 162 | static uint8_t sbus_pointer; // Pointer to current position of array 163 | static uint16_t Pulses[SBUS_CHANNELS]; // Array to hold pulse widths for all channels 164 | 165 | static uint8_t stateCount; // counts the number of times this state has been repeated 166 | static decodeState_t State; // The current state 167 | static uint8_t frameCount; // Used to keep track of frames for the purpose of discarding some 168 | static uint8_t framesToDiscard; // How many frames to discard for each frame we read 169 | }; 170 | 171 | 172 | #endif 173 | 174 | -------------------------------------------------------------------------------- /OpenPanzerTCB/src/OP_SBusDecode/keywords.txt: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------- 2 | # Syntax Coloring Map 3 | # Words separated by TAB, not SPACE 4 | #------------------------------------------------------------- 5 | 6 | 7 | #------------------------------------------------------------- 8 | # KEYWORD1 - Classes 9 | #------------------------------------------------------------- 10 | 11 | SBusDecode KEYWORD1 12 | 13 | 14 | #------------------------------------------------------------- 15 | # KEYWORD2 - Methods, functions, members 16 | #------------------------------------------------------------- 17 | begin KEYWORD2 18 | shutdown KEYWORD2 19 | getState KEYWORD2 20 | getChanCount KEYWORD2 21 | GetSBus_Frame KEYWORD2 22 | NewFrame KEYWORD2 23 | update KEYWORD2 24 | 25 | 26 | #------------------------------------------------------------- 27 | # LITERAL1 - Constants & Defines 28 | #------------------------------------------------------------- 29 | 30 | UBBR_SBUS LITERAL1 31 | SBUS_STARTBYTE LITERAL1 32 | SBUS_ENDBYTE LITERAL1 33 | SBUS_DIGI_CHAN1_BIT LITERAL1 34 | SBUS_DIGI_CHAN2_BIT LITERAL1 35 | SBUS_CHANNELS LITERAL1 36 | SBUS_FRAME_BYTES LITERAL1 37 | SBUS_ACQUISITION_COUNT LITERAL1 38 | DISCARD_FRAMES LITERAL1 39 | 40 | -------------------------------------------------------------------------------- /OpenPanzerTCB/src/OP_Sabertooth/OP_Sabertooth.cpp: -------------------------------------------------------------------------------- 1 | /* OP_Sabertooth.cpp Open Panzer Sabertooth library - 2 | * functions for communicating with Dimension Engineering's Sabertooth seriers of dual-motor controllers, 3 | * such as the 2X5, 2X12, 2X25, 2X32, 2X60 4 | * Source: http://www.dimensionengineering.com/ 5 | * Authors: Dimension Engineering 6 | * 7 | * This library is a stripped-down version of DE's original for use in the Open Panzer project. 8 | * Please use the full version of the library for any other application. 9 | * The original copyright is reprinted below: 10 | * 11 | * Arduino Libraries for SyRen/Sabertooth 12 | * Copyright (c) 2012-2013 Dimension Engineering LLC 13 | * http://www.dimensionengineering.com/arduino 14 | * 15 | * Permission to use, copy, modify, and/or distribute this software for any 16 | * purpose with or without fee is hereby granted, provided that the above 17 | * copyright notice and this permission notice appear in all copies. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 20 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 22 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER 23 | * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, 24 | * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE 25 | * USE OR PERFORMANCE OF THIS SOFTWARE. 26 | */ 27 | 28 | #include "OP_Sabertooth.h" 29 | 30 | 31 | OP_Sabertooth::OP_Sabertooth(byte address, HardwareSerial *port) : _address(address), _port(port) 32 | { 33 | 34 | } 35 | 36 | void OP_Sabertooth::autobaud(boolean dontWait) const 37 | { 38 | autobaud(port(), dontWait); 39 | } 40 | 41 | void OP_Sabertooth::autobaud(HardwareSerial *thisport, boolean dontWait) 42 | { 43 | if (!dontWait) { delay(1500); } 44 | 45 | // Sabertooth V1 Devices (2x5, 2x10, 2x25V1) 46 | // ------------------------------------------------------------------------------------------------------------------------------>> 47 | // For these devices the baud rate is set automatically by the appearance of 170/0xAA at the desired baud rate 48 | thisport->write(0xAA); 49 | thisport->flush(); 50 | if (!dontWait) { delay(500); } 51 | 52 | // Sabertooth V2 Devices (2x12, 2x25V2, 2x60) 53 | // ------------------------------------------------------------------------------------------------------------------------------>> 54 | // These devices do NOT auto-detect the baud rate. The baud rate must be set by sending a Baud Rate command at whatever baud rate the device is already set at. 55 | // They come from the factory with a default rate of 9600 (strange choice) but if it was changed before you will have no idea what the current rate is. In that case 56 | // the only way to issue a successful change baud rate command is to issue it once at every possible baud rate. After each command the Sabertooth will reboot which 57 | // takes time, and there are 5 possible rates. For that reason we do not bother trying to set the baud rate within this routine. If the user needs to change the 58 | // baud rate on their V2 device they can use the utility provided in OP Config. 59 | 60 | } 61 | 62 | void OP_Sabertooth::command(byte command, byte value) const 63 | { 64 | _port->write(address()); 65 | _port->write(command); 66 | _port->write(value); 67 | _port->write((address() + command + value) & B01111111); 68 | } 69 | 70 | void OP_Sabertooth::throttleCommand(byte command, int speed) const 71 | { 72 | speed = constrain(speed, -127, 127); 73 | this->command(command, (byte)abs(speed)); 74 | } 75 | 76 | void OP_Sabertooth::motor(byte motor, int speed) const 77 | { 78 | if (motor < 1 || motor > 2) { return; } 79 | throttleCommand((motor == 2 ? 4 : 0) + (speed < 0 ? 1 : 0), speed); 80 | } 81 | 82 | void OP_Sabertooth::allStop() const 83 | { 84 | motor(1, 0); 85 | motor(2, 0); 86 | } 87 | 88 | // For the 2x5, valid baud rates for packetized serial are 2400, 9600, 19200, and 38400. Some of the other controllers (2x60 for example) 89 | // can also work at 115200. 90 | // 9600 is the default baud rate for Sabertooth packet serial for all their products, however, it does not work well with Arduino! 91 | // 38400 has been tested to work very well. 19200 may also work but faster is better. 92 | // NOTE: This routine is only useful if you already know what baud rate the Sabertooth is presently running at. Otherwise you won't know 93 | // what baud rate to send the command at; you will have to send the command once at every possible rate and wait after each transmission 94 | // to allow the Sabertooth to reboot. In our opinion this is a really poor setup. We prefer the auto-baud detection capabilities of the 2x5, 95 | // or else at least a predictable boot-up baud rate ala the Scout. 96 | void OP_Sabertooth::setBaudRate(long baudRate) const 97 | { 98 | _port->flush(); 99 | 100 | 101 | byte value; 102 | switch (baudRate) 103 | { 104 | case 2400: value = 1; break; 105 | case 9600: default: value = 2; break; 106 | case 19200: value = 3; break; 107 | case 38400: value = 4; break; 108 | case 115200: value = 5; break; 109 | } 110 | command(15, value); 111 | 112 | _port->flush(); 113 | 114 | // (1) flush() does not seem to wait until transmission is complete. 115 | // As a result, a Serial.end() directly after this appears to 116 | // not always transmit completely. So, we manually add a delay. 117 | // (2) Sabertooth takes about 200 ms after setting the baud rate to 118 | // respond to commands again (it restarts). 119 | // So, this 500 ms delay should deal with this. 120 | delay(500); 121 | } 122 | 123 | 124 | 125 | -------------------------------------------------------------------------------- /OpenPanzerTCB/src/OP_Sabertooth/OP_Sabertooth.h: -------------------------------------------------------------------------------- 1 | /* OP_Sabertooth.h Open Panzer Sabertooth library - 2 | * functions for communicating with Dimension Engineering's Sabertooth seriers of dual-motor controllers, 3 | * such as the 2X5, 2X12, 2X25, 2X32, 2X60 4 | * Source: http://www.dimensionengineering.com/ 5 | * Authors: Dimension Engineering 6 | * 7 | * This library is a stripped-down version of DE's original for use in the Open Panzer project. 8 | * Please use the full version of the library for any other application. 9 | * The original copyright is reprinted below: 10 | * 11 | * Arduino Libraries for SyRen/Sabertooth 12 | * Copyright (c) 2012-2013 Dimension Engineering LLC 13 | * http://www.dimensionengineering.com/arduino 14 | * 15 | * Permission to use, copy, modify, and/or distribute this software for any 16 | * purpose with or without fee is hereby granted, provided that the above 17 | * copyright notice and this permission notice appear in all copies. 18 | * 19 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 20 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 21 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 22 | * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER 23 | * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, 24 | * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE 25 | * USE OR PERFORMANCE OF THIS SOFTWARE. 26 | */ 27 | 28 | #ifndef OP_Sabertooth_h 29 | #define OP_Sabertooth_h 30 | 31 | #include 32 | 33 | #define SABERTOOTH_CMD_SERIALTIMEOUT 0x0E // Decimal 14 34 | #define SABERTOOTH_CMD_BAUDRATE 0x0F // Decimal 15 35 | #define SABERTOOTH_BAUD_2400 1 // Baud value byte for 2400 36 | #define SABERTOOTH_BAUD_9600 2 // Baud value byte for 9600 37 | #define SABERTOOTH_BAUD_19200 3 // Baud value byte for 19200 38 | #define SABERTOOTH_BAUD_38400 4 // Baud value byte for 38400 39 | #define SABERTOOTH_BAUD_115200 5 // Baud value byte for 115200 40 | #define SABERTOOTH_CMD_RAMPING 0x10 // Decimal 16 NOT USED IN OP 41 | #define SABERTOOTH_CMD_DEADBAND 0x11 // Decimal 17 NOT USED IN OP 42 | 43 | 44 | /*! 45 | \class OP_Sabertooth 46 | \brief Controls a %Sabertooth or %SyRen motor driver running in Packet Serial mode. 47 | */ 48 | class OP_Sabertooth 49 | { 50 | public: 51 | 52 | /*! 53 | Initializes a new instance of the Sabertooth class. 54 | The driver address is set to the value given, and the specified serial port is used. 55 | \param address The driver address. 56 | \param port The port to use. 57 | */ 58 | OP_Sabertooth(byte address, HardwareSerial *port); 59 | 60 | public: 61 | /*! 62 | Gets the driver address. 63 | \return The driver address. 64 | */ 65 | inline byte address() const { return _address; } 66 | 67 | /*! 68 | Gets the serial port. 69 | \return The serial port. 70 | */ 71 | inline HardwareSerial* port() const { return _port; } 72 | 73 | /*! 74 | Sends the autobaud character. 75 | \param dontWait If false, a delay is added to give the driver time to start up. 76 | */ 77 | void autobaud(boolean dontWait = false) const; 78 | 79 | /*! 80 | Sends the autobaud character. 81 | \param port The port to use. 82 | \param dontWait If false, a delay is added to give the driver time to start up. 83 | */ 84 | static void autobaud(HardwareSerial *port, boolean dontWait = false); 85 | 86 | /*! 87 | Sends a packet serial command to the motor driver. 88 | \param command The number of the command. 89 | \param value The command's value. 90 | */ 91 | void command(byte command, byte value) const; 92 | 93 | public: 94 | /*! 95 | Sets the speed of the specified motor. 96 | \param motor The motor number, 1 or 2. 97 | \param speed The speed, between -127 and 127. 98 | */ 99 | void motor(byte motor, int speed) const; 100 | 101 | /*! 102 | Stops. 103 | */ 104 | void allStop() const; 105 | 106 | public: 107 | /*! 108 | Sets the baud rate. 109 | Baud rate is stored in EEPROM, so changes persist between power cycles. 110 | \param baudRate The baud rate. This can be 2400, 9600, 19200, 38400, or on some drivers 115200. 111 | */ 112 | void setBaudRate(long baudRate) const; 113 | 114 | private: 115 | void throttleCommand(byte command, int speed) const; 116 | 117 | private: 118 | const byte _address; 119 | HardwareSerial *_port; 120 | }; 121 | 122 | #endif 123 | -------------------------------------------------------------------------------- /OpenPanzerTCB/src/OP_Sabertooth/keywords.txt: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------- 2 | # Syntax Coloring Map 3 | # Words separated by TAB, not SPACE 4 | #------------------------------------------------------------- 5 | 6 | 7 | #------------------------------------------------------------- 8 | # KEYWORD1 - Classes 9 | #------------------------------------------------------------- 10 | 11 | OP_Sabertooth KEYWORD1 12 | 13 | 14 | #------------------------------------------------------------- 15 | # KEYWORD2 - Methods, functions, members 16 | #------------------------------------------------------------- 17 | address KEYWORD2 18 | port KEYWORD2 19 | autobaud KEYWORD2 20 | command KEYWORD2 21 | motor KEYWORD2 22 | allStop KEYWORD2 23 | setBaudRate KEYWORD2 24 | 25 | 26 | #------------------------------------------------------------- 27 | # LITERAL1 - Constants & Defines 28 | #------------------------------------------------------------- 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /OpenPanzerTCB/src/OP_Scout/Examples/ScoutControl/ScoutControl.ino: -------------------------------------------------------------------------------- 1 | 2 | // Include the Open Panzer Scout library 3 | #include "OP_Scout.h" 4 | 5 | 6 | // Declare the Scout object. 7 | // Pass the address you want to use (A or B) as well as the hardware serial port 8 | // For most Arduinos there will only be one serial port, but some like the Mega may have multiple (Serial1, Serial2, etc.) 9 | OP_Scout Scout(SCOUT_ADDRESS_A, &Serial); 10 | 11 | 12 | 13 | void setup() 14 | { 15 | // Scout communicates at 38400 baud by default 16 | Serial.begin(38400); 17 | 18 | // Give the Scout some time to startup 19 | delay(1000); 20 | 21 | 22 | 23 | // SERIAL WATCHDOG 24 | // This is optional. You can choose to enable the Serial Watchdog feature on the Scout (it is disabled by default). 25 | // The watchdog will expect a serial command within an interval you set, if none is received in that time the motors will 26 | // be shut down. This can be a useful safety feature but it also requires your control sketch to send the command at routine 27 | // intervals even if the command hasn't changed. 28 | 29 | // The watchdog timeout can range from 100mS to 25.5 seconds in 100mS increments 30 | // The function for converting desired watchdog time to data byte is 31 | // Data byte = Desired time in mS / 100 32 | // Let's enable the serial watchdog with a timeout of 1 second (1000mS), so data byte will be: 33 | // 1000 / 100 = 10 34 | 35 | Scout.EnableWatchdog(10); 36 | 37 | 38 | 39 | // CURRENT LIMITS 40 | // By default the Scout will limit current to 12 amps per motor, since this is roughly the amount of continuous current draw the board can handle 41 | // without extra heatsinking/cooling. The absolute limit of the motor driver chips is 30 amps per motor, but that will definitely require the 42 | // addition of heatsinks and fan. If the chips become too hot, they are over-temperature protected and will automatically shut down. 43 | // You may also want to limit the current to an even lower level than default, for example to protect a sensitive drive-train. 44 | // You can use the SetMaxCurrent function to specify the maximum current (per motor) that the Scout will permit, but beyond which it will turn off the motors. 45 | // Note: if even one motor exceeds the current limit, both motors will be turned off. 46 | // Note: any custom current limit setting is not retained by the Scout, it always boots to the default of 12 amps, so if you want a different value send it each time on boot 47 | 48 | Scout.SetMaxCurrent(5); // This would limit the maximum current per motor to 5 amps. Acceptable values are 1 to 30 49 | 50 | } 51 | 52 | 53 | void loop() 54 | { 55 | // TEST MOTORS 56 | // ================================================================================================================================>> 57 | // Uncomment this routine to cycle both motors 58 | WaveMotors(); 59 | 60 | 61 | // TEST DIRECT FAN CONTROL 62 | // ================================================================================================================================>> 63 | // Uncomment this section to test direct fan control, which could be used as a third channel, uni-directional, low current ESC (1 amp), running at VBatt 64 | /* 65 | Scout.SetFanSpeed(127); // 50% 66 | delay(4000); 67 | Scout.SetFanSpeed(255); // 100% 68 | delay(4000); 69 | Scout.SetFanSpeed(0); // Stop 70 | delay(4000); 71 | 72 | // We can also revert back to auto fan control, where the Scout manages the fan in order to cool itself 73 | // Auto control is the default mode and the Scout will initialize to that mode unless and until an explicity SetFanSpeed function call is made. 74 | AutoFanControl(); 75 | */ 76 | 77 | 78 | // TEST SERIAL WATCHDOG 79 | // ================================================================================================================================>> 80 | // Uncomment this to section to test the serial watchdog feature 81 | /* 82 | // Set Motor 1 to half speed forward 83 | Scout.motor(1, 64); 84 | 85 | // Now delay for 5 seconds 86 | delay(5000); 87 | 88 | // In the setup above we told the Scout to time-out after 1 second without a command. After 1 second, the Scout should automatically stop Motor 1 89 | // and start flashing the blue LED rapidly. 90 | 91 | // Now let's disable the serial watchdog: 92 | Scout.DisableWatchdog(); 93 | 94 | // Then set Motor 1 back to half speed forward 95 | Scout.motor(1, 64); 96 | 97 | // Now delay again for 5 seconds 98 | delay(5000); 99 | 100 | // In this case the Scout should just keep running the motor indefinitely. After a short amount of time the blue LED on the Scout will start to blink 101 | // slowly (not a quick flash). The slow blink means it is waiting for a signal, but in the meantime it is still going to maintain the last command. 102 | */ 103 | 104 | } 105 | 106 | 107 | 108 | // This routine will gradually run up each motor to full speed and then back down, first in one direction, and then in the other direction, 109 | // alternating between motor 1 and 2 each time 110 | void WaveMotors(void) 111 | { 112 | #define StepDelay 10 113 | static uint32_t TimeLastStep = 0; 114 | static byte CurrentMotor = 1; 115 | static int8_t CurrentStep = 0; 116 | static byte CurrentDirection = 1; // 1 means go forward, 0 means go reverse 117 | static boolean GoingUp = true; // Are we accelerating, or decelerating 118 | static boolean RampStarted = false; 119 | 120 | if (millis() - TimeLastStep > StepDelay) 121 | { 122 | switch (CurrentStep) 123 | { 124 | case 0: 125 | if (RampStarted) 126 | { 127 | // This cycle is over 128 | if (CurrentMotor == 1) 129 | { 130 | CurrentMotor = 2; 131 | } 132 | else 133 | { 134 | // Start over with motor 1, but now go in the opposite direction 135 | CurrentMotor = 1; 136 | CurrentDirection ? CurrentDirection = 0 : CurrentDirection = 1; 137 | } 138 | RampStarted = false; 139 | } 140 | else 141 | { 142 | // We are just starting to ramp up, set the motor in the correct direction 143 | RampStarted = true; 144 | GoingUp = true; 145 | CurrentDirection ? CurrentStep += 1 : CurrentStep -= 1; 146 | } 147 | break; 148 | 149 | case 127: 150 | // We were accelerating in the forward direction, now decelerate 151 | GoingUp = false; 152 | CurrentDirection ? CurrentStep -= 1 : CurrentStep += 1; 153 | break; 154 | 155 | case -127: 156 | // We were accelerating in the reverse direction, now decelerate 157 | GoingUp = false; 158 | CurrentDirection ? CurrentStep -= 1 : CurrentStep += 1; 159 | break; 160 | 161 | default: 162 | if (GoingUp) 163 | { 164 | CurrentDirection ? CurrentStep += 1 : CurrentStep -= 1; 165 | } 166 | else 167 | { 168 | CurrentDirection ? CurrentStep -= 1 : CurrentStep += 1; 169 | } 170 | } 171 | 172 | Scout.motor(CurrentMotor, CurrentStep); 173 | TimeLastStep = millis(); 174 | } 175 | 176 | } 177 | 178 | -------------------------------------------------------------------------------- /OpenPanzerTCB/src/OP_Scout/OP_Scout.cpp: -------------------------------------------------------------------------------- 1 | /* OP_Scout.cpp Library for communicating with the Open Panzer Scout dual brushed motor serial ESC 2 | * Source: openpanzer.org 3 | * Authors: Luke Middleton 4 | * 5 | * DESCRIPTION 6 | * =============================================================================================================== 7 | * This library is not part of the firmware for the Scout ESC - this library is used to communicate WITH the Scout ESC from some other microcontroller, such as an Arduino. 8 | * 9 | * The Scout responds to a serial protocol using the same data packet structure as the Dimension Engineering Sabertooth controllers. 10 | * Some commands are shared with the Sabertooth line, but the Sabertooth has some commands the Scout does not, and the Scout has others the Sabertooth do not. 11 | * 12 | * The serial packet is 4 bytes long: Address byte, command byte, data byte, checksum. 13 | * 14 | * Unlike the Sabertooth line which have 8 device addresses (128-135), the Scout only has two possible addresses: 131 (Address A) and 132 (Address B). The device address is selected by the 15 | * physical swich on the Scout. 16 | * 17 | * 18 | * FURTHER RESOURCES 19 | * =============================================================================================================== 20 | * Scout Firmware & Manual https://github.com/OpenPanzerProject/Scout-ESC 21 | * Scout Schematics, Board Files, and BOM: http://openpanzer.org/downloads#scout 22 | * 23 | * 24 | * LICENSE 25 | * =============================================================================================================== 26 | * This program is free software: you can redistribute it and/or modify 27 | * it under the terms of the GNU General Public License as published by 28 | * the Free Software Foundation, either version 3 of the License, or 29 | * (at your option) any later version. 30 | * 31 | * This program is distributed in the hope that it will be useful, 32 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 33 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 34 | * GNU General Public License for more details. 35 | * 36 | * You should have received a copy of the GNU General Public License 37 | * along with this program. If not, see . 38 | * 39 | */ 40 | 41 | #include "OP_Scout.h" 42 | 43 | 44 | OP_Scout::OP_Scout(byte address, HardwareSerial *port) : _address(address), _port(port) { } 45 | 46 | void OP_Scout::command(byte command, byte value) const 47 | { 48 | _port->write(address()); 49 | _port->write(command); 50 | _port->write(value); 51 | _port->write((address() + command + value) & B01111111); 52 | } 53 | 54 | void OP_Scout::throttleCommand(byte command, int speed) const 55 | { 56 | speed = constrain(speed, -127, 127); 57 | this->command(command, (byte)abs(speed)); 58 | } 59 | 60 | void OP_Scout::motor(byte motor, int speed) const 61 | { 62 | if (motor < 1 || motor > 2) { return; } 63 | throttleCommand((motor == 2 ? 4 : 0) + (speed < 0 ? 1 : 0), speed); 64 | } 65 | 66 | void OP_Scout::allStop() const 67 | { 68 | motor(1, 0); 69 | motor(2, 0); 70 | } 71 | 72 | -------------------------------------------------------------------------------- /OpenPanzerTCB/src/OP_Scout/OP_Scout.h: -------------------------------------------------------------------------------- 1 | /* OP_Scout.cpp Library for communicating with the Open Panzer Scout dual brushed motor serial ESC 2 | * Source: openpanzer.org 3 | * Authors: Luke Middleton 4 | * 5 | * DESCRIPTION 6 | * =============================================================================================================== 7 | * This library is not part of the firmware for the Scout ESC - this library is used to communicate WITH the Scout ESC from some other microcontroller, such as an Arduino. 8 | * 9 | * The Scout responds to a serial protocol using the same data packet structure as the Dimension Engineering Sabertooth controllers. 10 | * Some commands are shared with the Sabertooth line, but the Sabertooth has some commands the Scout does not, and the Scout has others the Sabertooth do not. 11 | * 12 | * The serial packet is 4 bytes long: Address byte, command byte, data byte, checksum. 13 | * 14 | * Unlike the Sabertooth line which have 8 device addresses (128-135), the Scout only has two possible addresses: 131 (Address A) and 132 (Address B). The device address is selected by the 15 | * physical switch on the Scout. 16 | * 17 | * 18 | * FURTHER RESOURCES 19 | * =============================================================================================================== 20 | * Scout Firmware & Manual https://github.com/OpenPanzerProject/Scout-ESC 21 | * Scout Schematics, Board Files, and BOM: http://openpanzer.org/downloads#scout 22 | * 23 | * 24 | * LICENSE 25 | * =============================================================================================================== 26 | * This program is free software: you can redistribute it and/or modify 27 | * it under the terms of the GNU General Public License as published by 28 | * the Free Software Foundation, either version 3 of the License, or 29 | * (at your option) any later version. 30 | * 31 | * This program is distributed in the hope that it will be useful, 32 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 33 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 34 | * GNU General Public License for more details. 35 | * 36 | * You should have received a copy of the GNU General Public License 37 | * along with this program. If not, see . 38 | * 39 | */ 40 | 41 | #ifndef OP_Scout_h 42 | #define OP_Scout_h 43 | 44 | #include 45 | 46 | 47 | // Addresses 48 | #define SCOUT_ADDRESS_A 0x83 // 131 49 | #define SCOUT_ADDRESS_B 0x84 // 132 50 | 51 | // Defaults 52 | #define SCOUT_DEFAULT_CURRENT_LIMIT 12 // 12 amps by default per motor, this is the amount it should be able to maintain continuously without extra cooling 53 | #define SCOUT_MAXIMUM_CURRENT_LIMIT 30 // 30 amps maximum current per motor 54 | 55 | // Commands // 0 Motor 1 forward 56 | // 1 Motor 1 reverse 57 | #define SCOUT_CMD_MIN_VOLTAGE 0x02 // 2 Set minimum voltage 58 | #define SCOUT_CMD_MAX_VOLTAGE 0x03 // 3 Set maximum voltage 59 | // 4 Motor 2 forward 60 | // 5 Motor 2 reverse 61 | // 6 Reserved for Motor 1 7-bit commands - not presently implemented 62 | // 7 Reserved for Motor 2 7-bit commands - not presently implemented 63 | // 8-13 Reserved - could add compatibility with Sabertooth mixed-mode commands, not presently implemented 64 | #define SCOUT_CMD_SERIAL_WATCHDOG 0x0E // 14 65 | #define SCOUT_CMD_BAUD_RATE 0x0F // 15 66 | // 16 Reserved for future compatibility with Sabertooth ramping features 67 | // 17 Reserved for future compatibility with Sabertooth deadband feature 68 | // 19 Unused 69 | #define SCOUT_CMD_SET_FAN_SPEED 0x14 // 20 Direct fan speed control (or use it as a third, uni-directional ESC) 70 | #define SCOUT_CMD_SET_AUTO_FAN_CONTROL 0x15 // 21 Revert fan control to Scout auto control (based on temperature) 71 | #define SCOUT_CMD_SET_MAX_CURRENT 0x16 // 22 Set maximum current 72 | #define SCOUT_CMD_BRAKE_AT_STOP 0x17 // 23 Command used to enable/disable braking motors when stopped (by shorting motor leads). Pass true to enable, false to disable. 73 | #define SCOUT_CMD_DRAG_INNER_TRACK 0x18 // 24 Command used to pulse brake commands to the slower of the two motors, can be used in tanks withe freewheeling gearboxes to assist in turning. See online documentation for more. 74 | 75 | // Codes 76 | #define SCOUT_BAUD_CODE_2400 1 // Codes for changing baud rates 77 | #define SCOUT_BAUD_CODE_9600 2 // These are the same codes used by certain Dimension Engineering Sabertooth controllers 78 | #define SCOUT_BAUD_CODE_19200 3 // 79 | #define SCOUT_BAUD_CODE_38400 4 // 80 | #define SCOUT_BAUD_CODE_115200 5 // 81 | #define SCOUT_BAUD_CODE_57600 6 // The preceding codes are numbered identically to the codes used for Sabertooth controllers, which do not include 57600. That is why 57600 is number 6 and not number 5. 82 | 83 | class OP_Scout 84 | { 85 | public: 86 | 87 | // Initializes a new instance of the Scout class. 88 | // The driver address is set to the value given, and the specified serial port is used. 89 | OP_Scout(byte address, HardwareSerial *port); 90 | 91 | public: 92 | // Return the driver address. 93 | inline byte address() const { return _address; } 94 | 95 | // Return the serial port. 96 | inline HardwareSerial* port() const { return _port; } 97 | 98 | // Sends a packet serial command to the Scout 99 | // command The number of the command. 100 | // value The command's value. 101 | void command(byte command, byte value) const; 102 | 103 | // Sets the speed of the specified motor 104 | // motor The motor number, 1 or 2. 105 | // speed The speed, between -127 and 127. 106 | void motor(byte motor, int speed) const; 107 | 108 | // Stops both motors 109 | void allStop() const; 110 | 111 | // Convenience functions 112 | 113 | // Manually set fan speed (can be used as a third, uni-directional, low current ESC) 114 | inline void SetFanSpeed(byte speed) { command(SCOUT_CMD_SET_FAN_SPEED, speed); } 115 | 116 | // Revert to automatic fan control based on temperature 117 | inline void AutoFanControl() { command(SCOUT_CMD_SET_AUTO_FAN_CONTROL, 0); } 118 | 119 | // Enable serial watchdog 120 | inline void EnableWatchdog(byte timeout) { command(SCOUT_CMD_SERIAL_WATCHDOG, timeout); } 121 | 122 | // Disable serial watchdog (send timeout value of 0) 123 | inline void DisableWatchdog() { command(SCOUT_CMD_SERIAL_WATCHDOG, 0); } 124 | 125 | // Brake at stop 126 | inline void BrakeAtStop(boolean enable) { command(SCOUT_CMD_BRAKE_AT_STOP, enable); } 127 | 128 | // Drag inner track 129 | inline void DragInnerTrack(boolean enable) { command(SCOUT_CMD_DRAG_INNER_TRACK, enable); } 130 | 131 | // Set maximum current 132 | inline void SetMaxCurrent(uint8_t cl) 133 | { 134 | if (cl > 0 && cl <= SCOUT_MAXIMUM_CURRENT_LIMIT) command(SCOUT_CMD_SET_MAX_CURRENT, cl); 135 | else command(SCOUT_CMD_SET_MAX_CURRENT, SCOUT_DEFAULT_CURRENT_LIMIT); 136 | } 137 | 138 | // Set minimum voltage 139 | // Used to set a custom minimum voltage for the battery supplying power (essentially LVC level). If battery voltage drops below this value, 140 | // motors will be turned off. This value is cleared at startup, so must be set each run (Scout reverts to default min voltage of 6 volts at boot). 141 | // The value is sent in 0.2 volt increments with a command of zero corresponding to 6v, which is the minimum. Valid data is from 0 to 50 (6-16 volts). 142 | // The function for converting volts to command data is Value = (desired volts-6) x 5 143 | inline void SetMinVoltage(uint8_t v) 144 | { 145 | if (v >= 0 && v <= 50) command(SCOUT_CMD_MIN_VOLTAGE, v); 146 | } 147 | 148 | // Set maximum voltage 149 | // Used to set a custom maximum voltage. If voltage exceeds this level, the motors will be turned off. The Scout reverts to a default maximum 150 | // voltage of 16 volts at boot, so this command must be sent at each startup if you want something different. 151 | // The value is sent in 0.2 volt increments within the allowed range of 6-28 volts that equates to values of 30 to 140. 152 | // The function for converting volts to command data is Value = (desired volts * 5) 153 | inline void SetMaxVoltage(uint8_t v) 154 | { 155 | if (v >= 30 && v <= 140) command(SCOUT_CMD_MAX_VOLTAGE, v); 156 | } 157 | 158 | private: 159 | void throttleCommand(byte command, int speed) const; 160 | 161 | const byte _address; 162 | HardwareSerial *_port; 163 | 164 | }; 165 | 166 | #endif 167 | -------------------------------------------------------------------------------- /OpenPanzerTCB/src/OP_Scout/keywords.txt: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------- 2 | # Syntax Coloring Map 3 | # Words separated by a single TAB, not SPACE 4 | #------------------------------------------------------------- 5 | 6 | 7 | #------------------------------------------------------------- 8 | # KEYWORD1 - Classes 9 | #------------------------------------------------------------- 10 | OP_Scout KEYWORD1 11 | 12 | 13 | #------------------------------------------------------------- 14 | # KEYWORD2 - Methods, functions, members 15 | #------------------------------------------------------------- 16 | address KEYWORD2 17 | port KEYWORD2 18 | command KEYWORD2 19 | motor KEYWORD2 20 | allStop KEYWORD2 21 | SetFanSpeed KEYWORD2 22 | AutoFanControl KEYWORD2 23 | EnableWatchdog KEYWORD2 24 | DisableWatchdog KEYWORD2 25 | BrakeAtStop KEYWORD2 26 | DragInnerTrack KEYWORD2 27 | SetMaxCurrent KEYWORD2 28 | 29 | 30 | #------------------------------------------------------------- 31 | # LITERAL1 - Constants & Defines 32 | #------------------------------------------------------------- 33 | SCOUT_ADDRESS_A LITERAL1 34 | SCOUT_ADDRESS_B LITERAL1 35 | SCOUT_CMD_SET_FAN_SPEED LITERAL1 36 | SCOUT_CMD_SET_AUTO_FAN_CONTROL LITERAL1 37 | SCOUT_CMD_SET_MAX_CURRENT LITERAL1 38 | SCOUT_CMD_MIN_VOLTAGE LITERAL1 39 | SCOUT_CMD_MAX_VOLTAGE LITERAL1 40 | SCOUT_CMD_ENABLE_SERIAL_WATCHDOG LITERAL1 41 | SCOUT_CMD_DISABLE_SERIAL_WATCHDOG LITERAL1 42 | 43 | -------------------------------------------------------------------------------- /OpenPanzerTCB/src/OP_Servo/OP_Servo.h: -------------------------------------------------------------------------------- 1 | /* OP_Servo.h Open Panzer Servo - a library for writing servo pulses to 8 pins on a single port 2 | * Source: openpanzer.org 3 | * Authors: Michael Margolis, DuaneB, Luke Middleton 4 | * 5 | * This library is a modification of DuaneB's RCArduionFastLib: http://rcarduino.blogspot.com/ 6 | * ...which itself was a modification of the standard Arduino Servo library written by Michael Margolis (Arduino Forum user "MEM") 7 | * 8 | * This library is intended to be used on a specific piece of hardware, the Open Panzer TCB board. 9 | * It has been stripped down substantially. It can only drive 8 servos, and they must all be on the same hardware port (PORTA for now). 10 | * Additions have been made for servo ramping (used for panning servos and other effects, such as recoil) 11 | * This library is therefore not compatible with MEM or DuaneB's library nor is it entirely compatible with most Arduino boards except the Mega (with caveats). 12 | * 13 | * 14 | * This program is free software: you can redistribute it and/or modify 15 | * it under the terms of the GNU General Public License as published by 16 | * the Free Software Foundation, either version 3 of the License, or 17 | * (at your option) any later version. 18 | * 19 | * This program is distributed in the hope that it will be useful, 20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 | * GNU General Public License for more details. 23 | * 24 | * You should have received a copy of the GNU General Public License 25 | * along with this program. If not, see . 26 | * 27 | */ 28 | 29 | #ifndef OP_Servo_H 30 | #define OP_Servo_H 31 | #include 32 | #include "../OP_Settings/OP_Settings.h" 33 | 34 | // This library is stripped down and makes several assumptions, so don't change anything unless you know exactly what you are doing! 35 | // Assumption 1 - we only have 8 servos 36 | // Assumption 2 - they are all on the same Atmega port (the port can be changed in OP_Servos.cpp) 37 | // Assumption 3 - Servos are numbered 0-7. They correspond to Pins 0-7 of the selected Port register 38 | 39 | // If anything about those assumptions changes, this library will not work correctly, or at all! 40 | 41 | 42 | // The frame space is treated as an extra "servo" so this number needs to be 1 greater than the total number of actual outputs 43 | // This library is hard-coded to 8 servos, so this number should always be 9! 44 | #define SERVO_OUT_COUNT 9 45 | 46 | // Default minimum and maximum servo pulse widths. They can be modified on a per-servo basis 47 | // later if the user needs. As a comparison you can also see what we allow for incoming pulses in OP_RadioDefines.h 48 | #define SERVO_OUT_MINPULSE 750 49 | #define SERVO_OUT_MAXPULSE 2250 50 | #define SERVO_OUT_CENTERPULSE 1500 51 | 52 | #define SERVO_MAXRAMP_TICKSTEP 50 53 | 54 | class OP_Servos 55 | { 56 | // We are using static for everything because we only want one instance of this class. 57 | public: 58 | OP_Servos(); 59 | 60 | // configures timer1 61 | static void begin(); 62 | 63 | // Called by the timer interrupt service routine, see the cpp file for details. 64 | // Don't really want it public, but it has to be for the ISR to see it 65 | static void OCR1A_ISR(); 66 | 67 | // called to set the pulse width for a specific channel, pulse widths are in microseconds 68 | static void attach(uint8_t); 69 | static void detach(uint8_t); 70 | static boolean isAttached(uint8_t); 71 | static void writeMicroseconds(uint8_t, uint16_t); 72 | static void setFrameSpace(uint8_t, uint16_t); 73 | static void setMinPulseWidth(uint8_t, uint16_t); 74 | static void setMaxPulseWidth(uint8_t, uint16_t); 75 | static uint16_t getMinPulseWidth(uint8_t); 76 | static uint16_t getMaxPulseWidth(uint8_t); 77 | static uint16_t getPulseWidth(uint8_t); 78 | static void setRampSpeed_mS(uint8_t, uint16_t, uint8_t); 79 | static void setRampStepPerFrame(uint8_t, int16_t); 80 | static void stopRamping(uint8_t); 81 | static void setupRecoil_mS(uint8_t, uint16_t, uint16_t, boolean); // Setup recoil parameters, pass ramping speed in mS 82 | static void StartRecoil(uint8_t); // Kick off a recoil event 83 | static void setRecoilReversed(uint8_t, boolean); 84 | 85 | protected: 86 | class PortPin 87 | { public: 88 | uint8_t PinMask; 89 | uint16_t NumTicks; // Current pulse width in timer ticks 90 | uint16_t MaxTicks; // Maximum pulse width in ticks 91 | uint16_t MinTicks; // Minimum pulse width in ticks 92 | boolean Enabled; // Is this servo enabled (attached) 93 | int16_t TickStep; // Used for slowly ramping a servo from one position to another 94 | uint8_t RecoilState; // Special flag for recoil effect 95 | uint32_t RecoilStartTime; // Time when recoil action starts 96 | uint16_t RecoilTime_mS; // How long to wait for the recoil action to complete 97 | uint16_t RecoiledNumTicks; // The full-back position of the recoiled servo, in ticks. Will equal either MaxTicks or MinTicks depending on if the servo is reversed. 98 | int16_t RecoilTickStep_Return; // Specific tick step for slowly returning the barrel to starting position after recoil kick 99 | }; 100 | 101 | static boolean initialized; 102 | static void setPinHigh(uint8_t) __attribute__((always_inline)); 103 | static void setPinLow(uint8_t) __attribute__((always_inline)); 104 | static void setPulseWidthTimer(uint8_t) __attribute__((always_inline)); 105 | static void setPulseWidthTimer_Ramp(uint8_t); 106 | 107 | // Information about each channel 108 | static volatile PortPin Channel[SERVO_OUT_COUNT]; 109 | 110 | // current output channel 111 | static volatile uint8_t CurrentChannel; 112 | 113 | // Moved to OP_Settings.h as defines 114 | // Convert microseconds to timer ticks 115 | //static uint16_t uS_to_Ticks(uint16_t) __attribute__((always_inline)); 116 | //static uint16_t Ticks_to_uS(uint16_t) __attribute__((always_inline)); 117 | 118 | private: 119 | // Remember, static variables must be initialized outside the class 120 | 121 | }; 122 | 123 | 124 | 125 | #endif 126 | 127 | -------------------------------------------------------------------------------- /OpenPanzerTCB/src/OP_Servo/keywords.txt: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------- 2 | # Syntax Coloring Map 3 | # Words separated by TAB, not SPACE 4 | #------------------------------------------------------------- 5 | 6 | 7 | #------------------------------------------------------------- 8 | # KEYWORD1 - Classes 9 | #------------------------------------------------------------- 10 | 11 | OP_Servos KEYWORD1 12 | 13 | 14 | #------------------------------------------------------------- 15 | # KEYWORD2 - Methods, functions, members 16 | #------------------------------------------------------------- 17 | begin KEYWORD2 18 | attach KEYWORD2 19 | detach KEYWORD2 20 | isAttached KEYWORD2 21 | writeMicroseconds KEYWORD2 22 | setFrameSpace KEYWORD2 23 | setMinPulseWidth KEYWORD2 24 | setMaxPulseWidth KEYWORD2 25 | getMinPulseWidth KEYWORD2 26 | getMaxPulseWidth KEYWORD2 27 | getPulseWidth KEYWORD2 28 | setRampSpeed_mS KEYWORD2 29 | setRampStepPerFrame KEYWORD2 30 | stopRamping KEYWORD2 31 | setupRecoil_mS KEYWORD2 32 | StartRecoil KEYWORD2 33 | setRecoilReversed KEYWORD2 34 | 35 | 36 | #------------------------------------------------------------- 37 | # LITERAL1 - Constants & Defines 38 | #------------------------------------------------------------- 39 | 40 | SERVO_OUT_COUNT LITERAL1 41 | SERVO_OUT_MINPULSE LITERAL1 42 | SERVO_OUT_MAXPULSE LITERAL1 43 | SERVO_OUT_CENTERPULSE LITERAL1 44 | SERVO_MAXRAMP_TICKSTEP LITERAL1 45 | 46 | 47 | -------------------------------------------------------------------------------- /OpenPanzerTCB/src/OP_Settings/keywords.txt: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------- 2 | # Syntax Coloring Map 3 | # Words separated by TAB, not SPACE 4 | #------------------------------------------------------------- 5 | 6 | 7 | #------------------------------------------------------------- 8 | # KEYWORD1 - Classes 9 | #------------------------------------------------------------- 10 | 11 | 12 | 13 | #------------------------------------------------------------- 14 | # KEYWORD2 - Methods, functions, members 15 | #------------------------------------------------------------- 16 | 17 | 18 | 19 | #------------------------------------------------------------- 20 | # LITERAL1 - Constants & Defines 21 | #------------------------------------------------------------- 22 | FIRMWARE_VERSION LITERAL1 23 | MotorSerial LITERAL1 24 | AuxSerial LITERAL1 25 | Serial3Tx LITERAL1 26 | DEFAULTBAUDRATE LITERAL1 27 | USB_BAUD_RATE LITERAL1 28 | SERVO_ESC_STOP LITERAL1 29 | SERVONUM_LEFTTREAD LITERAL1 30 | SERVONUM_RIGHTTREAD LITERAL1 31 | SERVONUM_TURRETROTATION LITERAL1 32 | SERVONUM_TURRETELEVATION LITERAL1 33 | SERVONUM_RECOIL LITERAL1 34 | SERVONUM_PROP3 LITERAL1 35 | SERVONUM_PROP2 LITERAL1 36 | SERVONUM_PROP1 LITERAL1 37 | Sabertooth_DRIVE_Address LITERAL1 38 | Sabertooth_TURRET_Address LITERAL1 39 | Pololu_DRIVE_ID LITERAL1 40 | Pololu_TURRET_ID LITERAL1 41 | OPScout_DRIVE_Address LITERAL1 42 | OPScout_TURRET_Address LITERAL1 43 | MOTOR_MAX_FWDSPEED LITERAL1 44 | MOTOR_MAX_REVSPEED LITERAL1 45 | MOTOR_MAX_FWDSPEED_DBL LITERAL1 46 | MOTOR_MAX_REVSPEED_DBL LITERAL1 47 | OB_MA1 LITERAL1 48 | OB_MA2 LITERAL1 49 | OB_MA_PWM LITERAL1 50 | OB_MA_OCR LITERAL1 51 | OB_MB1 LITERAL1 52 | OB_MB2 LITERAL1 53 | OB_MB_PWM LITERAL1 54 | OB_MB_OCR LITERAL1 55 | OB_SMOKER_PWM LITERAL1 56 | OB_SMOKER_OCR LITERAL1 57 | IOA LITERAL1 58 | IOB LITERAL1 59 | pin_IO_A LITERAL1 60 | pin_IO_B LITERAL1 61 | IO_port LITERAL1 62 | IO_A_bit LITERAL1 63 | IO_B_bit LITERAL1 64 | pin_BattVoltage LITERAL1 65 | NUMDIPSWITCHES LITERAL1 66 | pin_Dip1 LITERAL1 67 | pin_Dip2 LITERAL1 68 | pin_Dip3 LITERAL1 69 | pin_Dip4 LITERAL1 70 | pin_Dip5 LITERAL1 71 | pin_RepairTank LITERAL1 72 | pin_Button LITERAL1 73 | pin_RedLED LITERAL1 74 | pin_GreenLED LITERAL1 75 | pin_Light1 LITERAL1 76 | pin_Light2 LITERAL1 77 | pin_Brakelights LITERAL1 78 | pin_AuxOutput LITERAL1 79 | pin_MuzzleFlash LITERAL1 80 | pin_HitNotifyLEDs LITERAL1 81 | MG_PORT LITERAL1 82 | MG_DDR LITERAL1 83 | MG_PORTPIN LITERAL1 84 | pin_MechRecoilMotor LITERAL1 -------------------------------------------------------------------------------- /OpenPanzerTCB/src/OP_SimpleTimer/OP_SimpleTimer.cpp: -------------------------------------------------------------------------------- 1 | /* OP_SimpleTimer.cpp Open Panzer Simple Timer library - for handling timed events without using delays 2 | * Source: openpanzer.org 3 | * Authors: Marcello Romani, Luke Middleton 4 | * 5 | * This library is a modification of the Simple Timer timer library written by Marcello Romani. 6 | * Timer events now return a unique ID. Even though timer "slots" are constantly being 7 | * reused, timer IDs are always unique. This prevents routines inadvertently deleting timers associated 8 | * with other routines, which was a problem with the orignal code. 9 | * 10 | * The library has also been re-named to OP_SimpleTimer to avoid conflicts with other libraries. 11 | * 12 | * The rest of the library remains as written by Marcello Romani. 13 | * For the Arduino page on his original version, see: http://playground.arduino.cc/Code/SimpleTimer 14 | * 15 | * This program is free software: you can redistribute it and/or modify 16 | * it under the terms of the GNU General Public License as published by 17 | * the Free Software Foundation, either version 3 of the License, or 18 | * (at your option) any later version. 19 | * 20 | * This program is distributed in the hope that it will be useful, 21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | * GNU General Public License for more details. 24 | * 25 | * You should have received a copy of the GNU General Public License 26 | * along with this program. If not, see . 27 | * 28 | */ 29 | 30 | 31 | #include "OP_SimpleTimer.h" 32 | 33 | 34 | static inline unsigned long elapsed() { return millis(); } 35 | 36 | 37 | OP_SimpleTimer::OP_SimpleTimer() { 38 | unsigned long current_millis = elapsed(); 39 | 40 | NextID = 1; // Initialize Next ID 41 | 42 | for (int i = 0; i < MAX_TIMERS; i++) { 43 | enabled[i] = false; 44 | callbacks[i] = 0; // if the callback pointer is zero, the slot is free, i.e. doesn't "contain" any timer 45 | prev_millis[i] = current_millis; 46 | numRuns[i] = 0; 47 | timerID[i] = 0; // Initialize IDs to Zero, which is an invalid ID 48 | } 49 | 50 | numTimers = 0; 51 | } 52 | 53 | 54 | void OP_SimpleTimer::run() { 55 | int i; 56 | unsigned long current_millis; 57 | 58 | // get current time 59 | current_millis = elapsed(); 60 | 61 | for (i = 0; i < MAX_TIMERS; i++) { 62 | 63 | toBeCalled[i] = DEFCALL_DONTRUN; 64 | 65 | // no callback == no timer, i.e. jump over empty slots 66 | if (callbacks[i]) { 67 | 68 | // is it time to process this timer ? 69 | // see http://arduino.cc/forum/index.php/topic,124048.msg932592.html#msg932592 70 | 71 | if (current_millis - prev_millis[i] >= delays[i]) { 72 | 73 | // update time 74 | //prev_millis[i] = current_millis; 75 | prev_millis[i] += delays[i]; 76 | 77 | // check if the timer callback has to be executed 78 | if (enabled[i]) { 79 | 80 | // "run forever" timers must always be executed 81 | if (maxNumRuns[i] == RUN_FOREVER) { 82 | toBeCalled[i] = DEFCALL_RUNONLY; 83 | } 84 | // other timers get executed the specified number of times 85 | else if (numRuns[i] < maxNumRuns[i]) { 86 | 87 | toBeCalled[i] = DEFCALL_RUNONLY; 88 | numRuns[i]++; 89 | 90 | // after the last run, delete the timer 91 | if (numRuns[i] >= maxNumRuns[i]) { 92 | toBeCalled[i] = DEFCALL_RUNANDDEL; 93 | } 94 | } 95 | } 96 | } 97 | } 98 | } 99 | 100 | for (i = 0; i < MAX_TIMERS; i++) { 101 | switch(toBeCalled[i]) { 102 | case DEFCALL_DONTRUN: 103 | break; 104 | 105 | case DEFCALL_RUNONLY: 106 | (*callbacks[i])(); 107 | break; 108 | 109 | case DEFCALL_RUNANDDEL: 110 | (*callbacks[i])(); 111 | deleteTimer(timerID[i]); // Pass the unique ID, not the Timer Number 112 | break; 113 | } 114 | } 115 | } 116 | 117 | 118 | // find the first available slot 119 | // return -1 if none found 120 | int OP_SimpleTimer::findFirstFreeSlot() { 121 | int i; 122 | 123 | // all slots are used 124 | if (numTimers >= MAX_TIMERS) { 125 | return -1; 126 | } 127 | 128 | // return the first slot with no callback (i.e. free) 129 | for (i = 0; i < MAX_TIMERS; i++) { 130 | if (callbacks[i] == 0) { 131 | return i; 132 | } 133 | } 134 | 135 | // no free slots found 136 | return -1; 137 | } 138 | 139 | 140 | int OP_SimpleTimer::setTimer(long d, timer_callback f, int n) { 141 | int returnID; 142 | int freeTimer; 143 | 144 | freeTimer = findFirstFreeSlot(); 145 | if (freeTimer < 0) { 146 | return -1; 147 | } 148 | 149 | if (f == NULL) { 150 | return -1; 151 | } 152 | 153 | delays[freeTimer] = d; 154 | callbacks[freeTimer] = f; 155 | maxNumRuns[freeTimer] = n; 156 | enabled[freeTimer] = true; 157 | prev_millis[freeTimer] = elapsed(); 158 | timerID[freeTimer] = NextID; 159 | 160 | // Increment number of timers 161 | numTimers++; 162 | 163 | // Save timer ID to return to user 164 | returnID = NextID; 165 | // Increment timer ID 166 | NextID++; 167 | // Handle rollover 168 | if (NextID < 1) { NextID = 1; } 169 | 170 | //return freeTimer; // OLD 171 | // Serial.print(F("Created ")); Serial.print(returnID); Serial.print(" ("); Serial.print(freeTimer); Serial.println(F(")")); 172 | return (returnID); 173 | } 174 | 175 | 176 | int OP_SimpleTimer::setInterval(long d, timer_callback f) { 177 | return setTimer(d, f, RUN_FOREVER); 178 | } 179 | 180 | 181 | int OP_SimpleTimer::setTimeout(long d, timer_callback f) { 182 | return setTimer(d, f, RUN_ONCE); 183 | } 184 | 185 | 186 | void OP_SimpleTimer::deleteTimer(int ID) 187 | { 188 | int timerNum; 189 | 190 | // nothing to delete if no timers are in use 191 | if (numTimers == 0) { 192 | return; 193 | } 194 | 195 | timerNum = getTimerNum(ID); 196 | 197 | if (timerNum == -1) { 198 | return; 199 | } 200 | 201 | // don't decrease the number of timers if the 202 | // specified slot is already empty 203 | if (callbacks[timerNum] != NULL) { 204 | callbacks[timerNum] = 0; 205 | enabled[timerNum] = false; 206 | toBeCalled[timerNum] = DEFCALL_DONTRUN; 207 | delays[timerNum] = 0; 208 | numRuns[timerNum] = 0; 209 | timerID[timerNum] = 0; 210 | 211 | // update number of timers 212 | numTimers--; 213 | 214 | //Serial.print(F("Deleted ")); Serial.print(ID); Serial.print(" ("); Serial.print(timerNum); Serial.println(F(")")); 215 | } 216 | } 217 | 218 | 219 | void OP_SimpleTimer::restartTimer(int ID) 220 | { 221 | 222 | int timerNum; 223 | 224 | timerNum = getTimerNum(ID); 225 | 226 | if (timerNum == -1) { 227 | return; 228 | } 229 | 230 | prev_millis[timerNum] = elapsed(); 231 | } 232 | 233 | 234 | boolean OP_SimpleTimer::isEnabled(int ID) 235 | { 236 | int timerNum; 237 | 238 | timerNum = getTimerNum(ID); 239 | 240 | if (timerNum == -1) { 241 | return false; 242 | } 243 | 244 | return enabled[timerNum]; 245 | } 246 | 247 | 248 | void OP_SimpleTimer::enable(int ID) 249 | { 250 | int timerNum; 251 | 252 | timerNum = getTimerNum(ID); 253 | 254 | if (timerNum == -1) { 255 | return; 256 | } 257 | 258 | enabled[timerNum] = true; 259 | } 260 | 261 | 262 | void OP_SimpleTimer::disable(int ID) 263 | { 264 | int timerNum; 265 | 266 | timerNum = getTimerNum(ID); 267 | 268 | if (timerNum == -1) { 269 | return; 270 | } 271 | 272 | enabled[timerNum] = false; 273 | } 274 | 275 | 276 | void OP_SimpleTimer::toggle(int ID) 277 | { 278 | int timerNum; 279 | 280 | timerNum = getTimerNum(ID); 281 | 282 | if (timerNum == -1) { 283 | return; 284 | } 285 | 286 | enabled[timerNum] = !enabled[timerNum]; 287 | } 288 | 289 | 290 | int OP_SimpleTimer::getNumTimers() { 291 | return numTimers; 292 | } 293 | 294 | 295 | int OP_SimpleTimer::getTimerNum(int ID) 296 | { 297 | int timerNum = -1; 298 | 299 | for (int i = 0; i < MAX_TIMERS; i++) 300 | { 301 | if (timerID[i] == ID) { timerNum = i; break;} 302 | } 303 | 304 | return timerNum; 305 | } -------------------------------------------------------------------------------- /OpenPanzerTCB/src/OP_SimpleTimer/OP_SimpleTimer.h: -------------------------------------------------------------------------------- 1 | /* OP_SimpleTimer.h Open Panzer Simple Timer library - for handling timed events without using delays 2 | * Source: openpanzer.org 3 | * Authors: Marcello Romani, Luke Middleton 4 | * 5 | * This library is a modification of the Simple Timer timer library written by Marcello Romani. 6 | * Timer events now return a unique ID. Even though timer "slots" are constantly being 7 | * reused, timer IDs are always unique. This prevents routines inadvertently deleting timers associated 8 | * with other routines, which was a problem with the orignal code. 9 | * 10 | * The library has also been re-named to OP_SimpleTimer to avoid conflicts with other libraries. 11 | * 12 | * The rest of the library remains as written by Marcello Romani. 13 | * For the Arduino page on his original version, see: http://playground.arduino.cc/Code/SimpleTimer 14 | * 15 | * This program is free software: you can redistribute it and/or modify 16 | * it under the terms of the GNU General Public License as published by 17 | * the Free Software Foundation, either version 3 of the License, or 18 | * (at your option) any later version. 19 | * 20 | * This program is distributed in the hope that it will be useful, 21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 | * GNU General Public License for more details. 24 | * 25 | * You should have received a copy of the GNU General Public License 26 | * along with this program. If not, see . 27 | * 28 | */ 29 | 30 | 31 | #ifndef OP_SIMPLETIMER_H 32 | #define OP_SIMPLETIMER_H 33 | 34 | #include 35 | #include "../OP_Settings/OP_Settings.h" 36 | 37 | typedef void (*timer_callback)(void); 38 | 39 | class OP_SimpleTimer { 40 | 41 | public: 42 | // maximum number of timers 43 | const static int MAX_TIMERS = MAX_SIMPLETIMER_SLOTS; // See OP_Settings.h under the SIMPER TIMER heading for the definition of MAX_SIMPLETIMER_SLOTS and how it was calculated. 44 | 45 | // setTimer() constants 46 | const static int RUN_FOREVER = 0; 47 | const static int RUN_ONCE = 1; 48 | 49 | // constructor 50 | OP_SimpleTimer(); 51 | 52 | // this function must be called inside loop() 53 | void run(); 54 | 55 | // call function f every d milliseconds 56 | int setInterval(long d, timer_callback f); 57 | 58 | // call function f once after d milliseconds 59 | int setTimeout(long d, timer_callback f); 60 | 61 | // call function f every d milliseconds for n times 62 | int setTimer(long d, timer_callback f, int n); 63 | 64 | // destroy the specified timer 65 | void deleteTimer(int ID); 66 | 67 | // restart the specified timer 68 | void restartTimer(int ID); 69 | 70 | // returns true if the specified timer is enabled 71 | boolean isEnabled(int ID); 72 | 73 | // enables the specified timer 74 | void enable(int ID); 75 | 76 | // disables the specified timer 77 | void disable(int ID); 78 | 79 | // enables the specified timer if it's currently disabled, 80 | // and vice-versa 81 | void toggle(int ID); 82 | 83 | // returns the number of used timers 84 | int getNumTimers(); 85 | 86 | // returns the number of available timers 87 | int getNumAvailableTimers() { return MAX_TIMERS - numTimers; }; 88 | 89 | // Gets the timer number (0-MAX_TIMERS) by ID 90 | int getTimerNum(int ID); 91 | 92 | private: 93 | // deferred call constants 94 | const static int DEFCALL_DONTRUN = 0; // don't call the callback function 95 | const static int DEFCALL_RUNONLY = 1; // call the callback function but don't delete the timer 96 | const static int DEFCALL_RUNANDDEL = 2; // call the callback function and delete the timer 97 | 98 | // find the first available slot 99 | int findFirstFreeSlot(); 100 | 101 | // value returned by the millis() function 102 | // in the previous run() call 103 | unsigned long prev_millis[MAX_TIMERS]; 104 | 105 | // pointers to the callback functions 106 | timer_callback callbacks[MAX_TIMERS]; 107 | 108 | // delay values 109 | long delays[MAX_TIMERS]; 110 | 111 | // number of runs to be executed for each timer 112 | int maxNumRuns[MAX_TIMERS]; 113 | 114 | // number of executed runs for each timer 115 | int numRuns[MAX_TIMERS]; 116 | 117 | // which timers are enabled 118 | boolean enabled[MAX_TIMERS]; 119 | 120 | // deferred function call (sort of) - N.B.: this array is only used in run() 121 | int toBeCalled[MAX_TIMERS]; 122 | 123 | // IDs for each timer (not equal to the timer number) 124 | int timerID[MAX_TIMERS]; 125 | int NextID; 126 | 127 | // actual number of timers in use 128 | int numTimers; 129 | }; 130 | 131 | #endif -------------------------------------------------------------------------------- /OpenPanzerTCB/src/OP_SimpleTimer/keywords.txt: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------- 2 | # Syntax Coloring Map 3 | # Words separated by TAB, not SPACE 4 | #------------------------------------------------------------- 5 | 6 | 7 | #------------------------------------------------------------- 8 | # KEYWORD1 - Classes 9 | #------------------------------------------------------------- 10 | 11 | OP_SimpleTimer KEYWORD1 12 | 13 | 14 | #------------------------------------------------------------- 15 | # KEYWORD2 - Methods, functions, members 16 | #------------------------------------------------------------- 17 | run KEYWORD2 18 | 19 | setInterval KEYWORD2 20 | 21 | setTimeout KEYWORD2 22 | setTimer KEYWORD2 23 | 24 | deleteTimer KEYWORD2 25 | 26 | restartTimer KEYWORD2 27 | 28 | isEnabled KEYWORD2 29 | 30 | enable KEYWORD2 31 | 32 | disable KEYWORD2 33 | 34 | toggle KEYWORD2 35 | 36 | getNumTimers KEYWORD2 37 | 38 | getNumAvailableTimers KEYWORD2 39 | 40 | getTimerNum KEYWORD2 41 | 42 | 43 | 44 | #------------------------------------------------------------- 45 | # LITERAL1 - Constants & Defines 46 | #------------------------------------------------------------- 47 | 48 | MAX_TIMERS LITERAL1 49 | RUN_FOREVER LITERAL1 50 | RUN_ONCE LITERAL1 51 | 52 | 53 | -------------------------------------------------------------------------------- /OpenPanzerTCB/src/OP_Smoker/keywords.txt: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------- 2 | # Syntax Coloring Map 3 | # Words separated by a single TAB, not SPACE 4 | #------------------------------------------------------------- 5 | 6 | 7 | #------------------------------------------------------------- 8 | # KEYWORD1 - Classes 9 | #------------------------------------------------------------- 10 | OP_Smoker KEYWORD1 11 | 12 | 13 | #------------------------------------------------------------- 14 | # KEYWORD2 - Methods, functions, members 15 | #------------------------------------------------------------- 16 | setSpeed KEYWORD2 17 | getSpeed KEYWORD2 18 | begin KEYWORD2 19 | stop KEYWORD2 20 | setIdle KEYWORD2 21 | setFastIdle KEYWORD2 22 | update KEYWORD2 23 | Startup KEYWORD2 24 | Shutdown KEYWORD2 25 | command KEYWORD2 26 | setLevelSerial KEYWORD2 27 | set_InternalSpeedRange KEYWORD2 28 | set_DefaultInternalSpeedRange KEYWORD2 29 | set_InternalHeatRange KEYWORD2 30 | set_DetaultInternalHeatRange KEYWORD2 31 | restore_Speed KEYWORD2 32 | cut_SpeedPct KEYWORD2 33 | set_MaxSpeedPct KEYWORD2 34 | cut_HeatPct KEYWORD2 35 | set_MaxHeatPct KEYWORD2 36 | map_RangeFan KEYWORD2 37 | map_RangeHeat KEYWORD2 38 | 39 | 40 | #------------------------------------------------------------- 41 | # LITERAL1 - Constants & Defines 42 | #------------------------------------------------------------- 43 | SMOKER_ADDRESS LITERAL1 44 | SMOKER_CMD_HEATER_LEVEL LITERAL1 45 | SMOKER_CMD_FAN_SPEED LITERAL1 46 | SMOKER_CMD_SERIAL_WATCHDOG LITERAL1 47 | SMOKER_CMD_BAUD_RATE LITERAL1 48 | SMOKER_BAUD_CODE_2400 LITERAL1 49 | SMOKER_BAUD_CODE_9600 LITERAL1 50 | SMOKER_BAUD_CODE_19200 LITERAL1 51 | SMOKER_BAUD_CODE_38400 LITERAL1 52 | SMOKER_BAUD_CODE_115200 LITERAL1 53 | SMOKER_BAUD_CODE_57600 LITERAL1 54 | OP_Smoker_WatchdogTimeout_mS LITERAL1 55 | 56 | -------------------------------------------------------------------------------- /OpenPanzerTCB/src/OP_Sound/OP_Sound.cpp: -------------------------------------------------------------------------------- 1 | /* OP_Sound.cpp Open Panzer Sound - container class for various supported sound devices 2 | * Source: openpanzer.org 3 | * Authors: Luke Middleton 4 | * 5 | * This program is free software: you can redistribute it and/or modify 6 | * it under the terms of the GNU General Public License as published by 7 | * the Free Software Foundation, either version 3 of the License, or 8 | * (at your option) any later version. 9 | * 10 | * This program is distributed in the hope that it will be useful, 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | * GNU General Public License for more details. 14 | * 15 | * You should have received a copy of the GNU General Public License 16 | * along with this program. If not, see . 17 | * 18 | */ 19 | 20 | 21 | #include "OP_Sound.h" 22 | 23 | // Little function to help us print out actual sound device names, rather than numbers. 24 | // To use, call something like this: Serial.print(printSoundDevice(SOUND_DEVICE)) 25 | const __FlashStringHelper *printSoundDevice(SOUND_DEVICE Device) 26 | { 27 | if(Device>SD_LAST_SD) Device=SD_LAST_SD+1; 28 | const __FlashStringHelper *Names[SD_LAST_SD+2]={F("Benedini TBS Mini"),F("Open Panzer Sound Card"),F("Taigen Sound Card"),F("Beier USM-RC-2"),F("Benedini TBS Micro"),F("UNKNOWN")}; 29 | return Names[Device]; 30 | } 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /OpenPanzerTCB/src/OP_Sound/OP_SoundCard.cpp: -------------------------------------------------------------------------------- 1 | /* OP_SoundCard.cpp Library for communicating via serial with Open Panzer sound cards 2 | * Source: openpanzer.org 3 | * Authors: Luke Middleton 4 | * 5 | * NOTE: OP_SoundCard does not have a corresponding .h (header) file, other than the header information 6 | * in OP_Sound.h 7 | * 8 | * LICENSE 9 | * =============================================================================================================== 10 | * This program is free software: you can redistribute it and/or modify 11 | * it under the terms of the GNU General Public License as published by 12 | * the Free Software Foundation, either version 3 of the License, or 13 | * (at your option) any later version. 14 | * 15 | * This program is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | * GNU General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU General Public License 21 | * along with this program. If not, see . 22 | * 23 | */ 24 | 25 | #include "OP_Sound.h" 26 | 27 | 28 | void OP_SoundCard::begin() 29 | { 30 | // Initialize to false, but they will ultimately get set to the user's preference 31 | _squeaksActive = false; 32 | _headlightEnabled = false; 33 | _headlight2Enabled = false; 34 | _turretEnabled = false; 35 | _turretSoundActive = false; 36 | _barrelEnabled = false; 37 | _barrelSoundActive = false; 38 | } 39 | 40 | void OP_SoundCard::command(byte command, byte value, byte modifier) const 41 | { 42 | _port->write(OPSC_ADDRESS); 43 | _port->write(command); 44 | _port->write(value); 45 | _port->write(modifier); 46 | _port->write((OPSC_ADDRESS + command + value + modifier) & B01111111); 47 | } 48 | 49 | void OP_SoundCard::command(byte command, byte value) const 50 | { 51 | this->command(command, value, 0); 52 | } 53 | 54 | void OP_SoundCard::command(byte command) const 55 | { 56 | this->command(command, 0, 0); 57 | } 58 | 59 | void OP_SoundCard::SendSqueakIntervals(unsigned int min, unsigned int max, uint8_t squeakNum) const 60 | { 61 | uint8_t fmin; 62 | uint8_t fmax; 63 | // OP Config allows intervals from 500 to 10,000 mS (1/2 to 10 seconds) in 50 mS increments. 64 | min = constrain(min, 500, 10000); 65 | max = constrain(max, 500, 10000); 66 | 67 | // The value we pass is in 50mS increments and will be some number from 0-190 (0=500, 190=10000) 68 | fmin = (min - 500) / 50; 69 | fmax = (max - 500) / 50; 70 | command(OPSC_CMD_SQUEAK_SET_MIN, fmin, squeakNum); // Command, value, modifier 71 | command(OPSC_CMD_SQUEAK_SET_MAX, fmax, squeakNum); 72 | } 73 | 74 | -------------------------------------------------------------------------------- /OpenPanzerTCB/src/OP_Sound/keywords.txt: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------- 2 | # Syntax Coloring Map 3 | # Words separated by TAB, not SPACE 4 | #------------------------------------------------------------- 5 | 6 | 7 | #------------------------------------------------------------- 8 | # KEYWORD1 - Classes 9 | #------------------------------------------------------------- 10 | OP_Sound KEYWORD1 11 | BenediniTBS KEYWORD1 12 | OP_SoundCard KEYWORD1 13 | 14 | 15 | #------------------------------------------------------------- 16 | # KEYWORD2 - Methods, functions, members 17 | #------------------------------------------------------------- 18 | begin LITERAL2 19 | StartEngine LITERAL2 20 | StopEngine LITERAL2 21 | SetEngineSpeed LITERAL2 22 | IdleEngine LITERAL2 23 | Repair LITERAL2 24 | StopRepairSound LITERAL2 25 | Cannon LITERAL2 26 | CannonHit LITERAL2 27 | Destroyed LITERAL2 28 | MachineGun LITERAL2 29 | StopMachineGun LITERAL2 30 | MGHit LITERAL2 31 | SetVehicleDamaged LITERAL2 32 | Turret LITERAL2 33 | StopTurret LITERAL2 34 | TurretSound_SetEnabled LITERAL2 35 | Barrel LITERAL2 36 | StopBarrel LITERAL2 37 | BarrelSound_SetEnabled LITERAL2 38 | HeadlightSound LITERAL2 39 | HeadlightSound_SetEnabled LITERAL2 40 | SetVolume LITERAL2 41 | IncreaseVolume LITERAL2 42 | DecreaseVolume LITERAL2 43 | StopVolume LITERAL2 44 | UserSound1 LITERAL2 45 | UserSound1_Repeat LITERAL2 46 | UserSound1_Stop LITERAL2 47 | UserSound2 LITERAL2 48 | UserSound2_Repeat LITERAL2 49 | UserSound2_Stop LITERAL2 50 | UserSound3 LITERAL2 51 | UserSound3_Repeat LITERAL2 52 | UserSound3_Stop LITERAL2 53 | UserSound4 LITERAL2 54 | UserSound4_Repeat LITERAL2 55 | UserSound4_Stop LITERAL2 56 | StartSqueaks LITERAL2 57 | StopSqueaks LITERAL2 58 | AreSqueaksActive LITERAL2 59 | SetSqueak1_Interval LITERAL2 60 | SetSqueak2_Interval LITERAL2 61 | SetSqueak3_Interval LITERAL2 62 | SetSqueak4_Interval LITERAL2 63 | SetSqueak5_Interval LITERAL2 64 | SetSqueak6_Interval LITERAL2 65 | Squeak1_SetEnabled LITERAL2 66 | Squeak2_SetEnabled LITERAL2 67 | Squeak3_SetEnabled LITERAL2 68 | Squeak4_SetEnabled LITERAL2 69 | Squeak5_SetEnabled LITERAL2 70 | Squeak6_SetEnabled LITERAL2 71 | Brake LITERAL2 72 | Beep LITERAL2 73 | Beeps LITERAL2 74 | 75 | 76 | #------------------------------------------------------------- 77 | # LITERAL1 - Constants & Defines 78 | #------------------------------------------------------------- 79 | SOUND_DEVICE LITERAL1 80 | 81 | 82 | -------------------------------------------------------------------------------- /OpenPanzerTCB/src/OP_TBS/keywords.txt: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------- 2 | # Syntax Coloring Map 3 | # Words separated by TAB, not SPACE 4 | #------------------------------------------------------------- 5 | 6 | 7 | #------------------------------------------------------------- 8 | # KEYWORD1 - Classes 9 | #------------------------------------------------------------- 10 | OP_TBS KEYWORD1 11 | 12 | 13 | #------------------------------------------------------------- 14 | # KEYWORD2 - Methods, functions, members 15 | #------------------------------------------------------------- 16 | begin LITERAL2 17 | SetEngineSpeed LITERAL2 18 | IdleEngine LITERAL2 19 | PROP2_OFF LITERAL2 20 | ToggleEngineSound LITERAL2 21 | Repair LITERAL2 22 | StopRepairSound LITERAL2 23 | Beep LITERAL2 24 | ForceBeep LITERAL2 25 | ForceBeeps LITERAL2 26 | TriggerSpecialSound LITERAL2 27 | StopSpecialSounds LITERAL2 28 | Cannon LITERAL2 29 | MachineGun LITERAL2 30 | StopMachineGun LITERAL2 31 | Turret LITERAL2 32 | StopTurret LITERAL2 33 | MGHit LITERAL2 34 | CannonHit LITERAL2 35 | Destroyed LITERAL2 36 | HeadlightSound LITERAL2 37 | UserSound1 LITERAL2 38 | UserSound1_Repeat LITERAL2 39 | UserSound1_Stop LITERAL2 40 | UserSound2 LITERAL2 41 | UserSound2_Repeat LITERAL2 42 | UserSound2_Stop LITERAL2 43 | Squeak1_SetEnabled LITERAL2 44 | Squeak2_SetEnabled LITERAL2 45 | Squeak3_SetEnabled LITERAL2 46 | HeadlightSound_SetEnabled LITERAL2 47 | TurretSound_SetEnabled LITERAL2 48 | StartSqueaks LITERAL2 49 | StopSqueaks LITERAL2 50 | AreSqueaksActive LITERAL2 51 | SetSqueak1_Interval LITERAL2 52 | SetSqueak2_Interval LITERAL2 53 | SetSqueak3_Interval LITERAL2 54 | 55 | 56 | #------------------------------------------------------------- 57 | # LITERAL1 - Constants & Defines 58 | #------------------------------------------------------------- 59 | PROP1 LITERAL1 60 | PROP2 LITERAL1 61 | PROP3 LITERAL1 62 | PROP1_IDLE LITERAL1 63 | PROP1_JUST_MOVING LITERAL1 64 | PROP1_FULL_SPEED LITERAL1 65 | PROP2_SWITCH_OFF LITERAL1 66 | PROP2_SWITCH_1 LITERAL1 67 | PROP2_SWITCH_2 LITERAL1 68 | BEEP_LENGTH_mS LITERAL1 69 | SOUND_OFF LITERAL1 70 | SOUND_CANNON LITERAL1 71 | SOUND_MG LITERAL1 72 | SOUND_TURRET LITERAL1 73 | SOUND_MG_HIT LITERAL1 74 | SOUND_CANNON_HIT LITERAL1 75 | SOUND_BATTLE_DESTROY LITERAL1 76 | SOUND_HEADLIGHTS LITERAL1 77 | SOUND_SQUEAK_1 LITERAL1 78 | SOUND_SQUEAK_2 LITERAL1 79 | SOUND_SQUEAK_3 LITERAL1 80 | SOUND_USER_1 LITERAL1 81 | SOUND_USER_2 LITERAL1 82 | Prop3Settings LITERAL1 83 | TBS_SIGNAL_mS LITERAL1 84 | DEFAULT_SQUEAK_MIN_mS LITERAL1 85 | DEFAULT_SQUEAK_MAX_mS LITERAL1 86 | SQUEAK_DELAY_mS LITERAL1 87 | 88 | 89 | -------------------------------------------------------------------------------- /OpenPanzerTCB/src/OP_Tank/OP_BattleTimes.h: -------------------------------------------------------------------------------- 1 | #ifndef OP_BattleTimes_h 2 | #define OP_BattleTimes_h 3 | 4 | // This is kind of silly, but due to complicated include rules, we need the definition of REPAIR_TIME_mS to be in a separate h file. 5 | // This file needs to be included in both OP_Tank.h and OP_TBS.h (and other future sound header files). 6 | // It would make most sense to put these definitions in OP_Tank.h, but we can't include OP_Tank.h in OP_TBS.h 7 | 8 | 9 | // Repairs take 15 seconds 10 | #define REPAIR_TIME_mS 15000 // How long does a repair operation take. During this time the tank can still receive hits, but 11 | // it can't move. 12 | 13 | // Tanks is dead for 15 seconds 14 | #define DESTROYED_INOPERATIVE_TIME_mS 15000 // How long is the vehicle immobilized after being destroyed. 15 seconds is the Tamiya spec. After this, 15 | // the vehicle will automatically re-generate with full health restored. 16 | 17 | 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /OpenPanzerTCB/src/OP_Tank/keywords.txt: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------- 2 | # Syntax Coloring Map 3 | # Words separated by TAB, not SPACE 4 | #------------------------------------------------------------- 5 | 6 | 7 | #------------------------------------------------------------- 8 | # KEYWORD1 - Classes 9 | #------------------------------------------------------------- 10 | 11 | OP_Tank KEYWORD1 12 | 13 | 14 | #------------------------------------------------------------- 15 | # KEYWORD2 - Methods, functions, members 16 | #------------------------------------------------------------- 17 | begin KEYWORD2 18 | Fire KEYWORD2 19 | CannonReloaded KEYWORD2 20 | SetMechBarrelWithCannon KEYWORD2 21 | isMechBarrelSetWithCannon KEYWORD2 22 | TriggerMechBarrel KEYWORD2 23 | TriggerMuzzleFlash KEYWORD2 24 | WasHit KEYWORD2 25 | LastHitProtocol KEYWORD2 26 | LastHitTeam KEYWORD2 27 | PctDamaged KEYWORD2 28 | PctHealthRemaining KEYWORD2 29 | isRepairTank KEYWORD2 30 | isRepairOngoing KEYWORD2 31 | Damage KEYWORD2 32 | BattleSettings KEYWORD2 33 | isInvulnerable KEYWORD2 34 | isDestroyed KEYWORD2 35 | CannonHitsTaken KEYWORD2 36 | MGHitsTaken KEYWORD2 37 | MachineGun KEYWORD2 38 | MachineGun_Stop KEYWORD2 39 | EnableIR KEYWORD2 40 | DisableIR KEYWORD2 41 | 42 | 43 | #------------------------------------------------------------- 44 | # LITERAL1 - Constants & Defines 45 | #------------------------------------------------------------- 46 | 47 | REPAIR_TIME_mS LITERAL1 48 | DESTROYED_INOPERATIVE_TIME_mS LITERAL1 49 | MECHRECOIL_TRIGGER_MODE LITERAL1 50 | AIRSOFT_TRIGGER_MODE LITERAL1 51 | HIT_FILTER_mS LITERAL1 52 | MUZZLE_FLASH_TRIGGER_mS LITERAL1 53 | AIRSOFT_DEBOUNCE_mS LITERAL1 54 | MECH_RECOIL_DEBOUNCE_mS LITERAL1 55 | IR_RECEIVE_INT_NUM LITERAL1 56 | MAX_BRIGHT LITERAL1 57 | MIN_BRIGHT LITERAL1 58 | BRIGHT_FADE_BREAK LITERAL1 59 | DIM_FADE_BREAK LITERAL1 60 | MAX_FADE_STEP LITERAL1 61 | MIN_FADE_STEP LITERAL1 62 | FADE_UPDATE_mS LITERAL1 63 | FLICKER_EFFECT_LENGTH_mS LITERAL1 64 | MG_HIT_BLINK_TIME LITERAL1 65 | WC_CUSTOM LITERAL1 66 | WC_LIGHT LITERAL1 67 | WC_MEDIUM LITERAL1 68 | WC_HEAVY LITERAL1 69 | TAMIYA_DAMAGE LITERAL1 70 | OPENPANZER_DAMAGE LITERAL1 71 | HIT_TYPE_NONE LITERAL1 72 | HIT_TYPE_CANNON LITERAL1 73 | HIT_TYPE_MG LITERAL1 74 | HIT_TYPE_REPAIR LITERAL1 75 | 76 | -------------------------------------------------------------------------------- /OpenPanzerTCB/src/elapsedMillis/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2011 PJRC.COM, LLC 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /OpenPanzerTCB/src/elapsedMillis/README.md: -------------------------------------------------------------------------------- 1 | elapsedMillis [![Build Status](https://travis-ci.org/pfeerick/elapsedMillis.svg?branch=master)](https://travis-ci.org/pfeerick/elapsedMillis) 2 | ===================== 3 | 4 | These special variable types (*objects*) automatically increase as time elapses. This makes it easy to check if a certain time has elapsed, while allowing your program to perform other work or checks for user input. It is also very to handle multiple tasks requiring different delays. 5 | 6 | Documentation on how to use this library is located in the [wiki](https://github.com/pfeerick/elapsedMillis/wiki) and also on the [Arduino Playground](http://playground.arduino.cc//Code/ElapsedMillis). 7 | 8 | Please report any bugs or issues you find on the [issue tracker](https://github.com/pfeerick/elapsedMillis/issues). 9 | 10 | Initial code derived from Paul Stoffregen's elapsedMillis and elapsedMicros helper code for the Teensy USB developer board. Code contributes and initial examples created by John Plocher. 11 | -------------------------------------------------------------------------------- /OpenPanzerTCB/src/elapsedMillis/elapsedMillis.h: -------------------------------------------------------------------------------- 1 | /* Elapsed time types - for easy-to-use measurements of elapsed time 2 | * http://www.pjrc.com/teensy/ 3 | * Copyright (c) 2011 PJRC.COM, LLC 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | */ 23 | 24 | #ifndef elapsedMillis_h 25 | #define elapsedMillis_h 26 | #ifdef __cplusplus 27 | 28 | #if ARDUINO >= 100 29 | #include "Arduino.h" 30 | #else 31 | #include "WProgram.h" 32 | #endif 33 | 34 | class elapsedMillis 35 | { 36 | private: 37 | unsigned long ms; 38 | public: 39 | elapsedMillis(void) { ms = millis(); } 40 | elapsedMillis(unsigned long val) { ms = millis() - val; } 41 | elapsedMillis(const elapsedMillis &orig) { ms = orig.ms; } 42 | operator unsigned long () const { return millis() - ms; } 43 | elapsedMillis & operator = (const elapsedMillis &rhs) { ms = rhs.ms; return *this; } 44 | elapsedMillis & operator = (unsigned long val) { ms = millis() - val; return *this; } 45 | elapsedMillis & operator -= (unsigned long val) { ms += val ; return *this; } 46 | elapsedMillis & operator += (unsigned long val) { ms -= val ; return *this; } 47 | elapsedMillis operator - (int val) const { elapsedMillis r(*this); r.ms += val; return r; } 48 | elapsedMillis operator - (unsigned int val) const { elapsedMillis r(*this); r.ms += val; return r; } 49 | elapsedMillis operator - (long val) const { elapsedMillis r(*this); r.ms += val; return r; } 50 | elapsedMillis operator - (unsigned long val) const { elapsedMillis r(*this); r.ms += val; return r; } 51 | elapsedMillis operator + (int val) const { elapsedMillis r(*this); r.ms -= val; return r; } 52 | elapsedMillis operator + (unsigned int val) const { elapsedMillis r(*this); r.ms -= val; return r; } 53 | elapsedMillis operator + (long val) const { elapsedMillis r(*this); r.ms -= val; return r; } 54 | elapsedMillis operator + (unsigned long val) const { elapsedMillis r(*this); r.ms -= val; return r; } 55 | }; 56 | 57 | class elapsedMicros 58 | { 59 | private: 60 | unsigned long us; 61 | public: 62 | elapsedMicros(void) { us = micros(); } 63 | elapsedMicros(unsigned long val) { us = micros() - val; } 64 | elapsedMicros(const elapsedMicros &orig) { us = orig.us; } 65 | operator unsigned long () const { return micros() - us; } 66 | elapsedMicros & operator = (const elapsedMicros &rhs) { us = rhs.us; return *this; } 67 | elapsedMicros & operator = (unsigned long val) { us = micros() - val; return *this; } 68 | elapsedMicros & operator -= (unsigned long val) { us += val ; return *this; } 69 | elapsedMicros & operator += (unsigned long val) { us -= val ; return *this; } 70 | elapsedMicros operator - (int val) const { elapsedMicros r(*this); r.us += val; return r; } 71 | elapsedMicros operator - (unsigned int val) const { elapsedMicros r(*this); r.us += val; return r; } 72 | elapsedMicros operator - (long val) const { elapsedMicros r(*this); r.us += val; return r; } 73 | elapsedMicros operator - (unsigned long val) const { elapsedMicros r(*this); r.us += val; return r; } 74 | elapsedMicros operator + (int val) const { elapsedMicros r(*this); r.us -= val; return r; } 75 | elapsedMicros operator + (unsigned int val) const { elapsedMicros r(*this); r.us -= val; return r; } 76 | elapsedMicros operator + (long val) const { elapsedMicros r(*this); r.us -= val; return r; } 77 | elapsedMicros operator + (unsigned long val) const { elapsedMicros r(*this); r.us -= val; return r; } 78 | }; 79 | 80 | #endif // __cplusplus 81 | #endif // elapsedMillis_h 82 | -------------------------------------------------------------------------------- /OpenPanzerTCB/src/elapsedMillis/keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map For elapsedMillis 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | 9 | elapsedMillis KEYWORD1 10 | elapsedMicros KEYWORD1 11 | 12 | ####################################### 13 | # Methods and Functions (KEYWORD2) 14 | ####################################### 15 | 16 | ####################################### 17 | # Constants (LITERAL1) 18 | ####################################### 19 | 20 | -------------------------------------------------------------------------------- /OpenPanzerTCB/src/elapsedMillis/library.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "elapsedMillis", 3 | "version": "1.0.4", 4 | "keywords": "timing, delay", 5 | "description": "Library for making responsive code easier using elapsed time objects", 6 | "authors": 7 | [ 8 | { 9 | "name": "Paul Stoffregen", 10 | "email": "paul@pjrc.com", 11 | "url": "http://pjrc.com/about/contact.html" 12 | }, 13 | { 14 | "name": "Peter Feerick", 15 | "email": "peter.feerick@gmail.com", 16 | "url": "https://blog.peterfeerick.com.au/contact/", 17 | "maintainer": true 18 | } 19 | ], 20 | "repository": 21 | { 22 | "type": "git", 23 | "url": "https://github.com/pfeerick/elapsedMillis.git" 24 | }, 25 | "frameworks": "arduino" 26 | } 27 | -------------------------------------------------------------------------------- /OpenPanzerTCB/src/elapsedMillis/library.properties: -------------------------------------------------------------------------------- 1 | name=elapsedMillis 2 | version=1.0.4 3 | author=Paul Stoffregen 4 | maintainer=Peter Feerick 5 | sentence=Makes coding responsive sketches easier. 6 | paragraph=When using delay(), your code can not (easily) respond to user input while the delay is happening (unless you use interrupts or complex timer code). This library makes this easy by allowing you to create variables (objects) that automatically increase as time elapses. It is easy to check if a certain time has elapsed, while your program performs other work or checks for user input. 7 | category=Timing 8 | url=http://github.com/pfeerick/elapsedMillis/wiki 9 | architectures=* 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Open Panzer](http://www.openpanzer.org/images/github/openpanzer3.png) 2 | # Introduction 3 | * [Open Panzer](http://www.openpanzer.org) is a community project to develop open source products for the RC tank market. 4 | * The TCB (tank control board) is a highly capable circuit board designed specifically for RC model tanks, but also suitable for halftracks, cars, or even battleships. The hardware is based on an ATmega 2560 processor and the firmware consists of an Arduino sketch as well as various C++ libraries. The repository you are in now contains the TCB source code. 5 | * OP Config is a desktop application used to configure the many options on the TCB and to simplify flashing new firmware to the TCB. It was written in C++ using the open source application development software called ["Qt"](http://www.qt.io/developers/). It has its own firmware repository, [see here](https://github.com/OpenPanzerProject/OP-Config) 6 | 7 | ![Open Panzer](http://www.openpanzer.org/images/github/tcb_intro_git.jpg) 8 | 9 | ## Resources 10 | * For the TCB hardware files and bill of materials, see the [Open Panzer Downloads page](http://openpanzer.org/downloads). 11 | * For more information on the Open Panzer project, see the [OpenPanzer Wiki](http://wiki.openpanzer.org). 12 | * To discuss the project, feel free to join the [Open Panzer Community](http://openpanzer.org/forum/index.php?action=forum). 13 | 14 | ## General Users 15 | If you are not a developer, you probably don't need to worry about anything on this site. Instead [download the OP Config Windows desktop program](http://www.openpanzer.org/downloads), check out the [OpenPanzer Wiki](http://wiki.openpanzer.org) for instructions, and have fun tanking! 16 | 17 | ## Developers 18 | The processor used on the TCB is an ATmega 2560 and the firmware can be compiled in the Arduino IDE. To compile yourself you first have to obtain the code, and you also have to set up the IDE for our board. 19 | 20 | ### 1. Get the Code 21 | 22 | #### Fork the Repo 23 | If you would like to contribute your changes back to the project, you need to "fork" this repo and use Git to submit pull requests. A GitHub tutorial is beyond the scope of this introduction but SparkFun has a good one you can read here: [Using GiHub](https://learn.sparkfun.com/tutorials/using-github). 24 | 25 | #### Just Download It 26 | If you just want to make changes for yourself but don't care to contribute them back to the project, you can simply click the green **Clone or download** button at the top of this page, then select **Download ZIP**. 27 | ![Download ZIP](http://openpanzer.org/images/github/CloneOrDownloadTCB.png "Download ZIP") 28 | 29 | #### Either Way 30 | Whether you fork or download, either way you need to locate the **`OpenPanzerTCB`** folder in your Arduino Sketchbook directory. If you don't know where this is you can view its location in the Arduino IDE by going to **File > Preferences > Sketchbook Location**. 31 | 32 | ### 2. Setup the IDE 33 | Now you have the source code, we also need to install the board definition files in the Arduino IDE. It's probably best to use the [latest Arduino IDE](https://www.arduino.cc/en/main/software) but any from 1.6.4 theoretically should work. 34 | 35 | Adding our board to the IDE is a simple process. 36 | * Open the Arduino IDE and go to **File > Preferences** (or if using OS X, go to Arduino > Preferences). A window will appear like the one shown below: 37 | ![Add JSON to Preferences](http://openpanzer.org/images/github/boards/Preferences_JSON.png "Add JSON to Preferences") 38 | * Paste the following URL into the 'Additional Boards Manager URLs' input field: 39 | `https://openpanzerproject.github.io/OpenPanzerBoards/package_openpanzer_index.json` 40 | * If there are already other entries in that field just add the link at the end separated from the others with a comma. 41 | * Next close the Preferences window, then go to the **Tools** menu and select **Board > Boards Manager**. Once the Board Manager opens, click on the category drop down menu on the top left hand side of the window and select **Contributed** - or, just type "Open Panzer" into the search bar. When you find the Open Panzer Boards option, click on the **Install** button and wait for the process to complete. If there are multiple versions listed, install the newest one. 42 | ![Boards Manager](http://openpanzer.org/images/github/boards/BoardsManager.png "Boards Manager") 43 | * Finally, **quit and reopen the Arduino IDE** to ensure the new board packages are properly installed. You should now be able to select the new board listed in the **Tools->Board** menu. 44 | ![TCB Board shown in List](http://openpanzer.org/images/github/boards/BoardList.png "TCB Board shown in List") 45 | * Now you are reading to start coding! 46 | 47 | ## Helpful Tip for Coders 48 | If you are running Windows, it is highly recommended you install Arduino to a clean folder like `C:\Arduino` rather than the default location which is something like `C:\Program Files (x86)\` - which has spaces and parentheses in the file name. As a developer this can save you much grief later. 49 | 50 | In addition to the various tabs in the sketch, most of the functionality actually resides in the many C++ libraries. These will be in your `Sketches\libraries\` folder and they will all begin with the prefix **OP_**. See the [Libraries Reference](http://openpanzer.org/wiki/doku.php?id=wiki:devl:libref) page in the Wiki for a brief explanation of each one. 51 | 52 | ## License 53 | Firmware for the TCB is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License version 3 as published by the Free Software Foundation. 54 | 55 | This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 56 | 57 | For more specific details see [http://www.gnu.org/licenses](http://www.gnu.org/licenses), the [Quick Guide to GPLv3.](http://www.gnu.org/licenses/quick-guide-gplv3.html) and the [copying.txt](https://github.com/OpenPanzerProject/TCB/blob/master/COPYING.txt) file in the codebase. 58 | 59 | The GNU operating system which is under the same license has an informative [FAQ here](http://www.gnu.org/licenses/gpl-faq.html). 60 | --------------------------------------------------------------------------------