├── OSL Light Setup_v7.xls ├── OpenSourceLights ├── AA_LightSetup.ino ├── AA_UserConfig.h ├── DRIVE.ino ├── EEPROM.ino ├── Lights.ino ├── OpenSourceLights.ino ├── RADIO_SETUP.ino ├── RC.ino ├── SIMPLE_TIMER.ino ├── UTILITIES.ino └── src │ ├── OSL_Button │ ├── JChristensen-Button · GitHub.url │ ├── OSL_Button.cpp │ ├── OSL_Button.h │ ├── ReadMe.txt │ └── keywords.txt │ ├── OSL_LedHandler │ ├── OSL_LedHandler.cpp │ ├── OSL_LedHandler.h │ └── keywords.txt │ ├── OSL_PinChangeInterrupt │ ├── NicoHood-PinChangeInterrupt- A simple & compact PinChangeInterrupt library for Arduino.url │ ├── PinChangeInterrupt.cpp │ ├── PinChangeInterrupt.h │ ├── PinChangeInterrupt0.cpp │ ├── PinChangeInterrupt1.cpp │ ├── PinChangeInterrupt2.cpp │ ├── PinChangeInterrupt3.cpp │ ├── PinChangeInterruptBoards.h │ ├── PinChangeInterruptPins.h │ ├── PinChangeInterruptSettings.h │ ├── Readme.md │ ├── keywords.txt │ └── library.properties │ ├── OSL_Settings │ ├── OSL_Settings.cpp │ ├── OSL_Settings.h │ └── keywords.txt │ ├── OSL_SimpleTimer │ ├── OSL_SimpleTimer.cpp │ ├── OSL_SimpleTimer.h │ └── keywords.txt │ └── elapsedMillis │ ├── LICENSE │ ├── README.md │ ├── elapsedMillis.h │ ├── keywords.txt │ ├── library.json │ └── library.properties ├── README.md └── hardware ├── Bill_Of_Materials └── OpenSourceLights_BOM.pdf ├── EagleFiles ├── OpenSourceLights_v17.brd └── OpenSourceLights_v17.sch └── OpenSourceLights_v17_Schematic.pdf /OSL Light Setup_v7.xls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OSRCL/OSL_Original/e6a4c5d1c5c118ac8a249af194856d07d6b79cea/OSL Light Setup_v7.xls -------------------------------------------------------------------------------- /OpenSourceLights/AA_LightSetup.ino: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------------------------------------------------------------------------------------> 2 | // THIS IS WHERE YOU SPECIFY THE SETTINGS FOR YOUR LIGHTS 3 | // ----------------------------------------------------------------------------------------------------------------------------------------------------> 4 | 5 | // SETUP INSTRUCTIONS 6 | 7 | // EXPLANATION OF STATES 8 | // ------------------------------------------------------------------------------------------------------------------------------------------------> 9 | // Each light can respond to multiple different conditions, or States. These are: 10 | // - Channel 3 - Position 1 11 | // - Channel 3 - Position 2 12 | // - Channel 3 - Position 3 (This is the middle position if using a 3-position switch) 13 | // - Channel 3 - Position 4 14 | // - Channel 3 - Position 5 (This is position 3 if using a 3-position switch, or position 2 if using a 2-position switch) 15 | // - Forward 16 | // - Reverse 17 | // - Stop 18 | // - Stop Delay (stopped for LongStopTime_mS milliseconds, set by user on UserConfig tab) 19 | // - Brake 20 | // - Right Turn 21 | // - Left Turn 22 | // - No Turn 23 | // - Accelerating - this is a subset of the Forward state, and occurs during heavy acceleration (defined in UserConfig) 24 | // - Decelerating - this is a subset of the Forward state, and occurs during deceleration (defined in UserConfig) 25 | // 26 | // State Notes: 27 | // - At the very least, you must plug in the Throttle channel. Steering and Channel 3 are optional 28 | // - If you do not plug in a steering channel, then obviously you will never encounter the Right, Left and No Turn states. If you don't want to use 29 | // the steering wheel but have another 3 position switch on your transmitter, you can plug that channel into the steering input and use the three 30 | // states (Left turn, Right turn, No turn) for the 3 switch positions. 31 | // - If you do not plug in a third channel, the program will only use the values specified in Position 1 as the default. In other words, it acts 32 | // as if you have a one-position switch that is always in Position 1 33 | // - If your third channel is only a 2-position switch, the program will switch between Position 1 and Position 5 34 | // - If your third channel is a 3-position switch, you will be able to switch between Positions 1, 3, and 5 35 | // - If your third channel is a 5-position switch, you will be able to select all five Positions 36 | // - For the third channel to operate correctly, and in fact, for all channels to operate correctly, you need to run through the Radio Setup once. 37 | 38 | // EXPLANATION OF SETTINGS 39 | // ------------------------------------------------------------------------------------------------------------------------------------------------> 40 | // For each light, you need to specify what will happen in each state - this is called the setting. The possible settings are: 41 | // - ON 42 | // - OFF 43 | // - FADEON * Fades on slowly, time set in AA_UserConfig.h (FadeInTime) 44 | // - FADEOFF * Fades off slowly, time set in AA_UserConfig.h (FadeOutTime) 45 | // - NA 46 | // - BLINK Will blink at the rate set in AA_UserConfig.h (BlinkInterval) 47 | // - BLINK_ALT Same as BLINK but alternating 48 | // - FASTBLINK Will blink at the fast rate set in AA_UserConfig.h (FastBlinkInterval) 49 | // - FASTBLINK_ALT Same as FASTBLINK but alternating 50 | // - SOFTBLINK A blink that recreates the look of old incandescant light bulbs. The timing of this blink is not user adjustable. 51 | // - DIM * Will dim to the level set in AA_UserConfig.h (DimLevel) 52 | // - XENON * Turns a light on but with a special effect that looks like a xenon bulb turning on 53 | // - BACKFIRE Special effect that blinks a light randomly for a short period of time (use this under the Decelerating state for tailpipe/muffler LEDs) 54 | // - SAFETYBLINK A series of blinks (the number can be defined on AA_UserConfig.h), followed by a pause while the same number of blinks occurs on the ALT side. 55 | // - SAFETYBLINK_ALT The alternate side of SAFETYBLINK, it will blink when SAFETYBLINK is off, and SAFETYBLINK will blink when SAFETYBLINK_ALT is off. Used on emergency vehicles. 56 | // 57 | // Settings Notes: 58 | // - For the positions determined by Channel 3, it is best to specify an explicit setting, in other words, you probably don't want any of them to be NA - 59 | // they should be ON, OFF, whatever. 60 | // - The opposite is true for the other states - if you don't want anything to happen during the Forward state for example, set it to NA, not OFF. 61 | // Otherwise, your light will turn off when going forward. 62 | // * Some settings require a special feature known as PWM. These are marked above with an asterisks (*). Not all of the lights on the board are capable of implementing PWM, 63 | // only the first 6 sockets. If you look at the underside of the physical board, these lights are marked with an asterisks (*). If you want to use these special settings, 64 | // they must be on lights 1-6. Otherwise if you specify one of these settings on lights 7 or 8, the program will simply turn them OFF isntead. 65 | 66 | // EXPLANATION OF SCHEMES 67 | // ------------------------------------------------------------------------------------------------------------------------------------------------> 68 | // A Scheme defines every setting for every light in every state. You may have as many Schemes as code space allows. Two are provided below to start, 69 | // if you want more, add them below, but remember to also update the NumSchemes variable at the very top of AA_UserConfig.h 70 | 71 | // HOW TO SETUP YOUR LIGHTS 72 | // ------------------------------------------------------------------------------------------------------------------------------------------------> 73 | // Below you will see the lighting schemes. Each Scheme has a single row for each of the eight lights. The columns represent the states. The values 74 | // in the individual tables represent the settings for that light at that state. 75 | // 76 | // OK, YOU'RE READY. TRY NOT TO MESS UP THE LAYOUT. JUST CHANGE THE SETTINGS. 77 | 78 | const PROGMEM uint8_t Schemes[NumSchemes][NumLights][NumStates] = 79 | { 80 | { 81 | // IF CHANNEL 3 is only 3-position switch, values in Pos2 and Pos4 will be ignored (just use Pos1, Pos3, Pos5) 82 | // SCHEME ONE - EXAMPLE PROVIDED 83 | // Pos 1 Pos 2 Pos 3 Pos 4 Pos 5 Forward Reverse Stop StopDelay Brake Right Turn Left Turn No Turn Accelerating Decelerating 84 | // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 85 | { OFF, OFF, XENON, XENON, XENON, NA, NA, NA, NA, NA, NA, NA, NA, FASTBLINK, NA }, // Light 1 -- Headlight One - XENON on when Channel 3 is in the middle-to-far position - FASTBLINK on overtaking 86 | { FADEOFF, FADEOFF, ON, ON, ON, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA }, // Light 2 -- Headlight Two - ON when Channel 3 is in the middle-to-far position, fadeoff otherwise 87 | { OFF, OFF, DIM, DIM, DIM, NA, NA, NA, NA, ON, NA, NA, NA, NA, NA }, // Light 3 -- Brake Light - ON when Braking, otherwise DIM if Channel 3 is in the middle-to-far positions 88 | { OFF, OFF, DIM, DIM, DIM, NA, NA, NA, NA, NA, SOFTBLINK, NA, NA, NA, NA }, // Light 4 -- Right Turn Lights - SOFTBLINK when turning Right, otherwise DIM if Channel 3 is in middle-to-far positions 89 | { OFF, OFF, DIM, DIM, DIM, NA, NA, NA, NA, NA, NA, SOFTBLINK, NA, NA, NA }, // Light 5 -- Left Turn Lights - SOFTBLINK when turning Left, otherwise DIM if Channel 3 is in middle-to-far positions 90 | { OFF, OFF, OFF, OFF, OFF, NA, ON, NA, NA, NA, NA, NA, NA, NA, NA }, // Light 6 -- Reverse Lights - only on when moving in Reverse 91 | { OFF, OFF, OFF, OFF, OFF, NA, NA, NA, NA, NA, NA, NA, NA, NA, BACKFIRE }, // Light 7 -- Muffler Light - special backfire effect when decelerating 92 | { OFF, OFF, OFF, OFF, OFF, NA, BLINK, NA, NA, NA, NA, NA, NA, NA, NA } // Light 8 -- Backup hazards - blinks when car is in reverse. 93 | }, 94 | { 95 | // SCHEME TWO - B LANK 96 | // Pos 1 Pos 2 Pos 3 Pos 4 Pos 5 Forward Reverse Stop StopDelay Brake Right Turn Left Turn No Turn Accelerating Decelerating 97 | // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 98 | { OFF, OFF, OFF, OFF, OFF, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA }, // Light 1 -- 99 | { OFF, OFF, OFF, OFF, OFF, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA }, // Light 2 -- 100 | { OFF, OFF, OFF, OFF, OFF, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA }, // Light 3 -- 101 | { OFF, OFF, OFF, OFF, OFF, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA }, // Light 4 -- 102 | { OFF, OFF, OFF, OFF, OFF, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA }, // Light 5 -- 103 | { OFF, OFF, OFF, OFF, OFF, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA }, // Light 6 -- 104 | { OFF, OFF, OFF, OFF, OFF, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA }, // Light 7 -- 105 | { OFF, OFF, OFF, OFF, OFF, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA } // Light 8 -- 106 | } 107 | }; 108 | -------------------------------------------------------------------------------- /OpenSourceLights/AA_UserConfig.h: -------------------------------------------------------------------------------- 1 | // ----------------------------------------------------------------------------------------------------------------------------------------------------> 2 | // THIS IS WHERE YOU ADJUST THE PROGRAM FUNCTIONALITY 3 | // ----------------------------------------------------------------------------------------------------------------------------------------------------> 4 | 5 | // ----------------------------------------------------------------------------------------------------------------------------------------------------------------> 6 | // NUMBER OF SCHEMES 7 | // ----------------------------------------------------------------------------------------------------------------------------------------------------------------> 8 | #define NumSchemes 2 // The number of lighting schemes implemented. Theoretically it can be anything up the memory limit. Defaults to 2. 9 | // MAKE SURE THIS NUMBER MATCHES THE NUMBER OF SCHEMES DEFINED IN AA_LIGHT_SETUP !! 10 | 11 | 12 | // ----------------------------------------------------------------------------------------------------------------------------------------------------------------> 13 | // RADIO AND ESC 14 | // ----------------------------------------------------------------------------------------------------------------------------------------------------------------> 15 | 16 | // Electronic Speed Controller 17 | // --------------------------------------------------------------------------------------------------------------------------------------------> 18 | #define DoubleTapReverse true // Most ESCs require you to tap reverse twice before the car actually goes into reverse. 19 | // If yours is like this, set it to true. Most touring cars operate like this. 20 | // But if you can shift directly into reverse from forward, set this to false - this is typical of crawlers. 21 | // Channel Deadband 22 | // --------------------------------------------------------------------------------------------------------------------------------------------> 23 | // Because the receiver signal will tend to drift even when your radio controls are resting at center, you may find your turn signals or other lights 24 | // turning on randomly. To prevent this from happening you can adjust the deadband, and if that is insufficient, you can enabled channel smoothing (later below). 25 | // Start with deadband first, it reduces the sensitivity around the channel center point. 26 | // The channel values (as used in this program) range from 0 (center) to 100 (full travel). If you set the deadband to 10, that means any command 27 | // of 10 or less will be ignored. This will reduce sensitivity, but since we are only controlling lights here and not the actual vehicle, that's fine. 28 | // Experiment with the values, but keep them as low as practical. 29 | // If that doesn't work, try channel smoothing below. Another thing is to try running through Radio Setup again, to make sure OSL really does know your 30 | // radio's actual center points. 31 | 32 | #define ThrottleDeadband 10 // Throttle channel hysteresis. Values below this will be ignored. Default is 10, number should be small. 33 | #define TurnDeadband 20 // Same thing, but for steering channel. 34 | 35 | 36 | // Channel Smoothing 37 | // --------------------------------------------------------------------------------------------------------------------------------------------> 38 | // Unlike deadband which ignores minor RC changes around the center point, smoothing will average the incoming signals. This will eliminate 39 | //random glitching, but comes once again at the expense of decreased sensitivity. 40 | 41 | #define smoothingStrength 1 // Number from 0-4, the higher the number the greater the smoothing. Use minimum acceptable value. 42 | #define SmoothThrottle false 43 | #define SmoothSteering false 44 | #define SmoothChannel3 false 45 | 46 | 47 | // ----------------------------------------------------------------------------------------------------------------------------------------------------------------> 48 | // STATE ADJUSTMENTS 49 | // ----------------------------------------------------------------------------------------------------------------------------------------------------------------> 50 | 51 | // StopDelay (activates after the vehicle has been stopped for some time) 52 | // --------------------------------------------------------------------------------------------------------------------------------------------> 53 | #define LongStopTime_mS 30000L // The Stop Delay state only occurs when the vehicle has been stopped for some length of time, which is set here. 54 | // Recall that 1000 mS = 1 second (default value is 30 seconds) (for large define numbers, we put an "L" after the number) 55 | 56 | // Brake Lights at Low Throttle 57 | // --------------------------------------------------------------------------------------------------------------------------------------------> 58 | #define BrakeAtThrottlePctBelow 0 // Background: Normally the Brake state can only occur if DoubleTapReverse = true and you hit reverse for the first time. This doesn't put you into reverse, 59 | // instead it turns on the brake lights. Only the second time you command reverse will the reverse state actually occur. 60 | // If DoubleTapReverse = false, there is no way for the brake state to ever occur, because you can instantly transition from forward to reverse and vice versa. 61 | // Of course you also have the option of setting your brake lights to ON in the Stop state, but then they are always on when stopped, which you may or may not want. 62 | // What this setting does: here you can set a percent and whenever the throttle command is above zero but less than or equal to that percent, 63 | // the Brake state will occur. This allows your brake lights to come on when you slow down, but you are still able to have them turn off when stopped. 64 | // Set this value to 0 (zero) to disable the low throttle brake lights effect. 65 | // Turn Signals 66 | // --------------------------------------------------------------------------------------------------------------------------------------------> 67 | #define BlinkTurnOnlyAtStop true // If you only want your turn signal blinkers to come on when the car is Stopped, set this to true. 68 | // Turn signals are cool, but they look silly when they start blinking every time you turn the steering wheel while driving. 69 | // For that reason, you will probably want to keep this "true" 70 | // NOTE: This only applies to a BLINK or SOFTBLINK setting in the "RightTurn" or "LeftTurn" states. 71 | // Any setting other than BLINK or SOFTBLINK in the "RightTurn" or "LeftTurn" column will NOT be affected. 72 | #define AllTurnSettingsMatch false // Set to true to restrict all other left or right turn settings (not just BLINK and SOFTBLINK) to the same conditions imposed by BlinkTurnOnlyAtStop 73 | 74 | #define TurnSignalDelay_mS 3000 // If BlinkTurnOnlyAtStop = true, this setting further refines when the turn signals can come on. Instead of coming on right when the 75 | // car reaches a stop, you can set a delay in milliseconds (1000 mS = 1 second) before they will be enabled. This way, if you come 76 | // to a stop while the wheels are turned the turn signals will not come on instantly, which looks very strange. 77 | // Instead there will be a delay of TurnSignalDelay_mS milliseconds after which you can hold the wheels over and the turn signals will then come on. 78 | // Once again we are trying to prevent the unrealistic engagement of turn signals, but rather have them only engaged when you specifically 79 | // want to for display purposes. 80 | #define TurnFromStartContinue_mS 1000 // If BlinkTurnOnlyAtStop = true, this setting determines the length of time the turn signal will continue to blink when you begin moving from 81 | // a stop with the wheels turned. In a real car, the blinker remains on through the turn but then is cancelled after the steering wheel returns 82 | // to center. That is the effect we are trying to mimic, but we don't do it by checking the steering wheel, we simply set a length of time for the 83 | // turn signal to continue blinking. If you don't want this effect to happen, set this to 0 (zero). 84 | 85 | // Acceleration and Deceleration 86 | // --------------------------------------------------------------------------------------------------------------------------------------------> 87 | #define AccelPct 35 // How much does the throttle have to increase (1-100 pct) to be considered a sharp acceleration. 88 | // This will trigger the OvertakeTime timer set below, during which your lights will do whatever 89 | // setting you put in the Accelerating column (BLINK or FASTBLINK makes sense, like they do in 90 | // 24hr Le Mans when overtaking) 91 | #define OvertakeTime 500 // How long should the overtake event last in ms (1000ms = 1 second) 92 | 93 | #define DecelPct 20 // How much does the throttle need to decrease (1-100 pct) to be considered a sharp deceleration. 94 | // This will trigger the Backfire effect for any light in the Decelerating column with the setting 95 | // of BACKFIRE. You can put other settings in the Decelerating column besides Backfire, and they will 96 | // work, but they will only be enabled for the same length of time as the backfire event 97 | #define BF_Time_Short 200 // How long in milliseconds (1000 ms = 1 second) on average should a backfire event last. It will actually be 98 | #define BF_Time_Long 600 // a random length of time spanning from BF_Time_Short to BF_Time_Long 99 | 100 | #define BFF_Short 30 // The two defines above determine the total length of time the backfire event will take, these two defines determine the upper and lower 101 | #define BFF_Long 100 // limits to the time each individual blink (or flicker) will take within the overall backfire event. In other words, while backfiring 102 | // the light will blink randomly on and off for some values between BFF_Short and BFF_Long 103 | 104 | // ----------------------------------------------------------------------------------------------------------------------------------------------------------------> 105 | // LIGHT SETTINGS 106 | // ----------------------------------------------------------------------------------------------------------------------------------------------------------------> 107 | 108 | // Blinking 109 | // ------------------------------------------------------------------------------------------------------------------------------------------------> 110 | #define BlinkInterval 378 // A value in milliseconds that sets the blink rate for blinking lights set to "BLINK" or "BLINK_ALT" (for example, turn signals). 1000 = 1 second 111 | #define FastBlinkInterval 50 // A value in milliseconds that sets the fast blink rate for lights set to "FASTBLINK" or "FASTBLINK_ALT" 112 | // The "_ALT" versions blink just like the regular versions, but in an alternating fashion - that is, if you have one output set to FASTBLINK, 113 | // and another to FASTBLINK_ALT, they will each blink at the same rate (FastBlinkInterval) but when one is on the other will be off, and vice-versa. 114 | // This can be used to create effects such as those seen on police cars, fire trucks, and other emergency vehicles. 115 | 116 | 117 | // Dim 118 | // ------------------------------------------------------------------------------------------------------------------------------------------------> 119 | #define DimLevel 50 // The level of brightness for the DIM setting, this is a number from 0-255, with 0 being off, 255 being full on. 120 | // Often numbers much greater than half (128) are hard to distinguish from full on. Experiment to get the number 121 | // that makes your lights as dim as you want them. 122 | 123 | // Fadein and Fadeout 124 | // ------------------------------------------------------------------------------------------------------------------------------------------------> 125 | #define FadeOutTime 300 // Length of time the fade out takes, in milliseconds (1000 mS = 1 second) 126 | #define FadeInTime 50 // Length of time the fade-in takes. For realism this should usually be quite short, but the minimum 127 | // value is 50 (1/20th of a second). If you set it lower than that, it will automatically be changed to 50 at runtime. 128 | 129 | // "Safety Lights" 130 | // ------------------------------------------------------------------------------------------------------------------------------------------------> 131 | // "Safety Lights" are the kind of alternating blinking that are seen on ambulances, police cars and other emergency vehicles. It consists of a pattern of blinks 132 | // on one side of the vehicle, then that same pattern being displayed on the other side, alternating back and forth. This effect is created by using the 133 | // SAFETYBLINK and SAFETYBLINK_ALT settings in AA_LightSetup. 134 | #define SafetyBlinkRate 40 // Rate of blinking for the SafetyBlink effect in milliseconds - small numbers are fast, large numbers are slow. 135 | #define SafetyBlinkCount 3 // The number of blinks in a row on one side, then the same number of blinks will occur on the other ("ALT") side, alternating back and forth. 136 | #define SafetyBlink_Pause 80 // The length of time to pause between a series of blinks on one side followed by a series on the other side, in milliseconds. 137 | // If you don't want a pause, set this to zero. 138 | 139 | 140 | 141 | // ----------------------------------------------------------------------------------------------------------------------------------------------------------------> 142 | // SHELF-QUEEN MODE 143 | // ----------------------------------------------------------------------------------------------------------------------------------------------------------------> 144 | // Shelf-queen mode allows the OSL to operate even without radio signals. You can use this for models that will be put on display (aka, "shelf queens"), 145 | // just apply power to the OSL without connecting that radio signal wire. 146 | // If enableShelfQueenMode = true, and the OSL does not detect a radio signal, it will set all lights to their settings in "Pos 1" (first position) of 147 | // Channel 3 for the scheme number specified ("shelfQueenSchemeNumber") 148 | // NOTE: the shelf-queen check will only happen once at startup. If a radio signal is later detected, the OSL will return to normal operation and it will 149 | // initialize itself to the prior active scheme regardless of what the shelf queen scheme number is set to below. If the radio signal is lost after that, 150 | // OSL will go into failsafe mode as usual, it will not attempt to return to shelf-queen mode until the next startup. 151 | // NOTE: if you specify a scheme number greater than 1, you need to make sure you have that scheme defined in AA_LIGHT_SETUP! 152 | 153 | #define enableShelfQueenMode true 154 | #define shelfQueenSchemeNumber 2 155 | 156 | // We can also add a random delay before the lights come on in shelf queen mode, this may be desirable if you have multiple models on display with a single 157 | // power source to all of them, the random delay will mean the lights on each model will turn on at a different time. To enable this feature set 158 | // "enableShelfQueenDelay" to true and then define the range of time within which you want the random delay to occur ("sqd_Time_Short" and "sqd_Time_Long"). 159 | // If you want the lights to come on immediately, set "enableShelfQueenDelay" to false. 160 | 161 | #define enableShelfQueenDelay true 162 | #define sqd_Time_Short 100 163 | #define sqd_Time_Long 6000 164 | 165 | 166 | // ----------------------------------------------------------------------------------------------------------------------------------------------------------------> 167 | // DEBUGGING 168 | // ----------------------------------------------------------------------------------------------------------------------------------------------------------------> 169 | #define DEBUG false // Set this to true to receive debugging messages out the serial port. 170 | #define LED_DEBUG true // If this is set to true, the Green LED on the board will be on whenever the car is moving forward, 171 | // the Red LED will come on whenever the car is moving in reverse, 172 | // both LEDs will turn OFF when the car is stopped, 173 | // both LEDs will turn ON when the car is braking, 174 | // the Red LED will blink if you are turning left, and 175 | // the Green LED will blink if you are turning right. 176 | // You can use these to verify the board is working correctly without having any external lights connected. 177 | #define BLINK_LIGHTS_RX_LOST false // If true, all eight LED outputs will blink rapidly when the radio signal has been lost. 178 | // If set to false, only the onboard Red and Green LEDs will blink when the radio signal has been lost. 179 | -------------------------------------------------------------------------------- /OpenSourceLights/DRIVE.ino: -------------------------------------------------------------------------------- 1 | 2 | int ReturnDriveMode(int ThrottleCMD) 3 | { 4 | if (ThrottleCMD > ThrottleDeadband) { return FWD; } 5 | else if (ThrottleCMD < -ThrottleDeadband) { return REV; } 6 | else { return STOP; } 7 | } 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /OpenSourceLights/EEPROM.ino: -------------------------------------------------------------------------------- 1 | 2 | void Initialize_EEPROM() 3 | { // If EEPROM has not been used before, we initialize to some sensible, yet conservative, default values. 4 | // The first time a radio setup is performed, these will be overwritten with actual values, and never referred to again. 5 | // Because the radio setup is the first thing a user should do, these in fact should not come into play. 6 | 7 | eeprom_write(PULSE_WIDTH_TYP_MIN, E_ThrottlePulseMin); 8 | eeprom_write(PULSE_WIDTH_TYP_MAX, E_ThrottlePulseMax); 9 | eeprom_write(PULSE_WIDTH_TYP_CENTER, E_ThrottlePulseCenter); 10 | eeprom_write(PULSE_WIDTH_TYP_MIN, E_TurnPulseMin); 11 | eeprom_write(PULSE_WIDTH_TYP_MAX, E_TurnPulseMax); 12 | eeprom_write(PULSE_WIDTH_TYP_CENTER, E_TurnPulseCenter); 13 | eeprom_write(PULSE_WIDTH_TYP_MIN, E_Channel3PulseMin); 14 | eeprom_write(PULSE_WIDTH_TYP_MAX, E_Channel3PulseMax); 15 | eeprom_write(PULSE_WIDTH_TYP_CENTER, E_Channel3PulseCenter); 16 | 17 | eeprom_write(false, E_ThrottleChannelReverse); 18 | eeprom_write(false, E_TurnChannelReverse); 19 | eeprom_write(false, E_Channel3Reverse); 20 | 21 | eeprom_write(1, E_CurrentScheme); // Default to Scheme #1 22 | 23 | // This is our initialization constant 24 | eeprom_write(EEPROM_Init, E_InitNum); 25 | 26 | // Finally - we still need to set up our variables, so now we call Load_EEPROM 27 | Load_EEPROM(); 28 | } 29 | 30 | void Load_EEPROM() 31 | { 32 | // If EEPROM has been used before, we run this routine to load all our saved values at startup 33 | eeprom_read(CurrentScheme, E_CurrentScheme); 34 | } 35 | 36 | void SaveScheme_To_EEPROM() 37 | { // Save the current scheme to EEPROM 38 | eeprom_write(CurrentScheme, E_CurrentScheme); 39 | return; 40 | } 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /OpenSourceLights/RADIO_SETUP.ino: -------------------------------------------------------------------------------- 1 | 2 | void RadioSetup() 3 | { 4 | unsigned long TotThrottlePulse = 0; 5 | unsigned long TotTurnPulse = 0; 6 | unsigned long TotChannel3Pulse = 0; 7 | float TempFloat; 8 | int Count; 9 | #define _line_width 40 10 | BlinkStream bs; // Used for some blinking effects 11 | 12 | 13 | // RUN SETUP 14 | // --------------------------------------------------------------------------------------------------------------------------------------------------> 15 | Serial.println(); 16 | Serial.println(); 17 | Serial.println(F("ENTERING SETUP...")); 18 | Serial.println(); 19 | 20 | // While in setup, Red LED remains on: 21 | RedLED.on(); 22 | delayWhilePolling(2000); 23 | 24 | 25 | // STAGE 1 = Read max travel values from radio, save to EEPROM 26 | // ------------------------------------------------------------------------------------------------------------------------------------------> 27 | // Transition to Stage 1: 28 | // Green LED on steady for two seconds 29 | PrintLine(_line_width); 30 | Serial.println(F("STAGE 1 - STORE MAX TRAVEL VALUES")); 31 | PrintLine(_line_width); 32 | Serial.println(F("Move all controls to maximum values")); 33 | Serial.println(F("while green LED blinks")); 34 | Serial.println(); 35 | GreenLED.on(); 36 | delayWhilePolling(2000); 37 | GreenLED.off(); 38 | delayWhilePolling(2000); 39 | 40 | // Start green LED blinking for stage one: one blink every 1200 ms 41 | GreenLED.startBlinking(100, 1200); 42 | StartWaiting_sec(15); 43 | Serial.println(F("Reading...")); 44 | 45 | // We initialize every min and max value to TypicalPulseCenter. In the loop below we will record deviations from the center. 46 | for (uint8_t i=0; i RC_Channel[i].pulseMax) RC_Channel[i].pulseMax = RC_Channel[i].pulse; 64 | if (RC_Channel[i].pulse > 0 && RC_Channel[i].pulse < RC_Channel[i].pulseMin) RC_Channel[i].pulseMin = RC_Channel[i].pulse; 65 | } 66 | } 67 | while (!TimeUp); // Keep looping until time's up 68 | GreenLED.stopBlinking(); 69 | 70 | // Sanity check in case something weird happened (like Tx turned off during setup, or some channels disconnected) 71 | for (uint8_t i=0; i PULSE_WIDTH_ABS_MAX) RC_Channel[i].pulseMax = PULSE_WIDTH_ABS_MAX; 75 | } 76 | 77 | // Save values to EEPROM 78 | eeprom_write(RC_Channel[0].pulseMin, E_ThrottlePulseMin); 79 | eeprom_write(RC_Channel[0].pulseMax, E_ThrottlePulseMax); 80 | eeprom_write(RC_Channel[1].pulseMin, E_TurnPulseMin); 81 | eeprom_write(RC_Channel[1].pulseMax, E_TurnPulseMax); 82 | eeprom_write(RC_Channel[2].pulseMin, E_Channel3PulseMin); 83 | eeprom_write(RC_Channel[2].pulseMax, E_Channel3PulseMax); 84 | 85 | Serial.println(); 86 | Serial.println(F("Stage 1 Results: Min & Max pulse values")); 87 | Serial.println(F("Channel Min Max")); 88 | PrintLine(_line_width); 89 | for (uint8_t i=0; i 105 | // Transition to Stage 2: 106 | // Off for two seconds, two slow blinks 107 | GreenLED.off(); 108 | delayWhilePolling(2000); 109 | PrintLine(_line_width); 110 | Serial.println(F("STAGE 2 - STORE CENTER VALUES")); 111 | PrintLine(_line_width); 112 | Serial.println(F("Place throttle and steering in NEUTRAL.")); 113 | Serial.println(F("If Channel 3 is a 3-position switch, set it to CENTER.")); 114 | Serial.println(); 115 | GreenLED.Blink(2, 750, 500); // Blink twice, 750mS on, 500mS off 116 | delayWhilePolling(2000); 117 | 118 | // Initialize some variables 119 | TotThrottlePulse = 0; 120 | TotTurnPulse = 0; 121 | TotChannel3Pulse = 0; 122 | Count = 0; 123 | 124 | // Start green LED blinking for stage two: two blinks every 1200 ms 125 | bs.interval[0] = 100; // On 126 | bs.interval[1] = 90; // Off 127 | bs.interval[2] = 100; // On 128 | bs.interval[3] = 1200; // Off 129 | bs.repeat = true; 130 | GreenLED.StreamBlink(bs, 4); // 4 steps in the stream 131 | 132 | StartWaiting_sec(6); // For the first bit of time we don't take any readings, this lets the user get the sticks centered 133 | Serial.println(F("Reading...")); 134 | while (!TimeUp) 135 | { PerLoopUpdates(); } 136 | 137 | StartWaiting_sec(4); // Now for the next four seconds we check the sticks 138 | do 139 | { 140 | delayWhilePolling(100); 141 | TotThrottlePulse += RC_Channel[0].pulse; 142 | TotTurnPulse += RC_Channel[1].pulse; 143 | TotChannel3Pulse += RC_Channel[2].pulse; 144 | // Increment reading count 145 | Count++; 146 | } 147 | while (!TimeUp); // Keep looping until time's up 148 | GreenLED.stopBlinking(); 149 | 150 | // Finally we record our readings 151 | TempFloat = (float)TotThrottlePulse / (float)Count; 152 | RC_Channel[0].pulseCenter = (int)lround(TempFloat); 153 | TempFloat = (float)TotTurnPulse / (float)Count; 154 | RC_Channel[1].pulseCenter = (int)lround(TempFloat); 155 | TempFloat = (float)TotChannel3Pulse / (float)Count; 156 | RC_Channel[2].pulseCenter = (int)lround(TempFloat); 157 | 158 | // Sanity check in case something weird happened (like Tx turned off during setup, or some channels disconnected) 159 | for (uint8_t i=0; i PULSE_WIDTH_TYP_MAX)) {RC_Channel[i].pulseCenter = PULSE_WIDTH_TYP_CENTER; } 162 | } 163 | 164 | // Save values to EEPROM 165 | eeprom_write(RC_Channel[0].pulseCenter, E_ThrottlePulseCenter); 166 | eeprom_write(RC_Channel[1].pulseCenter, E_TurnPulseCenter); 167 | eeprom_write(RC_Channel[2].pulseCenter, E_Channel3PulseCenter); 168 | 169 | Serial.println(); 170 | Serial.println(F("Stage 2 Results - Pulse center values")); 171 | Serial.println(F("Channel Center")); 172 | PrintLine(_line_width); 173 | for (uint8_t i=0; i 185 | // Method used here is to ask the user to: 186 | // Hold throttle stick for full forward, 187 | // Hold steering wheel to full right, 188 | // Move Channel 3 to full ON 189 | // We take a string of readings and average them. We see if the pulse lengths are long or short, and knowing where the sticks are physically, 190 | // allows us to determine if we need to reverse any channels in software. 191 | 192 | // Transition to Stage 3: 193 | GreenLED.off(); 194 | delayWhilePolling(2000); 195 | PrintLine(_line_width); 196 | Serial.println(F("STAGE 3 - STORE CHANNEL DIRECTIONS")); 197 | PrintLine(_line_width); 198 | Serial.println(F("Hold trigger down (full forward), hold steering wheel full right, set Channel 3 to ON")); 199 | Serial.println(); 200 | GreenLED.Blink(2, 750, 500); // Blink three times, 750mS on, 500mS off 201 | delayWhilePolling(2000); 202 | 203 | // Initialize some variables 204 | TotThrottlePulse = 0; 205 | TotTurnPulse = 0; 206 | TotChannel3Pulse = 0; 207 | Count = 0; 208 | 209 | // Clear reverse flag to start 210 | for (uint8_t i=0; i PULSE_WIDTH_ABS_MIN)) { RC_Channel[0].reversed = true; } 263 | // Turn stick was held right, should have been long pulse. If not, reverse 264 | if ((TotTurnPulse < 1300) && (TotTurnPulse > PULSE_WIDTH_ABS_MIN)) { RC_Channel[1].reversed = true; } 265 | // We consider on to be high, should have been long pulse. If not, reverse 266 | if ((TotChannel3Pulse < 1300) && (TotChannel3Pulse > PULSE_WIDTH_ABS_MIN)) { RC_Channel[2].reversed = true; } 267 | 268 | // Save values to EEPROM 269 | eeprom_write(RC_Channel[0].reversed, E_ThrottleChannelReverse); 270 | eeprom_write(RC_Channel[1].reversed, E_TurnChannelReverse); 271 | eeprom_write(RC_Channel[2].reversed, E_Channel3Reverse); 272 | 273 | Serial.println(); 274 | Serial.println(F("Stage 3 Results - Channel reversed")); 275 | Serial.println(F("Channel Reversed")); 276 | PrintLine(_line_width); 277 | for (uint8_t i=0; i 3 | // RC INPUTS 4 | // --------------------------------------------------------------------------------------------------------------------------------------------------> 5 | 6 | void InitializeRCChannels(void) 7 | { 8 | 9 | // Assign pins 10 | if (HardwareVersion == 1) 11 | { 12 | RC_Channel[0].pin = pin_HW1_Throttle; 13 | RC_Channel[1].pin = pin_HW1_Steering; 14 | RC_Channel[2].pin = pin_HW1_Ch3; 15 | } 16 | else if (HardwareVersion == 2) 17 | { 18 | RC_Channel[0].pin = pin_HW2_Throttle; 19 | RC_Channel[1].pin = pin_HW2_Steering; 20 | RC_Channel[2].pin = pin_HW2_Ch3; 21 | } 22 | 23 | // Settings common to all channels 24 | for (uint8_t i=0; i= PULSE_WIDTH_ABS_MIN && RC_Channel[ch].rawPulseWidth <= PULSE_WIDTH_ABS_MAX) 146 | { 147 | // rawPulseWidth is valid, transfer it to actual pulse variable 148 | RC_Channel[ch].pulse = RC_Channel[ch].rawPulseWidth; 149 | 150 | // Appply smoothing if specified on this channel 151 | if (RC_Channel[ch].smooth) 152 | { 153 | // Smoothing code submitted by Wombii 154 | // https://www.rcgroups.com/forums/showthread.php?1539753-Open-Source-Lights-Arduino-based-RC-Light-Controller/page57#post41145245 155 | // Takes difference between current and old value, divides difference by none/2/4/8/16 and adds difference to old value (a quick and simple way of averaging) 156 | RC_Channel[ch].smoothedValue = RC_Channel[ch].smoothedValue + ((RC_Channel[ch].pulse - RC_Channel[ch].smoothedValue) >> smoothingStrength); 157 | RC_Channel[ch].pulse = RC_Channel[ch].smoothedValue; 158 | } 159 | 160 | RC_Channel[ch].lastGoodPulseTime = RC_Channel[ch].lastEdgeTime; 161 | // Update the channel's state if needed 162 | switch (RC_Channel[ch].state) 163 | { 164 | case RC_SIGNAL_SYNCHED: 165 | // Do something with the pulse 166 | ProcessRCCommand(RC_Channel[ch]); 167 | break; 168 | 169 | case RC_SIGNAL_LOST: 170 | RC_Channel[ch].state = RC_SIGNAL_ACQUIRE; 171 | RC_Channel[ch].acquireCount = 1; 172 | break; 173 | 174 | case RC_SIGNAL_ACQUIRE: 175 | if (++RC_Channel[ch].acquireCount >= RC_PULSECOUNT_TO_ACQUIRE) 176 | { 177 | RC_Channel[ch].state = RC_SIGNAL_SYNCHED; 178 | // if (DEBUG) Serial.print(F("Channel ")); Serial.print(ch+1); Serial.println(F(" acquired")); 179 | } 180 | break; 181 | } 182 | } 183 | else 184 | { 185 | // Invalid pulse. If we haven't had a good pulse for a while, set the state of this channel to SIGNAL_LOST. 186 | if (RC_Channel[ch].lastEdgeTime - RC_Channel[ch].lastGoodPulseTime > RC_TIMEOUT_US) 187 | { 188 | RC_Channel[ch].state = RC_SIGNAL_LOST; 189 | RC_Channel[ch].acquireCount = 0; 190 | } 191 | } 192 | 193 | // Clear the update flag since we are done processing this pulse 194 | RC_Channel[ch].readyForUpdate = false; 195 | 196 | // We know what the individual channel's state is, but let's combine all channel's states into a single 'RC state' 197 | // If all channels share the same state, then that is also the state of the overall RC system 198 | uint8_t countSame = 1; 199 | boolean anySynched = false; 200 | uint8_t i; 201 | for (i=1; i RC_TIMEOUT_MS) 232 | { 233 | TimeLastRCCheck = millis(); 234 | uS = micros(); // Current time 235 | cli(); // We need to disable interrupts for this check, otherwise value of (uS - LastGoodPulseTime) could return very big number if channel updates in the middle of the check 236 | for (uint8_t i=0; i RC_TIMEOUT_US) 239 | { 240 | countOverdue += 1; 241 | // If this channel had previously been synched, set it now to lost 242 | if (RC_Channel[i].state == RC_SIGNAL_SYNCHED) 243 | { 244 | RC_Channel[i].state = RC_SIGNAL_LOST; 245 | RC_Channel[i].acquireCount = 0; 246 | // if (DEBUG) Serial.print(F("Channel ")); Serial.print(i+1); Serial.println(F(" lost!")); 247 | } 248 | } 249 | } 250 | sei(); // Resume interrupts 251 | 252 | if (countOverdue == NUM_RC_CHANNELS) 253 | { 254 | RC_State = RC_SIGNAL_LOST; // Ok, we've lost radio on all channels 255 | } 256 | 257 | // If state has changed, update the LEDs 258 | if (RC_State != Last_RC_State) ChangeRCState(); 259 | } 260 | } 261 | 262 | void ChangeRCState(void) 263 | { 264 | switch (RC_State) 265 | { 266 | case RC_SIGNAL_SYNCHED: 267 | if (Failsafe) 268 | { 269 | Failsafe = false; 270 | StopFailsafeLights(); 271 | } 272 | break; 273 | 274 | case RC_SIGNAL_LOST: 275 | if (!Failsafe) 276 | { 277 | Failsafe = true; 278 | StartFailsafeLights(); 279 | } 280 | break; 281 | 282 | case RC_SIGNAL_ACQUIRE: 283 | // do nothing 284 | break; 285 | } 286 | 287 | Last_RC_State = RC_State; 288 | 289 | if (DEBUG) 290 | { 291 | Serial.print(F("Radio state change: ")); 292 | Serial.print(printRadioState(RC_State)); 293 | if (RC_State == RC_SIGNAL_LOST) Serial.print(F("!")); 294 | Serial.println(); 295 | } 296 | } 297 | 298 | void ProcessRCCommand(_rc_channel &ch) 299 | { 300 | uint8_t pos; 301 | boolean WasSomething; 302 | 303 | if (ch.Digital) // This is a switch 304 | { 305 | pos = PulseToMultiSwitchPos(ch); // Calculate switch position 306 | if (pos != ch.switchPos) // Proceed only if switch position has changed 307 | { 308 | ch.switchPos = pos; // Update switch position 309 | ch.updated = true; // And the updated flag... 310 | } 311 | } 312 | else // Variable input 313 | { 314 | // If the last command was zero, this will be false, otherwise true. 315 | WasSomething = ch.mappedCommand; 316 | 317 | if (ch.pulse >= (ch.pulseCenter + ch.deadband)) 318 | { 319 | if (ch.reversed) ch.mappedCommand = map(ch.pulse, ch.pulseCenter, ch.pulseMax, 0, COMMAND_MAX_REVERSE); 320 | else ch.mappedCommand = map(ch.pulse, ch.pulseCenter, ch.pulseMax, 0, COMMAND_MAX_FORWARD); 321 | } 322 | else if (ch.pulse <= (ch.pulseCenter - ch.deadband)) 323 | { 324 | if (ch.reversed) ch.mappedCommand = map(ch.pulse, ch.pulseMin, ch.pulseCenter, COMMAND_MAX_FORWARD, 0); 325 | else ch.mappedCommand = map(ch.pulse, ch.pulseMin, ch.pulseCenter, COMMAND_MAX_REVERSE, 0); 326 | } 327 | else 328 | { 329 | ch.mappedCommand = 0; 330 | if (!WasSomething) ch.updated = false; // In this case, it was zero to start with, and is still zero. Even though the pulse might have changed slightly, 331 | // the command didn't really update (basically we are still within deadband). 332 | } 333 | 334 | // Keep the command in limits 335 | if (ch.mappedCommand != 0) 336 | { 337 | ch.mappedCommand = constrain(ch.mappedCommand, COMMAND_MAX_REVERSE, COMMAND_MAX_FORWARD); 338 | } 339 | } 340 | 341 | // Ok great, we've been manipulating the channel with an array variable to save on code bloat, but now we really need to know what is what 342 | switch (ch.channel) 343 | { 344 | case 0: // Throttle 345 | ThrottleCommand = ch.mappedCommand; 346 | break; 347 | 348 | case 1: // Steering 349 | TurnCommand = ch.mappedCommand; 350 | if (TurnCommand > 0) Direction = RIGHT_TURN; 351 | else if (TurnCommand < 0) Direction = LEFT_TURN; 352 | else Direction = NO_TURN; 353 | break; 354 | 355 | case 2: // Channel 3 356 | Channel3Command = ch.switchPos; 357 | break; 358 | 359 | default: 360 | break; 361 | } 362 | } 363 | 364 | uint8_t PulseToMultiSwitchPos(_rc_channel &ch) 365 | { 366 | int POS; 367 | 368 | if (ch.pulse == 0) 369 | { // In this case, there was no signal found 370 | POS = Pos1; // Default to position 1 371 | } 372 | else 373 | { 374 | // Turn pulse into one of five possible positions 375 | if (ch.pulse >= ch.pulseMax - 150) 376 | { 377 | POS = Pos5; 378 | } 379 | else if ((ch.pulse > (ch.pulseCenter + 100)) && (ch.pulse < (ch.pulseMax - 150))) 380 | { 381 | POS = Pos4; 382 | } 383 | else if ((ch.pulse >= (ch.pulseCenter - 100)) && (ch.pulse <= (ch.pulseCenter + 100))) 384 | { 385 | POS = Pos3; 386 | } 387 | else if ((ch.pulse < (ch.pulseCenter - 100)) && (ch.pulse > (ch.pulseMin + 150))) 388 | { 389 | POS = Pos2; 390 | } 391 | else 392 | { 393 | POS = Pos1; 394 | } 395 | 396 | // Swap positions if channel is reversed. 397 | if (ch.reversed) 398 | { 399 | if (POS == Pos1) POS = Pos5; 400 | else if (POS == Pos2) POS = Pos4; 401 | else if (POS == Pos4) POS = Pos2; 402 | else if (POS == Pos5) POS = Pos1; 403 | } 404 | } 405 | 406 | return POS; 407 | } 408 | -------------------------------------------------------------------------------- /OpenSourceLights/SIMPLE_TIMER.ino: -------------------------------------------------------------------------------- 1 | 2 | // FUNCTIONS RELATED TO THE SIMPLE TIMER 3 | 4 | unsigned int StartWaiting_mS(int mS) 5 | { 6 | TimeUp = false; 7 | return timer.setTimeout(mS, SetTimeUp); // will call function once after ms duration 8 | } 9 | 10 | 11 | unsigned int StartWaiting_sec(int seconds) 12 | { 13 | return StartWaiting_mS(seconds*1000); 14 | } 15 | 16 | 17 | void SetTimeUp() 18 | { 19 | TimeUp = true; 20 | } 21 | 22 | 23 | void ExitChangeSchemeMode() 24 | { 25 | ChangeSchemeMode = false; // As soon as this gets set to false, Change-Scheme-Mode exits 26 | } 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /OpenSourceLights/UTILITIES.ino: -------------------------------------------------------------------------------- 1 | 2 | void PerLoopUpdates() 3 | { 4 | // Handle any radio pulses that have come in 5 | // ------------------------------------------------------------------------------------------------------------------------------------------------> 6 | // RC signals are measured through pin change ISRs (interrupt service routines). The signal starts on a rising edge and ends on a falling edge, the time between them is recorded 7 | // and a flag is then set. ProcessChannelPulses checks each channel for the presence of this flag, checks the pulse width and if valid takes whatever action is required. 8 | ProcessChannelPulses(); 9 | // The RC pin change ISRs will try to determine the status of each channel, but of course if a channel becomes disconnected its ISR won't even trigger. 10 | // So we also force a check from the main loop, but only if we are not in shelf-queen mode 11 | if (!shelfQueenMode) CheckRCStatus(); 12 | 13 | 14 | // Per loop updates that have to be polled 15 | // ------------------------------------------------------------------------------------------------------------------------------------------------> 16 | timer.run(); // SimpleTimer object, used for various timing tasks. Must be polled. 17 | InputButton.read(); // Button must be polled 18 | RedLED.update(); // Led handlers must be polled 19 | GreenLED.update(); // " " 20 | for (uint8_t i=0; i= ms) ? 1 : 0; 121 | } 122 | 123 | uint8_t OSL_Button::releasedFor(uint32_t ms) 124 | { 125 | return (_state == 0 && _time - _lastChange >= ms) ? 1 : 0; 126 | } 127 | 128 | /*----------------------------------------------------------------------* 129 | * lastChange() returns the time the button last changed state, * 130 | * in milliseconds. * 131 | *----------------------------------------------------------------------*/ 132 | uint32_t OSL_Button::lastChange(void) 133 | { 134 | return _lastChange; 135 | } 136 | -------------------------------------------------------------------------------- /OpenSourceLights/src/OSL_Button/OSL_Button.h: -------------------------------------------------------------------------------- 1 | /*----------------------------------------------------------------------* 2 | * Arduino Button Library v1.0 * 3 | * Jack Christensen Mar 2012 * 4 | * * 5 | * This work is licensed under the Creative Commons Attribution- * 6 | * ShareAlike 3.0 Unported License. To view a copy of this license, * 7 | * visit http://creativecommons.org/licenses/by-sa/3.0/ or send a * 8 | * letter to Creative Commons, 171 Second Street, Suite 300, * 9 | * San Francisco, California, 94105, USA. * 10 | *----------------------------------------------------------------------*/ 11 | #ifndef OSL_Button_h 12 | #define OSL_Button_h 13 | #if ARDUINO >= 100 14 | #include 15 | #else 16 | #include 17 | #endif 18 | class OSL_Button 19 | { 20 | public: 21 | OSL_Button() {}; 22 | 23 | void begin (uint8_t pin, boolean puEnable, boolean invert, uint32_t dbTime); // pin, pull-up enable, inverted, debounce time 24 | uint8_t read(); 25 | uint8_t isPressed(); 26 | uint8_t isReleased(); 27 | uint8_t wasPressed(); 28 | uint8_t wasReleased(); 29 | uint8_t pressedFor(uint32_t ms); 30 | uint8_t releasedFor(uint32_t ms); 31 | uint32_t lastChange(); 32 | 33 | private: 34 | uint8_t _pin; //arduino pin number 35 | boolean _puEnable; //internal pullup resistor enabled 36 | boolean _invert; //if false, interpret high state as pressed, else interpret low state as pressed 37 | uint8_t _state; //current button state 38 | uint8_t _lastState; //previous button state 39 | uint8_t _changed; //state changed since last read 40 | uint32_t _time; //time of current state (all times are in ms) 41 | uint32_t _lastChange; //time of last state change 42 | uint32_t _dbTime; //debounce time 43 | }; 44 | #endif -------------------------------------------------------------------------------- /OpenSourceLights/src/OSL_Button/ReadMe.txt: -------------------------------------------------------------------------------- 1 | ReadMe file for Arduino Button Library v1.0 2 | https://github.com/JChristensen/Button 3 | Jack Christensen Mar 2012 4 | 5 | This work is licensed under the Creative Commons Attribution-ShareAlike 3.0 6 | Unported License. To view a copy of this license, visit 7 | http://creativecommons.org/licenses/by-sa/3.0/ or send a letter to Creative 8 | Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA. 9 | 10 | -------------------------------------------------------------------------------- 11 | Arduino library for debouncing and reading momentary contact switches like 12 | tactile button switches. "Long presses" of arbitrary length can be detected. 13 | Works well in state machine constructs. Use the read() function to read each 14 | button in the main loop, which should execute as fast as possible. 15 | 16 | -------------------------------------------------------------------------------- 17 | To use the library: 18 | (1) Go to https://github.com/JChristensen/Button and click the ZIP button to 19 | download the repository as a ZIP file to a convenient location on your PC. 20 | (2) Uncompress the downloaded file. This will result in a folder containing all 21 | the files for the library, that has a name that includes the branch name, 22 | for example "Button-master". 23 | (3) Rename the folder to just "Button". 24 | (4) Copy the renamed folder to the Arduino sketchbook\libraries folder. 25 | 26 | -------------------------------------------------------------------------------- 27 | The following example sketches are included with the Button library: 28 | 29 | SimpleOnOff: Just turns the Arduino's pin 13 LED on and off. 30 | 31 | LongPress: Demonstrates detecting long and short button presses. 32 | 33 | UpDown: Counts up or down, one number at a time or rapidly by holding the button 34 | down. 35 | 36 | -------------------------------------------------------------------------------- 37 | Declare button objects as follows. 38 | 39 | Button(pin, puEnable, invert, dbTime) instantiates a button object. 40 | 41 | Where: 42 | pin -- Is the Arduino pin the button is connected to, 43 | 44 | puEnable -- Enables the AVR internal pullup resistor if != 0 (can also use true 45 | or false), 46 | 47 | invert -- If invert == 0, a high state is interpreted as pressed, low as 48 | released. If invert != 0, a high state is interpreted as released, low as 49 | pressed (can also use true or false), and 50 | 51 | dbTime Is the debounce time in milliseconds. 52 | 53 | Example. Wire a normally-open tactile button switch between Arduino pin 2 and 54 | ground. We will use the internal pullup resistor, so the pin will be high when 55 | the button is not pressed, and low when the button is pressed. Therefore we 56 | should use invert == true to invert the logic: 57 | 58 | Button myButton = Button(2, true, true, 25); 59 | 60 | -------------------------------------------------------------------------------- 61 | The read() method reads the button and returns a boolean value (true or false) 62 | to indicate whether the button is pressed. The read() function needs to execute 63 | very frequently in order for the sketch to be responsive. A good place for 64 | read() is at the top of loop(). I don't normally use the return value from 65 | read(), because I use the other functions. 66 | 67 | Example: myButton.read(); 68 | 69 | -------------------------------------------------------------------------------- 70 | The isPressed() and isReleased() functions check the button state when it was 71 | last read, and return false or true accordingly. These functions DO NOT cause 72 | the button to be read. 73 | 74 | Example: if ( myButton.isPressed ) { 75 | //do some stuff 76 | } 77 | else { 78 | //do some different stuff 79 | } 80 | 81 | -------------------------------------------------------------------------------- 82 | The wasPressed() and wasReleased() functions check the button state to see if it 83 | changed between the last two reads and return false or true accordingly. These 84 | functions DO NOT cause the button to be read. Note that these functions may be 85 | more useful than isPressed() and isReleased() since they actually detect a 86 | CHANGE in the state of the button, which is usually what we want in order to 87 | cause some action. 88 | 89 | Example: if ( myButton.wasPressed() ) { ... 90 | 91 | -------------------------------------------------------------------------------- 92 | The pressedFor(ms) and releasedFor(ms) functions check to see if the button is 93 | pressed (or released), and has been in that state for the specified time in 94 | milliseconds. Returns false or true accordingly. These functions are useful to 95 | detect "long presses". Note that these functions DO NOT cause the button to be 96 | read. 97 | 98 | Example: if ( myButton.pressedFor(1000) ) { //has button been pressed 99 | //for one second? 100 | 101 | -------------------------------------------------------------------------------- 102 | Under certain circumstances, it may be useful to know when a button last changed 103 | state. lastChange() returns the time the button last changed state, in 104 | mlliseconds (the value is from the Arduino millis() function). 105 | 106 | Example: unsigned long lastChange = myButton.lastChange(); 107 | 108 | -------------------------------------------------------------------------------- 109 | -------------------------------------------------------------------------------- /OpenSourceLights/src/OSL_Button/keywords.txt: -------------------------------------------------------------------------------- 1 | OSL_Button KEYWORD1 2 | read KEYWORD2 3 | isPressed KEYWORD2 4 | isReleased KEYWORD2 5 | wasPressed KEYWORD2 6 | wasReleased KEYWORD2 7 | pressedFor KEYWORD2 8 | releasedFor KEYWORD2 9 | lastChange KEYWORD2 10 | -------------------------------------------------------------------------------- /OpenSourceLights/src/OSL_LedHandler/OSL_LedHandler.h: -------------------------------------------------------------------------------- 1 | /* OSL_LedHandler.h Led Handler - class for handling LEDs, requires use of elapsedMillis 2 | * Source: https://github.com/OSRCL 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 OSL_LedHandler_h 21 | #define OSL_LedHandler_h 22 | 23 | #include 24 | #include "../elapsedMillis/elapsedMillis.h" 25 | #include "../../AA_UserConfig.h" 26 | 27 | 28 | // These are all the possible states the light can be in, within this class. These are not always strictly the same thing as the states within the sketch, 29 | // and an output may go though multiple states to get to the state the sketch wants (transition states) 30 | #define LED_STATE_OFF 0 31 | #define LED_STATE_ON 1 32 | #define LED_STATE_DIM 2 33 | #define LED_STATE_BLINK 3 // Applies to both Blink and FastBlink 34 | #define LED_STATE_SOFTBLINK 4 35 | #define LED_STATE_RANDOMBLINK 5 36 | #define LED_STATE_FADE 6 37 | #define LED_STATE_XENON 7 38 | #define LED_STATE_FADE_TO 8 39 | #define LED_STATE_SAFETYBLINK 9 40 | 41 | // Stream blinker struct 42 | #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. 43 | typedef struct // This struct holds an array of blink patterns, and a flag to indicate if it should repeat or not 44 | { 45 | uint16_t interval[MAX_STREAM_STEPS]; 46 | boolean repeat; 47 | boolean altBlink; 48 | } BlinkStream; 49 | 50 | #define DEFAULT_BLINK_INTERVAL 378 // Used when an interval is not specified, though OSL always will 51 | 52 | #define MIN_PWM 0 // PWM value at Off 53 | #define MIN_PWM_FLOAT 0.0 54 | #define MAX_PWM 255 // PWM value at On 55 | #define MAX_PWM_FLOAT 255.0 56 | 57 | // Fading - You really probably shouldn't change any of this! These are the settings that work best with the hardcoded processes in the cpp file. 58 | #define FADE_IN 1 59 | #define FADE_OUT 2 60 | #define FADE_TYPE_EXP 0 // There are two types of fades, but for purposes of RC cars exponential looks better (and sometimes we modify even that) 61 | #define FADE_TYPE_SINE 1 // I don't believe we end up using the sine fade anywhere 62 | // For exponential fades the formula for fade-outs (decrease brightness) is pwm = priorPWM * Ratio. 63 | // For fade-ins (increase brightness) the formula is pwm = priorPWM + ((1-Ratio) * priorPWM) 64 | #define SINE_START_ANGLE_ON 1.57 // Sine fading is more complicated and involves using angular math, these are the angles on a sine wave 65 | #define SINE_START_ANGLE_OFF 4.712 // that represent the peak of the curve (on) or the trough (off) 66 | #define NUM_FADE_UPDATES 50 // Used for fading in or out from full on or off 67 | #define DEFAULT_FADE_TIME 500 // Length of time for generic fade 68 | #define FADE_OFF_RATIO 0.9 // We decrease the PWM by this ratio each step of a standard fade 69 | #define FADE_ON_R_VAL 12.5088 // Used for exponential fade-ins 70 | #define FADE_TO_RATIO 0.9 // We can have a different fade-out ratio for the fade-to function (fades to a target, rather than full off) 71 | 72 | #define XENON_STEP_1_ON_TIME 50 // Step 1 in the xenon process - how long to flash the LED at full brightness to start 73 | #define XENON_STEP_2_DIM_TIME 100 // Step 2 in the xenon process - how long to turn off the light, or set it very dim, after the first flash 74 | #define XENON_STEP_2_DIM_LEVEL 0 // Step 2 in the xenon process - how bright during this brief interval between the flash and fade in. Set to 0 to keep it off 75 | #define XENON_STEP_3_FADE_TIME 6000 // Step 3 in the xenon process - how long should the fade-in take. Sergio Pizzotti's original implementation was about 6.3 seconds with the initial flash. 76 | #define XENON_STEP_3_FADE_STEPS 150 // Step 3 in the xenon process - how many steps for the fade in. All these numbers work together, and with the actual code in .cpp, so if you change anything, 77 | // you will need to change the code as well. See the Excel spreadsheet for what they represent. Best to just leave everything alone. 78 | 79 | #define SOFTBLINK_STEP_1_FADE_ON_TIME 220 // Step 1 in the soft blink process - how long does the initial fade-in take 80 | #define SOFTBLINK_STEP_1_FADE_ON_STEPS 20 81 | #define SOFTBLINK_STEP_2_ON_TIME 100 // Step 2 in the soft blink process - how long to remain at full brightness 82 | #define SOFTBLINK_STEP_3_FADE_OFF_TIME 416 // Step 3 in the soft blink process - how long does the fade-out take 83 | #define SOFTBLINK_STEP_3_FADE_OFF_STEPS 32 84 | #define SOFTBLINK_FADE_ON_RATIO 0.24 85 | #define SOFTBLINK_FADE_OFF_RATIO 0.84 86 | #define SOFTBLINK_TO_TARGET_FADEDOWN_ONLY false // This is one of the few defines you can change without messing anything up. If set to true, when a softblink ends and the next state is dim, 87 | // this will cause the blink to stop at the dim level only when fading down. That means if the change to dim occurs when the softblink effect is lower 88 | // than the desired dim level, the softblink will blink one more time to full brightness and then stop at dim on the way down. 89 | // If set to false, it will stop at the desired dim level on either the upswing or down, depending on which happens first. 90 | // I think the stop on fadedown only looks better, but you may end up with one extra blink at stop, so if you don't like that set the define to false. 91 | class OSL_LedHandler 92 | { public: 93 | OSL_LedHandler() {}; 94 | 95 | void begin (byte p, boolean i=false, boolean w=false); // p = pin, i = invert, w = pwm-able 96 | void on(void); 97 | boolean isOn(void); 98 | void off(void); 99 | void toggle(void); 100 | void dim(uint8_t level); // Level should be between 0-MAX_PWM 101 | void update(void); // Update blinking effect 102 | void Blink(uint16_t interval=DEFAULT_BLINK_INTERVAL); // Blinks once at interval specified 103 | void Blink(uint8_t times, uint16_t interval=DEFAULT_BLINK_INTERVAL); // Overload - Blinks N times at interval specified (on and off interval will be the same) 104 | void Blink(uint8_t times, uint16_t on_interval=DEFAULT_BLINK_INTERVAL, uint16_t off_interval=DEFAULT_BLINK_INTERVAL); // Overload - Blinks N times at intervals specified (on and off time individually set) 105 | void startBlinking(uint16_t on_interval=DEFAULT_BLINK_INTERVAL, uint16_t off_interval=DEFAULT_BLINK_INTERVAL, boolean alt=false); // Starts a continuous blink at the set intervals 106 | void stopBlinking(void); 107 | void softBlink(void); 108 | void StreamBlink(BlinkStream bs, uint8_t numSteps); 109 | void randomBlink(void); 110 | void Fade(uint8_t fade_in, uint16_t span, char f=FADE_TYPE_EXP); 111 | void FadeTo(uint8_t desiredLevel); 112 | void stopFading(void); 113 | void Xenon(void); 114 | void SafetyBlink(uint16_t sbRate, uint8_t sbCount, uint16_t sbInt, boolean alt=false); 115 | 116 | 117 | private: 118 | void clearUpdateProcess(void); 119 | void pinOn(void); 120 | void pinOff(void); 121 | void offWithExtra(boolean includeExtra=false); 122 | void setPWM(float level); 123 | void changeLEDState(uint8_t changeState); 124 | void softBlinkWithStartFlag(boolean start=false); 125 | elapsedMillis _time; 126 | byte _pin; 127 | boolean _pwmable; 128 | float _pwm; 129 | boolean _fadeToTarget; 130 | int16_t _pwmTarget; 131 | boolean _invert; 132 | uint8_t _fadeType; 133 | uint8_t _fadeDirection; 134 | uint8_t _curProcessStep; 135 | uint8_t _numProcessSteps; 136 | boolean _AltProcess; 137 | uint8_t _curStep; 138 | uint8_t _numSteps; 139 | uint16_t _nextWait; 140 | boolean _fixedInterval; 141 | BlinkStream _blinkStream; 142 | boolean _blinkToDim; 143 | float _fadeAdjustment; 144 | uint8_t _ledCurState; 145 | uint8_t _ledPriorState; 146 | uint16_t _safetyBlinkRate; 147 | uint8_t _safetyBlinkCount; 148 | uint16_t _safetyBlinkInterval; 149 | uint16_t _safetyBlinkCountTimesTwo; 150 | }; 151 | 152 | 153 | #endif 154 | -------------------------------------------------------------------------------- /OpenSourceLights/src/OSL_LedHandler/keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map For PinChangeInterrupt 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | 9 | ####################################### 10 | # Methods and Functions (KEYWORD2) 11 | ####################################### 12 | 13 | begin KEYWORD2 14 | on KEYWORD2 15 | isOn KEYWORD2 16 | off KEYWORD2 17 | toggle KEYWORD2 18 | dim KEYWORD2 19 | update KEYWORD2 20 | Blink KEYWORD2 21 | startBlinking KEYWORD2 22 | stopBlinking KEYWORD2 23 | softBlink KEYWORD2 24 | StreamBlink KEYWORD2 25 | randomBlink KEYWORD2 26 | Fade KEYWORD2 27 | FadeTo KEYWORD2 28 | stopFading KEYWORD2 29 | Xenon KEYWORD2 30 | 31 | ####################################### 32 | # Instances (KEYWORD2) 33 | ####################################### 34 | OSL_LedHandler KEYWORD2 35 | 36 | ####################################### 37 | # Constants (LITERAL1) 38 | ####################################### 39 | LED_STATE_OFF LITERAL1 40 | LED_STATE_ON LITERAL1 41 | LED_STATE_DIM LITERAL1 42 | LED_STATE_BLINK LITERAL1 43 | LED_STATE_SOFTBLINK LITERAL1 44 | LED_STATE_RANDOMBLINK LITERAL1 45 | LED_STATE_FADE LITERAL1 46 | LED_STATE_XENON LITERAL1 47 | LED_STATE_FADE_TO LITERAL1 48 | MAX_STREAM_STEPS LITERAL1 49 | DEFAULT_BLINK_INTERVAL LITERAL1 50 | MIN_PWM LITERAL1 51 | MIN_PWM_FLOAT LITERAL1 52 | MAX_PWM LITERAL1 53 | MAX_PWM_FLOAT LITERAL1 54 | FADE_IN LITERAL1 55 | FADE_OUT LITERAL1 56 | FADE_TYPE_EXP LITERAL1 57 | FADE_TYPE_SINE LITERAL1 58 | SINE_START_ANGLE_ON LITERAL1 59 | SINE_START_ANGLE_OFF LITERAL1 60 | NUM_FADE_UPDATES LITERAL1 61 | DEFAULT_FADE_TIME LITERAL1 62 | FADE_OFF_RATIO LITERAL1 63 | FADE_ON_R_VAL LITERAL1 64 | FADE_TO_RATIO LITERAL1 65 | XENON_STEP_1_ON_TIME LITERAL1 66 | XENON_STEP_2_DIM_TIME LITERAL1 67 | XENON_STEP_2_DIM_LEVEL LITERAL1 68 | XENON_STEP_3_FADE_TIME LITERAL1 69 | XENON_STEP3_FADE_STEPS LITERAL1 70 | SOFTBLINK_STEP_1_FADE_ON_TIME LITERAL1 71 | SOFTBLINK_STEP_1_FADE_ON_STEPS LITERAL1 72 | SOFTBLINK_STEP_2_ON_TIME LITERAL1 73 | SOFTBLINK_STEP_3_FADE_OFF_TIME LITERAL1 74 | SOFTBLINK_STEP_3_FADE_OFF_STEPS LITERAL1 75 | SOFTBLINK_FADE_ON_RATIO LITERAL1 76 | SOFTBLINK_FADE_OFF_RATIO LITERAL1 77 | SOFTBLINK_TO_TARGET_FADEDOWN_ONLY LITERAL1 78 | -------------------------------------------------------------------------------- /OpenSourceLights/src/OSL_PinChangeInterrupt/NicoHood-PinChangeInterrupt- A simple & compact PinChangeInterrupt library for Arduino.url: -------------------------------------------------------------------------------- 1 | [InternetShortcut] 2 | URL=https://github.com/NicoHood/PinChangeInterrupt 3 | -------------------------------------------------------------------------------- /OpenSourceLights/src/OSL_PinChangeInterrupt/PinChangeInterrupt.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2014-2015 NicoHood 3 | See the readme for credit to other people. 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 | #include "PinChangeInterrupt.h" 25 | 26 | // manually include cpp files here to save flash if only 1 ISR is present 27 | // or if the user knows he just wants to compile all enabled ports. 28 | #if defined(PCINT_ALINKAGE) && defined(PCINT_COMPILE_ENABLED_ISR) 29 | #define PCINT_INCLUDE_FROM_CPP 30 | #include "PinChangeInterrupt0.cpp" 31 | #include "PinChangeInterrupt1.cpp" 32 | #include "PinChangeInterrupt2.cpp" 33 | #include "PinChangeInterrupt3.cpp" 34 | #else 35 | 36 | //================================================================================ 37 | // Weak Callbacks 38 | //================================================================================ 39 | 40 | // create all weak functions which are all (if not used) alias of the pcint_null_callback above 41 | /* 42 | for (int i = 0; i < 32; i++) { 43 | Serial.print("void PinChangeInterruptEventPCINT"); 44 | Serial.print(i); 45 | Serial.println("(void) __attribute__((weak, alias(\"pcint_null_callback\")));"); 46 | } 47 | */ 48 | void PinChangeInterruptEventPCINT0(void) __attribute__((weak, alias("pcint_null_callback"))); 49 | void PinChangeInterruptEventPCINT1(void) __attribute__((weak, alias("pcint_null_callback"))); 50 | void PinChangeInterruptEventPCINT2(void) __attribute__((weak, alias("pcint_null_callback"))); 51 | void PinChangeInterruptEventPCINT3(void) __attribute__((weak, alias("pcint_null_callback"))); 52 | void PinChangeInterruptEventPCINT4(void) __attribute__((weak, alias("pcint_null_callback"))); 53 | void PinChangeInterruptEventPCINT5(void) __attribute__((weak, alias("pcint_null_callback"))); 54 | void PinChangeInterruptEventPCINT6(void) __attribute__((weak, alias("pcint_null_callback"))); 55 | void PinChangeInterruptEventPCINT7(void) __attribute__((weak, alias("pcint_null_callback"))); 56 | void PinChangeInterruptEventPCINT8(void) __attribute__((weak, alias("pcint_null_callback"))); 57 | void PinChangeInterruptEventPCINT9(void) __attribute__((weak, alias("pcint_null_callback"))); 58 | void PinChangeInterruptEventPCINT10(void) __attribute__((weak, alias("pcint_null_callback"))); 59 | void PinChangeInterruptEventPCINT11(void) __attribute__((weak, alias("pcint_null_callback"))); 60 | void PinChangeInterruptEventPCINT12(void) __attribute__((weak, alias("pcint_null_callback"))); 61 | void PinChangeInterruptEventPCINT13(void) __attribute__((weak, alias("pcint_null_callback"))); 62 | void PinChangeInterruptEventPCINT14(void) __attribute__((weak, alias("pcint_null_callback"))); 63 | void PinChangeInterruptEventPCINT15(void) __attribute__((weak, alias("pcint_null_callback"))); 64 | void PinChangeInterruptEventPCINT16(void) __attribute__((weak, alias("pcint_null_callback"))); 65 | void PinChangeInterruptEventPCINT17(void) __attribute__((weak, alias("pcint_null_callback"))); 66 | void PinChangeInterruptEventPCINT18(void) __attribute__((weak, alias("pcint_null_callback"))); 67 | void PinChangeInterruptEventPCINT19(void) __attribute__((weak, alias("pcint_null_callback"))); 68 | void PinChangeInterruptEventPCINT20(void) __attribute__((weak, alias("pcint_null_callback"))); 69 | void PinChangeInterruptEventPCINT21(void) __attribute__((weak, alias("pcint_null_callback"))); 70 | void PinChangeInterruptEventPCINT22(void) __attribute__((weak, alias("pcint_null_callback"))); 71 | void PinChangeInterruptEventPCINT23(void) __attribute__((weak, alias("pcint_null_callback"))); 72 | void PinChangeInterruptEventPCINT24(void) __attribute__((weak, alias("pcint_null_callback"))); 73 | void PinChangeInterruptEventPCINT25(void) __attribute__((weak, alias("pcint_null_callback"))); 74 | void PinChangeInterruptEventPCINT26(void) __attribute__((weak, alias("pcint_null_callback"))); 75 | void PinChangeInterruptEventPCINT27(void) __attribute__((weak, alias("pcint_null_callback"))); 76 | void PinChangeInterruptEventPCINT28(void) __attribute__((weak, alias("pcint_null_callback"))); 77 | void PinChangeInterruptEventPCINT29(void) __attribute__((weak, alias("pcint_null_callback"))); 78 | void PinChangeInterruptEventPCINT30(void) __attribute__((weak, alias("pcint_null_callback"))); 79 | void PinChangeInterruptEventPCINT31(void) __attribute__((weak, alias("pcint_null_callback"))); 80 | 81 | #endif // PCINT_INCLUDE_FROM_CPP 82 | 83 | // useless function for weak implemented/not used functions, extern c needed for the alias 84 | extern "C" { 85 | void pcint_null_callback(void) { 86 | // useless 87 | } 88 | } 89 | 90 | //================================================================================ 91 | // PinChangeInterrupt User Functions 92 | //================================================================================ 93 | 94 | // variables to save the last port states and the interrupt settings 95 | uint8_t oldPorts[PCINT_NUM_USED_PORTS] = { 0 }; 96 | uint8_t fallingPorts[PCINT_NUM_USED_PORTS] = { 0 }; 97 | uint8_t risingPorts[PCINT_NUM_USED_PORTS] = { 0 }; 98 | 99 | void enablePinChangeInterruptHelper(const uint8_t pcintPort, const uint8_t pcintMask, const uint8_t arrayPos){ 100 | // Update the old state to the actual state 101 | switch(pcintPort){ 102 | #ifdef PCINT_INPUT_PORT0_USED 103 | case 0: 104 | oldPorts[arrayPos] = PCINT_INPUT_PORT0; 105 | break; 106 | #endif 107 | #ifdef PCINT_INPUT_PORT1_USED 108 | case 1: 109 | oldPorts[arrayPos] = PCINT_INPUT_PORT1; 110 | break; 111 | #endif 112 | #ifdef PCINT_INPUT_PORT2_USED 113 | case 2: 114 | oldPorts[arrayPos] = PCINT_INPUT_PORT2; 115 | break; 116 | #endif 117 | #ifdef PCINT_INPUT_PORT3_USED 118 | case 3: 119 | oldPorts[arrayPos] = PCINT_INPUT_PORT3; 120 | break; 121 | #endif 122 | } 123 | 124 | // Pin change mask registers decide which pins are ENABLE as triggers 125 | #ifdef PCMSK0 126 | #ifdef PCMSK1 127 | #ifdef PCMSK3 128 | // Special case for ATmega1284P where PCMSK3 is not directly after PCMSK2 129 | if(false){ 130 | #else 131 | // Special case for Attinyx4 where PCMSK1 and PCMSK0 are not next to each other 132 | if(&PCMSK1 - &PCMSK0 == 1){ 133 | #endif 134 | #endif 135 | *(&PCMSK0 + pcintPort) |= pcintMask; 136 | #ifdef PCMSK1 137 | } 138 | else{ 139 | switch(pcintPort){ 140 | case 0: 141 | PCMSK0 |= pcintMask; 142 | break; 143 | case 1: 144 | PCMSK1 |= pcintMask; 145 | break; 146 | #ifdef PCMSK2 147 | case 2: 148 | PCMSK2 |= pcintMask; 149 | break; 150 | #endif 151 | #ifdef PCMSK3 152 | case 3: 153 | PCMSK3 |= pcintMask; 154 | break; 155 | #endif 156 | } 157 | } 158 | #endif 159 | #elif defined(PCMSK) 160 | *(&PCMSK + pcintPort) |= pcintMask; 161 | #endif 162 | 163 | // PCICR: Pin Change Interrupt Control Register - enables interrupt vectors 164 | #ifdef PCICR 165 | PCICR |= (1 << (pcintPort + PCIE0)); 166 | #elif defined(GICR) /* e.g. ATmega162 */ 167 | GICR |= (1 << (pcintPort + PCIE0)); 168 | #elif defined(GIMSK) && defined(PCIE0) /* e.g. ATtiny X4 */ 169 | GIMSK |= (1 << (pcintPort + PCIE0)); 170 | #elif defined(GIMSK) && defined(PCIE) /* e.g. ATtiny X5 */ 171 | GIMSK |= (1 << (pcintPort + PCIE)); 172 | #else 173 | #error MCU has no such a register 174 | #endif 175 | } 176 | 177 | void disablePinChangeInterruptHelper(const uint8_t pcintPort, const uint8_t pcintMask) { 178 | bool disable = false; 179 | #ifdef PCMSK0 180 | #ifdef PCMSK1 181 | // Special case for Attinyx4 where PCMSK1 and PCMSK0 are not next to each other 182 | if(&PCMSK1 - &PCMSK0 == 1){ 183 | #endif 184 | // disable the mask. 185 | *(&PCMSK0 + pcintPort) &= ~pcintMask; 186 | 187 | // if that's the last one, disable the interrupt. 188 | if (*(&PCMSK0 + pcintPort) == 0) 189 | disable = true; 190 | #ifdef PCMSK1 191 | } 192 | else{ 193 | switch(pcintPort){ 194 | case 0: 195 | // disable the mask. 196 | PCMSK0 &= ~pcintMask; 197 | 198 | // if that's the last one, disable the interrupt. 199 | if (!PCMSK0) 200 | disable = true; 201 | break; 202 | case 1: 203 | // disable the mask. 204 | PCMSK1 &= ~pcintMask; 205 | 206 | // if that's the last one, disable the interrupt. 207 | if (!PCMSK1) 208 | disable = true; 209 | break; 210 | #ifdef PCMSK2 211 | case 2: 212 | // disable the mask. 213 | PCMSK2 &= ~pcintMask; 214 | 215 | // if that's the last one, disable the interrupt. 216 | if (!PCMSK2) 217 | disable = true; 218 | break; 219 | #endif 220 | #ifdef PCMSK3 221 | case 3: 222 | // disable the mask. 223 | PCMSK3 &= ~pcintMask; 224 | 225 | // if that's the last one, disable the interrupt. 226 | if (!PCMSK3) 227 | disable = true; 228 | break; 229 | #endif 230 | } 231 | } 232 | #endif 233 | #elif defined(PCMSK) 234 | // disable the mask. 235 | *(&PCMSK + pcintPort) &= ~pcintMask; 236 | 237 | // if that's the last one, disable the interrupt. 238 | if (*(&PCMSK + pcintPort) == 0) 239 | disable = true; 240 | #endif 241 | if(disable) 242 | { 243 | #ifdef PCICR 244 | PCICR &= ~(1 << (pcintPort + PCIE0)); 245 | #elif defined(GICR) /* e.g. ATmega162 */ 246 | GICR &= ~(1 << (pcintPort + PCIE0)); 247 | #elif defined(GIMSK) && defined(PCIE0) /* e.g. ATtiny X4 */ 248 | GIMSK &= ~(1 << (pcintPort + PCIE0)); 249 | #elif defined(GIMSK) && defined(PCIE) /* e.g. ATtiny X5 */ 250 | GIMSK &= ~(1 << (pcintPort + PCIE)); 251 | #else 252 | #error MCU has no such a register 253 | #endif 254 | } 255 | } 256 | 257 | /* 258 | asm output (nothing to optimize here) 259 | 260 | ISR(PCINT0_vect) { 261 | push r1 262 | push r0 263 | in r0, 0x3f ; 63 264 | push r0 265 | eor r1, r1 266 | push r18 267 | push r19 268 | push r20 269 | push r21 270 | push r22 271 | push r23 272 | push r24 273 | push r25 274 | push r26 275 | push r27 276 | push r28 277 | push r30 278 | push r31 279 | 280 | // get the new and old pin states for port 281 | // uint8_t newPort = pinChangeInterruptPortToInput(port); 282 | in r24, 0x03; 3 //(1) loads byte into newPort from I/O register 283 | 284 | // loads old port and high + low setting 285 | lds r18, 0x011E //(1 or 2) loads oldPorts into register 286 | lds r28, 0x011B //(1 or 2) loads fallingPorts into register 287 | lds r25, 0x0118 //(1 or 2) loads risingPorts into register 288 | 289 | and r28, r18 // oldPorts & fallingPorts 290 | and r25, r24 // newPort & risingPorts 291 | or r28, r25 // (oldPorts & fallingPorts) | (newPort & risingPorts) 292 | eor r18, r24 // oldPorts^newPort 293 | and r28, r18 // ((oldPorts & fallingPorts) | (newPort & risingPorts)) & (oldPorts^newPort) 294 | 295 | // save the new state for next comparison 296 | // oldPorts[arrayPos] = newPort; 297 | sts 0x011E, r24 298 | 299 | // Execute all functions that should be triggered 300 | sbrc r28, 0 301 | call 0x37c ; 0x37c <_Z20PinChangeInterruptEventPCINT0v> 302 | sbrc r28, 1 303 | call 0x37c ; 0x37c <_Z20PinChangeInterruptEventPCINT0v> 304 | sbrc r28, 2 305 | call 0x318 ; 0x318 <_Z20PinChangeInterruptEventPCINT2v> 306 | sbrc r28, 3 307 | call 0x340 ; 0x340 <_Z20PinChangeInterruptEventPCINT3v> 308 | sbrc r28, 4 309 | call 0x37c ; 0x37c <_Z20PinChangeInterruptEventPCINT0v> 310 | sbrc r28, 5 311 | call 0x37c ; 0x37c <_Z20PinChangeInterruptEventPCINT0v> 312 | sbrc r28, 6 313 | call 0x37c ; 0x37c <_Z20PinChangeInterruptEventPCINT0v> 314 | sbrc r28, 7 315 | call 0x37c ; 0x37c <_Z20PinChangeInterruptEventPCINT0v> 316 | 317 | pop r31 318 | pop r30 319 | pop r28 320 | pop r27 321 | pop r26 322 | pop r25 323 | pop r24 324 | pop r23 325 | pop r22 326 | pop r21 327 | pop r20 328 | pop r19 329 | pop r18 330 | pop r0 331 | out 0x3f, r0 ; 63 332 | pop r0 333 | pop r1 334 | reti 335 | } 336 | */ 337 | -------------------------------------------------------------------------------- /OpenSourceLights/src/OSL_PinChangeInterrupt/PinChangeInterrupt0.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2014-2015 NicoHood 3 | See the readme for credit to other people. 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 | #include "PinChangeInterrupt.h" 25 | 26 | //================================================================================ 27 | // Interrupt Handler 28 | //================================================================================ 29 | 30 | // prevent compilation twice if included from the .cpp to force compile all ISRs 31 | #if defined(PCINT_ALINKAGE) && defined(PCINT_COMPILE_ENABLED_ISR) && defined(PCINT_INCLUDE_FROM_CPP) \ 32 | || !defined(PCINT_ALINKAGE) || !defined(PCINT_COMPILE_ENABLED_ISR) 33 | 34 | #if (PCINT_USE_PORT0 == true) 35 | 36 | void attachPinChangeInterrupt0(void) { 37 | // fake function to make the IDE link this file 38 | } 39 | 40 | ISR(PCINT0_vect) { 41 | // get the new and old pin states for port 42 | uint8_t newPort = PCINT_INPUT_PORT0; 43 | 44 | // compare with the old value to detect a rising or falling 45 | uint8_t arrayPos = getArrayPosPCINT(0); 46 | uint8_t change = newPort ^ oldPorts[arrayPos]; 47 | uint8_t rising = change & newPort; 48 | uint8_t falling = change & oldPorts[arrayPos]; 49 | 50 | // check which pins are triggered, compared with the settings 51 | uint8_t risingTrigger = rising & risingPorts[arrayPos]; 52 | uint8_t fallingTrigger = falling & fallingPorts[arrayPos]; 53 | uint8_t trigger = risingTrigger | fallingTrigger; 54 | 55 | // save the new state for next comparison 56 | oldPorts[arrayPos] = newPort; 57 | 58 | // Execute all functions that should be triggered 59 | // This way we can exclude a single function 60 | // and the calling is also much faster 61 | // We may also reorder the pins for different priority 62 | #if !defined(PCINT_CALLBACK_PORT0) 63 | PCINT_CALLBACK(0, 0); 64 | PCINT_CALLBACK(1, 1); 65 | PCINT_CALLBACK(2, 2); 66 | PCINT_CALLBACK(3, 3); 67 | PCINT_CALLBACK(4, 4); 68 | PCINT_CALLBACK(5, 5); 69 | PCINT_CALLBACK(6, 6); 70 | PCINT_CALLBACK(7, 7); 71 | #else 72 | PCINT_CALLBACK_PORT0 73 | #endif 74 | } 75 | 76 | #if defined(PCINT_API) 77 | 78 | /* 79 | for (int i = 0; i < 32; i++) { 80 | Serial.print("#if (PCINT_USE_PCINT"); 81 | Serial.print(i); 82 | Serial.println(" == true)"); 83 | Serial.print("volatile callback callbackPCINT"); 84 | Serial.print(i); 85 | Serial.println(" = pcint_null_callback;"); 86 | Serial.print("void PinChangeInterruptEventPCINT"); 87 | Serial.print(i); 88 | Serial.println("(void){"); 89 | Serial.print(" callbackPCINT"); 90 | Serial.print(i); 91 | Serial.println("();"); 92 | Serial.println("}"); 93 | Serial.println("#endif"); 94 | } 95 | */ 96 | #if (PCINT_USE_PCINT0 == true) 97 | volatile callback callbackPCINT0 = pcint_null_callback; 98 | void PinChangeInterruptEventPCINT0(void) { 99 | callbackPCINT0(); 100 | } 101 | #endif 102 | #if (PCINT_USE_PCINT1 == true) 103 | volatile callback callbackPCINT1 = pcint_null_callback; 104 | void PinChangeInterruptEventPCINT1(void) { 105 | callbackPCINT1(); 106 | } 107 | #endif 108 | #if (PCINT_USE_PCINT2 == true) 109 | volatile callback callbackPCINT2 = pcint_null_callback; 110 | void PinChangeInterruptEventPCINT2(void) { 111 | callbackPCINT2(); 112 | } 113 | #endif 114 | #if (PCINT_USE_PCINT3 == true) 115 | volatile callback callbackPCINT3 = pcint_null_callback; 116 | void PinChangeInterruptEventPCINT3(void) { 117 | callbackPCINT3(); 118 | } 119 | #endif 120 | #if (PCINT_USE_PCINT4 == true) 121 | volatile callback callbackPCINT4 = pcint_null_callback; 122 | void PinChangeInterruptEventPCINT4(void) { 123 | callbackPCINT4(); 124 | } 125 | #endif 126 | #if (PCINT_USE_PCINT5 == true) 127 | volatile callback callbackPCINT5 = pcint_null_callback; 128 | void PinChangeInterruptEventPCINT5(void) { 129 | callbackPCINT5(); 130 | } 131 | #endif 132 | #if (PCINT_USE_PCINT6 == true) 133 | volatile callback callbackPCINT6 = pcint_null_callback; 134 | void PinChangeInterruptEventPCINT6(void) { 135 | callbackPCINT6(); 136 | } 137 | #endif 138 | #if (PCINT_USE_PCINT7 == true) 139 | volatile callback callbackPCINT7 = pcint_null_callback; 140 | void PinChangeInterruptEventPCINT7(void) { 141 | callbackPCINT7(); 142 | } 143 | #endif 144 | 145 | #endif // PCINT_API 146 | 147 | #endif // PCINT_USE_PORT0 148 | 149 | #endif // PCINT_INCLUDE_FROM_CPP 150 | -------------------------------------------------------------------------------- /OpenSourceLights/src/OSL_PinChangeInterrupt/PinChangeInterrupt1.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2014-2015 NicoHood 3 | See the readme for credit to other people. 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 | #include "PinChangeInterrupt.h" 25 | 26 | //================================================================================ 27 | // Interrupt Handler 28 | //================================================================================ 29 | 30 | // prevent compilation twice if included from the .cpp to force compile all ISRs 31 | #if defined(PCINT_ALINKAGE) && defined(PCINT_COMPILE_ENABLED_ISR) && defined(PCINT_INCLUDE_FROM_CPP) \ 32 | || !defined(PCINT_ALINKAGE) || !defined(PCINT_COMPILE_ENABLED_ISR) 33 | 34 | #if (PCINT_USE_PORT1 == true) 35 | 36 | void attachPinChangeInterrupt1(void) { 37 | // fake function to make the IDE link this file 38 | } 39 | 40 | ISR(PCINT1_vect) { 41 | // get the new and old pin states for port 42 | uint8_t newPort = PCINT_INPUT_PORT1; 43 | 44 | // compare with the old value to detect a rising or falling 45 | uint8_t arrayPos = getArrayPosPCINT(1); 46 | uint8_t change = newPort ^ oldPorts[arrayPos]; 47 | uint8_t rising = change & newPort; 48 | uint8_t falling = change & oldPorts[arrayPos]; 49 | 50 | // check which pins are triggered, compared with the settings 51 | uint8_t risingTrigger = rising & risingPorts[arrayPos]; 52 | uint8_t fallingTrigger = falling & fallingPorts[arrayPos]; 53 | uint8_t trigger = risingTrigger | fallingTrigger; 54 | 55 | // save the new state for next comparison 56 | oldPorts[arrayPos] = newPort; 57 | 58 | // Execute all functions that should be triggered 59 | // This way we can exclude a single function 60 | // and the calling is also much faster 61 | // We may also reorder the pins for different priority 62 | #if !defined(PCINT_CALLBACK_PORT1) 63 | PCINT_CALLBACK(0, 8); 64 | PCINT_CALLBACK(1, 9); 65 | PCINT_CALLBACK(2, 10); 66 | PCINT_CALLBACK(3, 11); 67 | PCINT_CALLBACK(4, 12); 68 | PCINT_CALLBACK(5, 13); 69 | PCINT_CALLBACK(6, 14); 70 | PCINT_CALLBACK(7, 15); 71 | #else 72 | PCINT_CALLBACK_PORT1 73 | #endif 74 | } 75 | 76 | #if defined(PCINT_API) 77 | 78 | /* 79 | for (int i = 0; i < 32; i++) { 80 | Serial.print("#if (PCINT_USE_PCINT"); 81 | Serial.print(i); 82 | Serial.println(" == true)"); 83 | Serial.print("volatile callback callbackPCINT"); 84 | Serial.print(i); 85 | Serial.println(" = pcint_null_callback;"); 86 | Serial.print("void PinChangeInterruptEventPCINT"); 87 | Serial.print(i); 88 | Serial.println("(void){"); 89 | Serial.print(" callbackPCINT"); 90 | Serial.print(i); 91 | Serial.println("();"); 92 | Serial.println("}"); 93 | Serial.println("#endif"); 94 | } 95 | */ 96 | #if (PCINT_USE_PCINT8 == true) 97 | volatile callback callbackPCINT8 = pcint_null_callback; 98 | void PinChangeInterruptEventPCINT8(void) { 99 | callbackPCINT8(); 100 | } 101 | #endif 102 | #if (PCINT_USE_PCINT9 == true) 103 | volatile callback callbackPCINT9 = pcint_null_callback; 104 | void PinChangeInterruptEventPCINT9(void) { 105 | callbackPCINT9(); 106 | } 107 | #endif 108 | #if (PCINT_USE_PCINT10 == true) 109 | volatile callback callbackPCINT10 = pcint_null_callback; 110 | void PinChangeInterruptEventPCINT10(void) { 111 | callbackPCINT10(); 112 | } 113 | #endif 114 | #if (PCINT_USE_PCINT11 == true) 115 | volatile callback callbackPCINT11 = pcint_null_callback; 116 | void PinChangeInterruptEventPCINT11(void) { 117 | callbackPCINT11(); 118 | } 119 | #endif 120 | #if (PCINT_USE_PCINT12 == true) 121 | volatile callback callbackPCINT12 = pcint_null_callback; 122 | void PinChangeInterruptEventPCINT12(void) { 123 | callbackPCINT12(); 124 | } 125 | #endif 126 | #if (PCINT_USE_PCINT13 == true) 127 | volatile callback callbackPCINT13 = pcint_null_callback; 128 | void PinChangeInterruptEventPCINT13(void) { 129 | callbackPCINT13(); 130 | } 131 | #endif 132 | #if (PCINT_USE_PCINT14 == true) 133 | volatile callback callbackPCINT14 = pcint_null_callback; 134 | void PinChangeInterruptEventPCINT14(void) { 135 | callbackPCINT14(); 136 | } 137 | #endif 138 | #if (PCINT_USE_PCINT15 == true) 139 | volatile callback callbackPCINT15 = pcint_null_callback; 140 | void PinChangeInterruptEventPCINT15(void) { 141 | callbackPCINT15(); 142 | } 143 | #endif 144 | 145 | #endif // PCINT_API 146 | 147 | #endif // PCINT_USE_PORT1 148 | 149 | #endif // PCINT_INCLUDE_FROM_CPP 150 | -------------------------------------------------------------------------------- /OpenSourceLights/src/OSL_PinChangeInterrupt/PinChangeInterrupt2.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2014-2015 NicoHood 3 | See the readme for credit to other people. 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 | #include "PinChangeInterrupt.h" 25 | 26 | //================================================================================ 27 | // Interrupt Handler 28 | //================================================================================ 29 | 30 | // prevent compilation twice if included from the .cpp to force compile all ISRs 31 | #if defined(PCINT_ALINKAGE) && defined(PCINT_COMPILE_ENABLED_ISR) && defined(PCINT_INCLUDE_FROM_CPP) \ 32 | || !defined(PCINT_ALINKAGE) || !defined(PCINT_COMPILE_ENABLED_ISR) 33 | 34 | #if (PCINT_USE_PORT2 == true) 35 | 36 | void attachPinChangeInterrupt2(void) { 37 | // fake function to make the IDE link this file 38 | } 39 | 40 | ISR(PCINT2_vect) { 41 | // get the new and old pin states for port 42 | uint8_t newPort = PCINT_INPUT_PORT2; 43 | 44 | // compare with the old value to detect a rising or falling 45 | uint8_t arrayPos = getArrayPosPCINT(2); 46 | uint8_t change = newPort ^ oldPorts[arrayPos]; 47 | uint8_t rising = change & newPort; 48 | uint8_t falling = change & oldPorts[arrayPos]; 49 | 50 | // check which pins are triggered, compared with the settings 51 | uint8_t risingTrigger = rising & risingPorts[arrayPos]; 52 | uint8_t fallingTrigger = falling & fallingPorts[arrayPos]; 53 | uint8_t trigger = risingTrigger | fallingTrigger; 54 | 55 | // save the new state for next comparison 56 | oldPorts[arrayPos] = newPort; 57 | 58 | // Execute all functions that should be triggered 59 | // This way we can exclude a single function 60 | // and the calling is also much faster 61 | // We may also reorder the pins for different priority 62 | #if !defined(PCINT_CALLBACK_PORT2) 63 | PCINT_CALLBACK(0, 16); 64 | PCINT_CALLBACK(1, 17); 65 | PCINT_CALLBACK(2, 18); 66 | PCINT_CALLBACK(3, 19); 67 | PCINT_CALLBACK(4, 20); 68 | PCINT_CALLBACK(5, 21); 69 | PCINT_CALLBACK(6, 22); 70 | PCINT_CALLBACK(7, 23); 71 | #else 72 | PCINT_CALLBACK_PORT2 73 | #endif 74 | } 75 | 76 | #if defined(PCINT_API) 77 | 78 | /* 79 | for (int i = 0; i < 32; i++) { 80 | Serial.print("#if (PCINT_USE_PCINT"); 81 | Serial.print(i); 82 | Serial.println(" == true)"); 83 | Serial.print("volatile callback callbackPCINT"); 84 | Serial.print(i); 85 | Serial.println(" = pcint_null_callback;"); 86 | Serial.print("void PinChangeInterruptEventPCINT"); 87 | Serial.print(i); 88 | Serial.println("(void){"); 89 | Serial.print(" callbackPCINT"); 90 | Serial.print(i); 91 | Serial.println("();"); 92 | Serial.println("}"); 93 | Serial.println("#endif"); 94 | } 95 | */ 96 | #if (PCINT_USE_PCINT16 == true) 97 | volatile callback callbackPCINT16 = pcint_null_callback; 98 | void PinChangeInterruptEventPCINT16(void) { 99 | callbackPCINT16(); 100 | } 101 | #endif 102 | #if (PCINT_USE_PCINT17 == true) 103 | volatile callback callbackPCINT17 = pcint_null_callback; 104 | void PinChangeInterruptEventPCINT17(void) { 105 | callbackPCINT17(); 106 | } 107 | #endif 108 | #if (PCINT_USE_PCINT18 == true) 109 | volatile callback callbackPCINT18 = pcint_null_callback; 110 | void PinChangeInterruptEventPCINT18(void) { 111 | callbackPCINT18(); 112 | } 113 | #endif 114 | #if (PCINT_USE_PCINT19 == true) 115 | volatile callback callbackPCINT19 = pcint_null_callback; 116 | void PinChangeInterruptEventPCINT19(void) { 117 | callbackPCINT19(); 118 | } 119 | #endif 120 | #if (PCINT_USE_PCINT20 == true) 121 | volatile callback callbackPCINT20 = pcint_null_callback; 122 | void PinChangeInterruptEventPCINT20(void) { 123 | callbackPCINT20(); 124 | } 125 | #endif 126 | #if (PCINT_USE_PCINT21 == true) 127 | volatile callback callbackPCINT21 = pcint_null_callback; 128 | void PinChangeInterruptEventPCINT21(void) { 129 | callbackPCINT21(); 130 | } 131 | #endif 132 | #if (PCINT_USE_PCINT22 == true) 133 | volatile callback callbackPCINT22 = pcint_null_callback; 134 | void PinChangeInterruptEventPCINT22(void) { 135 | callbackPCINT22(); 136 | } 137 | #endif 138 | #if (PCINT_USE_PCINT23 == true) 139 | volatile callback callbackPCINT23 = pcint_null_callback; 140 | void PinChangeInterruptEventPCINT23(void) { 141 | callbackPCINT23(); 142 | } 143 | #endif 144 | 145 | #endif // PCINT_API 146 | 147 | #endif // PCINT_USE_PORT2 148 | 149 | #endif // PCINT_INCLUDE_FROM_CPP -------------------------------------------------------------------------------- /OpenSourceLights/src/OSL_PinChangeInterrupt/PinChangeInterrupt3.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2014-2015 NicoHood 3 | See the readme for credit to other people. 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 | #include "PinChangeInterrupt.h" 25 | 26 | //================================================================================ 27 | // Interrupt Handler 28 | //================================================================================ 29 | 30 | // prevent compilation twice if included from the .cpp to force compile all ISRs 31 | #if defined(PCINT_ALINKAGE) && defined(PCINT_COMPILE_ENABLED_ISR) && defined(PCINT_INCLUDE_FROM_CPP) \ 32 | || !defined(PCINT_ALINKAGE) || !defined(PCINT_COMPILE_ENABLED_ISR) 33 | 34 | #if (PCINT_USE_PORT3 == true) 35 | 36 | void attachPinChangeInterrupt3(void) { 37 | // fake function to make the IDE link this file 38 | } 39 | 40 | ISR(PCINT3_vect) { 41 | // get the new and old pin states for port 42 | uint8_t newPort = PCINT_INPUT_PORT3; 43 | 44 | // compare with the old value to detect a rising or falling 45 | uint8_t arrayPos = getArrayPosPCINT(3); 46 | uint8_t change = newPort ^ oldPorts[arrayPos]; 47 | uint8_t rising = change & newPort; 48 | uint8_t falling = change & oldPorts[arrayPos]; 49 | 50 | // check which pins are triggered, compared with the settings 51 | uint8_t risingTrigger = rising & risingPorts[arrayPos]; 52 | uint8_t fallingTrigger = falling & fallingPorts[arrayPos]; 53 | uint8_t trigger = risingTrigger | fallingTrigger; 54 | 55 | // save the new state for next comparison 56 | oldPorts[arrayPos] = newPort; 57 | 58 | // Execute all functions that should be triggered 59 | // This way we can exclude a single function 60 | // and the calling is also much faster 61 | // We may also reorder the pins for different priority 62 | #if !defined(PCINT_CALLBACK_PORT3) 63 | PCINT_CALLBACK(0, 24); 64 | PCINT_CALLBACK(1, 25); 65 | PCINT_CALLBACK(2, 26); 66 | PCINT_CALLBACK(3, 27); 67 | PCINT_CALLBACK(4, 28); 68 | PCINT_CALLBACK(5, 29); 69 | PCINT_CALLBACK(6, 30); 70 | PCINT_CALLBACK(7, 31); 71 | #else 72 | PCINT_CALLBACK_PORT3 73 | #endif 74 | } 75 | 76 | #if defined(PCINT_API) 77 | 78 | /* 79 | for (int i = 0; i < 32; i++) { 80 | Serial.print("#if (PCINT_USE_PCINT"); 81 | Serial.print(i); 82 | Serial.println(" == true)"); 83 | Serial.print("volatile callback callbackPCINT"); 84 | Serial.print(i); 85 | Serial.println(" = pcint_null_callback;"); 86 | Serial.print("void PinChangeInterruptEventPCINT"); 87 | Serial.print(i); 88 | Serial.println("(void){"); 89 | Serial.print(" callbackPCINT"); 90 | Serial.print(i); 91 | Serial.println("();"); 92 | Serial.println("}"); 93 | Serial.println("#endif"); 94 | } 95 | */ 96 | #if (PCINT_USE_PCINT24 == true) 97 | volatile callback callbackPCINT24 = pcint_null_callback; 98 | void PinChangeInterruptEventPCINT24(void) { 99 | callbackPCINT24(); 100 | } 101 | #endif 102 | #if (PCINT_USE_PCINT25 == true) 103 | volatile callback callbackPCINT25 = pcint_null_callback; 104 | void PinChangeInterruptEventPCINT25(void) { 105 | callbackPCINT25(); 106 | } 107 | #endif 108 | #if (PCINT_USE_PCINT26 == true) 109 | volatile callback callbackPCINT26 = pcint_null_callback; 110 | void PinChangeInterruptEventPCINT26(void) { 111 | callbackPCINT26(); 112 | } 113 | #endif 114 | #if (PCINT_USE_PCINT27 == true) 115 | volatile callback callbackPCINT27 = pcint_null_callback; 116 | void PinChangeInterruptEventPCINT27(void) { 117 | callbackPCINT27(); 118 | } 119 | #endif 120 | #if (PCINT_USE_PCINT28 == true) 121 | volatile callback callbackPCINT28 = pcint_null_callback; 122 | void PinChangeInterruptEventPCINT28(void) { 123 | callbackPCINT28(); 124 | } 125 | #endif 126 | #if (PCINT_USE_PCINT29 == true) 127 | volatile callback callbackPCINT29 = pcint_null_callback; 128 | void PinChangeInterruptEventPCINT29(void) { 129 | callbackPCINT29(); 130 | } 131 | #endif 132 | #if (PCINT_USE_PCINT30 == true) 133 | volatile callback callbackPCINT30 = pcint_null_callback; 134 | void PinChangeInterruptEventPCINT30(void) { 135 | callbackPCINT30(); 136 | } 137 | #endif 138 | #if (PCINT_USE_PCINT31 == true) 139 | volatile callback callbackPCINT31 = pcint_null_callback; 140 | void PinChangeInterruptEventPCINT31(void) { 141 | callbackPCINT31(); 142 | } 143 | #endif 144 | 145 | #endif // PCINT_API 146 | 147 | #endif // PCINT_USE_PORT3 148 | 149 | #endif // PCINT_INCLUDE_FROM_CPP -------------------------------------------------------------------------------- /OpenSourceLights/src/OSL_PinChangeInterrupt/PinChangeInterruptBoards.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2014-2015 NicoHood 3 | See the readme for credit to other people. 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 | // include guard 25 | #pragma once 26 | 27 | //================================================================================ 28 | // Board Definitions 29 | //================================================================================ 30 | 31 | // Microcontroller specific definitions 32 | 33 | #if defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__) || defined(__AVR_ATmega88__) 34 | // Arduino Uno 35 | #define PCINT_INPUT_PORT0 PINB 36 | #define PCINT_INPUT_PORT1 PINC 37 | #define PCINT_INPUT_PORT2 PIND 38 | 39 | #elif defined(__AVR_ATmega162__) 40 | 41 | #define PCINT_INPUT_PORT0 PINA 42 | #define PCINT_INPUT_PORT1 PINC 43 | 44 | #elif defined(__AVR_ATmega2560__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega640__) 45 | // Arduino Mega/Mega2560 46 | #define PCINT_INPUT_PORT0 PINB 47 | #define PCINT_INPUT_PORT2 PINK 48 | 49 | // special Port1 case, pins are on 2 HW Pin Ports (E,J) 50 | #if defined(PCINT_ENABLE_PCINT16) // PortE 51 | #if defined(PCINT_ENABLE_PCINT17) || defined(PCINT_ENABLE_PCINT18) \ 52 | || defined(PCINT_ENABLE_PCINT19) || defined(PCINT_ENABLE_PCINT20) \ 53 | || defined(PCINT_ENABLE_PCINT21) || defined(PCINT_ENABLE_PCINT22) \ 54 | || defined(PCINT_ENABLE_PCINT23) // PortJ 55 | // PortE and PortJ selected 56 | #define PCINT_INPUT_PORT1 ((PINE & 0x01) | (PINJ << 1)) 57 | #else 58 | // PortE only selected 59 | #define PCINT_INPUT_PORT1 PINE 60 | #endif 61 | #else 62 | // PortJ only selected 63 | // we still have to do the shift because the attach 64 | // function is not designed for this optimization 65 | #define PCINT_INPUT_PORT1 (PINJ << 1) 66 | #endif 67 | 68 | #elif defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega16U4__) 69 | // Arduino Leonardo/Micro 70 | #define PCINT_INPUT_PORT0 PINB 71 | 72 | #elif defined(__AVR_AT90USB82__) || defined(__AVR_AT90USB162__) || defined(__AVR_ATmega32U2__) || defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega8U2__) 73 | // u2 Series/HoodLoader2 74 | // u2 Series has crappy pin mappings for port 1 75 | #define PCINT_INPUT_PORT0 PINB 76 | #define PCINT_INPUT_PORT1 (((PINC >> 6) & (1 << 0)) | ((PINC >> 4) & (1 << 1)) | ((PINC >> 2) & (1 << 2)) | ((PINC << 1) & (1 << 3)) | ((PIND >> 1) & (1 << 4))) 77 | 78 | #elif defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) 79 | // Attiny x5 80 | #define PCINT_INPUT_PORT0 PINB 81 | 82 | #elif defined(__AVR_ATtiny13__) 83 | // Attiny 13A 84 | #define PCINT_INPUT_PORT0 PINB 85 | #ifndef portInputRegister 86 | #define portInputRegister(P) ( (volatile uint8_t *)(PINB) ) 87 | #endif 88 | 89 | #elif defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) 90 | // Attiny x4 91 | #define PCINT_INPUT_PORT0 PINA 92 | #define PCINT_INPUT_PORT1 PINB 93 | 94 | #elif defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__) 95 | // 1284p and 644p, special 4 port case 96 | #define PCINT_INPUT_PORT0 PINA 97 | #define PCINT_INPUT_PORT1 PINB 98 | #define PCINT_INPUT_PORT2 PINC 99 | #define PCINT_INPUT_PORT3 PIND 100 | 101 | #elif defined(__AVR_ATtinyX41__) || defined(__AVR_ATtiny441__) || defined(__AVR_ATtiny841__) 102 | // Attiny x41 103 | #define PCINT_INPUT_PORT0 PINA 104 | #define PCINT_INPUT_PORT1 PINB 105 | 106 | // "iotn841.h" is missing those definitions, so we add them here 107 | #define PCINT0 0 108 | #define PCINT1 1 109 | #define PCINT2 2 110 | #define PCINT3 3 111 | #define PCINT4 4 112 | #define PCINT5 5 113 | #define PCINT6 6 114 | #define PCINT7 7 115 | 116 | #define PCINT8 0 117 | #define PCINT9 1 118 | #define PCINT10 2 119 | #define PCINT11 3 120 | 121 | #elif defined(__AVR_ATtinyX313__) 122 | // ATtiny x313, PORT A is almost useless, left out here 123 | #define PCINT_INPUT_PORT1 PINB 124 | #define PCINT_INPUT_PORT2 PIND 125 | 126 | #else // Microcontroller not supported 127 | #error PinChangeInterrupt library does not support this MCU. 128 | #endif 129 | 130 | //================================================================================ 131 | // Add missing definitions 132 | //================================================================================ 133 | 134 | // add fakes if ports are not used 135 | #ifndef PCINT_INPUT_PORT0 136 | #define PCINT_INPUT_PORT0 0 137 | #else 138 | #define PCINT_INPUT_PORT0_USED 139 | #endif 140 | #ifndef PCINT_INPUT_PORT1 141 | #define PCINT_INPUT_PORT1 0 142 | #else 143 | #define PCINT_INPUT_PORT1_USED 144 | #endif 145 | #ifndef PCINT_INPUT_PORT2 146 | #define PCINT_INPUT_PORT2 0 147 | #else 148 | #define PCINT_INPUT_PORT2_USED 149 | #endif 150 | #ifndef PCINT_INPUT_PORT3 151 | #define PCINT_INPUT_PORT3 0 152 | #else 153 | #define PCINT_INPUT_PORT3_USED 154 | #endif 155 | -------------------------------------------------------------------------------- /OpenSourceLights/src/OSL_PinChangeInterrupt/PinChangeInterruptSettings.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2014-2015 NicoHood 3 | See the readme for credit to other people. 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 | // include guard 25 | #pragma once 26 | 27 | //================================================================================ 28 | // General Settings 29 | //================================================================================ 30 | 31 | /* Settings to de/activate ports/pins 32 | This will save you flash and ram because the arrays 33 | are managed dynamically with the definitions below. 34 | Make sure you still have all needed ports activated. 35 | Each deactivated port saves 3 bytes of ram. 36 | If you deactivate the whole port, 37 | you dont need to deactivate the pins. 38 | Same for the port if you deactivate all 8 pins. 39 | You dont have to deactivate pins/ports that dont exist. 40 | That is done by the macros. */ 41 | 42 | #ifndef PCINT_ENABLE_MANUAL 43 | 44 | #define PCINT_ENABLE_PORT0 45 | #define PCINT_ENABLE_PORT1 46 | #define PCINT_ENABLE_PORT2 47 | #define PCINT_ENABLE_PORT3 48 | 49 | #define PCINT_ENABLE_PCINT0 50 | #define PCINT_ENABLE_PCINT1 51 | #define PCINT_ENABLE_PCINT2 52 | #define PCINT_ENABLE_PCINT3 53 | #define PCINT_ENABLE_PCINT4 54 | #define PCINT_ENABLE_PCINT5 55 | #define PCINT_ENABLE_PCINT6 56 | #define PCINT_ENABLE_PCINT7 57 | #define PCINT_ENABLE_PCINT8 58 | #define PCINT_ENABLE_PCINT9 59 | #define PCINT_ENABLE_PCINT10 60 | #define PCINT_ENABLE_PCINT11 61 | #define PCINT_ENABLE_PCINT12 62 | #define PCINT_ENABLE_PCINT13 63 | #define PCINT_ENABLE_PCINT14 64 | #define PCINT_ENABLE_PCINT15 65 | #define PCINT_ENABLE_PCINT16 66 | #define PCINT_ENABLE_PCINT17 67 | #define PCINT_ENABLE_PCINT18 68 | #define PCINT_ENABLE_PCINT19 69 | #define PCINT_ENABLE_PCINT20 70 | #define PCINT_ENABLE_PCINT21 71 | #define PCINT_ENABLE_PCINT22 72 | #define PCINT_ENABLE_PCINT23 73 | #define PCINT_ENABLE_PCINT24 74 | #define PCINT_ENABLE_PCINT25 75 | #define PCINT_ENABLE_PCINT26 76 | #define PCINT_ENABLE_PCINT27 77 | #define PCINT_ENABLE_PCINT28 78 | #define PCINT_ENABLE_PCINT29 79 | #define PCINT_ENABLE_PCINT30 80 | #define PCINT_ENABLE_PCINT31 81 | 82 | #endif 83 | 84 | #ifdef ARDUINO 85 | // use API with function pointers (better optimized with .a linkage) 86 | #define PCINT_API 87 | 88 | // is the library compiled via .a file? 89 | // see readme for more information 90 | #define PCINT_ALINKAGE 91 | 92 | // force compile all enabled port ISRs (with .a linkage) 93 | //#define PCINT_COMPILE_ENABLED_ISR 94 | 95 | #endif 96 | 97 | //================================================================================ 98 | // Suggested Settings 99 | //================================================================================ 100 | 101 | // Arduino Uno (328) 102 | #if defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__) || defined(__AVR_ATmega88__) 103 | /* Reordering interrupt callbacks priority 104 | Port0 has SPI on higher pins, ordering is fine 105 | Port1 has I2C on higher pins, ordering is fine 106 | Port2 has USART and Pin Interrupt on lower pins, 107 | move the priority down 108 | Its more likely the user will use pin 4-7 109 | */ 110 | #if !defined(PCINT_CALLBACK_PORT2) 111 | #define PCINT_CALLBACK_PORT2 \ 112 | PCINT_CALLBACK(4, 20); \ 113 | PCINT_CALLBACK(5, 21); \ 114 | PCINT_CALLBACK(6, 22); \ 115 | PCINT_CALLBACK(7, 23); \ 116 | PCINT_CALLBACK(0, 16); /* USART RX */ \ 117 | PCINT_CALLBACK(1, 17); /* USART TX */ \ 118 | PCINT_CALLBACK(2, 18); /* Pin Interrupt 0 */ \ 119 | PCINT_CALLBACK(3, 19); /* Pin Interrupt 1 */ 120 | #endif 121 | 122 | // deactivate crystal and reset pins by default 123 | #if defined(PCINT_ENABLE_PCINT6) 124 | #undef PCINT_ENABLE_PCINT6 // crystal 125 | #endif 126 | #if defined(PCINT_ENABLE_PCINT7) 127 | #undef PCINT_ENABLE_PCINT7 // crystal 128 | #endif 129 | #if defined(PCINT_ENABLE_PCINT14) 130 | #undef PCINT_ENABLE_PCINT14 // reset 131 | #endif 132 | #endif 133 | 134 | // Arduino Mega (2560) 135 | #if defined(ARDUINO_AVR_MEGA2560) || defined(ARDUINO_AVR_MEGA) 136 | /* Port1 is structured a bit more complicated 137 | Also only 3 pins are connected on standard boards 138 | Seeeduino Mega has these pins optional! 139 | Disabling Port1 gives more speed and uses less flash 140 | Pins: 0(RX0), 14(TX3), 15(RX3) */ 141 | #if defined(PCINT_ENABLE_PORT1) 142 | #undef PCINT_ENABLE_PORT1 // better performence 143 | #endif 144 | 145 | /* Reordering interrupt callbacks priority 146 | Port2 has SPI on lower pins, move the priority down 147 | Its more likely the user will use pin 10-13 148 | Port1 by default deactivated, ordering is fine 149 | Port2 only has ADCs, ordering is fine 150 | */ 151 | #if !defined(PCINT_CALLBACK_PORT0) 152 | #define PCINT_CALLBACK_PORT0 \ 153 | PCINT_CALLBACK(4, 4); \ 154 | PCINT_CALLBACK(5, 5); \ 155 | PCINT_CALLBACK(6, 6); \ 156 | PCINT_CALLBACK(7, 7); \ 157 | PCINT_CALLBACK(0, 0); /* SPI SS */ \ 158 | PCINT_CALLBACK(1, 1); /* SPI SCK */ \ 159 | PCINT_CALLBACK(2, 2); /* SPI MISO */ \ 160 | PCINT_CALLBACK(3, 3); /* SPI MOSI */ 161 | #endif 162 | #endif 163 | 164 | // Arduino Leonardo/Micro (32u4) 165 | #if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega16U4__) 166 | /* Reordering interrupt callbacks priority 167 | Port0 has SPI on lower pins, move the priority down 168 | Its more likely the user will use pin 8-11 */ 169 | #if !defined(PCINT_CALLBACK_PORT0) 170 | #define PCINT_CALLBACK_PORT0 \ 171 | PCINT_CALLBACK(4, 4); \ 172 | PCINT_CALLBACK(5, 5); \ 173 | PCINT_CALLBACK(6, 6); \ 174 | PCINT_CALLBACK(7, 7); \ 175 | PCINT_CALLBACK(0, 0); /* SPI SS / RX LED */ \ 176 | PCINT_CALLBACK(1, 1); /* SPI SCK */ \ 177 | PCINT_CALLBACK(2, 2); /* SPI MISO */ \ 178 | PCINT_CALLBACK(3, 3); /* SPI MOSI */ 179 | #endif 180 | 181 | // RX LED on normal leonardo/micro 182 | #if defined(PCINT_ENABLE_PCINT0) && (defined(ARDUINO_AVR_LEONARDO) || defined(ARDUINO_AVR_MICRO)) 183 | #undef PCINT_ENABLE_PCINT0 184 | #endif 185 | #endif 186 | 187 | // Hoodloader2 (u2 Series) 188 | #if defined(__AVR_AT90USB82__) || defined(__AVR_AT90USB162__) || defined(__AVR_ATmega32U2__) || defined(__AVR_ATmega16U2__) || defined(__AVR_ATmega8U2__) 189 | #if defined(ARDUINO_HOODLOADER2) 190 | // on HoodLoader2 Arduino boards only PB1-7 (port0) is broken out, save this flash 191 | #if defined(PCINT_ENABLE_PORT1) 192 | #undef PCINT_ENABLE_PORT1 193 | #endif 194 | 195 | // SS (PB0) is not connected on normal Arduino boards 196 | #if defined(PCINT_ENABLE_PCINT0) 197 | #undef PCINT_ENABLE_PCINT0 198 | #endif 199 | 200 | /* Reordering interrupt callbacks priority 201 | Port0 has SPI on lower pins, move the priority down 202 | Its more likely the user will use PB4-7 203 | Pretend the User has not soldered the 4 Pinheader 204 | so only do this for non Arduino boards. */ 205 | #else 206 | #if !defined(PCINT_CALLBACK_PORT0) 207 | #define PCINT_CALLBACK_PORT0 \ 208 | PCINT_CALLBACK(4, 4); \ 209 | PCINT_CALLBACK(5, 5); \ 210 | PCINT_CALLBACK(6, 6); \ 211 | PCINT_CALLBACK(7, 7); \ 212 | PCINT_CALLBACK(0, 0); /* SPI SS */ \ 213 | PCINT_CALLBACK(1, 1); /* SPI SCK */ \ 214 | PCINT_CALLBACK(2, 2); /* SPI MISO */ \ 215 | PCINT_CALLBACK(3, 3); /* SPI MOSI */ 216 | #endif 217 | #endif 218 | #endif 219 | 220 | /* Attiny 25/45/85 only has a very few pins 221 | activate all by default 222 | The order is also okay. */ 223 | 224 | #if defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) 225 | // Port1 is connected to reset, crystal and Pin Interrupt 0 226 | // Deactivate it by default 227 | #if defined(PCINT_ENABLE_PORT1) 228 | #undef PCINT_ENABLE_PORT1 229 | #endif 230 | #endif 231 | -------------------------------------------------------------------------------- /OpenSourceLights/src/OSL_PinChangeInterrupt/Readme.md: -------------------------------------------------------------------------------- 1 | PinChangeInterrupt Library 1.2.8 2 | ================================ 3 | 4 | ![Header Picture](header.png) 5 | 6 | PinChangeInterrupt library with a resource friendly implementation (API and LowLevel). 7 | PinChangeInterrupts are different than normal Interrupts. See detail below. 8 | 9 | ##### Features: 10 | * PinChangeInterrupt for a lot of pins 11 | * Rising, Falling or Change detection for every pin separately 12 | * Usable on a lot Arduino compatible boards 13 | * Implementation is fast, compact and resource friendly 14 | * Ports/Pins can be manually deactivated in the Settings file 15 | * API and LowLevel option 16 | * Full Port0-3 support 17 | * .a linkage optimization (Arduino IDE) 18 | 19 | Buy Me A Coffee 20 | 21 | #### Supported pins for PinChangeInterrupt: 22 | See [PCINT pin table](https://github.com/NicoHood/PinChangeInterrupt/#pinchangeinterrupt-table) at the bottom for more details. 23 | 24 | ``` 25 | Arduino Uno/Nano/Mini: All pins are usable 26 | Arduino Mega: 10, 11, 12, 13, 50, 51, 52, 53, A8 (62), A9 (63), A10 (64), 27 | A11 (65), A12 (66), A13 (67), A14 (68), A15 (69) 28 | Arduino Leonardo/Micro: 8, 9, 10, 11, 14 (MISO), 15 (SCK), 16 (MOSI) 29 | HoodLoader2: All (broken out 1-7) pins are usable 30 | Attiny 24/44/84: All pins are usable 31 | Attiny 25/45/85: All pins are usable 32 | Attiny 13: All pins are usable 33 | Attiny 441/841: All pins are usable 34 | ATmega644/ATmega644P/ATmega1284P: All pins are usable 35 | ATmega 162: PORTA and PORTC usable 36 | ``` 37 | 38 | Contact information can be found here: 39 | 40 | www.nicohood.de 41 | 42 | Installation 43 | ============ 44 | 45 | Download the zip, extract and remove the "-master" of the folder. 46 | Install the library [as described here](http://arduino.cc/en/pmwiki.php?n=Guide/Libraries). 47 | 48 | This library can also be used with the [DMBS AVR Library Collection](https://github.com/NicoHood/avr) and a pure makefile. 49 | 50 | How to use 51 | ========== 52 | 53 | It is important that you know at least the basic difference between **PinInterrupts** and **PinChangeInterrupts**. 54 | I will explain the basics of **PinChangeInterrupts** (PCINTs) based on an Arduino Uno. 55 | 56 | On a standard Arduino Uno Pin 2 and 3 have **PinInterrupts**. Those are exclusively for a single pin and can detect RISING, FALLING and CHANGE. 57 | 58 | **PinChangeInterrupts** instead are used for a whole port (they should have better named them PortChangeInterrupts) and can only detect CHANGE for a whole port. 59 | Each pin row (0-7, 8-13, A0-A5) represents a port. If an interrupt (ISR) occurs on one pin of a port 60 | it is still unclear what pin of the port caused this interrupt. Therefore this library saves the state of the whole port and compares with the last state. 61 | This way we can also see if it was a RISING or FALLING edge instead of only knowing the CHANGE. 62 | 63 | A **PinChangeInterrupt** will only be triggered for the attached pins per port. 64 | Meaning if you set PCINT for a pin and another pin on the same port is changing a lot 65 | it will not interrupt your code. 66 | 67 | **PinChangeInterrupts** might be a tiny bit slower and not that reliable because of that detection overhead (talking about micro seconds). 68 | Make sure to not use longer function calls inside the ISR or Serial print. 69 | You have the same issues on normal **PinInterrupts** and interrupts in general. 70 | 71 | The library is coded to get maximum speed and minimum code size. The LowLevel example without the API takes 4uS to enter the interrupt function in the worst case 72 | which is pretty good and might be even better than the **PinInterrupt** code from the official Arduino core due to high optimization. 73 | If you need very precise interrupts you better use **PinInterrupts** without the Arduino IDE at all. 74 | 75 | ### Examples 76 | To see how the code works just check the Led and TickTock example. 77 | The LowLevel example is for advanced users with more optimization and more direct access. 78 | The HowItWorks example shows the basic PinChangeInterrupt setup and decoding routine, similar to the library. 79 | See the notes in the examples about more details. 80 | 81 | An useful "real use" example of the PinChangeInterrupt library can be found here: 82 | https://github.com/NicoHood/IRLremote 83 | 84 | ### API Reference 85 | 86 | ##### Attach a PinChangeInterrupt 87 | ```cpp 88 | // The pin has to be a PCINT number. Use the makro to convert a pin to a PCINT number. 89 | // Enables event functions which need to be defined in the sketch. 90 | // Valid interrupt modes are: RISING, FALLING or CHANGE 91 | attachPinChangeInterrupt(digitalPinToPinChangeInterrupt(pinTick), tick, RISING); 92 | 93 | // You can also input the PCINT number (see table below) 94 | attachPinChangeInterrupt(5, tock, FALLING); 95 | 96 | // PinChangeInterrupt can always be abbreviated with PCINT 97 | attachPCINT(digitalPinToPCINT(pinBlink), blinkLed, CHANGE); 98 | ``` 99 | 100 | ##### Detach a PinChangeInterrupt 101 | ```cpp 102 | // Similar usage as the attachPCINT function. 103 | // Interrupts will no longer occur. 104 | detachPinChangeInterrupt(digitalPinToPinChangeInterrupt(pinTick)); 105 | detachPinChangeInterrupt(5); 106 | detachPCINT(digitalPinToPCINT(pinTock)); 107 | ``` 108 | 109 | ##### Enable/Disable a PinChangeInterrupt 110 | ```cpp 111 | // Similar usage as the attachPCINT function. 112 | // Use this to temporary enable/disable the Interrupt 113 | disablePinChangeInterrupt(digitalPinToPinChangeInterrupt(pinTick)); 114 | disablePinChangeInterrupt(5); 115 | disablePCINT(digitalPinToPCINT(pinBlink)); 116 | 117 | // Enable the PCINT with the old settings again (function + mode) 118 | enablePinChangeInterrupt(digitalPinToPinChangeInterrupt(pinTick)); 119 | enablePinChangeInterrupt(5); 120 | enablePCINT(digitalPinToPCINT(pinBlink)); 121 | ``` 122 | 123 | ##### Get Trigger on mode CHANGE 124 | ```cpp 125 | // Differenciate between RISING and FALLING on mode CHANGE. 126 | // Only use this in the attached interrupt function. 127 | uint8_t trigger = getPinChangeInterruptTrigger(digitalPinToPCINT(pinTick)); 128 | if(trigger == RISING) 129 | // Do something 130 | else if(trigger == FALLING) 131 | // Do something 132 | else 133 | // Wrong usage (trigger == CHANGE) 134 | ``` 135 | 136 | ##### LowLevel API 137 | See [LowLevel example](examples/PinChangeInterrupt_LowLevel/PinChangeInterrupt_LowLevel.ino) for more details. 138 | ```cpp 139 | // Use the attach function as you are used to, just leave out the function name 140 | attachPinChangeInterrupt(interruptBlink, CHANGE); 141 | 142 | // LowLevel function that is called when an interrupt occurs for a specific PCINT. 143 | // It is required to know the exact PCINT number, no Arduino pin number will work here. 144 | void PinChangeInterruptEvent(5)(void) { 145 | // Do something 146 | } 147 | ``` 148 | 149 | PinchangeInterrupt Table 150 | ======================== 151 | Pins with * are not broken out/deactivated by default. 152 | You may activate them in the setting file (advanced). 153 | 154 | Each row section represents a port(0-3). 155 | Not all MCUs have all Ports/Pins physically available. 156 | 157 | #### Official Arduinos 158 | ``` 159 | | PCINT | Uno/Nano/Mini | Mega/2560 | Leonardo/Micro | HL2 (8/16/32u2) | 160 | | ----- | --------------- | -------------- | -------------- | --------------- | 161 | | 0 | 8 (PB0) | 53 SS (PB0) | SS (PB0)* | 0 SS (PB0)* | 162 | | 1 | 9 (PB1) | 52 SCK (PB1) | SCK (PB1) | 1 SCK (PB1) | 163 | | 2 | 10 SS (PB2) | 51 MOSI (PB2) | MOSI (PB2) | 2 MOSI (PB2) | 164 | | 3 | 11 MISO (PB3) | 50 MISO (PB3) | MISO (PB3) | 3 MISO (PB3) | 165 | | 4 | 12 MOSI (PB4) | 10 (PB4) | 8/A8 (PB4) | 4 (PB4) | 166 | | 5 | 13 SCK (PB5) | 11 (PB5) | 9/A9 (PB5) | 5 (PB5) | 167 | | 6 | XTAL1 (PB6)* | 12 (PB6) | 10/A10 (PB6) | 6 (PB6) | 168 | | 7 | XTAL2 (PB7)* | 13 (PB7) | 11 (PB7) | 7 (PB7) | 169 | | ----- | --------------- | -------------- | -------------- | --------------- | 170 | | 8 | A0 (PC0) | 0 RX (PE0)* | | (PC6)* | 171 | | 9 | A1 (PC1) | 15 RX3 (PJ0)* | | (PC5)* | 172 | | 10 | A2 (PC2) | 14 TX3 (PJ1)* | | (PC4)* | 173 | | 11 | A3 (PC3) | NC (PJ2)* | | (PC2)* | 174 | | 12 | A4 SDA (PC4) | NC (PJ3)* | | (PD5)* | 175 | | 13 | A5 SDC (PC5) | NC (PJ4)* | | | 176 | | 14 | RST (PC6)* | NC (PJ5)* | | | 177 | | 15 | | NC (PJ6)* | | | 178 | | ----- | --------------- | -------------- | -------------- | --------------- | 179 | | 16 | 0 RX (PD0) | A8 (PK0) | | | 180 | | 17 | 1 TX (PD1) | A9 (PK1) | | | 181 | | 18 | 2 INT0 (PD2) | A10 (PK2) | | | 182 | | 19 | 3 INT1 (PD3) | A11 (PK3) | | | 183 | | 20 | 4 (PD4) | A12 (PK4) | | | 184 | | 21 | 5 (PD5) | A13 (PK5) | | | 185 | | 22 | 6 (PD6) | A14 (PK6) | | | 186 | | 23 | 7 (PD7) | A15 (PK7) | | | 187 | | ----- | --------------- | -------------- | -------------- | --------------- | 188 | ``` 189 | 190 | #### Atmel Attinys 191 | ``` 192 | | PCINT | Attiny13 | Attiny x4 | Attiny x5 | Attiny x41 | 193 | | ----- | ------------ | --------------- | ------------- | ------------------- | 194 | | 0 | 0 MOSI (PB0) | 0 (PA0) | 0 MOSI (PB0) | A0/D0 (PA0) | 195 | | 1 | 1 MISO (PB1) | 1 (PA1) | 1 MISO (PB1) | A1/D1 (PA1) | 196 | | 2 | 2 SCK (PB2) | 2 (PA2) | 2 SCK (PB2) | A2/D2 (PA2) | 197 | | 3 | 3 (PB3) | 3 (PA3) | 3 XTAL1 (PB3) | A3/D3 (PA3) | 198 | | 4 | 4 (PB4) | 4 SCK (PA4) | 4 XTAL2 (PB4) | A4/D4 (PA4) | 199 | | 5 | 5 RST (PB5) | 5 MISO (PA5) | 5 RST (PB5) | A5/D5 PWM (PA5) | 200 | | 6 | | 6 MOSI (PA6) | | A7/D7 PWM (PA6) | 201 | | 7 | | 7 (PA7) | | A6/D6 PWM (PA7) | 202 | | ----- | ------------ | --------------- | ------------- | ------------------- | 203 | | 8 | | 10 XTAL1 (PB0)* | | A10/D10 XTAL1 (PB0) | 204 | | 9 | | 9 XTAL2 (PB1)* | | A9/D9 XTAL2 (PB1) | 205 | | 10 | | 8 INT0 (PB2)* | | A8/D8 PWM (PB2) | 206 | | 11 | | RST (PB3)* | | RST (PB3) | 207 | | 12 | | | | | 208 | | 13 | | | | | 209 | | 14 | | | | | 210 | | 15 | | | | | 211 | | ----- | ------------ | --------------- | ------------- | ------------------- | 212 | ``` 213 | 214 | #### Other Atmel MCUs 215 | ``` 216 | | PCINT | ATmega644P/1284P | 217 | | ----- | ----------------- | 218 | | 0 | A0/D24 (PA0) | 219 | | 1 | A1/D25 (PA1) | 220 | | 2 | A2/D26 (PA2) | 221 | | 3 | A3/D27 (PA3) | 222 | | 4 | A4/D28 (PA4) | 223 | | 5 | A5/D29 (PA5) | 224 | | 6 | A6/D30 (PA6) | 225 | | 7 | A7/D31 (PA7) | 226 | | ----- | ----------------- | 227 | | 8 | 0 (PB0) | 228 | | 9 | 1 (PB1) | 229 | | 10 | 2 INT2 (PB2) | 230 | | 11 | 3 PWM (PB3) | 231 | | 12 | 4 SS/PWM (PB4) | 232 | | 13 | 5 MOSI/PWM (PB5) | 233 | | 14 | 6 MISO/PWM (PB6) | 234 | | 15 | 7 SCK (PB7) | 235 | | ----- | ----------------- | 236 | | 16 | 16 SCL (PC0) | 237 | | 17 | 17 SDA (PC1) | 238 | | 18 | 18 TCK (PC2) | 239 | | 19 | 19 TMS (PC3) | 240 | | 20 | 20 TDO (PC4) | 241 | | 21 | 21 TDI (PC5) | 242 | | 22 | 22 (PC6) | 243 | | 23 | 23 (PC7) | 244 | | ----- | ----------------- | 245 | | 24 | 8 RX0 (PD0) | 246 | | 25 | 9 TX0 (PD1) | 247 | | 26 | 10 RX1/INT0 (PD2) | 248 | | 27 | 11 TX1/INT1 (PD3) | 249 | | 28 | 12 PWM (PD4) | 250 | | 29 | 13 PWM (PD5) | 251 | | 30 | 14 PWM (PD6) | 252 | | 31 | 15 PWM (PD7) | 253 | | ----- | ----------------- | 254 | ``` 255 | 256 | Developer Information 257 | ===================== 258 | If a PinChangeInterrupt occurs it will determine the triggered pin(s). 259 | The library uses weak callback functions that are called for the triggered pins(s). 260 | This way we can easily skip not triggered pins (I looked at the assembler) and also implement a fast LowLevel version. 261 | 262 | Also the order of the function execution is (normally) ordered from the lower pin number to the higher. 263 | Meaning pin 8 will be checked faster as pin 13 (Arduino Uno). Talking about micro seconds here! You can change the order in the settings. 264 | For example by default pin 0-3 have a low priority order than pin 4-7 (Arduino Uno). Because they are used for Serial and normal PinInterrupts. 265 | I don't expect anyone to use those pins at all with PCINT but at least the priority is lowered compared to the other pins. 266 | 267 | The API takes those weak functions and just overwrites all of them and call the function pointers of the attached functions instead. 268 | This way the function can be changed at runtime and its also easier to integrate into other libraries. 269 | The function pointers take a bit flash though (LowLevel: 1526/18, API: 1790/58 for Led example). 270 | 271 | You can get better performance and less code size if you deactivate the not used pins/ports manually in the settings file. 272 | This way only the needed pins get compiled and the code is optimized by the preprocessor. 273 | For a bit more comfortable/automatic optimization you can [install the library into the core](https://github.com/NicoHood/PinChangeInterrupt/#optional-installation) 274 | to get use of the .a linkage. This way only the used ports get compiled. 275 | So if you only use pins on a single port (eg 8-13) then only this port gets compiled. This only works with the core installation. 276 | 277 | 278 | That's it! I hope you like the library. I tried to make it as simple and small as possible. 279 | Keep in mind that PCINTs are not useful for every project but in most cases 280 | the new PinChangeInterrupts may help you a lot. 281 | 282 | 283 | Version History 284 | =============== 285 | ``` 286 | 1.2.8 Release (22.11.2020) 287 | * Add support for ATmega644 #34 288 | 289 | 1.2.7 Release (07.10.2018) 290 | * Add support for ATmega162 #21 291 | 292 | 1.2.6 Release (10.02.2018) 293 | * Fix makefile compilation problems 294 | 295 | 1.2.5 Release (02.09.2017) 296 | * Fixed makefile compilation 297 | * Added support to disable pcint/port via -DPCINT_DISABLE_PORT0 etc. 298 | * Added ATtinyX313 support 299 | * Fix ATmega1284P 300 | 301 | 1.2.4 Release (16.04.2016) 302 | * Fixed Attinyx4/x5 Issue #8 303 | 304 | 1.2.3 Release (24.12.2015) 305 | * Added Attiny441/841 support 306 | 307 | 1.2.2 Release (05.12.2015) 308 | * Fixed initial value when enabled issue 309 | * Enabled official dot_a_linkage 310 | * Added Attiny13 support Issue #4 311 | * Updated documentation 312 | * Improved detaching function 313 | * Improved attaching and enabling 314 | 315 | 1.2.1 Release (24.05.2015) 316 | * Fix Attiny Issue #1 317 | * Added enable/disable function 318 | * Added getPinChangeInterruptTrigger() function 319 | * Added to Arduino IDE library manager 320 | 321 | 1.2 Release (19.04.2015) 322 | * Added weak interrupt function 323 | * Improved interrupt function calls 324 | * Fixed attach/detach array position when ports are deactivated 325 | * Improved manual PCINT deactivation by user 326 | * Improved definitions for different boards 327 | * HoodLoader2 definition fixes 328 | * Improved speed 329 | * Improved specific boards 330 | * Moved attach function to .cpp file 331 | * Updated examples 332 | * Added API and LowLevel 333 | * Added Port3 support (ATmega644P/ATmega1284P) 334 | * Added PCINT_VERSION definition 335 | 336 | 1.1 Release (06.12.2014) 337 | * Added port deactivation 338 | * Ram usage improvements for AVRs with <3 PCINT ports 339 | 340 | 1.0 Release (04.12.2014) 341 | * Added general PinChangeInterrupt functions 342 | * Added support for most Arduino boards 343 | * Added basic example 344 | * Added an example with IRLremote 345 | ``` 346 | 347 | 348 | License and Copyright 349 | ===================== 350 | If you use this library for any cool project let me know! 351 | 352 | ``` 353 | Copyright (c) 2014-2018 NicoHood 354 | See the readme for credit to other people. 355 | 356 | Permission is hereby granted, free of charge, to any person obtaining a copy 357 | of this software and associated documentation files (the "Software"), to deal 358 | in the Software without restriction, including without limitation the rights 359 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 360 | copies of the Software, and to permit persons to whom the Software is 361 | furnished to do so, subject to the following conditions: 362 | 363 | The above copyright notice and this permission notice shall be included in 364 | all copies or substantial portions of the Software. 365 | 366 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 367 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 368 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 369 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 370 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 371 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 372 | THE SOFTWARE. 373 | ``` 374 | -------------------------------------------------------------------------------- /OpenSourceLights/src/OSL_PinChangeInterrupt/keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map For PinChangeInterrupt 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes (KEYWORD1) 7 | ####################################### 8 | 9 | ####################################### 10 | # Methods and Functions (KEYWORD2) 11 | ####################################### 12 | 13 | attachPinChangeInterrupt KEYWORD2 14 | detachPinChangeInterrupt KEYWORD2 15 | attachPCINT KEYWORD2 16 | detachPCINT KEYWORD2 17 | PinChangeInterruptEvent KEYWORD2 18 | PCINTEvent KEYWORD2 19 | enablePCINT KEYWORD2 20 | enablePinChangeInterrupt KEYWORD2 21 | disablePCINT KEYWORD2 22 | disablePinChangeInterrupt KEYWORD2 23 | getPCINTTrigger KEYWORD2 24 | getPinChangeInterruptTrigger KEYWORD2 25 | 26 | ####################################### 27 | # Instances (KEYWORD2) 28 | ####################################### 29 | 30 | ####################################### 31 | # Constants (LITERAL1) 32 | ####################################### 33 | -------------------------------------------------------------------------------- /OpenSourceLights/src/OSL_PinChangeInterrupt/library.properties: -------------------------------------------------------------------------------- 1 | name=PinChangeInterrupt 2 | version=1.2.8 3 | author=NicoHood 4 | maintainer=NicoHood 5 | sentence=A simple & compact PinChangeInterrupt library for Arduino. 6 | paragraph=PinChangeInterrupt library with a resource friendly implementation (API and LowLevel). PinChangeInterrupts are different than normal Interrupts. See readme for more information. 7 | category=Signal Input/Output 8 | url=https://github.com/NicoHood/PinChangeInterrupt 9 | architectures=avr 10 | dot_a_linkage=true 11 | -------------------------------------------------------------------------------- /OpenSourceLights/src/OSL_Settings/OSL_Settings.cpp: -------------------------------------------------------------------------------- 1 | #include "OSL_Settings.h" 2 | 3 | 4 | 5 | // Function to print out light settings names 6 | const __FlashStringHelper *ptrLightSetting(char setting) 7 | { 8 | if(setting>LAST_LIGHT_SETTING) setting=LS_UNKNOWN; 9 | const __FlashStringHelper *Names[LAST_LIGHT_SETTING+1]={F("Off"), F("On"),F("N/A"),F("Blink"),F("Blink Alt"), 10 | F("Fast Blink"),F("Fast Blink Alt"),F("Soft Blink"), 11 | F("Dim"),F("Fade-off"),F("Fade-on"),F("Xenon"),F("Backfire"), 12 | F("Safety Blink"), F("Safety Blink Alt"), 13 | F("Unknown")}; 14 | return Names[setting]; 15 | }; 16 | 17 | // Same thing, but these are the official capitalized versions 18 | const __FlashStringHelper *ptrLightSettingCap(char setting) 19 | { 20 | if(setting>LAST_LIGHT_SETTING) setting=LS_UNKNOWN; 21 | const __FlashStringHelper *Names[LAST_LIGHT_SETTING+1]={F("OFF"), F("ON"),F("NA"),F("BLINK"),F("BLINK_ALT"), 22 | F("FASTBLINK"),F("FASTBLINK_ALT"),F("SOFTBLINK"), 23 | F("DIM"),F("FADEOFF"),F("FADEON"),F("XENON"),F("BACKFIRE"), 24 | F("SAFETYBLINK"), F("SAFETYBLINK_ALT"), 25 | F("UNKNOWN")}; 26 | return Names[setting]; 27 | }; 28 | 29 | // Function to help us print out actual drive mode names, rather than numbers. 30 | // To use, call something like this: Serial.print(printMode(DriveModeCommand)); 31 | const __FlashStringHelper *printMode(char mode) 32 | { 33 | if(mode>LAST_MODE) mode=UNKNOWN; 34 | const __FlashStringHelper *Names[LAST_MODE+1]={F("UNKNOWN"),F("STOP"),F("FORWARD"),F("REVERSE")}; 35 | return Names[mode]; 36 | }; 37 | 38 | 39 | const __FlashStringHelper *printState(char state) 40 | { 41 | if(state>LAST_STATE) state=State_Unknown; 42 | const __FlashStringHelper *Names[LAST_STATE+1]={F("Pos 1"),F("Pos 2"),F("Pos 3"),F("Pos 4"),F("Pos 5"),F("Forward"), 43 | F("Reverse"),F("Stop"),F("Stop Delay"),F("Brake"),F("Right Turn"), 44 | F("Left Turn"),F("No Turn"),F("Accelerate"),F("Decelerate"),F("Unknown")}; 45 | return Names[state]; 46 | }; 47 | 48 | // Function to help us print out actual radio state names, rather than numbers. 49 | // To use, call something like this: Serial.print(printRadioState(RC_State)); 50 | const __FlashStringHelper *printRadioState(char rcstate) { 51 | if (rcstate>LAST_RC_STATE) rcstate = RC_SIGNAL_UNINITIALIZED; 52 | const __FlashStringHelper *StateNames[LAST_RC_STATE+1]={F("UNINITIALIZED"),F("Acquiring"),F("Connected"),F("Disconnected")}; 53 | return StateNames[rcstate]; 54 | }; -------------------------------------------------------------------------------- /OpenSourceLights/src/OSL_Settings/OSL_Settings.h: -------------------------------------------------------------------------------- 1 | /* OSL_Settings.h Settings file - a header file that defines many of the hardware elements of the OSL board 2 | * Source: https://github.com/OSRCL/OSL_Original 3 | * Authors: Luke Middleton 4 | * 5 | * These values should not need to be modified by general users. 6 | * 7 | */ 8 | 9 | 10 | #ifndef OSL_SETTINGS_H 11 | #define OSL_SETTINGS_H 12 | 13 | #include 14 | 15 | 16 | // ------------------------------------------------------------------------------------------------------------------------------------------------------->> 17 | // OPEN SOURCE LIGHTS (OSL) FIRMWARE VERSION NUMBER 18 | // ------------------------------------------------------------------------------------------------------------------------------------------------------->> 19 | #define FIRMWARE_VERSION "0.7.01" // version. Last update 5/24/2025 20 | 21 | 22 | 23 | // ------------------------------------------------------------------------------------------------------------------------------------------------------->> 24 | // PINS & HARDWARE DEFINITIONS 25 | // ------------------------------------------------------------------------------------------------------------------------------------------------------->> 26 | #define NumLights 8 // How many light outputs do we have on this board 27 | 28 | 29 | 30 | // ------------------------------------------------------------------------------------------------------------------------------------------------------->> 31 | // FIRMWARE DEFINITIONS 32 | // ------------------------------------------------------------------------------------------------------------------------------------------------------->> 33 | // There are 15 possible states a light can be in: 34 | // - Mode 1, Mode 2, Mode 3, Mode 4, Mode 5 (all from Channel3 switch), 35 | // - Forward, Reverse, Stop, Stop Delay, Brake (from Throttle Channel), 36 | // - Right Turn, Left Turn, No Turn (from Turn Channel) 37 | // - Accelerating - special state that occurs on heavy acceleration (from Throttle channel) 38 | // - Decelerating - special state that occurs on heavy deceleration (from Throttle channel) 39 | #define NumStates 15 // Number of possible states 40 | // State definitions 41 | #define Mode1 0 // Channel 3 in 1st position 42 | #define Mode2 1 // Channel 3 in 2nd position 43 | #define Mode3 2 // Channel 3 in 3rd position 44 | #define Mode4 3 // Channel 3 in 4th position 45 | #define Mode5 4 // Channel 3 in 5th position 46 | #define StateFwd 5 // Moving forward 47 | #define StateRev 6 // Moving backwards 48 | #define StateStop 7 // Stopped 49 | #define StateStopDelay 8 // Stopped for a user-defined length of time 50 | #define StateBrake 9 // Braking 51 | #define StateRT 10 // Right turn 52 | #define StateLT 11 // Left turn 53 | #define StateNT 12 // "Neutral" turn, ie, no turn 54 | #define StateAccel 13 // Acceleration 55 | #define StateDecel 14 // Deceleration 56 | #define State_Unknown 15 57 | #define LAST_STATE State_Unknown 58 | const __FlashStringHelper *printState(char state); //Returns a character string that is name of the state 59 | 60 | // For every state, each light output can have the following settings. 61 | // Giving names to numerical values allows the user to easily create their own light setup 62 | #define COUNT_SETTINGS 16 63 | #define OFF 0 64 | #define ON 1 65 | #define NA 2 66 | #define BLINK 3 67 | #define BLINK_ALT 4 68 | #define FASTBLINK 5 69 | #define FASTBLINK_ALT 6 70 | #define SOFTBLINK 7 71 | #define DIM 8 72 | #define FADEOFF 9 73 | #define FADEON 10 74 | #define XENON 11 75 | #define BACKFIRE 12 76 | #define SAFETYBLINK 13 77 | #define SAFETYBLINK_ALT 14 78 | #define LS_UNKNOWN 15 79 | #define LAST_LIGHT_SETTING LS_UNKNOWN 80 | const __FlashStringHelper *ptrLightSetting(char setting); //Returns a character string that is name of the light setting (more friendly name format) 81 | const __FlashStringHelper *ptrLightSettingCap(char setting); //Same thing, but the official capitalized names 82 | 83 | // For debugging, we'd like to print a neat table showing the scheme settings. This array lets us know how many spaces to pad 84 | // after each name. We are looking for a consistent 16 characters, so the padding is 16 - number of characters in name 85 | 86 | const PROGMEM uint8_t _SettingNamesPadding[COUNT_SETTINGS] = 87 | { 13, // OFF 88 | 14, // ON 89 | 14, // NA 90 | 11, // BLINK 91 | 7, // BLINK_ALT 92 | 7, // FASTBLINK 93 | 3, // FASTBLINK_ALT 94 | 7, // SOFTBLINK 95 | 13, // DIM 96 | 9, // FADEOFF 97 | 10, // FADEON 98 | 11, // XENON 99 | 8, // BACKFIRE 100 | 5, // SAFETYBLINK 101 | 1, // SAFETYBLINK_ALT 102 | 9 // UNKNOWN 103 | }; 104 | 105 | 106 | // These are simplifications of the turn channel state. We have the actual command, but this lets us know simply in which direction is the wheel turned 107 | #define RIGHT_TURN 1 108 | #define NO_TURN 0 109 | #define LEFT_TURN -1 110 | 111 | // Drive mode 112 | #define UNKNOWN 0 113 | #define STOP 1 114 | #define FWD 2 115 | #define REV 3 116 | #define LAST_MODE REV 117 | const __FlashStringHelper *printMode(char mode); //Returns a character string that is name of the drive mode. 118 | 119 | 120 | 121 | // ------------------------------------------------------------------------------------------------------------------------------------------------------->> 122 | // RADIO DEFINITIONS 123 | // ------------------------------------------------------------------------------------------------------------------------------------------------------->> 124 | #define NUM_RC_CHANNELS 3 // Number of RC channels we can read 125 | #define PULSE_WIDTH_ABS_MIN 800 // Absolute minimum pulse width considered valid 126 | #define PULSE_WIDTH_ABS_MAX 2200 // Absolute maximum pulse width considered valid 127 | #define PULSE_WIDTH_TYP_MIN 1000 // Typical minimum pulse width 128 | #define PULSE_WIDTH_TYP_MAX 2000 // Typical maximum pulse width 129 | #define PULSE_WIDTH_TYP_CENTER 1500 // Stick centered pulse width 130 | 131 | #define RC_PULSECOUNT_TO_ACQUIRE 5 // How many pulses on each channel to read before considering that channel SIGNAL_SYNCHED 132 | #define RC_TIMEOUT_US 100000UL // How many micro-seconds without a signal from any channel before we go to SIGNAL_LOST. Note a typical RC pulse would arrive once every 20,000 uS 133 | #define RC_TIMEOUT_MS 100 // Here it is again in milliseconds, so RC_TIMEOUT_US / 1000 which is 100 mS which is 1/10th of a second 134 | 135 | #define COMMAND_MAX_FORWARD 100 // We are ultimately going to change the throttle and steering pulses into 136 | #define COMMAND_MAX_REVERSE -100 // a more convenient -100/100 value range 137 | 138 | #define BLINK_RATE_LOST_SIGNAL 50 // How fast should we blink the lights when the radio signal is lost 139 | 140 | // RC state machine 141 | #define RC_SIGNAL_UNINITIALIZED 0 142 | #define RC_SIGNAL_ACQUIRE 1 143 | #define RC_SIGNAL_SYNCHED 2 144 | #define RC_SIGNAL_LOST 3 145 | #define LAST_RC_STATE RC_SIGNAL_LOST 146 | const __FlashStringHelper *printRadioState(char rcstate); //Returns a character string that is name of the radio state. 147 | 148 | // Position defines for Channel 3 switch (can be up to 5 positions) 149 | #define Pos1 0 150 | #define Pos2 1 151 | #define Pos3 2 152 | #define Pos4 3 153 | #define Pos5 4 154 | 155 | // Shelf queen Channel 3 position number 156 | #define ShelfQueenCh3Position 0 157 | 158 | 159 | #define FWD_to_REV_BrakeTime 200 // If DoubleTapReverse = true, we treat the first tap into reverse from forward as a brake command. However, depending on how fast the user moves 160 | // from forward to reverse, and when the radio signal is actually read, OSL may show it as a process from forward, to stop, and then to reverse. 161 | // This define sets the maximum amount of time from the last forward command to a reverse command that we will count as a brake signal on the first 162 | // tap into reverse. Should be small, we don't want the first transition from stop to reverse to show up as a brake command. 163 | 164 | 165 | // ------------------------------------------------------------------------------------------------------------------------------------------------------->> 166 | // PINS 167 | // ------------------------------------------------------------------------------------------------------------------------------------------------------->> 168 | // Note that the six Arduino analog pins can be referred to by numbers 14-19 169 | 170 | // Hardware check pins - the firmware will read the values of these pins to determine the hardware version 171 | #define pin_VCHECK_A 7 // Input - version check pin A 172 | #define pin_VCHECK_B 8 // Input - version check pin B 173 | 174 | // HARDWARE VERSION 1 175 | // --------------------------------------------------------------------------------------------------------------------------------------------------->> 176 | // This includes all original through-hole OSL boards up to and including version v1.7, plus user boards based on that design, which include the 177 | // three SMD boards designed by irun4fundotca, supercaby, and learningarduino 178 | // Radio channels 179 | #define pin_HW1_Throttle 2 // Input - Pin for throttle channel 180 | #define pin_HW1_Steering 17 // Input - Pin for steering channel 181 | #define pin_HW1_Ch3 4 // Input - Pin for channel 3 182 | 183 | // Light outputsHW1_ 184 | #define pin_HW1_Light1 9 // Output - Light 1 185 | #define pin_HW1_Light2 10 // Output - Light 2 186 | #define pin_HW1_Light3 11 // Output - Light 3 187 | #define pin_HW1_Light4 6 // Output - Light 4 188 | #define pin_HW1_Light5 5 // Output - Light 5 189 | #define pin_HW1_Light6 3 // Output - Light 6 190 | #define pin_HW1_Light7 15 // Output - Light 7 191 | #define pin_HW1_Light8 16 // Output - Light 8 192 | 193 | // Other 194 | #define pin_HW1_GreenLED 18 // Output - on-board Green LED (this is the same as saying pin A4) 195 | #define pin_HW1_RedLED 19 // Output - on-board Red LED (this is the same as saying pin A5) 196 | #define pin_HW1_SetupButton 14 // Input - on-board push button (this is the same as saying pin A0) 197 | 198 | 199 | // HARDWARE VERSION 2 200 | // --------------------------------------------------------------------------------------------------------------------------------------------------->> 201 | // For a future OSL board design 202 | // Radio channels 203 | #define pin_HW2_Throttle 2 // Input - Pin for throttle channel 204 | #define pin_HW2_Steering 17 // Input - Pin for steering channel 205 | #define pin_HW2_Ch3 4 // Input - Pin for channel 3 206 | 207 | // Light outputsHW2_ 208 | #define pin_HW2_Light1 9 // Output - Light 1 209 | #define pin_HW2_Light2 10 // Output - Light 2 210 | #define pin_HW2_Light3 11 // Output - Light 3 211 | #define pin_HW2_Light4 6 // Output - Light 4 212 | #define pin_HW2_Light5 5 // Output - Light 5 213 | #define pin_HW2_Light6 3 // Output - Light 6 214 | #define pin_HW2_Light7 15 // Output - Light 7 215 | #define pin_HW2_Light8 16 // Output - Light 8 216 | 217 | // Other 218 | #define pin_HW2_GreenLED 18 // Output - on-board Green LED (this is the same as saying pin A4) 219 | #define pin_HW2_RedLED 19 // Output - on-board Red LED (this is the same as saying pin A5) 220 | #define pin_HW2_SetupButton 14 // Input - on-board push button (this is the same as saying pin A0) 221 | 222 | 223 | 224 | // ------------------------------------------------------------------------------------------------------------------------------------------------------->> 225 | // EEPROM macros 226 | // ------------------------------------------------------------------------------------------------------------------------------------------------------->> 227 | #define eeprom_read_to(dst_p, eeprom_field, dst_size) eeprom_read_block(dst_p, (void *)offsetof(__eeprom_data, eeprom_field), MIN(dst_size, sizeof((__eeprom_data*)0)->eeprom_field)) 228 | #define eeprom_read(dst, eeprom_field) eeprom_read_to(&dst, eeprom_field, sizeof(dst)) 229 | #define eeprom_write_from(src_p, eeprom_field, src_size) eeprom_write_block(src_p, (void *)offsetof(__eeprom_data, eeprom_field), MIN(src_size, sizeof((__eeprom_data*)0)->eeprom_field)) 230 | #define eeprom_write(src, eeprom_field) { typeof(src) x = src; eeprom_write_from(&x, eeprom_field, sizeof(x)); } 231 | #define MIN(x,y) ( x > y ? y : x ) 232 | #define MAX(x,y) ( x > y ? x : y ) 233 | 234 | 235 | 236 | // ------------------------------------------------------------------------------------------------------------------------------------------------------->> 237 | // SIMPLE TIMER 238 | // ------------------------------------------------------------------------------------------------------------------------------------------------------->> 239 | // We use the OSL_SimpleTimer class for convenient timing functions throughout the project, it is a modified and improved version 240 | // of SimpleTimer: http://playground.arduino.cc/Code/SimpleTimer 241 | // The class needs to know how many simultaneous timers may be active at any one time. We don't want this number too low or operation will be eratic, 242 | // but setting it too high will waste RAM. Each additional slot costs 19 bytes of global RAM. 243 | // Timers used by this project: 244 | // - Turn from start continue (used for both forward and reverse, but will not occur at the same time) = 1 timer (no timer ID) 245 | // - BackfireTimerID, OvertakeTimerID - by definition will never occur at the same time = 1 timer 246 | // - CSM_TurnTimerID - used to enter change-scheme-mode, but not again while in it = 1 timer 247 | // - CSM_BlinkOffTimerID - used during change-scheme-mode = 1 timer 248 | // - Blink all lights to indicate the currently-selected scheme in change-scheme-mode = 1 timer 249 | // - RxSignalLostTimerID - used to flash the failsafe lights = 1 timer 250 | // - StartWaiting (time's up) timer - used during radio setup only, otherwise assigned to one of the above IDs = 1 timer 251 | // That makes 7 total, but the maximum that should ever be active at once is really only about 2. We give ourselves 5 to have plenty of 252 | // leeway, but if you need to save a few bytes you can drop this number. 253 | 254 | #define MAX_SIMPLETIMER_SLOTS 5 255 | 256 | 257 | 258 | // ------------------------------------------------------------------------------------------------------------------------------------------------------->> 259 | // SERIAL 260 | // ------------------------------------------------------------------------------------------------------------------------------------------------> 261 | #define BaudRate 38400 // This is the default baud rate for communication with the computer. 262 | 263 | 264 | 265 | #endif 266 | 267 | 268 | -------------------------------------------------------------------------------- /OpenSourceLights/src/OSL_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 | NumLights LITERAL1 24 | NumStates LITERAL1 25 | Mode1 LITERAL1 26 | Mode2 LITERAL1 27 | Mode3 LITERAL1 28 | Mode4 LITERAL1 29 | Mode5 LITERAL1 30 | StateFwd LITERAL1 31 | StateRev LITERAL1 32 | StateStop LITERAL1 33 | StateStopDelay LITERAL1 34 | StateBrake LITERAL1 35 | StateRT LITERAL1 36 | StateLT LITERAL1 37 | StateNT LITERAL1 38 | StateAccel LITERAL1 39 | StateDecel LITERAL1 40 | State_Unknown LITERAL1 41 | OFF LITERAL1 42 | ON LITERAL1 43 | NA LITERAL1 44 | BLINK LITERAL1 45 | FASTBLINK LITERAL1 46 | SOFTBLINK LITERAL1 47 | DIM LITERAL1 48 | FADEOFF LITERAL1 49 | FADEON LITERAL1 50 | XENON LITERAL1 51 | BACKFIRE LITERAL1 52 | LS_UNKNOWN LITERAL1 53 | RIGHT_TURN LITERAL1 54 | NO_TURN LITERAL1 55 | LEFT_TURN LITERAL1 56 | STOP LITERAL1 57 | FWD LITERAL1 58 | REV LITERAL1 59 | NUM_RC_CHANNELS LITERAL1 60 | PULSE_WIDTH_ABS_MIN LITERAL1 61 | PULSE_WIDTH_ABS_MAX LITERAL1 62 | PULSE_WIDTH_TYP_MIN LITERAL1 63 | UPLSE_WIDTH_TYP_MAX LITERAL1 64 | PULSE_WIDTH_TYP_CENTER LITERAL1 65 | RC_PULSECOUNT_TO_ACQUIRE LITERAL1 66 | RC_TIMEOUT_US LITERAL1 67 | RC_TIMEOUT_MS LITERAL1 68 | COMMAND_MAX_FORWARD LITERAL1 69 | COMMAND_MAX_REVERSE LITERAL1 70 | RC_SIGNA_UNINITIALIZED LITERAL1 71 | RC_SIGNAL_ACQUIRE LITERAL1 72 | RC_SIGNAL_SYNCHED LITERAL1 73 | RC_SIGNAL_LOST LITERAL1 74 | Pos1 LITERAL1 75 | Pos2 LITERAL1 76 | Pos3 LITERAL1 77 | Pos4 LITERAL1 78 | Pos5 LITERAL1 79 | ShelfQueenCh3Position LITERAL1 80 | FWD_to_REV_BrakeTime LITERAL1 81 | pin_VCHECK_A LITERAL1 82 | pin_VCHECK_B LITERAL1 83 | MAX_SIMPLETIMER_SLOTS LITERAL1 84 | -------------------------------------------------------------------------------- /OpenSourceLights/src/OSL_SimpleTimer/OSL_SimpleTimer.cpp: -------------------------------------------------------------------------------- 1 | /* OSL_SimpleTimer.h Simple Timer library - for handling timed events without using delays 2 | * Source: https://github.com/OSRCL 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 OSL_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 "OSL_SimpleTimer.h" 32 | 33 | 34 | static inline unsigned long elapsed() { return millis(); } 35 | 36 | 37 | OSL_SimpleTimer::OSL_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 OSL_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 OSL_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 OSL_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 OSL_SimpleTimer::setInterval(long d, timer_callback f) { 177 | return setTimer(d, f, RUN_FOREVER); 178 | } 179 | 180 | 181 | int OSL_SimpleTimer::setTimeout(long d, timer_callback f) { 182 | return setTimer(d, f, RUN_ONCE); 183 | } 184 | 185 | 186 | void OSL_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 OSL_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 OSL_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 OSL_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 OSL_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 OSL_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 OSL_SimpleTimer::getNumTimers() { 291 | return numTimers; 292 | } 293 | 294 | 295 | int OSL_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 | } 306 | -------------------------------------------------------------------------------- /OpenSourceLights/src/OSL_SimpleTimer/OSL_SimpleTimer.h: -------------------------------------------------------------------------------- 1 | /* OSL_SimpleTimer.h Simple Timer library - for handling timed events without using delays 2 | * Source: https://github.com/OSRCL 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 OSL_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 OSL_SimpleTimer_H 32 | #define OSL_SimpleTimer_H 33 | 34 | #include 35 | #include "../OSL_Settings/OSL_Settings.h" 36 | 37 | 38 | // Note: MAX_SIMPLETIMER_SLOTS is defined in OSL_Settings.h 39 | 40 | 41 | typedef void (*timer_callback)(void); 42 | 43 | class OSL_SimpleTimer { 44 | 45 | public: 46 | // maximum number of timers 47 | 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. 48 | 49 | // setTimer() constants 50 | const static int RUN_FOREVER = 0; 51 | const static int RUN_ONCE = 1; 52 | 53 | // constructor 54 | OSL_SimpleTimer(); 55 | 56 | // this function must be called inside loop() 57 | void run(); 58 | 59 | // call function f every d milliseconds 60 | int setInterval(long d, timer_callback f); 61 | 62 | // call function f once after d milliseconds 63 | int setTimeout(long d, timer_callback f); 64 | 65 | // call function f every d milliseconds for n times 66 | int setTimer(long d, timer_callback f, int n); 67 | 68 | // destroy the specified timer 69 | void deleteTimer(int ID); 70 | 71 | // restart the specified timer 72 | void restartTimer(int ID); 73 | 74 | // returns true if the specified timer is enabled 75 | boolean isEnabled(int ID); 76 | 77 | // enables the specified timer 78 | void enable(int ID); 79 | 80 | // disables the specified timer 81 | void disable(int ID); 82 | 83 | // enables the specified timer if it's currently disabled, 84 | // and vice-versa 85 | void toggle(int ID); 86 | 87 | // returns the number of used timers 88 | int getNumTimers(); 89 | 90 | // returns the number of available timers 91 | int getNumAvailableTimers() { return MAX_TIMERS - numTimers; }; 92 | 93 | // Gets the timer number (0-MAX_TIMERS) by ID 94 | int getTimerNum(int ID); 95 | 96 | private: 97 | // deferred call constants 98 | const static int DEFCALL_DONTRUN = 0; // don't call the callback function 99 | const static int DEFCALL_RUNONLY = 1; // call the callback function but don't delete the timer 100 | const static int DEFCALL_RUNANDDEL = 2; // call the callback function and delete the timer 101 | 102 | // find the first available slot 103 | int findFirstFreeSlot(); 104 | 105 | // value returned by the millis() function 106 | // in the previous run() call 107 | unsigned long prev_millis[MAX_TIMERS]; 108 | 109 | // pointers to the callback functions 110 | timer_callback callbacks[MAX_TIMERS]; 111 | 112 | // delay values 113 | unsigned long delays[MAX_TIMERS]; 114 | 115 | // number of runs to be executed for each timer 116 | int maxNumRuns[MAX_TIMERS]; 117 | 118 | // number of executed runs for each timer 119 | int numRuns[MAX_TIMERS]; 120 | 121 | // which timers are enabled 122 | boolean enabled[MAX_TIMERS]; 123 | 124 | // deferred function call (sort of) - N.B.: this array is only used in run() 125 | int toBeCalled[MAX_TIMERS]; 126 | 127 | // IDs for each timer (not equal to the timer number) 128 | int timerID[MAX_TIMERS]; 129 | int NextID; 130 | 131 | // actual number of timers in use 132 | int numTimers; 133 | }; 134 | 135 | #endif 136 | -------------------------------------------------------------------------------- /OpenSourceLights/src/OSL_SimpleTimer/keywords.txt: -------------------------------------------------------------------------------- 1 | OSL_SimpleTimer KEYWORD1 2 | run KEYWORD2 3 | setInterval KEYWORD2 4 | setTimer KEYWORD2 5 | deleteTimer KEYWORD2 6 | restartTimer KEYWORD2 7 | isEnabled KEYWORD2 8 | enable KEYWORD2 9 | disable KEYWORD2 10 | toggle KEYWORD2 11 | getNumTimers KEYWORD2 12 | getNumAvailableTimers KEYWORD2 13 | getTimerNum KEYWORD2 14 | -------------------------------------------------------------------------------- /OpenSourceLights/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 | -------------------------------------------------------------------------------- /OpenSourceLights/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 | -------------------------------------------------------------------------------- /OpenSourceLights/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 | -------------------------------------------------------------------------------- /OpenSourceLights/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 | -------------------------------------------------------------------------------- /OpenSourceLights/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 | -------------------------------------------------------------------------------- /OpenSourceLights/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 Source RC Lights 2 | (aka, "OSL") 3 | 4 | ![OSL Board](https://openpanzer.org/images/osl/OSL_gh.jpg "Assembled OSL Board") 5 | 6 | **--> [INSTRUCTIONS & DOCUMENTATION AVAILABLE HERE](https://openpanzer.org/wiki/doku.php?id=wiki:otherprojects:osl) <--** 7 | 8 | OSL is an Arduino-based, open source project for controlling lights in RC cars and trucks. It uses an ATmega328 as the processor and has 8 light outputs. All the components on the board are through-hole which makes it easy to assemble and solder. 9 | 10 | Some features: 11 | * Control up to 8 light circuits 12 | * Accepts three channels of RC input (throttle, steering, and an optional 3rd channel) 13 | * Each light can respond to various model **States**: forward, reverse, stopped, stopped after delay, braking, right turn, left turn, no turn, accelerating, decelerating, and any of up to 5 positions for the channel 3 switch if attached. 14 | * For each light in each State the **Setting** defines the behavior of the light: on, off, fade on, fade off, blink, fast blink, safety blink (and the alternate versions of blink, fast blink, and safety blink), soft blink, dim, xenon-on effect, or backfire effect. 15 | * The collection of all Settings for all lights in all States is called a **Scheme**. Multiple schemes can be defined and you can switch between them from your transmitter. 16 | * Schemes and other operating adjustments are made in the free Arduino IDE. Everything is well explained and you don't need to know how to write code. 17 | * Works with both 5 and 6 volt RC systems 18 |
19 | 20 | ## Resources 21 | * [OSL Wiki](https://openpanzer.org/wiki/doku.php?id=wiki:otherprojects:osl) 22 | * [RC Groups Discussion Thread](http://www.rcgroups.com/forums/showthread.php?t=1539753) 23 | * [Complete collection of resources and downloads](https://openpanzer.org/downloads#OSL) 24 |
25 | 26 | ## OSL Hardware 27 | **Board version 1.7** 28 | See the "hardware" folder in this repository for Eagle board files, schematic, and bill of materials. 29 | * [Printable Schematic](https://www.openpanzer.org/secure_downloads/osl/eagle/OpenSourceLights_v17_Schematic.pdf) (PDF) 30 | * [Bill of Materials](https://www.openpanzer.org/secure_downloads/osl/bom/OpenSourceLights_BOM.pdf) (PDF) 31 | * [Purchase PCBs at OSH Park](https://oshpark.com/shared_projects/kmCzNipk) 32 | * [Other user designs](https://www.openpanzer.org/forum/index.php?page=osl_other) 33 |
34 | 35 | ## Getting Started with Arduino 36 | First you will need to install the Arduino IDE on your computer, [you can download it from here](https://www.arduino.cc/en/software). 37 | 38 | Next download the OSL source files (Arduino calls this a "sketch"). Click the green "Clone or Download" button at the top of this page, then select "Download ZIP." 39 | 40 | 1. Unzip the download and put the folder named “OpenSourceLights” into your Arduino “Sketches” folder. This may be a location you specified or it may be the default location that Arduino chose when you installed the IDE. If you are unsure where Arduino thinks your Sketches folder is: 41 | - Open the Arduino IDE 42 | - Go to File -> Preferences 43 | - At the top of the popup screen that appears, look at the path under the heading "Sketchbook location". This shows you where your Sketches folder is. 44 | 45 | 2. Open the sketch through the IDE or just by clicking on any of the .ino files in the OpenSourceLights folder. Now let's make sure the IDE is setup to compile the project correctly: 46 | - In the IDE, go to the Tools menu and select Board -> Arduino AVR Boards -> "Arduino Nano." In fact several boards would work, but "Nano" is the easiest to remember. 47 | - Make sure we have the correct processor selected. Go to Tools -> Processor -> and select "ATmega328P". **Note:** Some users may need to select "Atmega328P (Old Bootloader)" if they have problems loading the sketch onto their device. 48 | 49 | 3. Compile. This is done by clicking the checkmark button at the top left of the IDE window, or by going to the Sketch menu and clicking "Verify/Compile." The IDE will run for a few moments then give you the results of the compilation at the bottom of the screen. If successful, you are ready to modify the sketch so that it does what you want! Read this page in the OSL Wiki for more information: [Modifying the Sketch](https://openpanzer.org/wiki/doku.php?id=wiki:otherprojects:osl:sketch) 50 | -------------------------------------------------------------------------------- /hardware/Bill_Of_Materials/OpenSourceLights_BOM.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OSRCL/OSL_Original/e6a4c5d1c5c118ac8a249af194856d07d6b79cea/hardware/Bill_Of_Materials/OpenSourceLights_BOM.pdf -------------------------------------------------------------------------------- /hardware/OpenSourceLights_v17_Schematic.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OSRCL/OSL_Original/e6a4c5d1c5c118ac8a249af194856d07d6b79cea/hardware/OpenSourceLights_v17_Schematic.pdf --------------------------------------------------------------------------------