├── MIDI_CC_to_NOTEs.ino ├── ManyEncoder.ino ├── OSC_Eos_Sub_37_with_Feedback.ino ├── OSC__with_three_Encoders_SDsetup.ino ├── OSC__with_two_Encoders_SDsetup.ino ├── README.md ├── TinySlipExample.ino ├── USB_OSC_4_encoders_5_Pages_RevC.ino ├── USB_OSC_5_encoders_5_Pages_wheels_With_fader.ino ├── faders_OSC_V2.ino ├── five_encoder_USB_OSC_No_Display.ino ├── four_encoder_USB_OSC_40X2_Display.ino ├── name.c └── settings.txt /MIDI_CC_to_NOTEs.ino: -------------------------------------------------------------------------------- 1 | /* Receive Incoming USB Host MIDI using functions. As usbMIDI 2 | reads incoming messages, handler functions are run. 3 | See the InputRead example for the non-function alterative. 4 | 5 | This very long example demonstrates all possible handler 6 | functions. Most applications need only some of these. 7 | This example is meant to allow easy copy-and-paste of the 8 | desired functions. 9 | 10 | Use the Arduino Serial Monitor to view the messages 11 | as Teensy receives them by USB MIDI 12 | 13 | You must select MIDI from the "Tools > USB Type" menu 14 | 15 | This example code is in the public domain. 16 | */ 17 | 18 | 19 | // Need this file and also the name.c file in the folder. You can change the name.c file to reflect the usb midi name that appears 20 | 21 | // need to upload this to a teensy in serial + MIDI mode so the teensy appears as a usb midi device when plugged into a console/computer 22 | 23 | 24 | #include 25 | 26 | USBHost myusb; 27 | USBHub hub1(myusb); 28 | USBHub hub2(myusb); 29 | MIDIDevice midi1(myusb); 30 | 31 | int programm = 0; 32 | int programmold = 0; 33 | int programnew = 0; 34 | 35 | void setup() { 36 | Serial.begin(115200); 37 | 38 | // Wait 1.5 seconds before turning on USB Host. If connected USB devices 39 | // use too much power, Teensy at least completes USB enumeration, which 40 | // makes isolating the power issue easier. 41 | delay(500); 42 | Serial.println("USB Host CC to Notes"); 43 | delay(10); 44 | myusb.begin(); 45 | 46 | // midi1.setHandleNoteOn(myNoteOn); 47 | // midi1.setHandleNoteOff(myNoteOff); 48 | // midi1.setHandleAfterTouchPoly(myAfterTouchPoly); 49 | midi1.setHandleControlChange(myControlChange); 50 | //midi1.setHandleProgramChange(myProgramChange); 51 | // midi1.setHandleAfterTouchChannel(myAfterTouchChannel); 52 | // midi1.setHandlePitchChange(myPitchChange); 53 | // Only one of these System Exclusive handlers will actually be 54 | // used. See the comments below for the difference between them. 55 | // midi1.setHandleSystemExclusive(mySystemExclusiveChunk); 56 | // midi1.setHandleSystemExclusive(mySystemExclusive); 57 | // midi1.setHandleTimeCodeQuarterFrame(myTimeCodeQuarterFrame); 58 | // midi1.setHandleSongPosition(mySongPosition); 59 | // midi1.setHandleSongSelect(mySongSelect); 60 | // midi1.setHandleTuneRequest(myTuneRequest); 61 | // midi1.setHandleClock(myClock); 62 | // midi1.setHandleStart(myStart); 63 | // midi1.setHandleContinue(myContinue); 64 | // midi1.setHandleStop(myStop); 65 | // midi1.setHandleActiveSensing(myActiveSensing); 66 | // midi1.setHandleSystemReset(mySystemReset); 67 | // This generic System Real Time handler is only used if the 68 | // more specific ones are not set. 69 | // midi1.setHandleRealTimeSystem(myRealTimeSystem); 70 | } 71 | 72 | void loop() { 73 | // The handler functions are called when midi1 reads data. They 74 | // will not be called automatically. You must call midi1.read() 75 | // regularly from loop() for midi1 to actually read incoming 76 | // data and run the handler functions as messages arrive. 77 | myusb.Task(); 78 | midi1.read(); 79 | } 80 | 81 | /* 82 | void myNoteOn(byte channel, byte note, byte velocity) { 83 | // When a USB device with multiple virtual cables is used, 84 | // midi1.getCable() can be used to read which of the virtual 85 | // MIDI cables received this message. 86 | Serial.print("Note On, ch="); 87 | Serial.print(channel, DEC); 88 | Serial.print(", note="); 89 | Serial.print(note, DEC); 90 | Serial.print(", velocity="); 91 | Serial.println(velocity, DEC); 92 | } 93 | 94 | void myNoteOff(byte channel, byte note, byte velocity) { 95 | Serial.print("Note Off, ch="); 96 | Serial.print(channel, DEC); 97 | Serial.print(", note="); 98 | Serial.print(note, DEC); 99 | Serial.print(", velocity="); 100 | Serial.println(velocity, DEC); 101 | } 102 | 103 | void myAfterTouchPoly(byte channel, byte note, byte velocity) { 104 | Serial.print("AfterTouch Change, ch="); 105 | Serial.print(channel, DEC); 106 | Serial.print(", note="); 107 | Serial.print(note, DEC); 108 | Serial.print(", velocity="); 109 | Serial.println(velocity, DEC); 110 | } 111 | */ 112 | void myControlChange(byte channel, byte control, byte value) { 113 | Serial.print("Control Change, ch="); 114 | Serial.print(channel, DEC); 115 | Serial.print(", control="); 116 | Serial.print(control, DEC); 117 | Serial.print(", value="); 118 | Serial.println(value, DEC); 119 | usbMIDI.sendNoteOn(control, value, channel); 120 | } 121 | /* 122 | void myProgramChange(byte channel, byte program) { 123 | Serial.print("Program Change, ch="); 124 | Serial.print(channel, DEC); 125 | Serial.print(", program="); 126 | Serial.println(program); 127 | programm = program; 128 | if (programm < programmold) 129 | { 130 | Serial.println("Lesser"); 131 | Serial.println(programmold, DEC); 132 | Serial.println(programm, DEC); 133 | Serial.println(programnew, DEC); 134 | programnew = 0; 135 | } 136 | if (programm > programmold) 137 | { 138 | Serial.println("Greater"); 139 | Serial.println(programmold, DEC); 140 | Serial.println(programm, DEC); 141 | Serial.println(programnew, DEC); 142 | programnew = 1; 143 | } 144 | 145 | Serial.println(programmold, DEC); 146 | Serial.println(programm, DEC); 147 | Serial.println(programnew, DEC); 148 | programmold = programm; 149 | 150 | usbMIDI.sendNoteOn(51, programnew, channel); 151 | 152 | } 153 | /* 154 | void myAfterTouchChannel(byte channel, byte pressure) { 155 | Serial.print("After Touch, ch="); 156 | Serial.print(channel, DEC); 157 | Serial.print(", pressure="); 158 | Serial.println(pressure, DEC); 159 | } 160 | 161 | void myPitchChange(byte channel, int pitch) { 162 | Serial.print("Pitch Change, ch="); 163 | Serial.print(channel, DEC); 164 | Serial.print(", pitch="); 165 | Serial.println(pitch, DEC); 166 | } 167 | 168 | 169 | // This 3-input System Exclusive function is more complex, but allows you to 170 | // process very large messages which do not fully fit within the midi1's 171 | // internal buffer. Large messages are given to you in chunks, with the 172 | // 3rd parameter to tell you which is the last chunk. This function is 173 | // a Teensy extension, not available in the Arduino MIDI library. 174 | // 175 | void mySystemExclusiveChunk(const byte *data, uint16_t length, bool last) { 176 | Serial.print("SysEx Message: "); 177 | printBytes(data, length); 178 | if (last) { 179 | Serial.println(" (end)"); 180 | } else { 181 | Serial.println(" (to be continued)"); 182 | } 183 | } 184 | 185 | // This simpler 2-input System Exclusive function can only receive messages 186 | // up to the size of the internal buffer. Larger messages are truncated, with 187 | // no way to receive the data which did not fit in the buffer. If both types 188 | // of SysEx functions are set, the 3-input version will be called by midi1. 189 | // 190 | void mySystemExclusive(byte *data, unsigned int length) { 191 | Serial.print("SysEx Message: "); 192 | printBytes(data, length); 193 | Serial.println(); 194 | } 195 | 196 | void myTimeCodeQuarterFrame(byte data) { 197 | static char SMPTE[8]={'0','0','0','0','0','0','0','0'}; 198 | static byte fps=0; 199 | byte index = data >> 4; 200 | byte number = data & 15; 201 | if (index == 7) { 202 | fps = (number >> 1) & 3; 203 | number = number & 1; 204 | } 205 | if (index < 8 || number < 10) { 206 | SMPTE[index] = number + '0'; 207 | Serial.print("TimeCode: "); // perhaps only print when index == 7 208 | Serial.print(SMPTE[7]); 209 | Serial.print(SMPTE[6]); 210 | Serial.print(':'); 211 | Serial.print(SMPTE[5]); 212 | Serial.print(SMPTE[4]); 213 | Serial.print(':'); 214 | Serial.print(SMPTE[3]); 215 | Serial.print(SMPTE[2]); 216 | Serial.print('.'); 217 | Serial.print(SMPTE[1]); // perhaps add 2 to compensate for MIDI latency? 218 | Serial.print(SMPTE[0]); 219 | switch (fps) { 220 | case 0: Serial.println(" 24 fps"); break; 221 | case 1: Serial.println(" 25 fps"); break; 222 | case 2: Serial.println(" 29.97 fps"); break; 223 | case 3: Serial.println(" 30 fps"); break; 224 | } 225 | } else { 226 | Serial.print("TimeCode: invalid data = "); 227 | Serial.println(data, HEX); 228 | } 229 | } 230 | 231 | void mySongPosition(uint16_t beats) { 232 | Serial.print("Song Position, beat="); 233 | Serial.println(beats); 234 | } 235 | 236 | void mySongSelect(byte songNumber) { 237 | Serial.print("Song Select, song="); 238 | Serial.println(songNumber, DEC); 239 | } 240 | 241 | void myTuneRequest() { 242 | Serial.println("Tune Request"); 243 | } 244 | 245 | void myClock() { 246 | Serial.println("Clock"); 247 | } 248 | 249 | void myStart() { 250 | Serial.println("Start"); 251 | } 252 | 253 | void myContinue() { 254 | Serial.println("Continue"); 255 | } 256 | 257 | void myStop() { 258 | Serial.println("Stop"); 259 | } 260 | 261 | void myActiveSensing() { 262 | Serial.println("Actvice Sensing"); 263 | } 264 | 265 | void mySystemReset() { 266 | Serial.println("System Reset"); 267 | } 268 | 269 | void myRealTimeSystem(uint8_t realtimebyte) { 270 | Serial.print("Real Time Message, code="); 271 | Serial.println(realtimebyte, HEX); 272 | } 273 | 274 | */ 275 | 276 | void printBytes(const byte *data, unsigned int size) { 277 | while (size > 0) { 278 | byte b = *data++; 279 | if (b < 16) Serial.print('0'); 280 | Serial.print(b, HEX); 281 | if (size > 1) Serial.print(' '); 282 | size = size - 1; 283 | } 284 | } 285 | -------------------------------------------------------------------------------- /ManyEncoder.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #define ENCODER_DO_NOT_USE_INTERRUPTS 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #ifdef BOARD_HAS_USB_SERIAL 11 | #include 12 | SLIPEncodedUSBSerial SLIPSerial(thisBoardsSerialUSB); 13 | #else 14 | #include 15 | SLIPEncodedSerial SLIPSerial(Serial); 16 | #endif 17 | 18 | 19 | Encoder myEnc1(22, 23); // the number of the encoder 1 pins 20 | Encoder myEnc2(24, 25); // the number of the encoder 2 pins 21 | Encoder myEnc3(26, 27); // the number of the encoder 3 pins 22 | Encoder myEnc4(28, 29); // the number of the encoder 4 pins 23 | Encoder myEnc5(30, 31); // the number of the encoder 5 pins 24 | Encoder myEnc6(32, 33); // the number of the encoder 6 pins 25 | Encoder myEnc7(34, 35); // the number of the encoder 7 pins 26 | Encoder myEnc8(36, 37); // the number of the encoder 8 pins 27 | Encoder myEnc9(38, 39); // the number of the encoder 9 pins 28 | Encoder myEnc10(40, 41); // the number of the encoder 10 pins 29 | Encoder myEnc11(42, 43); // the number of the encoder 11 pins 30 | Encoder myEnc12(44, 45); // the number of the encoder 12 pins 31 | Encoder myEnc13(46, 47); // the number of the encoder 13 pins 32 | Encoder myEnc14(48, 49); // the number of the encoder 14 pins 33 | Encoder myEnc15(14, 15); // the number of the encoder 15 pins 34 | Encoder myEnc16(16, 17); // the number of the encoder 16 pins 35 | Encoder myEnc17(18, 19); // the number of the encoder 17 pins 36 | Encoder myEnc18(20, 21); // the number of the encoder 18 pins 37 | 38 | const int buttonPin1 = 1; // the number of the pushbutton pin 39 | const int buttonPin2 = 2; // the number of the pushbutton pin 40 | const int buttonPin3 = ; // the number of the pushbutton pin 41 | const int buttonPin4 = 9; // the number of the pushbutton pin 42 | const int buttonPin5 = 8; // the number of the pushbutton pin 43 | const int buttonPin6 = 9; // the number of the pushbutton pin 44 | const int buttonPin7 = 8; // the number of the pushbutton pin 45 | const int buttonPin8 = 9; // the number of the pushbutton pin 46 | const int buttonPin9 = 8; // the number of the pushbutton pin 47 | const int buttonPin10 = 9; // the number of the pushbutton pin 48 | const int buttonPin11 = 8; // the number of the pushbutton pin 49 | const int buttonPin12 = 9; // the number of the pushbutton pin 50 | const int buttonPin13 = 8; // the number of the pushbutton pin 51 | const int buttonPin14 = 9; // the number of the pushbutton pin 52 | const int buttonPin15 = 8; // the number of the pushbutton pin 53 | const int buttonPin16 = 9; // the number of the pushbutton pin 54 | const int buttonPin17 = 8; // the number of the pushbutton pin 55 | const int buttonPin18 = 9; // the number of the pushbutton pin 56 | const int buttonPin19 = 8; // the number of the pushbutton pin 57 | const int buttonPin20 = 9; // the number of the pushbutton pin 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | const String HANDSHAKE_QUERY = "ETCOSC?"; 68 | const String HANDSHAKE_REPLY = "OK"; 69 | long oldPosition1 = -999; 70 | long oldPosition2 = -999; 71 | long oldPosition3 = -999; 72 | long oldPosition4 = -999; 73 | long oldPosition5 = -999; 74 | long oldPosition6 = -999; 75 | long oldPosition7 = -999; 76 | long oldPosition8 = -999; 77 | long oldPosition9 = -999; 78 | long oldPosition10 = -999; 79 | long oldPosition11 = -999; 80 | long oldPosition12 = -999; 81 | long oldPosition13 = -999; 82 | long oldPosition14 = -999; 83 | long oldPosition15 = -999; 84 | long oldPosition16 = -999; 85 | long oldPosition17 = -999; 86 | long oldPosition18 = -999; 87 | 88 | int lastButtonState = LOW; // the previous reading from the input pin 89 | int lastButtonState1 = LOW; // the previous reading from the input pin 90 | 91 | // the following variables are long's because the time, measured in miliseconds, 92 | // will quickly become a bigger number than can be stored in an int. 93 | long lastDebounceTime = 0; // the last time the output pin was toggled 94 | long debounceDelay = 50; // the debounce time; increase if the output flickers 95 | long lastDebounceTime1 = 0; // the last time the output pin was toggled 96 | long debounceDelay1 = 50; // the debounce time; increase if the output flickers 97 | 98 | int buttonState = 0; // variable for reading the pushbutton status 99 | int buttonState1 = 0; // variable for reading the pushbutton status 100 | 101 | char oscMsg1[32]; 102 | char oscMsg2[32]; 103 | char oscMsg3[32]; 104 | char oscMsg4[32]; 105 | char oscMsg5[32]; 106 | char oscMsg6[32]; 107 | char oscMsg7[32]; 108 | char oscMsg8[32]; 109 | char oscMsg9[32]; 110 | char oscMsg10[32]; 111 | char oscMsg11[32]; 112 | char oscMsg12[32]; 113 | char oscMsg13[32]; 114 | char oscMsg14[32]; 115 | char oscMsg15[32]; 116 | char oscMsg16[32]; 117 | char oscMsg17[32]; 118 | char oscMsg18[32]; 119 | 120 | 121 | byte myMac[6] = { 122 | 123 | }; 124 | byte myNM[4] = { 125 | 126 | }; 127 | byte myIP[4] = { 128 | 129 | }; 130 | byte myGW[4] = { 131 | 132 | }; 133 | byte RemIP[4] = { 134 | 135 | }; 136 | 137 | int RemPort = 0; // remote port to transmit to 138 | 139 | 140 | 141 | 142 | void setup() { 143 | pinMode(buttonPin, INPUT_PULLUP); 144 | pinMode(buttonPin1, INPUT_PULLUP); 145 | 146 | // pinMode(10, OUTPUT); 147 | // digitalWrite(10, HIGH); 148 | // pinMode(51, OUTPUT); 149 | 150 | ShieldSetup ();//setup ethernet shield 151 | 152 | pinMode(4, OUTPUT); 153 | digitalWrite(4, HIGH); 154 | 155 | SLIPSerial.begin(115200); 156 | // This is a hack around an arduino bug. It was taken from the OSC library examples 157 | #ifdef BOARD_HAS_USB_SERIAL 158 | while (!SerialUSB); 159 | #else 160 | while (!Serial); 161 | #endif 162 | 163 | // this is necessary for reconnecting a device because it need some timme for the serial port to get open, but meanwhile the handshake message was send from eos 164 | SLIPSerial.beginPacket(); 165 | SLIPSerial.write((const uint8_t*)HANDSHAKE_REPLY.c_str(), (size_t)HANDSHAKE_REPLY.length()); 166 | SLIPSerial.endPacket(); 167 | 168 | } 169 | 170 | 171 | 172 | void ShieldSetup() 173 | { 174 | // Serial.begin(9600); 175 | while (!Serial) ; 176 | 177 | if (!SD.begin(4)) Serial.println(F("SD fail")); 178 | else Serial.println(F("SD ok")); 179 | 180 | File fh = SD.open("settings.txt", FILE_READ); 181 | char netBuffer[32]; 182 | 183 | if (!fh) 184 | { 185 | Serial.println(F("SD open fail")); 186 | return; 187 | } 188 | 189 | int chPos = 0; 190 | int lineNo = 0; 191 | 192 | 193 | while (fh.available()) 194 | { 195 | char ch = fh.read(); 196 | if (ch == '\n') { 197 | chPos = 0; 198 | 199 | switch (lineNo) { 200 | case 0: 201 | if (getMAC(netBuffer, myMac)) Serial.println(F("mac ok")); 202 | break; 203 | 204 | case 2: 205 | if (getIP(netBuffer, myIP)) Serial.println(F("ip ok")); 206 | break; 207 | 208 | case 4: 209 | if (getIP(netBuffer, myNM)) Serial.println(F("NM ok")); 210 | break; 211 | 212 | case 6: 213 | if (getIP(netBuffer, myGW)) Serial.println(F("GW ok")); 214 | break; 215 | 216 | case 8: 217 | if (getIP(netBuffer, RemIP)) Serial.println(F("CNSL ok")); 218 | break; 219 | 220 | case 10: 221 | RemPort = atoi(&netBuffer[0]); 222 | Serial.print(F("Port ")); 223 | Serial.println(RemPort); 224 | break; 225 | 226 | case 12: 227 | strcpy( oscMsg1, netBuffer ); 228 | Serial.print(F("OSC Command1: ")); 229 | Serial.println(oscMsg1); 230 | break; 231 | 232 | case 14: 233 | strcpy( oscMsg2, netBuffer ); 234 | Serial.print(F("OSC Command2: ")); 235 | Serial.println(oscMsg2); 236 | break; 237 | 238 | case 16: 239 | strcpy( oscMsg3, netBuffer ); 240 | Serial.print(F("OSC Command3: ")); 241 | Serial.println(oscMsg3); 242 | break; 243 | 244 | case 18: 245 | strcpy( oscMsg4, netBuffer ); 246 | Serial.print(F("OSC Command4: ")); 247 | Serial.println(oscMsg4); 248 | break; 249 | 250 | case 20: 251 | strcpy( oscMsg5, netBuffer ); 252 | Serial.print(F("OSC Command5: ")); 253 | Serial.println(oscMsg5); 254 | break; 255 | case 22: 256 | strcpy( oscMsg6, netBuffer ); 257 | Serial.print(F("OSC Command6: ")); 258 | Serial.println(oscMsg6); 259 | break; 260 | 261 | case 24: 262 | strcpy( oscMsg7, netBuffer ); 263 | Serial.print(F("OSC Command7: ")); 264 | Serial.println(oscMsg7); 265 | break; 266 | 267 | case 26: 268 | strcpy( oscMsg8, netBuffer ); 269 | Serial.print(F("OSC Command8: ")); 270 | Serial.println(oscMsg8); 271 | break; 272 | 273 | case 28: 274 | strcpy( oscMsg9, netBuffer ); 275 | Serial.print(F("OSC Command9: ")); 276 | Serial.println(oscMsg9); 277 | break; 278 | 279 | case 30: 280 | strcpy( oscMsg10, netBuffer ); 281 | Serial.print(F("OSC Command10: ")); 282 | Serial.println(oscMsg10); 283 | break; 284 | 285 | case 32: 286 | strcpy( oscMsg11, netBuffer ); 287 | Serial.print(F("OSC Command11: ")); 288 | Serial.println(oscMsg11); 289 | break; 290 | 291 | case 34: 292 | strcpy( oscMsg12, netBuffer ); 293 | Serial.print(F("OSC Command12: ")); 294 | Serial.println(oscMsg12); 295 | break; 296 | 297 | case 36: 298 | strcpy( oscMsg13, netBuffer ); 299 | Serial.print(F("OSC Command13: ")); 300 | Serial.println(oscMsg13); 301 | break; 302 | 303 | case 38: 304 | strcpy( oscMsg14, netBuffer ); 305 | Serial.print(F("OSC Command14: ")); 306 | Serial.println(oscMsg14); 307 | break; 308 | 309 | case 40: 310 | strcpy( oscMsg15, netBuffer ); 311 | Serial.print(F("OSC Command15: ")); 312 | Serial.println(oscMsg15); 313 | break; 314 | 315 | case 42: 316 | strcpy( oscMsg16, netBuffer ); 317 | Serial.print(F("OSC Command16: ")); 318 | Serial.println(oscMsg16); 319 | break; 320 | 321 | case 44: 322 | strcpy( oscMsg17, netBuffer ); 323 | Serial.print(F("OSC Command17: ")); 324 | Serial.println(oscMsg17); 325 | break; 326 | 327 | case 46: 328 | strcpy( oscMsg18, netBuffer ); 329 | Serial.print(F("OSC Command18: ")); 330 | Serial.println(oscMsg18); 331 | break; 332 | 333 | } 334 | 335 | lineNo++; 336 | } 337 | else if (ch == '\r') { 338 | // do nothing 339 | } 340 | else if (chPos < 32) { 341 | netBuffer[chPos] = ch; 342 | chPos++; 343 | netBuffer[chPos] = 0; 344 | } 345 | } 346 | 347 | fh.close(); 348 | 349 | int x; 350 | 351 | Serial.print("\r\nmac "); 352 | for (x = 0; x < 6; x++) { 353 | Serial.print(myMac[x], HEX); 354 | if (x < 5) Serial.print(":"); 355 | } 356 | 357 | Serial.print("\r\nip "); 358 | for (x = 0; x < 4; x++) { 359 | Serial.print(myIP[x], DEC); 360 | if (x < 3) Serial.print("."); 361 | } 362 | 363 | Serial.print("\r\nnetmask "); 364 | for (x = 0; x < 4; x++) { 365 | Serial.print(myNM[x], DEC); 366 | if (x < 3) Serial.print("."); 367 | } 368 | 369 | Serial.print("\r\ngateway "); 370 | for (x = 0; x < 4; x++) { 371 | Serial.print(myGW[x], DEC); 372 | if (x < 3) Serial.print("."); 373 | } 374 | 375 | Serial.print("\r\nconsole "); 376 | for (x = 0; x < 4; x++) { 377 | Serial.print(RemIP[x], DEC); 378 | if (x < 3) Serial.print("."); 379 | } 380 | 381 | 382 | 383 | 384 | } 385 | 386 | 387 | 388 | void loop() { 389 | long newPosition1 = myEnc1.read(); 390 | long newPosition2 = myEnc2.read(); 391 | long newPosition3 = myEnc3.read(); 392 | long newPosition4 = myEnc4.read(); 393 | long newPosition5 = myEnc5.read(); 394 | long newPosition6 = myEnc6.read(); 395 | long newPosition7 = myEnc7.read(); 396 | long newPosition8 = myEnc8.read(); 397 | long newPosition9 = myEnc9.read(); 398 | long newPosition10 = myEnc10.read(); 399 | long newPosition11 = myEnc11.read(); 400 | long newPosition12 = myEnc12.read(); 401 | long newPosition13 = myEnc13.read(); 402 | long newPosition14 = myEnc14.read(); 403 | long newPosition15 = myEnc15.read(); 404 | long newPosition16 = myEnc16.read(); 405 | long newPosition17 = myEnc17.read(); 406 | float newPosition18 = myEnc18.read(); 407 | float outPosition18 = 0.000; 408 | int reading = digitalRead(buttonPin); 409 | int reading1 = digitalRead(buttonPin1); 410 | 411 | 412 | 413 | if (newPosition1 > oldPosition1) 414 | { //the message wants an OSC address as first argument 415 | OSCMessage msg(oscMsg1); 416 | msg.add("1"); 417 | SLIPSerial.beginPacket(); 418 | msg.send(SLIPSerial); // send the bytes to the SLIP stream 419 | SLIPSerial.endPacket(); // mark the end of the OSC Packet 420 | msg.empty(); // free space occupied by message 421 | oldPosition1 = newPosition1; 422 | 423 | } 424 | 425 | if (newPosition1 < oldPosition1) 426 | { //the message wants an OSC address as first argument 427 | OSCMessage msg(oscMsg1); 428 | msg.add("-1"); 429 | SLIPSerial.beginPacket(); 430 | msg.send(SLIPSerial); // send the bytes to the SLIP stream 431 | SLIPSerial.endPacket(); // mark the end of the OSC Packet 432 | msg.empty(); // free space occupied by message 433 | oldPosition1 = newPosition1; 434 | 435 | } 436 | 437 | 438 | if (newPosition2 > oldPosition2) 439 | { //the message wants an OSC address as first argument 440 | OSCMessage msg(oscMsg2); 441 | msg.add("1"); 442 | SLIPSerial.beginPacket(); 443 | msg.send(SLIPSerial); // send the bytes to the SLIP stream 444 | SLIPSerial.endPacket(); // mark the end of the OSC Packet 445 | msg.empty(); // free space occupied by message 446 | oldPosition2 = newPosition2; 447 | 448 | } 449 | 450 | if (newPosition2 < oldPosition2) 451 | { //the message wants an OSC address as first argument 452 | OSCMessage msg(oscMsg2); 453 | msg.add("-1"); 454 | SLIPSerial.beginPacket(); 455 | msg.send(SLIPSerial); // send the bytes to the SLIP stream 456 | SLIPSerial.endPacket(); // mark the end of the OSC Packet 457 | msg.empty(); // free space occupied by message 458 | oldPosition2 = newPosition2; 459 | 460 | } 461 | 462 | 463 | 464 | if (newPosition3 > oldPosition3) 465 | { //the message wants an OSC address as first argument 466 | OSCMessage msg(oscMsg3); 467 | msg.add("1"); 468 | SLIPSerial.beginPacket(); 469 | msg.send(SLIPSerial); // send the bytes to the SLIP stream 470 | SLIPSerial.endPacket(); // mark the end of the OSC Packet 471 | msg.empty(); // free space occupied by message 472 | oldPosition3 = newPosition3; 473 | 474 | } 475 | 476 | if (newPosition3 < oldPosition3) 477 | { //the message wants an OSC address as first argument 478 | OSCMessage msg(oscMsg3); 479 | msg.add("-1"); 480 | SLIPSerial.beginPacket(); 481 | msg.send(SLIPSerial); // send the bytes to the SLIP stream 482 | SLIPSerial.endPacket(); // mark the end of the OSC Packet 483 | msg.empty(); // free space occupied by message 484 | oldPosition3 = newPosition3; 485 | 486 | } 487 | 488 | 489 | 490 | if (newPosition4 > oldPosition4) 491 | { //the message wants an OSC address as first argument 492 | Serial.println(oscMsg4); 493 | 494 | OSCMessage msg(oscMsg4); 495 | msg.add("1"); 496 | SLIPSerial.beginPacket(); 497 | msg.send(SLIPSerial); // send the bytes to the SLIP stream 498 | SLIPSerial.endPacket(); // mark the end of the OSC Packet 499 | msg.empty(); // free space occupied by message 500 | oldPosition4 = newPosition4; 501 | 502 | } 503 | 504 | if (newPosition4 < oldPosition4) 505 | { //the message wants an OSC address as first argument 506 | Serial.println(oscMsg4); 507 | 508 | OSCMessage msg(oscMsg4); 509 | msg.add("-1"); 510 | SLIPSerial.beginPacket(); 511 | msg.send(SLIPSerial); // send the bytes to the SLIP stream 512 | SLIPSerial.endPacket(); // mark the end of the OSC Packet 513 | msg.empty(); // free space occupied by message 514 | oldPosition4 = newPosition4; 515 | 516 | } 517 | 518 | 519 | if (newPosition5 > oldPosition5) 520 | { //the message wants an OSC address as first argument 521 | OSCMessage msg(oscMsg5); 522 | msg.add("1"); 523 | SLIPSerial.beginPacket(); 524 | msg.send(SLIPSerial); // send the bytes to the SLIP stream 525 | SLIPSerial.endPacket(); // mark the end of the OSC Packet 526 | msg.empty(); // free space occupied by message 527 | oldPosition5 = newPosition5; 528 | 529 | } 530 | 531 | if (newPosition5 < oldPosition5) 532 | { //the message wants an OSC address as first argument 533 | OSCMessage msg(oscMsg5); 534 | msg.add("-1"); 535 | SLIPSerial.beginPacket(); 536 | msg.send(SLIPSerial); // send the bytes to the SLIP stream 537 | SLIPSerial.endPacket(); // mark the end of the OSC Packet 538 | msg.empty(); // free space occupied by message 539 | oldPosition5 = newPosition5; 540 | 541 | } 542 | 543 | 544 | 545 | if (newPosition6 > oldPosition6) 546 | { //the message wants an OSC address as first argument 547 | OSCMessage msg(oscMsg6); 548 | msg.add("1"); 549 | SLIPSerial.beginPacket(); 550 | msg.send(SLIPSerial); // send the bytes to the SLIP stream 551 | SLIPSerial.endPacket(); // mark the end of the OSC Packet 552 | msg.empty(); // free space occupied by message 553 | oldPosition6 = newPosition6; 554 | 555 | } 556 | 557 | if (newPosition6 < oldPosition6) 558 | { //the message wants an OSC address as first argument 559 | OSCMessage msg(oscMsg6); 560 | msg.add("-1"); 561 | SLIPSerial.beginPacket(); 562 | msg.send(SLIPSerial); // send the bytes to the SLIP stream 563 | SLIPSerial.endPacket(); // mark the end of the OSC Packet 564 | msg.empty(); // free space occupied by message 565 | oldPosition6 = newPosition6; 566 | 567 | } 568 | 569 | 570 | 571 | 572 | if (newPosition7 > oldPosition7) 573 | { //the message wants an OSC address as first argument 574 | OSCMessage msg(oscMsg7); 575 | msg.add("1"); 576 | SLIPSerial.beginPacket(); 577 | msg.send(SLIPSerial); // send the bytes to the SLIP stream 578 | SLIPSerial.endPacket(); // mark the end of the OSC Packet 579 | msg.empty(); // free space occupied by message 580 | oldPosition7 = newPosition7; 581 | 582 | } 583 | 584 | if (newPosition7 < oldPosition7) 585 | { //the message wants an OSC address as first argument 586 | OSCMessage msg(oscMsg7); 587 | msg.add("-1"); 588 | SLIPSerial.beginPacket(); 589 | msg.send(SLIPSerial); // send the bytes to the SLIP stream 590 | SLIPSerial.endPacket(); // mark the end of the OSC Packet 591 | msg.empty(); // free space occupied by message 592 | oldPosition7 = newPosition7; 593 | 594 | } 595 | 596 | 597 | if (newPosition8 > oldPosition8) 598 | { //the message wants an OSC address as first argument 599 | OSCMessage msg(oscMsg8); 600 | msg.add("1"); 601 | SLIPSerial.beginPacket(); 602 | msg.send(SLIPSerial); // send the bytes to the SLIP stream 603 | SLIPSerial.endPacket(); // mark the end of the OSC Packet 604 | msg.empty(); // free space occupied by message 605 | oldPosition8 = newPosition8; 606 | 607 | } 608 | 609 | if (newPosition8 < oldPosition8) 610 | { //the message wants an OSC address as first argument 611 | OSCMessage msg(oscMsg8); 612 | msg.add("-1"); 613 | SLIPSerial.beginPacket(); 614 | msg.send(SLIPSerial); // send the bytes to the SLIP stream 615 | SLIPSerial.endPacket(); // mark the end of the OSC Packet 616 | msg.empty(); // free space occupied by message 617 | oldPosition8 = newPosition8; 618 | 619 | } 620 | 621 | 622 | if (newPosition9 > oldPosition9) 623 | { //the message wants an OSC address as first argument 624 | OSCMessage msg(oscMsg9); 625 | msg.add("1"); 626 | SLIPSerial.beginPacket(); 627 | msg.send(SLIPSerial); // send the bytes to the SLIP stream 628 | SLIPSerial.endPacket(); // mark the end of the OSC Packet 629 | msg.empty(); // free space occupied by message 630 | oldPosition9 = newPosition9; 631 | 632 | } 633 | 634 | if (newPosition9 < oldPosition9) 635 | { //the message wants an OSC address as first argument 636 | OSCMessage msg(oscMsg9); 637 | msg.add("-1"); 638 | SLIPSerial.beginPacket(); 639 | msg.send(SLIPSerial); // send the bytes to the SLIP stream 640 | SLIPSerial.endPacket(); // mark the end of the OSC Packet 641 | msg.empty(); // free space occupied by message 642 | oldPosition9 = newPosition9; 643 | 644 | } 645 | 646 | 647 | 648 | 649 | if (newPosition10 > oldPosition10) 650 | { //the message wants an OSC address as first argument 651 | OSCMessage msg(oscMsg10); 652 | msg.add("1"); 653 | SLIPSerial.beginPacket(); 654 | msg.send(SLIPSerial); // send the bytes to the SLIP stream 655 | SLIPSerial.endPacket(); // mark the end of the OSC Packet 656 | msg.empty(); // free space occupied by message 657 | oldPosition10 = newPosition10; 658 | 659 | } 660 | 661 | if (newPosition10 < oldPosition10) 662 | { //the message wants an OSC address as first argument 663 | OSCMessage msg(oscMsg10); 664 | msg.add("-1"); 665 | SLIPSerial.beginPacket(); 666 | msg.send(SLIPSerial); // send the bytes to the SLIP stream 667 | SLIPSerial.endPacket(); // mark the end of the OSC Packet 668 | msg.empty(); // free space occupied by message 669 | oldPosition10 = newPosition10; 670 | 671 | } 672 | 673 | 674 | if (newPosition11 > oldPosition11) 675 | { //the message wants an OSC address as first argument 676 | OSCMessage msg(oscMsg11); 677 | msg.add("1"); 678 | SLIPSerial.beginPacket(); 679 | msg.send(SLIPSerial); // send the bytes to the SLIP stream 680 | SLIPSerial.endPacket(); // mark the end of the OSC Packet 681 | msg.empty(); // free space occupied by message 682 | oldPosition11 = newPosition11; 683 | 684 | } 685 | 686 | if (newPosition11 < oldPosition11) 687 | { //the message wants an OSC address as first argument 688 | OSCMessage msg(oscMsg11); 689 | msg.add("-1"); 690 | SLIPSerial.beginPacket(); 691 | msg.send(SLIPSerial); // send the bytes to the SLIP stream 692 | SLIPSerial.endPacket(); // mark the end of the OSC Packet 693 | msg.empty(); // free space occupied by message 694 | oldPosition11 = newPosition11; 695 | 696 | } 697 | 698 | 699 | if (newPosition12 > oldPosition12) 700 | { //the message wants an OSC address as first argument 701 | OSCMessage msg(oscMsg12); 702 | msg.add("1"); 703 | SLIPSerial.beginPacket(); 704 | msg.send(SLIPSerial); // send the bytes to the SLIP stream 705 | SLIPSerial.endPacket(); // mark the end of the OSC Packet 706 | msg.empty(); // free space occupied by message 707 | oldPosition12 = newPosition12; 708 | 709 | } 710 | 711 | if (newPosition12 < oldPosition12) 712 | { //the message wants an OSC address as first argument 713 | OSCMessage msg(oscMsg12); 714 | msg.add("-1"); 715 | SLIPSerial.beginPacket(); 716 | msg.send(SLIPSerial); // send the bytes to the SLIP stream 717 | SLIPSerial.endPacket(); // mark the end of the OSC Packet 718 | msg.empty(); // free space occupied by message 719 | oldPosition12 = newPosition12; 720 | 721 | } 722 | 723 | 724 | 725 | if (newPosition13 > oldPosition13) 726 | { //the message wants an OSC address as first argument 727 | OSCMessage msg(oscMsg13); 728 | msg.add("1"); 729 | SLIPSerial.beginPacket(); 730 | msg.send(SLIPSerial); // send the bytes to the SLIP stream 731 | SLIPSerial.endPacket(); // mark the end of the OSC Packet 732 | msg.empty(); // free space occupied by message 733 | oldPosition13 = newPosition13; 734 | 735 | } 736 | 737 | if (newPosition13 < oldPosition13) 738 | { //the message wants an OSC address as first argument 739 | OSCMessage msg(oscMsg13); 740 | msg.add("-1"); 741 | SLIPSerial.beginPacket(); 742 | msg.send(SLIPSerial); // send the bytes to the SLIP stream 743 | SLIPSerial.endPacket(); // mark the end of the OSC Packet 744 | msg.empty(); // free space occupied by message 745 | oldPosition13 = newPosition13; 746 | 747 | } 748 | 749 | 750 | 751 | if (newPosition14 > oldPosition14) 752 | { //the message wants an OSC address as first argument 753 | OSCMessage msg(oscMsg14); 754 | msg.add("1"); 755 | SLIPSerial.beginPacket(); 756 | msg.send(SLIPSerial); // send the bytes to the SLIP stream 757 | SLIPSerial.endPacket(); // mark the end of the OSC Packet 758 | msg.empty(); // free space occupied by message 759 | oldPosition14 = newPosition14; 760 | 761 | } 762 | 763 | if (newPosition14 < oldPosition14) 764 | { //the message wants an OSC address as first argument 765 | OSCMessage msg(oscMsg14); 766 | msg.add("-1"); 767 | SLIPSerial.beginPacket(); 768 | msg.send(SLIPSerial); // send the bytes to the SLIP stream 769 | SLIPSerial.endPacket(); // mark the end of the OSC Packet 770 | msg.empty(); // free space occupied by message 771 | oldPosition14 = newPosition14; 772 | 773 | } 774 | 775 | 776 | if (newPosition15 > oldPosition15) 777 | { //the message wants an OSC address as first argument 778 | OSCMessage msg(oscMsg15); 779 | msg.add("1"); 780 | SLIPSerial.beginPacket(); 781 | msg.send(SLIPSerial); // send the bytes to the SLIP stream 782 | SLIPSerial.endPacket(); // mark the end of the OSC Packet 783 | msg.empty(); // free space occupied by message 784 | oldPosition15 = newPosition15; 785 | 786 | } 787 | 788 | if (newPosition15 < oldPosition15) 789 | { //the message wants an OSC address as first argument 790 | OSCMessage msg(oscMsg15); 791 | msg.add("-1"); 792 | SLIPSerial.beginPacket(); 793 | msg.send(SLIPSerial); // send the bytes to the SLIP stream 794 | SLIPSerial.endPacket(); // mark the end of the OSC Packet 795 | msg.empty(); // free space occupied by message 796 | oldPosition15 = newPosition15; 797 | 798 | } 799 | 800 | 801 | 802 | if (newPosition16 > oldPosition16) 803 | { //the message wants an OSC address as first argument 804 | OSCMessage msg(oscMsg16); 805 | msg.add("1"); 806 | SLIPSerial.beginPacket(); 807 | msg.send(SLIPSerial); // send the bytes to the SLIP stream 808 | SLIPSerial.endPacket(); // mark the end of the OSC Packet 809 | msg.empty(); // free space occupied by message 810 | oldPosition16 = newPosition16; 811 | 812 | } 813 | 814 | if (newPosition16 < oldPosition16) 815 | { //the message wants an OSC address as first argument 816 | OSCMessage msg(oscMsg16); 817 | msg.add("-1"); 818 | SLIPSerial.beginPacket(); 819 | msg.send(SLIPSerial); // send the bytes to the SLIP stream 820 | SLIPSerial.endPacket(); // mark the end of the OSC Packet 821 | msg.empty(); // free space occupied by message 822 | oldPosition16 = newPosition16; 823 | 824 | } 825 | 826 | 827 | 828 | if (newPosition17 > oldPosition17) 829 | { //the message wants an OSC address as first argument 830 | OSCMessage msg(oscMsg17); 831 | msg.add("1"); 832 | SLIPSerial.beginPacket(); 833 | msg.send(SLIPSerial); // send the bytes to the SLIP stream 834 | SLIPSerial.endPacket(); // mark the end of the OSC Packet 835 | msg.empty(); // free space occupied by message 836 | oldPosition17 = newPosition17; 837 | 838 | } 839 | 840 | if (newPosition17 < oldPosition17) 841 | { //the message wants an OSC address as first argument 842 | OSCMessage msg(oscMsg17); 843 | msg.add("-1"); 844 | SLIPSerial.beginPacket(); 845 | msg.send(SLIPSerial); // send the bytes to the SLIP stream 846 | SLIPSerial.endPacket(); // mark the end of the OSC Packet 847 | msg.empty(); // free space occupied by message 848 | oldPosition17 = newPosition17; 849 | 850 | } 851 | 852 | 853 | if (newPosition18 > oldPosition18) 854 | { //the message wants an OSC address as first argument 855 | OSCMessage msg(oscMsg18); 856 | msg.add("1"); 857 | SLIPSerial.beginPacket(); 858 | msg.send(SLIPSerial); // send the bytes to the SLIP stream 859 | SLIPSerial.endPacket(); // mark the end of the OSC Packet 860 | msg.empty(); // free space occupied by message 861 | oldPosition18 = newPosition18; 862 | 863 | } 864 | 865 | if (newPosition18 < oldPosition18) 866 | { //the message wants an OSC address as first argument 867 | OSCMessage msg(oscMsg18); 868 | msg.add("-1"); 869 | SLIPSerial.beginPacket(); 870 | msg.send(SLIPSerial); // send the bytes to the SLIP stream 871 | SLIPSerial.endPacket(); // mark the end of the OSC Packet 872 | msg.empty(); // free space occupied by message 873 | oldPosition18 = newPosition18; 874 | 875 | } 876 | 877 | static String curMsg; 878 | int size; 879 | // Then we check to see if any OSC commands have come from Eos 880 | // and update the display accordingly. 881 | 882 | size = SLIPSerial.available(); 883 | if (size > 0) 884 | { 885 | // Fill the msg with all of the available bytes 886 | while (size--) 887 | curMsg += (char)(SLIPSerial.read()); 888 | } 889 | if (SLIPSerial.endofPacket()) 890 | { 891 | parseOSCMessage(curMsg); 892 | curMsg = String(); 893 | } 894 | 895 | 896 | 897 | if (reading1 != lastButtonState1) { 898 | // reset the debouncing timer 899 | lastDebounceTime1 = millis(); 900 | } 901 | 902 | if ((millis() - lastDebounceTime1) > debounceDelay1) { 903 | // whatever the reading is at, it's been there for longer 904 | // than the debounce delay, so take it as the actual current state: 905 | 906 | // if the button state has changed: 907 | if (reading1 != buttonState1) { 908 | buttonState1 = reading1; 909 | 910 | // only toggle the LED if the new button state is HIGH 911 | if (buttonState1 == HIGH) { 912 | OSCMessage msg(""); 913 | // msg.add("0"); 914 | SLIPSerial.beginPacket(); 915 | msg.send(SLIPSerial); // send the bytes to the SLIP stream 916 | SLIPSerial.endPacket(); // mark the end of the OSC Packet 917 | msg.empty(); // free space occupied by message 918 | } 919 | } 920 | } 921 | 922 | if (reading != lastButtonState) { 923 | // reset the debouncing timer 924 | lastDebounceTime = millis(); 925 | } 926 | 927 | if ((millis() - lastDebounceTime) > debounceDelay) { 928 | // whatever the reading is at, it's been there for longer 929 | // than the debounce delay, so take it as the actual current state: 930 | 931 | // if the button state has changed: 932 | if (reading != buttonState) { 933 | buttonState = reading; 934 | 935 | // only toggle the LED if the new button state is HIGH 936 | if (buttonState == HIGH) { 937 | //the message wants an OSC address as first argument 938 | OSCMessage msg(""); 939 | // msg.add("0"); 940 | SLIPSerial.beginPacket(); 941 | msg.send(SLIPSerial); // send the bytes to the SLIP stream 942 | SLIPSerial.endPacket(); // mark the end of the OSC Packet 943 | msg.empty(); // free space occupied by message 944 | } 945 | } 946 | } 947 | 948 | 949 | 950 | 951 | // delay(10); 952 | lastButtonState = reading; 953 | lastButtonState1 = reading1; 954 | 955 | } 956 | 957 | 958 | void parseOSCMessage(String& msg) 959 | { 960 | // check to see if this is the handshake string 961 | if (msg.indexOf(HANDSHAKE_QUERY) != -1) 962 | { 963 | // handshake string found! 964 | SLIPSerial.beginPacket(); 965 | SLIPSerial.write((const uint8_t*)HANDSHAKE_REPLY.c_str(), (size_t)HANDSHAKE_REPLY.length()); 966 | SLIPSerial.endPacket(); 967 | 968 | 969 | } 970 | else 971 | { 972 | // prepare the message for routing by filling an OSCMessage object with our message string 973 | OSCMessage oscmsg; 974 | oscmsg.fill((uint8_t*)msg.c_str(), (int)msg.length()); 975 | 976 | 977 | } 978 | } 979 | 980 | 981 | byte getMAC(char* macBuf, byte* thisMAC) { 982 | byte thisLen = strlen(macBuf); 983 | byte thisOctet = 1; 984 | 985 | thisMAC[0] = strtol(&macBuf[0], NULL, 16); 986 | 987 | for (int x = 0; x < thisLen; x++) { 988 | if (macBuf[x] == ':') { 989 | thisMAC[thisOctet] = strtol(&macBuf[x + 1], NULL, 16); 990 | thisOctet++; 991 | } 992 | } 993 | 994 | if (thisOctet == 6) return (1); 995 | else return (0); 996 | 997 | } 998 | 999 | byte getIP(char* ipBuf, byte* thisIP) { 1000 | byte thisLen = strlen(ipBuf); 1001 | byte thisOctet = 1; 1002 | 1003 | thisIP[0] = atoi(&ipBuf[0]); 1004 | 1005 | for (int x = 0; x < thisLen; x++) { 1006 | if (ipBuf[x] == '.') { 1007 | thisIP[thisOctet] = atoi(&ipBuf[x + 1]); 1008 | thisOctet++; 1009 | } 1010 | } 1011 | 1012 | if (thisOctet == 4) return (1); 1013 | else return (0); 1014 | } 1015 | 1016 | 1017 | 1018 | 1019 | 1020 | -------------------------------------------------------------------------------- /OSC_Eos_Sub_37_with_Feedback.ino: -------------------------------------------------------------------------------- 1 | 2 | #include // needed for Arduino versions later than 0018 3 | //#include 4 | //#include // UDP library from: bjoern@cs.stanford.edu 12/30/2008 5 | #include 6 | #include // UDP library from: bjoern@cs.stanford.edu 12/30/2008 7 | #include 8 | //#include 9 | #include 10 | //#include 11 | #include 12 | 13 | // DC motor on M2 14 | AF_DCMotor motor(1); 15 | const int wiper = A0; //Position of fader relative to GND (Analog 0) 16 | double faderMax = 0; //Value read by fader's maximum position (0-1023) 17 | double faderMin = 0; //Value read by fader's minimum position (0-1023) 18 | int ledState = LOW; 19 | int ledPin = 5; //pin 13 on Arduino Uno. Pin 6 on a Teensy++2 20 | int state = 0; 21 | int sensorPin = A0; 22 | //int sensorPin1 = A1; 23 | double sensorValue = 0; 24 | double outputValue = 0; 25 | double sensorVal = 0; 26 | int sensorValue1 = 0; 27 | int outputValue1 = 0; 28 | int sensorVal1 = 0; 29 | double sensorValstring = 0; 30 | int THRESHOLD = 2; //define a threshold amount 31 | // Enter a MAC address and IP address for your controller below. 32 | // The IP address will be dependent on your local network: 33 | byte mac[6] = { 34 | 0x90, 0xA2, 0xDA, 0x0E, 0xDA, 0x60 }; 35 | byte subnet[] = { 36 | 255, 255, 0, 0 }; 37 | byte gateway[] = { 38 | 10, 101, 95, 115 }; 39 | IPAddress ip(10, 101, 95, 115); 40 | unsigned int localPort = 8000; // local port to listen on 41 | char packetBuffer[UDP_TX_PACKET_MAX_SIZE]; //buffer to hold incoming packet, 42 | 43 | IPAddress RemIP(10, 101, 95, 101); 44 | unsigned int RemPort = 3501; // remote port to listen on 45 | char macstr[18]; 46 | 47 | const byte ID = 0x92; //used to identify if valid data in EEPROM the "know" bit, 48 | // if this is written in EEPROM the sketch has ran before 49 | // We use this, so that the very first time you'll run this sketch it will use 50 | // the values written above. 51 | // defining which EEPROM address we are using for what data 52 | 53 | 54 | // An EthernetUDP instance to let us send and receive packets over UDP 55 | EthernetUDP Udp; 56 | #define W5200_CS 10 57 | #define SDCARD_CS 4 58 | 59 | void setup() 60 | { 61 | 62 | ShieldSetup ();//setup ethernet shield 63 | // start the Ethernet and UDP: 64 | // Ethernet.begin(mac, ip); 65 | motor.setSpeed(200); 66 | 67 | motor.run(RELEASE); 68 | calibrateFader(); 69 | 70 | } 71 | 72 | void ShieldSetup() 73 | { // Random MAC address stored in EEPROM 74 | if (EEPROM.read(1) == '#') { 75 | for (int i = 2; i < 6; i++) { 76 | mac[i] = EEPROM.read(i); 77 | } 78 | } 79 | else { 80 | randomSeed(analogRead(0)); 81 | for (int i = 2; i < 6; i++) { 82 | mac[i] = random(0, 255); 83 | EEPROM.write(i, mac[i]); 84 | } 85 | EEPROM.write(1, '#'); 86 | } 87 | 88 | int idcheck = EEPROM.read(0); 89 | if (idcheck != ID){ 90 | //ifcheck id is not the value as const byte ID, 91 | //it means this sketch has NOT been used to setup the shield before 92 | //just use the values written in the beginning of the sketch 93 | } 94 | if (idcheck == ID){ 95 | //if id is the same value as const byte ID, 96 | //it means this sketch has been used to setup the shield. 97 | //So we will read the values out of EERPOM and use them 98 | //to setup the shield. 99 | for (int i = 2; i < 6; i++) { 100 | mac[i] = EEPROM.read(i); 101 | } 102 | 103 | } 104 | 105 | 106 | 107 | snprintf(macstr, 18, "%02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); 108 | // start the Ethernet and UDP: 109 | 110 | pinMode(SDCARD_CS,OUTPUT); 111 | digitalWrite(SDCARD_CS,HIGH);//Deselect the SD card 112 | Ethernet.begin(mac, ip, gateway, gateway, subnet); 113 | Udp.begin(localPort); 114 | 115 | } 116 | 117 | 118 | void loop() { 119 | OSCMsgReceive(); 120 | Subrun(); 121 | 122 | 123 | } 124 | 125 | void Subrun(){ 126 | sensorValue = analogRead(sensorPin); 127 | outputValue = sensorValue; 128 | outputValue = constrain(outputValue, 0, 1000); 129 | 130 | sensorValstring = outputValue/10; 131 | sensorValstring = sensorValstring -2; 132 | //reads and dispatches the incoming message 133 | 134 | 135 | if (sensorVal == sensorValue) { 136 | // Do Nothing 137 | } 138 | else 139 | { 140 | OSCMessage msg1("/eos/sub/1"); 141 | msg1.add(sensorValstring); 142 | 143 | Udp.beginPacket(RemIP, RemPort); 144 | msg1.send(Udp); 145 | Udp.endPacket(); 146 | msg1.empty(); 147 | } 148 | delay(100); 149 | sensorVal = sensorValue; 150 | 151 | } 152 | 153 | void OSCMsgReceive(){ 154 | OSCMessage msgIN; 155 | int size; 156 | if((size = Udp.parsePacket())>0){ 157 | while(size--) 158 | msgIN.fill(Udp.read()); 159 | if(!msgIN.hasError()){ 160 | msgIN.route("/fader/value1",moveFader); 161 | msgIN.route("/OnOff/toggle1",toggleOnOff); 162 | 163 | } 164 | } 165 | 166 | } 167 | 168 | void toggleOnOff(OSCMessage &msg, int addrOffset){ 169 | ledState = (boolean) msg.getFloat(0); 170 | OSCMessage msgOUT("/OnOff/toggle2"); 171 | 172 | 173 | motor.run(BACKWARD); 174 | delay(500); 175 | motor.run(RELEASE); 176 | 177 | ledState = !ledState; // toggle the state from HIGH to LOW to HIGH to LOW ... 178 | 179 | Udp.beginPacket(RemIP, RemPort); 180 | msgOUT.send(Udp); // send the bytes 181 | Udp.endPacket(); // mark the end of the OSC Packet 182 | msgOUT.empty(); // free space occupied by message 183 | } 184 | 185 | void moveFader(OSCMessage &msg, int addrOffset){ 186 | state = (boolean) msg.getFloat(0); 187 | // state = state * 10; 188 | OSCMessage msgOUT("/Fader/Mov"); 189 | msgOUT.add(state); 190 | 191 | Udp.beginPacket(RemIP, RemPort); 192 | msgOUT.send(Udp); // send the bytes 193 | Udp.endPacket(); // mark the end of the OSC Packet 194 | msgOUT.empty(); // free space occupied by message 195 | 196 | 197 | if (state < sensorValue - 10 && state > faderMin) { 198 | motor.run(BACKWARD); 199 | while (state < sensorValue - 10) { 200 | }; //Loops until motor is done moving 201 | motor.run(RELEASE); 202 | } 203 | 204 | else if (state > sensorValue + 10 && state < faderMax) { 205 | motor.run(FORWARD); 206 | while (state > sensorValue + 10) { 207 | }; //Loops until motor is done moving 208 | motor.run(RELEASE); 209 | } 210 | 211 | motor.run(RELEASE); 212 | delay(100); 213 | } 214 | 215 | 216 | void calibrateFader() { 217 | //Send fader to the top and read max position 218 | motor.run(FORWARD); 219 | delay(500); 220 | motor.run(RELEASE); 221 | faderMax = analogRead(sensorPin); 222 | 223 | //Send fader to the bottom and read max position 224 | motor.run(BACKWARD); 225 | delay(500); 226 | motor.run(RELEASE); 227 | faderMin = analogRead(sensorPin); 228 | } 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | -------------------------------------------------------------------------------- /OSC__with_three_Encoders_SDsetup.ino: -------------------------------------------------------------------------------- 1 | //THESE ARE THE LIBRARIES THAT NEED TO BE INSTALLED FOR THIS TO WORK 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #define ENCODER_DO_NOT_USE_INTERRUPTS 8 | #include 9 | 10 | Encoder myEnc1(A0, A1); // the number of the encoder 1 pins 11 | Encoder myEnc2(A2, A3); // the number of the encoder 2 pins 12 | Encoder myEnc3(A4, A5); // the number of the encoder 2 pins 13 | 14 | 15 | const int buttonPin = 2; // the number of the pushbutton pin 16 | const int buttonPin1 = 7; // the number of the pushbutton pin 17 | const int buttonPin2 = 8; // the number of the pushbutton pin 18 | 19 | const int ledPin = 3; 20 | const int ledPin1 = 5; 21 | const int ledPin2 = 6; 22 | long oldPosition1 = -999; 23 | long oldPosition2 = -999; 24 | long oldPosition3 = -999; 25 | 26 | 27 | int lastButtonState = LOW; // the previous reading from the input pin 28 | int lastButtonState1 = LOW; // the previous reading from the input pin 29 | int lastButtonState2 = LOW; // the previous reading from the input pin 30 | 31 | // the following variables are long's because the time, measured in miliseconds, 32 | // will quickly become a bigger number than can be stored in an int. 33 | long lastDebounceTime = 0; // the last time the output pin was toggled 34 | long debounceDelay = 50; // the debounce time; increase if the output flickers 35 | long lastDebounceTime1 = 0; // the last time the output pin was toggled 36 | long debounceDelay1 = 50; // the debounce time; increase if the output flickers 37 | long lastDebounceTime2 = 0; // the last time the output pin was toggled 38 | long debounceDelay2 = 50; // the debounce time; increase if the output flickers 39 | 40 | int buttonState = 0; // variable for reading the pushbutton status 41 | int buttonState1 = 0; // variable for reading the pushbutton status 42 | int buttonState2 = 0; // variable for reading the pushbutton status 43 | 44 | char oscMsg1[32]; 45 | char oscMsg2[32]; 46 | char oscMsg3[32]; 47 | char oscMsg4[32]; 48 | char oscMsg5[32]; 49 | char oscMsg6[32]; 50 | 51 | byte myMac[6] = { 52 | 53 | }; 54 | byte myNM[4] = { 55 | 56 | }; 57 | byte myIP[4] = { 58 | 59 | }; 60 | byte myGW[4] = { 61 | 62 | }; 63 | byte RemIP[4] = { 64 | 65 | }; 66 | 67 | int RemPort = 0; // remote port to transmit to 68 | 69 | 70 | EthernetUDP Udp; 71 | //SETUP FOR PIN DEFINITION 72 | void setup() { 73 | pinMode(buttonPin, INPUT_PULLUP); 74 | pinMode(buttonPin1, INPUT_PULLUP); 75 | pinMode(buttonPin2, INPUT_PULLUP); 76 | 77 | //LEDs on BUTTONS 78 | pinMode(ledPin, OUTPUT); 79 | analogWrite(ledPin, 67); 80 | pinMode(ledPin1, OUTPUT); 81 | analogWrite(ledPin1, 67); 82 | pinMode(ledPin2, OUTPUT); 83 | analogWrite(ledPin2, 67); 84 | 85 | //ETHERNET ENABLE 86 | pinMode(10, OUTPUT); 87 | digitalWrite(10, HIGH); 88 | 89 | 90 | ShieldSetup ();//setup ethernet shield 91 | 92 | 93 | Udp.begin(RemPort); 94 | 95 | 96 | } 97 | 98 | 99 | //THIS SECTION LOADS SETTINGS.TXT FILE INTO LOCAL MEMORY AND SETS UP ETHERNET 100 | void ShieldSetup() 101 | { 102 | Serial.begin(9600); 103 | while (!Serial) ; 104 | 105 | if (!SD.begin(4)) Serial.println(F("SD fail")); 106 | else Serial.println(F("SD ok")); 107 | 108 | File fh = SD.open("settings.txt", FILE_READ); 109 | char netBuffer[32]; 110 | 111 | if (!fh) 112 | { 113 | Serial.println(F("SD open fail")); 114 | return; 115 | } 116 | 117 | int chPos = 0; 118 | int lineNo = 0; 119 | 120 | 121 | while (fh.available()) 122 | { 123 | char ch = fh.read(); 124 | if (ch == '\n') { 125 | chPos = 0; 126 | //DIAG INFO FROM SD CARD 127 | switch (lineNo) { 128 | case 0: 129 | if (getMAC(netBuffer, myMac)) Serial.println(F("mac ok")); 130 | break; 131 | 132 | case 2: 133 | if (getIP(netBuffer, myIP)) Serial.println(F("ip ok")); 134 | break; 135 | 136 | case 4: 137 | if (getIP(netBuffer, myNM)) Serial.println(F("NM ok")); 138 | break; 139 | 140 | case 6: 141 | if (getIP(netBuffer, myGW)) Serial.println(F("GW ok")); 142 | break; 143 | 144 | case 8: 145 | if (getIP(netBuffer, RemIP)) Serial.println(F("CNSL ok")); 146 | break; 147 | 148 | case 10: 149 | RemPort = atoi(&netBuffer[0]); 150 | Serial.print(F("Port ")); 151 | Serial.println(RemPort); 152 | break; 153 | 154 | case 12: 155 | strcpy( oscMsg1, netBuffer ); 156 | Serial.print(F("OSC Command1: ")); 157 | Serial.println(oscMsg1); 158 | break; 159 | 160 | case 14: 161 | strcpy( oscMsg2, netBuffer ); 162 | Serial.print(F("OSC Command2: ")); 163 | Serial.println(oscMsg2); 164 | break; 165 | 166 | case 16: 167 | strcpy( oscMsg3, netBuffer ); 168 | Serial.print(F("OSC Command3: ")); 169 | Serial.println(oscMsg3); 170 | break; 171 | 172 | case 18: 173 | strcpy( oscMsg4, netBuffer ); 174 | Serial.print(F("OSC Command4: ")); 175 | Serial.println(oscMsg4); 176 | break; 177 | 178 | case 20: 179 | strcpy( oscMsg5, netBuffer ); 180 | Serial.print(F("OSC Command5: ")); 181 | Serial.println(oscMsg5); 182 | break; 183 | 184 | case 22: 185 | strcpy( oscMsg6, netBuffer ); 186 | Serial.print(F("OSC Command6: ")); 187 | Serial.println(oscMsg6); 188 | break; 189 | } 190 | 191 | lineNo++; 192 | } 193 | else if (ch == '\r') { 194 | // do nothing 195 | } 196 | else if (chPos < 32) { 197 | netBuffer[chPos] = ch; 198 | chPos++; 199 | netBuffer[chPos] = 0; 200 | } 201 | } 202 | 203 | fh.close(); 204 | 205 | int x; 206 | //THIS PRINTS OUT DIAGNOSTIC INFO IF YOU ARE CONNECTED TO THE ARDUINO IDE 207 | 208 | Serial.print("\r\nmac "); 209 | for (x = 0; x < 6; x++) { 210 | Serial.print(myMac[x], HEX); 211 | if (x < 5) Serial.print(":"); 212 | } 213 | 214 | Serial.print("\r\nip "); 215 | for (x = 0; x < 4; x++) { 216 | Serial.print(myIP[x], DEC); 217 | if (x < 3) Serial.print("."); 218 | } 219 | 220 | Serial.print("\r\nnetmask "); 221 | for (x = 0; x < 4; x++) { 222 | Serial.print(myNM[x], DEC); 223 | if (x < 3) Serial.print("."); 224 | } 225 | 226 | Serial.print("\r\ngateway "); 227 | for (x = 0; x < 4; x++) { 228 | Serial.print(myGW[x], DEC); 229 | if (x < 3) Serial.print("."); 230 | } 231 | 232 | Serial.print("\r\nconsole "); 233 | for (x = 0; x < 4; x++) { 234 | Serial.print(RemIP[x], DEC); 235 | if (x < 3) Serial.print("."); 236 | } 237 | 238 | 239 | Serial.println(F("\r\nStarting ethernet")); 240 | Ethernet.begin(myMac, myIP, myGW, myGW, myNM); 241 | 242 | Serial.println(Ethernet.localIP()); 243 | 244 | } 245 | 246 | //MAIN LOOP OF PROGRAM THIS IS WHERE THE MAGIC HAPPENS 247 | 248 | void loop() { 249 | long newPosition1 = myEnc1.read(); 250 | long newPosition2 = myEnc2.read(); 251 | long newPosition3 = myEnc3.read(); 252 | 253 | int reading = digitalRead(buttonPin); 254 | int reading1 = digitalRead(buttonPin1); 255 | int reading2 = digitalRead(buttonPin2); 256 | 257 | 258 | //ENCODER ONE OSCMSG1 259 | 260 | if (newPosition1 > oldPosition1) 261 | { //the message wants an OSC address as first argument 262 | OSCMessage msg(oscMsg1); 263 | msg.add("1"); 264 | Udp.beginPacket(RemIP, RemPort); 265 | msg.send(Udp); // send the bytes to the SLIP stream 266 | Udp.endPacket(); // mark the end of the OSC Packet 267 | msg.empty(); // free space occupied by message 268 | oldPosition1 = newPosition1; 269 | 270 | } 271 | 272 | if (newPosition1 < oldPosition1) 273 | { //the message wants an OSC address as first argument 274 | OSCMessage msg(oscMsg1); 275 | msg.add("-1"); 276 | Udp.beginPacket(RemIP, RemPort); 277 | msg.send(Udp); // send the bytes to the SLIP stream 278 | Udp.endPacket(); // mark the end of the OSC Packet 279 | msg.empty(); // free space occupied by message 280 | oldPosition1 = newPosition1; 281 | 282 | } 283 | 284 | 285 | //ENCODER 2 OSCMSG2 286 | 287 | if (newPosition2 > oldPosition2) 288 | { //the message wants an OSC address as first argument 289 | OSCMessage msg(oscMsg2); 290 | msg.add("1"); 291 | Udp.beginPacket(RemIP, RemPort); 292 | msg.send(Udp); // send the bytes to the SLIP stream 293 | Udp.endPacket(); // mark the end of the OSC Packet 294 | msg.empty(); // free space occupied by message 295 | oldPosition2 = newPosition2; 296 | 297 | } 298 | 299 | if (newPosition2 < oldPosition2) 300 | { //the message wants an OSC address as first argument 301 | OSCMessage msg(oscMsg2); 302 | msg.add("-1"); 303 | Udp.beginPacket(RemIP, RemPort); 304 | msg.send(Udp); // send the bytes to the SLIP stream 305 | Udp.endPacket(); // mark the end of the OSC Packet 306 | msg.empty(); // free space occupied by message 307 | oldPosition2 = newPosition2; 308 | 309 | } 310 | 311 | 312 | //ENCODER 3 OSCMSG3 313 | 314 | if (newPosition3 > oldPosition3) 315 | { //the message wants an OSC address as first argument 316 | OSCMessage msg(oscMsg3); 317 | msg.add("1"); 318 | Udp.beginPacket(RemIP, RemPort); 319 | msg.send(Udp); // send the bytes to the SLIP stream 320 | Udp.endPacket(); // mark the end of the OSC Packet 321 | msg.empty(); // free space occupied by message 322 | oldPosition3 = newPosition3; 323 | 324 | } 325 | 326 | if (newPosition3 < oldPosition3) 327 | { //the message wants an OSC address as first argument 328 | OSCMessage msg(oscMsg3); 329 | msg.add("-1"); 330 | Udp.beginPacket(RemIP, RemPort); 331 | msg.send(Udp); // send the bytes to the SLIP stream 332 | Udp.endPacket(); // mark the end of the OSC Packet 333 | msg.empty(); // free space occupied by message 334 | oldPosition3 = newPosition3; 335 | 336 | } 337 | 338 | //BUTTON 1 OSCMSG4 339 | 340 | if (reading != lastButtonState) { 341 | // reset the debouncing timer 342 | lastDebounceTime = millis(); 343 | } 344 | 345 | if ((millis() - lastDebounceTime) > debounceDelay) { 346 | // whatever the reading is at, it's been there for longer 347 | // than the debounce delay, so take it as the actual current state: 348 | 349 | // if the button state has changed: 350 | if (reading != buttonState) { 351 | buttonState = reading; 352 | 353 | // only toggle the LED if the new button state is LOW 354 | if (buttonState == LOW) { 355 | //the message wants an OSC address as first argument 356 | OSCMessage msg(oscMsg4); 357 | msg.add("1"); 358 | analogWrite(ledPin, 255); 359 | Udp.beginPacket(RemIP, RemPort); 360 | msg.send(Udp); // send the bytes to the SLIP stream 361 | Udp.endPacket(); // mark the end of the OSC Packet 362 | msg.empty(); // free space occupied by message 363 | } 364 | if (buttonState == HIGH) { 365 | //the message wants an OSC address as first argument 366 | OSCMessage msg(oscMsg4); 367 | msg.add("0"); 368 | analogWrite(ledPin, 67); 369 | Udp.beginPacket(RemIP, RemPort); 370 | msg.send(Udp); // send the bytes to the SLIP stream 371 | Udp.endPacket(); // mark the end of the OSC Packet 372 | msg.empty(); // free space occupied by message 373 | } 374 | } 375 | } 376 | 377 | //BUTTON 2 OSCMSG5 378 | 379 | if (reading1 != lastButtonState1) { 380 | // reset the debouncing timer 381 | lastDebounceTime1 = millis(); 382 | } 383 | 384 | if ((millis() - lastDebounceTime1) > debounceDelay1) { 385 | // whatever the reading is at, it's been there for longer 386 | // than the debounce delay, so take it as the actual current state: 387 | 388 | // if the button state has changed: 389 | if (reading1 != buttonState1) { 390 | buttonState1 = reading1; 391 | 392 | // only toggle the LED if the new button state is LOW 393 | if (buttonState1 == LOW) { 394 | OSCMessage msg(oscMsg5); 395 | msg.add("1"); 396 | analogWrite(ledPin1, 255); 397 | Udp.beginPacket(RemIP, RemPort); 398 | msg.send(Udp); // send the bytes to the SLIP stream 399 | Udp.endPacket(); // mark the end of the OSC Packet 400 | msg.empty(); // free space occupied by message 401 | } 402 | if (buttonState1 == HIGH) { 403 | //the message wants an OSC address as first argument 404 | OSCMessage msg(oscMsg5); 405 | msg.add("0"); 406 | analogWrite(ledPin1, 67); 407 | Udp.beginPacket(RemIP, RemPort); 408 | msg.send(Udp); // send the bytes to the SLIP stream 409 | Udp.endPacket(); // mark the end of the OSC Packet 410 | msg.empty(); // free space occupied by message 411 | } 412 | } 413 | } 414 | 415 | //BUTTON 3 OSCMSG6 416 | 417 | if ((millis() - lastDebounceTime2) > debounceDelay2) { 418 | // whatever the reading is at, it's been there for longer 419 | // than the debounce delay, so take it as the actual current state: 420 | 421 | // if the button state has changed: 422 | if (reading2 != buttonState2) { 423 | buttonState2 = reading2; 424 | 425 | // only toggle the LED if the new button state is LOW 426 | if (buttonState2 == LOW) { 427 | OSCMessage msg(oscMsg6); 428 | msg.add("1"); 429 | analogWrite(ledPin2, 255); 430 | Udp.beginPacket(RemIP, RemPort); 431 | msg.send(Udp); // send the bytes to the SLIP stream 432 | Udp.endPacket(); // mark the end of the OSC Packet 433 | msg.empty(); // free space occupied by message 434 | } 435 | if (buttonState2 == HIGH) { 436 | //the message wants an OSC address as first argument 437 | OSCMessage msg(oscMsg6); 438 | msg.add("0"); 439 | analogWrite(ledPin2, 67); 440 | Udp.beginPacket(RemIP, RemPort); 441 | msg.send(Udp); // send the bytes to the SLIP stream 442 | Udp.endPacket(); // mark the end of the OSC Packet 443 | msg.empty(); // free space occupied by message 444 | } 445 | } 446 | } 447 | 448 | 449 | lastButtonState = reading; 450 | lastButtonState1 = reading1; 451 | lastButtonState2 = reading2; 452 | 453 | } 454 | 455 | 456 | //THIS IS PART OF THE SETUP THAT CONVERTS TEXT FROM THE SD CARD INTO NUMBERS FOR THE MAC ADDRESS AND IP ADDRESS 457 | 458 | 459 | byte getMAC(char* macBuf, byte* thisMAC) { 460 | byte thisLen = strlen(macBuf); 461 | byte thisOctet = 1; 462 | 463 | thisMAC[0] = strtol(&macBuf[0], NULL, 16); 464 | 465 | for (int x = 0; x < thisLen; x++) { 466 | if (macBuf[x] == ':') { 467 | thisMAC[thisOctet] = strtol(&macBuf[x + 1], NULL, 16); 468 | thisOctet++; 469 | } 470 | } 471 | 472 | if (thisOctet == 6) return (1); 473 | else return (0); 474 | 475 | } 476 | 477 | byte getIP(char* ipBuf, byte* thisIP) { 478 | byte thisLen = strlen(ipBuf); 479 | byte thisOctet = 1; 480 | 481 | thisIP[0] = atoi(&ipBuf[0]); 482 | 483 | for (int x = 0; x < thisLen; x++) { 484 | if (ipBuf[x] == '.') { 485 | thisIP[thisOctet] = atoi(&ipBuf[x + 1]); 486 | thisOctet++; 487 | } 488 | } 489 | 490 | if (thisOctet == 4) return (1); 491 | else return (0); 492 | } 493 | 494 | 495 | 496 | 497 | 498 | -------------------------------------------------------------------------------- /OSC__with_two_Encoders_SDsetup.ino: -------------------------------------------------------------------------------- 1 | //THESE ARE THE LIBRARIES THAT NEED TO BE INSTALLED FOR THIS TO WORK 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #define ENCODER_DO_NOT_USE_INTERRUPTS 8 | #include 9 | 10 | Encoder myEnc1(6, 7); // the number of the encoder 1 pins 11 | Encoder myEnc2(8, 9); // the number of the encoder 2 pins 12 | 13 | 14 | const int buttonPin = A0; // the number of the pushbutton pin 15 | const int buttonPin1 = A1; // the number of the pushbutton pin 16 | const int ledPin = 3; 17 | const int ledPin1 = 5; 18 | long oldPosition1 = -999; 19 | long oldPosition2 = -999; 20 | 21 | 22 | int lastButtonState = LOW; // the previous reading from the input pin 23 | int lastButtonState1 = LOW; // the previous reading from the input pin 24 | 25 | // the following variables are long's because the time, measured in miliseconds, 26 | // will quickly become a bigger number than can be stored in an int. 27 | long lastDebounceTime = 0; // the last time the output pin was toggled 28 | long debounceDelay = 50; // the debounce time; increase if the output flickers 29 | long lastDebounceTime1 = 0; // the last time the output pin was toggled 30 | long debounceDelay1 = 50; // the debounce time; increase if the output flickers 31 | 32 | int buttonState = 0; // variable for reading the pushbutton status 33 | int buttonState1 = 0; // variable for reading the pushbutton status 34 | 35 | char oscMsg1[32]; 36 | char oscMsg2[32]; 37 | char oscMsg3[32]; 38 | char oscMsg4[32]; 39 | 40 | 41 | byte myMac[6] = { 42 | 43 | }; 44 | byte myNM[4] = { 45 | 46 | }; 47 | byte myIP[4] = { 48 | 49 | }; 50 | byte myGW[4] = { 51 | 52 | }; 53 | byte RemIP[4] = { 54 | 55 | }; 56 | 57 | int RemPort = 0; // remote port to transmit to 58 | 59 | 60 | EthernetUDP Udp; 61 | //SETUP FOR PIN DEFINITION 62 | void setup() { 63 | pinMode(buttonPin, INPUT_PULLUP); 64 | pinMode(buttonPin1, INPUT_PULLUP); 65 | 66 | //LEDs on BUTTONS 67 | pinMode(ledPin, OUTPUT); 68 | analogWrite(ledPin, 67); 69 | pinMode(ledPin1, OUTPUT); 70 | analogWrite(ledPin1, 67); 71 | 72 | //ETHERNET ENABLE 73 | pinMode(10, OUTPUT); 74 | digitalWrite(10, HIGH); 75 | 76 | 77 | ShieldSetup ();//setup ethernet shield 78 | 79 | 80 | Udp.begin(RemPort); 81 | 82 | 83 | } 84 | 85 | 86 | //THIS SECTION LOADS SETTINGS.TXT FILE INTO LOCAL MEMORY AND SETS UP ETHERNET 87 | void ShieldSetup() 88 | { 89 | Serial.begin(9600); 90 | while (!Serial) ; 91 | 92 | if (!SD.begin(4)) Serial.println(F("SD fail")); 93 | else Serial.println(F("SD ok")); 94 | 95 | File fh = SD.open("settings.txt", FILE_READ); 96 | char netBuffer[32]; 97 | 98 | if (!fh) 99 | { 100 | Serial.println(F("SD open fail")); 101 | return; 102 | } 103 | 104 | int chPos = 0; 105 | int lineNo = 0; 106 | 107 | 108 | while (fh.available()) 109 | { 110 | char ch = fh.read(); 111 | if (ch == '\n') { 112 | chPos = 0; 113 | //DIAG INFO FROM SD CARD 114 | switch (lineNo) { 115 | case 0: 116 | if (getMAC(netBuffer, myMac)) Serial.println(F("mac ok")); 117 | break; 118 | 119 | case 2: 120 | if (getIP(netBuffer, myIP)) Serial.println(F("ip ok")); 121 | break; 122 | 123 | case 4: 124 | if (getIP(netBuffer, myNM)) Serial.println(F("NM ok")); 125 | break; 126 | 127 | case 6: 128 | if (getIP(netBuffer, myGW)) Serial.println(F("GW ok")); 129 | break; 130 | 131 | case 8: 132 | if (getIP(netBuffer, RemIP)) Serial.println(F("CNSL ok")); 133 | break; 134 | 135 | case 10: 136 | RemPort = atoi(&netBuffer[0]); 137 | Serial.print(F("Port ")); 138 | Serial.println(RemPort); 139 | break; 140 | 141 | case 12: 142 | strcpy( oscMsg1, netBuffer ); 143 | Serial.print(F("OSC Command1: ")); 144 | Serial.println(oscMsg1); 145 | break; 146 | 147 | case 14: 148 | strcpy( oscMsg2, netBuffer ); 149 | Serial.print(F("OSC Command2: ")); 150 | Serial.println(oscMsg2); 151 | break; 152 | 153 | case 16: 154 | strcpy( oscMsg3, netBuffer ); 155 | Serial.print(F("OSC Command3: ")); 156 | Serial.println(oscMsg3); 157 | break; 158 | 159 | case 18: 160 | strcpy( oscMsg4, netBuffer ); 161 | Serial.print(F("OSC Command4: ")); 162 | Serial.println(oscMsg4); 163 | break; 164 | 165 | 166 | } 167 | 168 | lineNo++; 169 | } 170 | else if (ch == '\r') { 171 | // do nothing 172 | } 173 | else if (chPos < 32) { 174 | netBuffer[chPos] = ch; 175 | chPos++; 176 | netBuffer[chPos] = 0; 177 | } 178 | } 179 | 180 | fh.close(); 181 | 182 | int x; 183 | //THIS PRINTS OUT DIAGNOSTIC INFO IF YOU ARE CONNECTED TO THE ARDUINO IDE 184 | 185 | Serial.print("\r\nmac "); 186 | for (x = 0; x < 6; x++) { 187 | Serial.print(myMac[x], HEX); 188 | if (x < 5) Serial.print(":"); 189 | } 190 | 191 | Serial.print("\r\nip "); 192 | for (x = 0; x < 4; x++) { 193 | Serial.print(myIP[x], DEC); 194 | if (x < 3) Serial.print("."); 195 | } 196 | 197 | Serial.print("\r\nnetmask "); 198 | for (x = 0; x < 4; x++) { 199 | Serial.print(myNM[x], DEC); 200 | if (x < 3) Serial.print("."); 201 | } 202 | 203 | Serial.print("\r\ngateway "); 204 | for (x = 0; x < 4; x++) { 205 | Serial.print(myGW[x], DEC); 206 | if (x < 3) Serial.print("."); 207 | } 208 | 209 | Serial.print("\r\nconsole "); 210 | for (x = 0; x < 4; x++) { 211 | Serial.print(RemIP[x], DEC); 212 | if (x < 3) Serial.print("."); 213 | } 214 | 215 | 216 | Serial.println(F("\r\nStarting ethernet")); 217 | Ethernet.begin(myMac, myIP, myGW, myGW, myNM); 218 | 219 | Serial.println(Ethernet.localIP()); 220 | 221 | } 222 | 223 | //MAIN LOOP OF PROGRAM THIS IS WHERE THE MAGIC HAPPENS 224 | 225 | void loop() { 226 | long newPosition1 = myEnc1.read(); 227 | long newPosition2 = myEnc2.read(); 228 | 229 | int reading = digitalRead(buttonPin); 230 | int reading1 = digitalRead(buttonPin1); 231 | 232 | //ENCODER ONE OSCMSG1 233 | 234 | if (newPosition1 > oldPosition1) 235 | { //the message wants an OSC address as first argument 236 | OSCMessage msg(oscMsg1); 237 | msg.add("1"); 238 | Udp.beginPacket(RemIP, RemPort); 239 | msg.send(Udp); // send the bytes to the SLIP stream 240 | Udp.endPacket(); // mark the end of the OSC Packet 241 | msg.empty(); // free space occupied by message 242 | oldPosition1 = newPosition1; 243 | 244 | } 245 | 246 | if (newPosition1 < oldPosition1) 247 | { //the message wants an OSC address as first argument 248 | OSCMessage msg(oscMsg1); 249 | msg.add("-1"); 250 | Udp.beginPacket(RemIP, RemPort); 251 | msg.send(Udp); // send the bytes to the SLIP stream 252 | Udp.endPacket(); // mark the end of the OSC Packet 253 | msg.empty(); // free space occupied by message 254 | oldPosition1 = newPosition1; 255 | 256 | } 257 | 258 | 259 | //ENCODER 2 OSCMSG2 260 | 261 | if (newPosition2 > oldPosition2) 262 | { //the message wants an OSC address as first argument 263 | OSCMessage msg(oscMsg2); 264 | msg.add("1"); 265 | Udp.beginPacket(RemIP, RemPort); 266 | msg.send(Udp); // send the bytes to the SLIP stream 267 | Udp.endPacket(); // mark the end of the OSC Packet 268 | msg.empty(); // free space occupied by message 269 | oldPosition2 = newPosition2; 270 | 271 | } 272 | 273 | if (newPosition2 < oldPosition2) 274 | { //the message wants an OSC address as first argument 275 | OSCMessage msg(oscMsg2); 276 | msg.add("-1"); 277 | Udp.beginPacket(RemIP, RemPort); 278 | msg.send(Udp); // send the bytes to the SLIP stream 279 | Udp.endPacket(); // mark the end of the OSC Packet 280 | msg.empty(); // free space occupied by message 281 | oldPosition2 = newPosition2; 282 | 283 | } 284 | 285 | //BUTTON 1 OSCMSG3 286 | 287 | if (reading != lastButtonState) { 288 | // reset the debouncing timer 289 | lastDebounceTime = millis(); 290 | } 291 | 292 | if ((millis() - lastDebounceTime) > debounceDelay) { 293 | // whatever the reading is at, it's been there for longer 294 | // than the debounce delay, so take it as the actual current state: 295 | 296 | // if the button state has changed: 297 | if (reading != buttonState) { 298 | buttonState = reading; 299 | 300 | // only toggle the LED if the new button state is LOW 301 | if (buttonState == LOW) { 302 | //the message wants an OSC address as first argument 303 | OSCMessage msg(oscMsg3); 304 | msg.add("1"); 305 | analogWrite(ledPin, 255); 306 | Udp.beginPacket(RemIP, RemPort); 307 | msg.send(Udp); // send the bytes to the SLIP stream 308 | Udp.endPacket(); // mark the end of the OSC Packet 309 | msg.empty(); // free space occupied by message 310 | } 311 | if (buttonState == HIGH) { 312 | //the message wants an OSC address as first argument 313 | OSCMessage msg(oscMsg3); 314 | msg.add("0"); 315 | analogWrite(ledPin, 67); 316 | Udp.beginPacket(RemIP, RemPort); 317 | msg.send(Udp); // send the bytes to the SLIP stream 318 | Udp.endPacket(); // mark the end of the OSC Packet 319 | msg.empty(); // free space occupied by message 320 | } 321 | } 322 | } 323 | 324 | //BUTTON 2 OSCMSG4 325 | 326 | if (reading1 != lastButtonState1) { 327 | // reset the debouncing timer 328 | lastDebounceTime1 = millis(); 329 | } 330 | 331 | if ((millis() - lastDebounceTime1) > debounceDelay1) { 332 | // whatever the reading is at, it's been there for longer 333 | // than the debounce delay, so take it as the actual current state: 334 | 335 | // if the button state has changed: 336 | if (reading1 != buttonState1) { 337 | buttonState1 = reading1; 338 | 339 | // only toggle the LED if the new button state is LOW 340 | if (buttonState1 == LOW) { 341 | OSCMessage msg(oscMsg4); 342 | msg.add("1"); 343 | analogWrite(ledPin1, 255); 344 | Udp.beginPacket(RemIP, RemPort); 345 | msg.send(Udp); // send the bytes to the SLIP stream 346 | Udp.endPacket(); // mark the end of the OSC Packet 347 | msg.empty(); // free space occupied by message 348 | } 349 | if (buttonState1 == HIGH) { 350 | //the message wants an OSC address as first argument 351 | OSCMessage msg(oscMsg4); 352 | msg.add("0"); 353 | analogWrite(ledPin1, 67); 354 | Udp.beginPacket(RemIP, RemPort); 355 | msg.send(Udp); // send the bytes to the SLIP stream 356 | Udp.endPacket(); // mark the end of the OSC Packet 357 | msg.empty(); // free space occupied by message 358 | } 359 | } 360 | } 361 | 362 | 363 | lastButtonState = reading; 364 | lastButtonState1 = reading1; 365 | 366 | } 367 | 368 | 369 | //THIS IS PART OF THE SETUP THAT CONVERTS TEXT FROM THE SD CARD INTO NUMBERS FOR THE MAC ADDRESS AND IP ADDRESS 370 | 371 | 372 | byte getMAC(char* macBuf, byte* thisMAC) { 373 | byte thisLen = strlen(macBuf); 374 | byte thisOctet = 1; 375 | 376 | thisMAC[0] = strtol(&macBuf[0], NULL, 16); 377 | 378 | for (int x = 0; x < thisLen; x++) { 379 | if (macBuf[x] == ':') { 380 | thisMAC[thisOctet] = strtol(&macBuf[x + 1], NULL, 16); 381 | thisOctet++; 382 | } 383 | } 384 | 385 | if (thisOctet == 6) return (1); 386 | else return (0); 387 | 388 | } 389 | 390 | byte getIP(char* ipBuf, byte* thisIP) { 391 | byte thisLen = strlen(ipBuf); 392 | byte thisOctet = 1; 393 | 394 | thisIP[0] = atoi(&ipBuf[0]); 395 | 396 | for (int x = 0; x < thisLen; x++) { 397 | if (ipBuf[x] == '.') { 398 | thisIP[thisOctet] = atoi(&ipBuf[x + 1]); 399 | thisOctet++; 400 | } 401 | } 402 | 403 | if (thisOctet == 4) return (1); 404 | else return (0); 405 | } 406 | 407 | 408 | 409 | 410 | 411 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ETC Eos Arduino sketeches and Touch osc layouts. 2 | 3 | TouchOSC MK2 Eos Layout with built in encoders, faders, ability to store layouts, Label channels, cues, subs, etc. 4 | 5 | modified and expanded LightHack sketches for use with ETC Eos family consoles. 6 | Networked accessories that use OSC to communicate with the Eos consoles. 7 | Latest is example sketch for TCP based OSC communication from arduino using tinyslip. 8 | 9 | Feel free to use these sketches in your projects. I would love to hear what people are doing with them. This is a collection of sketches I've used on different projects and not all the same project. 10 | Some of the sketches are setup to have their network setup on an SD card. There is an example settings.txt file for reference. 11 | 12 | I haven't made a huge amount of documentation on connections for encoders/faders/lcd screens etc so there will be some puzzle work to be done on these projects. 13 | -------------------------------------------------------------------------------- /TinySlipExample.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | 11 | 12 | #define BUFFER_MAX_SIZE 256 13 | unsigned char parsedSlipBuffer[BUFFER_MAX_SIZE]; 14 | 15 | 16 | 17 | 18 | #define EOS_CUESTRING_MAX_SIZE 13 19 | char currentChannel[100]; 20 | char currentWheel[20]; 21 | char currentWheelName[100]; 22 | const char* EOS_ACTIVE_CUE = "/eos/out/active/cue"; 23 | 24 | 25 | EthernetClient client; 26 | TinySlip slip( &client ); 27 | 28 | 29 | 30 | 31 | //the Arduino's IP 32 | IPAddress ip(10, 101, 95, 135); 33 | //destination IP 34 | IPAddress outIp(10, 101, 95, 102); 35 | const unsigned int outPort = 3037; 36 | 37 | byte mac[] = { 38 | 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED 39 | }; // you can find this written on the board of some Arduino Ethernets or shields 40 | 41 | 42 | 43 | 44 | 45 | 46 | void setup() { 47 | 48 | Ethernet.init(10); 49 | Serial.begin(57600); 50 | Ethernet.begin(mac, ip); 51 | client.connect(outIp, outPort); 52 | Serial.println("connecting"); 53 | } 54 | 55 | void loop() { 56 | 57 | size_t packetLength = slip.parsePacket(parsedSlipBuffer, BUFFER_MAX_SIZE); 58 | 59 | 60 | 61 | 62 | OSCMessage msgIN; 63 | // IF WE RECEIVED A PACKET 64 | if ( packetLength > 0 ) { 65 | 66 | msgIN.fill(parsedSlipBuffer, BUFFER_MAX_SIZE); 67 | 68 | } 69 | parseOSCMessage(msgIN); 70 | 71 | 72 | sendOSCMessage(); 73 | 74 | } 75 | 76 | 77 | void parseOSCMessage(OSCMessage &msg) 78 | { 79 | 80 | // We will store temporary values in these variables until the entire string has been validated. 81 | float cCue; 82 | 83 | msg.route(EOS_ACTIVE_CUE, updateActiveCue); 84 | msg.route("/eos/out/active/chan", updateActiveChannel); 85 | //msg.route("/eos/out", updateActivity); 86 | msg.route("/eos/out/active/wheel", updateWheel); 87 | // msg.route("/eos/out/ping", updatePing); 88 | 89 | 90 | 91 | } 92 | 93 | 94 | void updateActivity(OSCMessage& msg, int addressOffset) 95 | { 96 | int length = msg.getDataLength(0); 97 | msg.getString(0, currentChannel, length); 98 | char * p = strchr (currentChannel, ' '); // search for space 99 | if (p) // if found truncate at space 100 | *p = 0; 101 | 102 | 103 | //Serial.print("Parsing OSC "); 104 | //Serial.println(currentChannel); 105 | 106 | } 107 | 108 | 109 | 110 | void updateWheel(OSCMessage& msg, int addressOffset) 111 | { 112 | int length = msg.getDataLength(0); 113 | 114 | //-------// 115 | 116 | 117 | char cueAddr[EOS_CUESTRING_MAX_SIZE]; 118 | msg.getAddress(cueAddr, addressOffset + 1, EOS_CUESTRING_MAX_SIZE); 119 | String addrString(cueAddr); 120 | int nextSlash = addrString.indexOf('/'); 121 | 122 | int cList = addrString.substring(0, nextSlash).toInt(); 123 | 124 | 125 | 126 | 127 | 128 | //-----// 129 | 130 | 131 | msg.getString(0, currentWheelName, length); 132 | char * p = strchr (currentWheelName, ' '); // search for space 133 | if (p) // if found truncate at space 134 | *p = 0; 135 | Serial.print("Current Wheel #"); 136 | Serial.println(cList); 137 | Serial.print("Current Wheel Name "); 138 | Serial.println(currentWheelName); 139 | } 140 | 141 | 142 | void updateActiveChannel(OSCMessage& msg, int addressOffset) 143 | { 144 | int length = msg.getDataLength(0); 145 | msg.getString(0, currentChannel, length); 146 | char * p = strchr (currentChannel, ' '); // search for space 147 | if (p) // if found truncate at space 148 | *p = 0; 149 | Serial.print(F("Current Channel :")); 150 | Serial.println(currentChannel); 151 | 152 | } 153 | 154 | 155 | 156 | void updateActiveCue(OSCMessage& msg, int addressOffset) 157 | { 158 | 159 | Serial.println("updating Cues"); 160 | 161 | char cueAddr[EOS_CUESTRING_MAX_SIZE]; 162 | msg.getAddress(cueAddr, addressOffset + 1, EOS_CUESTRING_MAX_SIZE); 163 | String addrString(cueAddr); 164 | int nextSlash = addrString.indexOf('/'); 165 | // if (nextSlash != -1) 166 | // { 167 | int cList = addrString.substring(0, nextSlash).toInt(); 168 | int cCue = addrString.substring(nextSlash + 1).toInt(); 169 | 170 | // Use the OSCMessage library to parse the argument(s) 171 | if (msg.isFloat(0)) 172 | { 173 | unsigned int cPct = (unsigned int)(msg.getFloat(0) * 100); 174 | // All parts of the message have been validated 175 | // Update the display 176 | 177 | // Current cue and list. Top left of display 178 | // lcd.setCursor(0,0); 179 | Serial.print("C:"); 180 | Serial.print(cList); 181 | Serial.print("/"); 182 | Serial.println(cCue); 183 | Serial.print("Cue % "); 184 | Serial.println(cPct); 185 | // } 186 | } 187 | } 188 | 189 | 190 | void updatePing () 191 | { 192 | OSCMessage msg("/eos/ping"); 193 | msg.add("1"); 194 | 195 | slip.beginPacket(); 196 | 197 | msg.send(client); 198 | 199 | slip.endPacket(); 200 | delay(20); 201 | 202 | } 203 | 204 | void sendOSCMessage () 205 | { 206 | 207 | OSCMessage msg("/eos/ping"); 208 | msg.add("1"); 209 | 210 | slip.beginPacket(); 211 | 212 | msg.send(client); 213 | 214 | slip.endPacket(); 215 | delay(20); 216 | } 217 | -------------------------------------------------------------------------------- /USB_OSC_4_encoders_5_Pages_RevC.ino: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Electronic Theatre Controls, Inc., http://www.etcconnect.com 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 22 | /******************************************************************************* 23 | 24 | Electronic Theatre Controls 25 | 26 | lighthack - Box 1 27 | 28 | (c) 2017 by ETC 29 | 30 | 31 | This code implements a Pan/Tilt module using two encoders and three 32 | buttons. The two encoders function as pan and tilt controllers with one 33 | button being reserved for controlling fine/coarse mode. The other two 34 | buttons are assigned to Next and Last which make it easy to switch between 35 | channels. 36 | 37 | This code adds to the initial with the addition of 2 more encoders bringing the total to 4 and adding 5 pages of encoder layouts 38 | This box is setup for 8 buttons plus using each encoder as a button bringing the total button inputs to 12 39 | Next/Last/Shift/Page1/Page2/Page3/Page4/Page5/Encoder1/Encoder2/Encoder3/Encoder4 40 | This sketch is intended for a Teensy 3.5 41 | This sketch will not work on an uno. 42 | It should work on a Mega2560 but would need pin changes for inputs. 43 | ******************************************************************************* 44 | 45 | NOTE: UPDATE VERSION_STRING IN DEFINITIONS BELOW WHEN VERSION NUMBER CHANGES 46 | 47 | Revision History 48 | 49 | yyyy-mm-dd Vxx By_Who Comment 50 | 51 | 2017-07-21 1.0.0.1 Ethan Oswald Massey Original creation 52 | 53 | 2017-10-19 1.0.0.2 Sam Kearney Fix build errors on some 54 | Arduino platforms. Change 55 | OSC subscribe parameters 56 | 57 | 2017-10-24 1.0.0.3 Sam Kearney Add ability to scale encoder 58 | output 59 | 60 | 2017-11-22 1.0.0.4 Hans Hinrichsen Add splash msg before Eos 61 | connects 62 | 63 | 2017-12-07 1.0.0.5 Hans Hinrichsen Added timeout to disconnect 64 | and show splash screen again 65 | 66 | ******************************************************************************/ 67 | /* 2018-10-17 1.0.0.5B Andrew Webberley Added Multiple pages with attribute on command line with encoder press. 68 | Changed how buttons are treated 69 | Hold encoder for super coarse mode. 70 | 2X40 Character Display 71 | Teensy 3.5 72 | If you want to use with consoles you must either spoof the PID/VID of an Uno or install Teensy serial driver 73 | 74 | 75 | */ 76 | /******************************************************************************* 77 | Includes 78 | ******************************************************************************/ 79 | #include 80 | #include 81 | #include 82 | #include 83 | #include 84 | #include 85 | #include 86 | #ifdef BOARD_HAS_USB_SERIAL 87 | #include 88 | SLIPEncodedUSBSerial SLIPSerial(thisBoardsSerialUSB); 89 | #else 90 | #include 91 | SLIPEncodedSerial SLIPSerial(Serial); 92 | #endif 93 | #include 94 | #include 95 | 96 | /******************************************************************************* 97 | Macros and Constants 98 | ******************************************************************************/ 99 | #define LCD_CHARS 40 100 | #define LCD_LINES 2 // Currently assume at least 2 lines 101 | 102 | #define NEXT_BTN 37 103 | #define LAST_BTN 38 104 | #define SHIFT_BTN 39 105 | #define MODE1_BTN 24 106 | #define MODE2_BTN 25 107 | #define MODE3_BTN 26 108 | #define MODE4_BTN 27 109 | #define MODE5_BTN 28 110 | #define ENC1_BTN 33 111 | #define ENC2_BTN 34 112 | #define ENC3_BTN 35 113 | #define ENC4_BTN 36 114 | 115 | 116 | #define SUBSCRIBE ((int32_t)1) 117 | #define UNSUBSCRIBE ((int32_t)0) 118 | 119 | #define EDGE_DOWN ((int32_t)1) 120 | #define EDGE_UP ((int32_t)0) 121 | 122 | #define FORWARD 0 123 | #define REVERSE 1 124 | 125 | // Change these values to switch which direction increase/decrease pan/tilt 126 | #define ENC1_DIR FORWARD 127 | #define ENC2_DIR FORWARD 128 | #define ENC3_DIR FORWARD 129 | #define ENC4_DIR FORWARD 130 | 131 | // Use these values to make the encoder more coarse or fine. This controls 132 | // the number of wheel "ticks" the device sends to Eos for each tick of the 133 | // encoder. 1 is the default and the most fine setting. Must be an integer. 134 | //#define ENC1_SCALE 1 135 | //#define ENC2_SCALE 1 136 | //#define ENC3_SCALE 1 137 | //#define ENC4_SCALE 1 138 | //changed to an int so they can be modified at run time. 139 | int ENC1_SCALE = 1; 140 | int ENC2_SCALE = 1; 141 | int ENC3_SCALE = 1; 142 | int ENC4_SCALE = 1; 143 | //added variables to set global "coarse" and "normal" encoder modes 144 | int encNorm = 1; 145 | int encCoarse = 8; 146 | #define SIG_DIGITS 2 // Number of significant digits displayed 147 | 148 | #define OSC_BUF_MAX_SIZE 512 149 | 150 | const String HANDSHAKE_QUERY = "ETCOSC?"; 151 | const String HANDSHAKE_REPLY = "OK"; 152 | 153 | //See displayScreen() below - limited to 10 chars (after 6 prefix chars) 154 | const String VERSION_STRING = "1.0.0.5B"; 155 | 156 | // Change these values to alter how long we wait before sending an OSC ping 157 | // to see if Eos is still there, and then finally how long before we 158 | // disconnect and show the splash screen 159 | // Values are in milliseconds 160 | #define PING_AFTER_IDLE_INTERVAL 5000 161 | #define TIMEOUT_AFTER_IDLE_INTERVAL 15000 162 | String enc1Name = "PAN"; 163 | String enc2Name = "TILT"; 164 | String enc3Name = "EDGE"; 165 | String enc4Name = "ZOOM"; 166 | char currentChannel[255]; 167 | int mode = 1; 168 | 169 | static uint32_t debounceTime1 = 0; 170 | static uint32_t debounceTime2 = 0; 171 | static uint32_t debounceTime11 = 0; 172 | static uint32_t debounceTime12 = 0; 173 | static uint32_t debounceTime13 = 0; 174 | static uint32_t debounceTime14 = 0; 175 | 176 | /******************************************************************************* 177 | Local Types 178 | ******************************************************************************/ 179 | enum WHEEL_TYPE { ENC1, ENC2, ENC3, ENC4 }; 180 | 181 | enum WHEEL_MODE { COARSE, FINE }; 182 | 183 | struct Encoder 184 | { 185 | uint8_t pinA; 186 | uint8_t pinB; 187 | int pinAPrevious; 188 | int pinBPrevious; 189 | float pos; 190 | uint8_t direction; 191 | }; 192 | struct Encoder enc1Wheel; 193 | struct Encoder enc2Wheel; 194 | struct Encoder enc3Wheel; 195 | struct Encoder enc4Wheel; 196 | 197 | /******************************************************************************* 198 | Global Variables 199 | ******************************************************************************/ 200 | 201 | // initialize the library with the numbers of the interface pins 202 | const int rs = 2, rw = 3, en = 5, d4 = 6, d5 = 7, d6 = 8, d7 = 9; 203 | LiquidCrystal lcd(rs, rw, en, d4, d5, d6, d7); 204 | 205 | bool updateDisplay = false; 206 | bool connectedToEos = false; 207 | unsigned long lastMessageRxTime = 0; 208 | bool timeoutPingSent = false; 209 | 210 | /******************************************************************************* 211 | Local Functions 212 | ******************************************************************************/ 213 | 214 | /******************************************************************************* 215 | Issues all our subscribes to Eos. When subscribed, Eos will keep us updated 216 | with the latest values for a given parameter. 217 | 218 | Parameters: none 219 | 220 | Return Value: void 221 | 222 | ******************************************************************************/ 223 | void issueSubscribes() 224 | { 225 | // Add a filter so we don't get spammed with unwanted OSC messages from Eos 226 | OSCMessage filter("/eos/filter/add"); 227 | filter.add("/eos/out/param/*"); 228 | filter.add("/eos/out/ping"); 229 | filter.add("/eos/out/active/chan"); 230 | SLIPSerial.beginPacket(); 231 | filter.send(SLIPSerial); 232 | SLIPSerial.endPacket(); 233 | 234 | 235 | if (mode == 1) { 236 | // subscribe to Eos pan & tilt updates 237 | OSCMessage subOne("/eos/subscribe/param/pan/tilt/zoom/edge"); 238 | subOne.add(SUBSCRIBE); 239 | SLIPSerial.beginPacket(); 240 | subOne.send(SLIPSerial); 241 | SLIPSerial.endPacket(); 242 | 243 | OSCMessage subTwo("/eos/subscribe/param/cyan/magenta/yellow/cto"); 244 | subTwo.add(UNSUBSCRIBE); 245 | SLIPSerial.beginPacket(); 246 | subTwo.send(SLIPSerial); 247 | SLIPSerial.endPacket(); 248 | 249 | OSCMessage subThree("/eos/subscribe/param/thrust_a/angle_a/thrust_c/angle_c"); 250 | subThree.add(UNSUBSCRIBE); 251 | SLIPSerial.beginPacket(); 252 | subThree.send(SLIPSerial); 253 | SLIPSerial.endPacket(); 254 | 255 | OSCMessage subFour("/eos/subscribe/param/thrust_b/angle_b/thrust_d/angle_d"); 256 | subFour.add(UNSUBSCRIBE); 257 | SLIPSerial.beginPacket(); 258 | subFour.send(SLIPSerial); 259 | SLIPSerial.endPacket(); 260 | 261 | OSCMessage subFive("/eos/subscribe/param/gobo_select/gobo_ind\\spd/gobo_select_2/gobo_ind\\spd_2"); 262 | subFive.add(UNSUBSCRIBE); 263 | SLIPSerial.beginPacket(); 264 | subFive.send(SLIPSerial); 265 | SLIPSerial.endPacket(); 266 | } 267 | 268 | if (mode == 2) { 269 | // subscribe to Eos color updates 270 | OSCMessage subOne("/eos/subscribe/param/pan/tilt/zoom/edge"); 271 | subOne.add(UNSUBSCRIBE); 272 | SLIPSerial.beginPacket(); 273 | subOne.send(SLIPSerial); 274 | SLIPSerial.endPacket(); 275 | 276 | OSCMessage subTwo("/eos/subscribe/param/cyan/magenta/yellow/cto"); 277 | subTwo.add(SUBSCRIBE); 278 | SLIPSerial.beginPacket(); 279 | subTwo.send(SLIPSerial); 280 | SLIPSerial.endPacket(); 281 | 282 | OSCMessage subThree("/eos/subscribe/param/thrust_a/angle_a/thrust_c/angle_c"); 283 | subThree.add(UNSUBSCRIBE); 284 | SLIPSerial.beginPacket(); 285 | subThree.send(SLIPSerial); 286 | SLIPSerial.endPacket(); 287 | 288 | OSCMessage subFour("/eos/subscribe/param/thrust_b/angle_b/thrust_d/angle_d"); 289 | subFour.add(UNSUBSCRIBE); 290 | SLIPSerial.beginPacket(); 291 | subFour.send(SLIPSerial); 292 | SLIPSerial.endPacket(); 293 | 294 | OSCMessage subFive("/eos/subscribe/param/gobo_select/gobo_ind\\spd/gobo_select_2/gobo_ind\\spd_2"); 295 | subFive.add(UNSUBSCRIBE); 296 | SLIPSerial.beginPacket(); 297 | subFive.send(SLIPSerial); 298 | SLIPSerial.endPacket(); 299 | 300 | } 301 | if (mode == 3) { 302 | // subscribe to Eos shutter A/C updates 303 | OSCMessage subOne("/eos/subscribe/param/pan/tilt/zoom/edge"); 304 | subOne.add(UNSUBSCRIBE); 305 | SLIPSerial.beginPacket(); 306 | subOne.send(SLIPSerial); 307 | SLIPSerial.endPacket(); 308 | 309 | OSCMessage subTwo("/eos/subscribe/param/cyan/magenta/yellow/cto"); 310 | subTwo.add(UNSUBSCRIBE); 311 | SLIPSerial.beginPacket(); 312 | subTwo.send(SLIPSerial); 313 | SLIPSerial.endPacket(); 314 | 315 | OSCMessage subThree("/eos/subscribe/param/thrust_a/angle_a/thrust_c/angle_c"); 316 | subThree.add(SUBSCRIBE); 317 | SLIPSerial.beginPacket(); 318 | subThree.send(SLIPSerial); 319 | SLIPSerial.endPacket(); 320 | 321 | OSCMessage subFour("/eos/subscribe/param/thrust_b/angle_b/thrust_d/angle_d"); 322 | subFour.add(UNSUBSCRIBE); 323 | SLIPSerial.beginPacket(); 324 | subFour.send(SLIPSerial); 325 | SLIPSerial.endPacket(); 326 | 327 | OSCMessage subFive("/eos/subscribe/param/gobo_select/gobo_ind\\spd/gobo_select_2/gobo_ind\\spd_2"); 328 | subFive.add(UNSUBSCRIBE); 329 | SLIPSerial.beginPacket(); 330 | subFive.send(SLIPSerial); 331 | SLIPSerial.endPacket(); 332 | 333 | 334 | } 335 | if (mode == 4) { 336 | // subscribe to Eos shutter B/D updates 337 | OSCMessage subOne("/eos/subscribe/param/pan/tilt/zoom/edge"); 338 | subOne.add(UNSUBSCRIBE); 339 | SLIPSerial.beginPacket(); 340 | subOne.send(SLIPSerial); 341 | SLIPSerial.endPacket(); 342 | 343 | OSCMessage subTwo("/eos/subscribe/param/cyan/magenta/yellow/cto"); 344 | subTwo.add(UNSUBSCRIBE); 345 | SLIPSerial.beginPacket(); 346 | subTwo.send(SLIPSerial); 347 | SLIPSerial.endPacket(); 348 | 349 | OSCMessage subThree("/eos/subscribe/param/thrust_a/angle_a/thrust_c/angle_c"); 350 | subThree.add(UNSUBSCRIBE); 351 | SLIPSerial.beginPacket(); 352 | subThree.send(SLIPSerial); 353 | SLIPSerial.endPacket(); 354 | 355 | OSCMessage subFour("/eos/subscribe/param/thrust_b/angle_b/thrust_d/angle_d"); 356 | subFour.add(SUBSCRIBE); 357 | SLIPSerial.beginPacket(); 358 | subFour.send(SLIPSerial); 359 | SLIPSerial.endPacket(); 360 | 361 | OSCMessage subFive("/eos/subscribe/param/gobo_select/gobo_ind\\spd/gobo_select_2/gobo_ind\\spd_2"); 362 | subFive.add(UNSUBSCRIBE); 363 | SLIPSerial.beginPacket(); 364 | subFive.send(SLIPSerial); 365 | SLIPSerial.endPacket(); 366 | 367 | 368 | 369 | } 370 | if (mode == 5) { 371 | // subscribe to Eos GOBO updates 372 | OSCMessage subOne("/eos/subscribe/param/pan/tilt/zoom/edge"); 373 | subOne.add(UNSUBSCRIBE); 374 | SLIPSerial.beginPacket(); 375 | subOne.send(SLIPSerial); 376 | SLIPSerial.endPacket(); 377 | 378 | OSCMessage subTwo("/eos/subscribe/param/cyan/magenta/yellow/cto"); 379 | subTwo.add(UNSUBSCRIBE); 380 | SLIPSerial.beginPacket(); 381 | subTwo.send(SLIPSerial); 382 | SLIPSerial.endPacket(); 383 | 384 | OSCMessage subThree("/eos/subscribe/param/thrust_a/angle_a/thrust_c/angle_c"); 385 | subThree.add(UNSUBSCRIBE); 386 | SLIPSerial.beginPacket(); 387 | subThree.send(SLIPSerial); 388 | SLIPSerial.endPacket(); 389 | 390 | OSCMessage subFour("/eos/subscribe/param/thrust_b/angle_b/thrust_d/angle_d"); 391 | subFour.add(UNSUBSCRIBE); 392 | SLIPSerial.beginPacket(); 393 | subFour.send(SLIPSerial); 394 | SLIPSerial.endPacket(); 395 | 396 | OSCMessage subFive("/eos/subscribe/param/gobo_select/gobo_ind\\spd/gobo_select_2/gobo_ind\\spd_2"); 397 | subFive.add(SUBSCRIBE); 398 | SLIPSerial.beginPacket(); 399 | subFive.send(SLIPSerial); 400 | SLIPSerial.endPacket(); 401 | 402 | 403 | } 404 | } 405 | 406 | /******************************************************************************* 407 | Given a valid OSCMessage (relevant to Pan/Tilt), we update our Encoder struct 408 | with the new position information. 409 | 410 | Parameters: 411 | msg - The OSC message we will use to update our internal data 412 | addressOffset - Unused (allows for multiple nested roots) 413 | 414 | Return Value: void 415 | 416 | ******************************************************************************/ 417 | void parseNull(OSCMessage& msg, int addressOffset) 418 | { 419 | 420 | } 421 | 422 | void parseenc1Update(OSCMessage& msg, int addressOffset) 423 | { 424 | enc1Wheel.pos = msg.getOSCData(0)->getFloat(); 425 | connectedToEos = true; // Update this here just in case we missed the handshake 426 | updateDisplay = true; 427 | } 428 | 429 | void parseenc2Update(OSCMessage& msg, int addressOffset) 430 | { 431 | enc2Wheel.pos = msg.getOSCData(0)->getFloat(); 432 | connectedToEos = true; // Update this here just in case we missed the handshake 433 | updateDisplay = true; 434 | } 435 | 436 | 437 | void parseenc3Update(OSCMessage& msg, int addressOffset) 438 | { 439 | enc3Wheel.pos = msg.getOSCData(0)->getFloat(); 440 | connectedToEos = true; // Update this here just in case we missed the handshake 441 | updateDisplay = true; 442 | } 443 | 444 | void parseenc4Update(OSCMessage& msg, int addressOffset) 445 | { 446 | enc4Wheel.pos = msg.getOSCData(0)->getFloat(); 447 | connectedToEos = true; // Update this here just in case we missed the handshake 448 | updateDisplay = true; 449 | } 450 | 451 | void parseChannelUpdate(OSCMessage& msg, int addressOffset) 452 | { 453 | int length = msg.getDataLength(0); 454 | msg.getString(0, currentChannel, length); 455 | char * p = strchr (currentChannel, ' '); // search for space 456 | if (p) // if found truncate at space 457 | *p = 0; 458 | connectedToEos = true; // Update this here just in case we missed the handshake 459 | updateDisplay = true; 460 | } 461 | /******************************************************************************* 462 | Given an unknown OSC message we check to see if it's a handshake message. 463 | If it's a handshake we issue a subscribe, otherwise we begin route the OSC 464 | message to the appropriate function. 465 | 466 | Parameters: 467 | msg - The OSC message of unknown importance 468 | 469 | Return Value: void 470 | 471 | ******************************************************************************/ 472 | void parseOSCMessage(String& msg) 473 | { 474 | // check to see if this is the handshake string 475 | if (msg.indexOf(HANDSHAKE_QUERY) != -1) 476 | { 477 | // handshake string found! 478 | SLIPSerial.beginPacket(); 479 | SLIPSerial.write((const uint8_t*)HANDSHAKE_REPLY.c_str(), (size_t)HANDSHAKE_REPLY.length()); 480 | SLIPSerial.endPacket(); 481 | 482 | // Let Eos know we want updates on some things 483 | issueSubscribes(); 484 | 485 | // Make our splash screen go away 486 | connectedToEos = true; 487 | updateDisplay = true; 488 | } 489 | else 490 | { 491 | // prepare the message for routing by filling an OSCMessage object with our message string 492 | OSCMessage oscmsg; 493 | oscmsg.fill((uint8_t*)msg.c_str(), (int)msg.length()); 494 | // route pan/tilt messages to the relevant update function 495 | if (mode == 1); { 496 | oscmsg.route("/eos/out/param/pan", parseenc1Update); 497 | oscmsg.route("/eos/out/param/tilt", parseenc2Update); 498 | oscmsg.route("/eos/out/param/edge", parseenc3Update); 499 | oscmsg.route("/eos/out/param/zoom", parseenc4Update); 500 | oscmsg.route("/eos/out/active/chan", parseChannelUpdate); 501 | 502 | } 503 | 504 | if (mode == 2); { 505 | oscmsg.route("/eos/out/param/cyan", parseenc1Update); 506 | oscmsg.route("/eos/out/param/magenta", parseenc2Update); 507 | oscmsg.route("/eos/out/param/yellow", parseenc3Update); 508 | oscmsg.route("/eos/out/param/cto", parseenc4Update); 509 | oscmsg.route("/eos/out/active/chan", parseChannelUpdate); 510 | 511 | 512 | 513 | } 514 | if (mode == 3); { 515 | oscmsg.route("/eos/out/param/thrust_a", parseenc1Update); 516 | oscmsg.route("/eos/out/param/angle_a", parseenc2Update); 517 | oscmsg.route("/eos/out/param/thrust_c", parseenc3Update); 518 | oscmsg.route("/eos/out/param/angle_c", parseenc4Update); 519 | oscmsg.route("/eos/out/active/chan", parseChannelUpdate); 520 | 521 | 522 | 523 | 524 | } 525 | if (mode == 4); { 526 | oscmsg.route("/eos/out/param/thrust_b", parseenc1Update); 527 | oscmsg.route("/eos/out/param/angle_b", parseenc2Update); 528 | oscmsg.route("/eos/out/param/thrust_d", parseenc3Update); 529 | oscmsg.route("/eos/out/param/angle_d", parseenc4Update); 530 | oscmsg.route("/eos/out/active/chan", parseChannelUpdate); 531 | 532 | 533 | 534 | } 535 | 536 | if (mode == 5); { 537 | oscmsg.route("/eos/out/param/gobo_select", parseenc1Update); 538 | oscmsg.route("/eos/out/param/gobo_ind/spd", parseenc2Update); 539 | oscmsg.route("/eos/out/param/gobo_select_2", parseenc3Update); 540 | oscmsg.route("/eos/out/param/gobo_ind/spd_2", parseenc4Update); 541 | oscmsg.route("/eos/out/active/chan", parseChannelUpdate); 542 | 543 | 544 | } 545 | } 546 | } 547 | /******************************************************************************* 548 | Updates the display with the latest pan and tilt positions. 549 | 550 | Parameters: none 551 | 552 | Return Value: void 553 | 554 | ******************************************************************************/ 555 | void displayStatus() 556 | { 557 | // lcd.clear(); 558 | 559 | if (!connectedToEos) 560 | { 561 | // display a splash message before the Eos connection is open 562 | lcd.clear(); 563 | lcd.setCursor(0, 0); 564 | lcd.print(String("4 Enc v" + VERSION_STRING).c_str()); 565 | lcd.setCursor(0, 1); 566 | lcd.print("waiting for eos"); 567 | } 568 | else 569 | { 570 | 571 | 572 | lcd.setCursor(10, 1); 573 | lcd.print("|"); 574 | lcd.setCursor(20, 0); 575 | lcd.print("|"); 576 | lcd.setCursor(20, 1); 577 | lcd.print("|"); 578 | lcd.setCursor(30, 0); 579 | lcd.print("|"); 580 | lcd.setCursor(30, 1); 581 | lcd.print("|"); 582 | 583 | 584 | // put the cursor at the begining of the first line 585 | lcd.setCursor(0, 0); 586 | lcd.print(" "); 587 | lcd.setCursor(0, 0); 588 | lcd.print(enc1Name); 589 | lcd.setCursor(0, 1); 590 | lcd.print(" "); 591 | lcd.setCursor(0, 1); 592 | lcd.print(enc1Wheel.pos, SIG_DIGITS); 593 | // lcd.print(" "); 594 | 595 | //find out how many digits in the current channel and offset the start to format properly 596 | int offSet = strlen(currentChannel); 597 | lcd.setCursor(9 - offSet / 2, 0); 598 | lcd.print("("); 599 | lcd.print(currentChannel); 600 | lcd.print(")"); 601 | 602 | //find the length of the current float to set the start position 603 | float tempFloat = (enc2Wheel.pos, SIG_DIGITS); 604 | int offSet1 = sizeof(tempFloat); 605 | offSet1 = (offSet1 + 2); 606 | lcd.setCursor(15, 0); 607 | lcd.print(" "); 608 | lcd.setCursor(15, 0); 609 | lcd.print(enc2Name); 610 | lcd.setCursor(11, 1); 611 | lcd.print(" "); 612 | lcd.setCursor(19 - offSet1, 1); 613 | lcd.print(enc2Wheel.pos, SIG_DIGITS); 614 | // lcd.print(" "); 615 | 616 | // put the cursor at the begining of the second line 617 | lcd.setCursor(21, 0); 618 | lcd.print(" "); 619 | lcd.setCursor(21, 0); 620 | lcd.print(" "); 621 | lcd.print(enc3Name); 622 | lcd.setCursor(21, 1); 623 | lcd.print(" "); 624 | lcd.setCursor(21, 1); 625 | lcd.print(" "); 626 | lcd.print(enc3Wheel.pos, SIG_DIGITS); 627 | // lcd.print(" "); 628 | 629 | // put the cursor at the begining of the second line 630 | lcd.setCursor(31, 0); 631 | lcd.print(" "); 632 | lcd.setCursor(31, 0); 633 | lcd.print(" "); lcd.print(enc4Name); 634 | lcd.setCursor(31, 1); 635 | lcd.print(" "); 636 | lcd.setCursor(31, 1); 637 | lcd.print(" "); 638 | lcd.print(enc4Wheel.pos, SIG_DIGITS); 639 | // lcd.print(" "); 640 | 641 | } 642 | 643 | updateDisplay = false; 644 | } 645 | 646 | /******************************************************************************* 647 | Initializes a given encoder struct to the requested parameters. 648 | 649 | Parameters: 650 | encoder - Pointer to the encoder we will be initializing 651 | pinA - Where the A pin is connected to the Arduino 652 | pinB - Where the B pin is connected to the Arduino 653 | direction - Determines if clockwise or counterclockwise is "forward" 654 | 655 | Return Value: void 656 | 657 | ******************************************************************************/ 658 | void initEncoder(struct Encoder* encoder, uint8_t pinA, uint8_t pinB, uint8_t direction) 659 | { 660 | encoder->pinA = pinA; 661 | encoder->pinB = pinB; 662 | encoder->pos = 0; 663 | encoder->direction = direction; 664 | 665 | pinMode(pinA, INPUT_PULLUP); 666 | pinMode(pinB, INPUT_PULLUP); 667 | 668 | encoder->pinAPrevious = digitalRead(pinA); 669 | encoder->pinBPrevious = digitalRead(pinB); 670 | } 671 | 672 | /******************************************************************************* 673 | Checks if the encoder has moved by comparing the previous state of the pins 674 | with the current state. If they are different, we know there is movement. 675 | In the event of movement we update the current state of our pins. 676 | 677 | Parameters: 678 | encoder - Pointer to the encoder we will be checking for motion 679 | 680 | Return Value: 681 | encoderMotion - Returns the 0 if the encoder has not moved 682 | 1 for forward motion 683 | -1 for reverse motion 684 | 685 | ******************************************************************************/ 686 | int8_t updateEncoder(struct Encoder* encoder) 687 | { 688 | int8_t encoderMotion = 0; 689 | int pinACurrent = digitalRead(encoder->pinA); 690 | int pinBCurrent = digitalRead(encoder->pinB); 691 | 692 | // has the encoder moved at all? 693 | if (encoder->pinAPrevious != pinACurrent) 694 | { 695 | // Since it has moved, we must determine if the encoder has moved forwards or backwards 696 | encoderMotion = (encoder->pinAPrevious == encoder->pinBPrevious) ? -1 : 1; 697 | 698 | // If we are in reverse mode, flip the direction of the encoder motion 699 | if (encoder->direction == REVERSE) 700 | encoderMotion = -encoderMotion; 701 | } 702 | encoder->pinAPrevious = pinACurrent; 703 | encoder->pinBPrevious = pinBCurrent; 704 | 705 | return encoderMotion; 706 | } 707 | 708 | /******************************************************************************* 709 | Sends a message to Eos informing them of a wheel movement. 710 | 711 | Parameters: 712 | type - the type of wheel that's moving (i.e. pan or tilt) 713 | ticks - the direction and intensity of the movement 714 | 715 | Return Value: void 716 | 717 | ******************************************************************************/ 718 | void sendWheelMove(WHEEL_TYPE type, float ticks) 719 | { 720 | String wheelMsg("/eos/wheel"); 721 | 722 | if (digitalRead(SHIFT_BTN) == LOW) 723 | wheelMsg.concat("/fine"); 724 | else 725 | wheelMsg.concat("/coarse"); 726 | 727 | if (type == ENC1) { 728 | if (mode == 1) 729 | wheelMsg.concat("/pan"); 730 | else if (mode == 2) 731 | wheelMsg.concat("/cyan"); 732 | else if (mode == 3) 733 | wheelMsg.concat("/thrust_a"); 734 | else if (mode == 4) 735 | wheelMsg.concat("/thrust_b"); 736 | else if (mode == 5) 737 | wheelMsg.concat("/gobo_select"); 738 | 739 | 740 | } 741 | else if (type == ENC2) { 742 | if (mode == 1) 743 | wheelMsg.concat("/tilt"); 744 | else if (mode == 2) 745 | wheelMsg.concat("/magenta"); 746 | else if (mode == 3) 747 | wheelMsg.concat("/angle_a"); 748 | else if (mode == 4) 749 | wheelMsg.concat("/angle_b"); 750 | else if (mode == 5) 751 | wheelMsg.concat("/gobo_ind\\spd"); 752 | } 753 | else if (type == ENC3) { 754 | if (mode == 1) 755 | wheelMsg.concat("/edge"); 756 | else if (mode == 2) 757 | wheelMsg.concat("/yellow"); 758 | else if (mode == 3) 759 | wheelMsg.concat("/thrust_c"); 760 | else if (mode == 4) 761 | wheelMsg.concat("/thrust_d"); 762 | else if (mode == 5) 763 | wheelMsg.concat("/gobo_select_2"); 764 | } 765 | else if (type == ENC4) { 766 | if (mode == 1) 767 | wheelMsg.concat("/zoom"); 768 | else if (mode == 2) 769 | wheelMsg.concat("/cto"); 770 | else if (mode == 3) 771 | wheelMsg.concat("/angle_c"); 772 | else if (mode == 4) 773 | wheelMsg.concat("/angle_d"); 774 | else if (mode == 5) 775 | wheelMsg.concat("/gobo_ind\\spd_2"); 776 | 777 | } 778 | else 779 | // something has gone very wrong 780 | return; 781 | 782 | OSCMessage wheelUpdate(wheelMsg.c_str()); 783 | wheelUpdate.add(ticks); 784 | SLIPSerial.beginPacket(); 785 | wheelUpdate.send(SLIPSerial); 786 | SLIPSerial.endPacket(); 787 | } 788 | 789 | /******************************************************************************* 790 | Sends a message to Eos informing them of a key press. 791 | 792 | Parameters: 793 | down - whether a key has been pushed down (true) or released (false) 794 | key - the key that has moved 795 | 796 | Return Value: void 797 | 798 | ******************************************************************************/ 799 | void sendKeyPress(bool down, String key) 800 | { 801 | key = "/eos/key/" + key; 802 | OSCMessage keyMsg(key.c_str()); 803 | 804 | // if (down) 805 | // keyMsg.add(EDGE_DOWN); 806 | // else 807 | // keyMsg.add(EDGE_UP); 808 | 809 | SLIPSerial.beginPacket(); 810 | keyMsg.send(SLIPSerial); 811 | SLIPSerial.endPacket(); 812 | } 813 | 814 | 815 | /******************************************************************************* 816 | Sends a message to Eos informing them of a attribute key press. 817 | 818 | Parameters: 819 | down - whether a key has been pushed down (true) or released (false) 820 | key - the key that has moved 821 | 822 | Return Value: void 823 | 824 | ******************************************************************************/ 825 | void sendParamPress(String key) 826 | { 827 | String key1 = "/eos/cmd"; // + key; 828 | String keyMsg(key1.c_str()); 829 | key = key; 830 | 831 | if (key == "ENC1") { 832 | if (mode == 1) 833 | keyMsg.concat("/pan"); 834 | else if (mode == 2) 835 | keyMsg.concat("/cyan"); 836 | else if (mode == 3) 837 | keyMsg.concat("/thrust_a"); 838 | else if (mode == 4) 839 | keyMsg.concat("/thrust_b"); 840 | else if (mode == 5) 841 | keyMsg.concat("/gobo_select"); 842 | 843 | } 844 | else if (key == "ENC2") { 845 | if (mode == 1) 846 | keyMsg.concat("/tilt"); 847 | else if (mode == 2) 848 | keyMsg.concat("/magenta"); 849 | else if (mode == 3) 850 | keyMsg.concat("/angle_a"); 851 | else if (mode == 4) 852 | keyMsg.concat("/angle_b"); 853 | else if (mode == 5) 854 | keyMsg.concat("/gobo_ind\\spd"); 855 | } 856 | else if (key == "ENC3") { 857 | if (mode == 1) 858 | keyMsg.concat("/edge"); 859 | else if (mode == 2) 860 | keyMsg.concat("/yellow"); 861 | else if (mode == 3) 862 | keyMsg.concat("/thrust_c"); 863 | else if (mode == 4) 864 | keyMsg.concat("/thrust_d"); 865 | else if (mode == 5) 866 | keyMsg.concat("/gobo_select_2"); 867 | } 868 | else if (key == "ENC4") { 869 | if (mode == 1) 870 | keyMsg.concat("/zoom"); 871 | else if (mode == 2) 872 | keyMsg.concat("/cto"); 873 | else if (mode == 3) 874 | keyMsg.concat("/angle_c"); 875 | else if (mode == 4) 876 | keyMsg.concat("/angle_d"); 877 | else if (mode == 5) 878 | keyMsg.concat("/gobo_ind\\spd_2"); 879 | 880 | } 881 | else 882 | // something has gone very wrong 883 | return; 884 | 885 | 886 | OSCMessage keyMsg1(keyMsg.c_str()); 887 | 888 | 889 | // keyMsg1.add(EDGE_DOWN); 890 | 891 | SLIPSerial.beginPacket(); 892 | keyMsg1.send(SLIPSerial); 893 | SLIPSerial.endPacket(); 894 | } 895 | 896 | 897 | 898 | /******************************************************************************* 899 | Checks the status of all the buttons relevant to Eos (i.e. Next & Last) 900 | 901 | NOTE: This does not check the shift key. The shift key is used in tandem with 902 | the encoder to determine coarse/fine mode and thus does not report to Eos 903 | directly. 904 | 905 | Parameters: none 906 | 907 | Return Value: void 908 | 909 | ******************************************************************************/ 910 | void checkButtons() 911 | { 912 | static int nextKeyState = HIGH; 913 | static int lastKeyState = HIGH; 914 | static int mode1KeyState = HIGH; 915 | static int mode2KeyState = HIGH; 916 | static int mode3KeyState = HIGH; 917 | static int mode4KeyState = HIGH; 918 | static int mode5KeyState = HIGH; 919 | 920 | static int enc1KeyState = HIGH; 921 | static int enc2KeyState = HIGH; 922 | static int enc3KeyState = HIGH; 923 | static int enc4KeyState = HIGH; 924 | 925 | 926 | // Has the button state changed 927 | if (digitalRead(NEXT_BTN) != nextKeyState) 928 | { 929 | nextKeyState = digitalRead(NEXT_BTN); 930 | // Notify Eos of this key press 931 | if (nextKeyState == LOW) 932 | { 933 | debounceTime1 = millis(); 934 | } 935 | else 936 | { 937 | debounceTime1 = 0; 938 | } 939 | } 940 | 941 | if (debounceTime1 > 0 && (millis() - debounceTime1 > 10)) { 942 | // ... set the time stamp to 0 to say we have finished debouncing 943 | debounceTime1 = 0; 944 | sendKeyPress(false, "NEXT"); 945 | } 946 | 947 | 948 | if (digitalRead(LAST_BTN) != lastKeyState) 949 | { 950 | lastKeyState = digitalRead(LAST_BTN); 951 | if (lastKeyState == LOW) 952 | { 953 | debounceTime2 = millis(); 954 | 955 | // sendKeyPress(false, "LAST"); 956 | // lastKeyState = HIGH; 957 | } 958 | else 959 | { 960 | debounceTime2 = 0; 961 | 962 | // sendKeyPress(true, "LAST"); 963 | // lastKeyState = LOW; 964 | } 965 | } 966 | 967 | if (debounceTime2 > 0 && (millis() - debounceTime2 > 10)) { 968 | // ... set the time stamp to 0 to say we have finished debouncing 969 | debounceTime2 = 0; 970 | sendKeyPress(false, "LAST"); 971 | } 972 | 973 | 974 | if (digitalRead(MODE1_BTN) != mode1KeyState) 975 | { 976 | if (mode1KeyState == LOW) 977 | { 978 | enc1Name = "PAN"; 979 | enc2Name = "TILT"; 980 | enc3Name = "EDGE"; 981 | enc4Name = "ZOOM"; 982 | mode = 1; 983 | mode1KeyState = HIGH; 984 | issueSubscribes(); 985 | lcd.clear(); 986 | } 987 | else 988 | { 989 | 990 | mode1KeyState = LOW; 991 | } 992 | } 993 | 994 | 995 | if (digitalRead(MODE2_BTN) != mode2KeyState) 996 | { 997 | if (mode2KeyState == LOW) 998 | { 999 | enc1Name = "CYN"; 1000 | enc2Name = "MAG"; 1001 | enc3Name = "YEL"; 1002 | enc4Name = "CTO"; 1003 | mode = 2; 1004 | mode2KeyState = HIGH; 1005 | issueSubscribes(); 1006 | lcd.clear(); 1007 | } 1008 | else 1009 | { 1010 | 1011 | mode2KeyState = LOW; 1012 | } 1013 | } 1014 | 1015 | if (digitalRead(MODE3_BTN) != mode3KeyState) 1016 | { 1017 | if (mode3KeyState == LOW) 1018 | { 1019 | enc1Name = "A THR"; 1020 | enc2Name = "A ANG"; 1021 | enc3Name = "C THR"; 1022 | enc4Name = "C ANG"; 1023 | mode = 3; 1024 | mode3KeyState = HIGH; 1025 | issueSubscribes(); 1026 | lcd.clear(); 1027 | } 1028 | else 1029 | { 1030 | 1031 | mode3KeyState = LOW; 1032 | } 1033 | } 1034 | 1035 | if (digitalRead(MODE4_BTN) != mode4KeyState) 1036 | { 1037 | if (mode4KeyState == LOW) 1038 | { 1039 | enc1Name = "B THR"; 1040 | enc2Name = "B ANG"; 1041 | enc3Name = "D THR"; 1042 | enc4Name = "D ANG"; 1043 | mode = 4; 1044 | mode4KeyState = HIGH; 1045 | issueSubscribes(); 1046 | lcd.clear(); 1047 | } 1048 | else 1049 | { 1050 | 1051 | mode4KeyState = LOW; 1052 | } 1053 | } 1054 | 1055 | if (digitalRead(MODE5_BTN) != mode5KeyState) 1056 | { 1057 | if (mode5KeyState == LOW) 1058 | { 1059 | enc1Name = "GOBO1"; 1060 | enc2Name = "G1ROT"; 1061 | enc3Name = "GOBO2"; 1062 | enc4Name = "G2ROT"; 1063 | mode = 5; 1064 | mode5KeyState = HIGH; 1065 | issueSubscribes(); 1066 | lcd.clear(); 1067 | } 1068 | else 1069 | { 1070 | 1071 | mode5KeyState = LOW; 1072 | } 1073 | } 1074 | 1075 | if (digitalRead(ENC1_BTN) != enc1KeyState) 1076 | { 1077 | enc1KeyState = digitalRead(ENC1_BTN); 1078 | 1079 | if (enc1KeyState == HIGH) 1080 | { 1081 | debounceTime11 = millis(); 1082 | ENC1_SCALE = encNorm; //added for encoder fine/coarse 1083 | 1084 | } 1085 | else 1086 | { 1087 | debounceTime11 = 0; 1088 | ENC1_SCALE = encCoarse; //added for encoder fine/coarse 1089 | 1090 | } 1091 | } 1092 | 1093 | if (debounceTime11 > 0 && (millis() - debounceTime11 > 10)) { 1094 | // ... set the time stamp to 0 to say we have finished debouncing 1095 | debounceTime11 = 0; 1096 | sendParamPress("ENC1"); 1097 | 1098 | } 1099 | 1100 | 1101 | 1102 | 1103 | if (digitalRead(ENC2_BTN) != enc2KeyState) 1104 | { 1105 | enc2KeyState = digitalRead(ENC2_BTN); 1106 | 1107 | if (enc2KeyState == HIGH) 1108 | { 1109 | debounceTime12 = millis(); 1110 | ENC2_SCALE = encNorm; //added for encoder fine/coarse 1111 | 1112 | } 1113 | else 1114 | { 1115 | debounceTime12 = 0; 1116 | ENC2_SCALE = encCoarse; //added for encoder fine/coarse 1117 | 1118 | 1119 | } 1120 | } 1121 | 1122 | if (debounceTime12 > 0 && (millis() - debounceTime12 > 10)) { 1123 | // ... set the time stamp to 0 to say we have finished debouncing 1124 | debounceTime12 = 0; 1125 | sendParamPress("ENC2"); 1126 | 1127 | } 1128 | 1129 | 1130 | if (digitalRead(ENC3_BTN) != enc3KeyState) 1131 | { 1132 | enc3KeyState = digitalRead(ENC3_BTN); 1133 | 1134 | if (enc3KeyState == HIGH) 1135 | { 1136 | debounceTime13 = millis(); 1137 | ENC3_SCALE = encNorm; //added for encoder fine/coarse 1138 | 1139 | } 1140 | else 1141 | { 1142 | debounceTime13 = 0; 1143 | ENC3_SCALE = encCoarse; //added for encoder fine/coarse 1144 | 1145 | 1146 | } 1147 | } 1148 | 1149 | if (debounceTime13 > 0 && (millis() - debounceTime13 > 10)) { 1150 | // ... set the time stamp to 0 to say we have finished debouncing 1151 | debounceTime13 = 0; 1152 | sendParamPress("ENC3"); 1153 | 1154 | } 1155 | 1156 | 1157 | if (digitalRead(ENC4_BTN) != enc4KeyState) 1158 | { 1159 | enc4KeyState = digitalRead(ENC4_BTN); 1160 | 1161 | if (enc4KeyState == HIGH) 1162 | { 1163 | debounceTime14 = millis(); 1164 | ENC4_SCALE = encNorm; //added for encoder fine/coarse 1165 | 1166 | 1167 | } 1168 | else 1169 | { 1170 | debounceTime14 = 0; 1171 | ENC4_SCALE = encCoarse; //added for encoder fine/coarse 1172 | 1173 | 1174 | } 1175 | } 1176 | 1177 | if (debounceTime14 > 0 && (millis() - debounceTime14 > 10)) { 1178 | // ... set the time stamp to 0 to say we have finished debouncing 1179 | debounceTime14 = 0; 1180 | sendParamPress("ENC4"); 1181 | 1182 | } 1183 | } 1184 | /******************************************************************************* 1185 | Here we setup our encoder, lcd, and various input devices. We also prepare 1186 | to communicate OSC with Eos by setting up SLIPSerial. Once we are done with 1187 | setup() we pass control over to loop() and never call setup() again. 1188 | 1189 | NOTE: This function is the entry function. This is where control over the 1190 | Arduino is passed to us (the end user). 1191 | 1192 | Parameters: none 1193 | 1194 | Return Value: void 1195 | 1196 | ******************************************************************************/ 1197 | void setup() 1198 | { 1199 | SLIPSerial.begin(115200); 1200 | // This is a hack around an Arduino bug. It was taken from the OSC library 1201 | //examples 1202 | //#ifdef BOARD_HAS_USB_SERIAL 1203 | // while (!SerialUSB); 1204 | //#else 1205 | // while (!Serial); 1206 | //#endif 1207 | 1208 | // This is necessary for reconnecting a device because it needs some time 1209 | // for the serial port to open, but meanwhile the handshake message was 1210 | // sent from Eos 1211 | SLIPSerial.beginPacket(); 1212 | SLIPSerial.write((const uint8_t*)HANDSHAKE_REPLY.c_str(), (size_t)HANDSHAKE_REPLY.length()); 1213 | SLIPSerial.endPacket(); 1214 | // Let Eos know we want updates on some things 1215 | issueSubscribes(); 1216 | 1217 | initEncoder(&enc1Wheel, A0, A1, ENC1_DIR); 1218 | initEncoder(&enc2Wheel, A2, A3, ENC2_DIR); 1219 | initEncoder(&enc3Wheel, A4, A5, ENC3_DIR); 1220 | initEncoder(&enc4Wheel, A6, A7, ENC4_DIR); 1221 | 1222 | lcd.begin(LCD_CHARS, LCD_LINES); 1223 | lcd.clear(); 1224 | 1225 | pinMode(NEXT_BTN, INPUT_PULLUP); 1226 | pinMode(LAST_BTN, INPUT_PULLUP); 1227 | pinMode(SHIFT_BTN, INPUT_PULLUP); 1228 | pinMode(MODE1_BTN, INPUT_PULLUP); 1229 | pinMode(MODE2_BTN, INPUT_PULLUP); 1230 | pinMode(MODE3_BTN, INPUT_PULLUP); 1231 | pinMode(MODE4_BTN, INPUT_PULLUP); 1232 | pinMode(MODE5_BTN, INPUT_PULLUP); 1233 | pinMode(ENC1_BTN, INPUT_PULLUP); 1234 | pinMode(ENC2_BTN, INPUT_PULLUP); 1235 | pinMode(ENC3_BTN, INPUT_PULLUP); 1236 | pinMode(ENC4_BTN, INPUT_PULLUP); 1237 | 1238 | displayStatus(); 1239 | 1240 | 1241 | 1242 | } 1243 | 1244 | /******************************************************************************* 1245 | Here we service, monitor, and otherwise control all our peripheral devices. 1246 | First, we retrieve the status of our encoders and buttons and update Eos. 1247 | Next, we check if there are any OSC messages for us. 1248 | Finally, we update our display (if an update is necessary) 1249 | 1250 | NOTE: This function is our main loop and thus this function will be called 1251 | repeatedly forever 1252 | 1253 | Parameters: none 1254 | 1255 | Return Value: void 1256 | 1257 | ******************************************************************************/ 1258 | void loop() 1259 | { 1260 | static String curMsg; 1261 | int size; 1262 | // get the updated state of each encoder 1263 | int32_t enc1Motion = updateEncoder(&enc1Wheel); 1264 | int32_t enc2Motion = updateEncoder(&enc2Wheel); 1265 | int32_t enc3Motion = updateEncoder(&enc3Wheel); 1266 | int32_t enc4Motion = updateEncoder(&enc4Wheel); 1267 | 1268 | // Scale the result by a scaling factor 1269 | enc1Motion *= ENC1_SCALE; 1270 | enc2Motion *= ENC2_SCALE; 1271 | enc3Motion *= ENC3_SCALE; 1272 | enc4Motion *= ENC4_SCALE; 1273 | 1274 | // check for next/last updates 1275 | checkButtons(); 1276 | 1277 | // now update our wheels 1278 | if (enc1Motion != 0) 1279 | sendWheelMove(ENC1, enc1Motion); 1280 | 1281 | if (enc2Motion != 0) 1282 | sendWheelMove(ENC2, enc2Motion); 1283 | 1284 | if (enc3Motion != 0) 1285 | sendWheelMove(ENC3, enc3Motion); 1286 | 1287 | if (enc4Motion != 0) 1288 | sendWheelMove(ENC4, enc4Motion); 1289 | 1290 | // Then we check to see if any OSC commands have come from Eos 1291 | // and update the display accordingly. 1292 | size = SLIPSerial.available(); 1293 | if (size > 0) 1294 | { 1295 | // Fill the msg with all of the available bytes 1296 | while (size--) 1297 | curMsg += (char)(SLIPSerial.read()); 1298 | } 1299 | if (SLIPSerial.endofPacket()) 1300 | { 1301 | parseOSCMessage(curMsg); 1302 | lastMessageRxTime = millis(); 1303 | // We only care about the ping if we haven't heard recently 1304 | // Clear flag when we get any traffic 1305 | timeoutPingSent = false; 1306 | curMsg = String(); 1307 | } 1308 | 1309 | if (lastMessageRxTime > 0) 1310 | { 1311 | unsigned long diff = millis() - lastMessageRxTime; 1312 | //We first check if it's been too long and we need to time out 1313 | if (diff > TIMEOUT_AFTER_IDLE_INTERVAL) 1314 | { 1315 | connectedToEos = false; 1316 | lastMessageRxTime = 0; 1317 | updateDisplay = true; 1318 | timeoutPingSent = false; 1319 | } 1320 | 1321 | //It could be the console is sitting idle. Send a ping once to 1322 | // double check that it's still there, but only once after 5s have passed 1323 | if (!timeoutPingSent && diff > PING_AFTER_IDLE_INTERVAL) 1324 | { 1325 | OSCMessage ping("/eos/ping"); 1326 | ping.add("4Enc_hello"); // This way we know who is sending the ping 1327 | SLIPSerial.beginPacket(); 1328 | ping.send(SLIPSerial); 1329 | SLIPSerial.endPacket(); 1330 | timeoutPingSent = true; 1331 | } 1332 | } 1333 | 1334 | if (updateDisplay) 1335 | displayStatus(); 1336 | } 1337 | -------------------------------------------------------------------------------- /USB_OSC_5_encoders_5_Pages_wheels_With_fader.ino: -------------------------------------------------------------------------------- 1 | 2 | 3 | // Copyright (c) 2017 Electronic Theatre Controls, Inc., http://www.etcconnect.com 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 | /******************************************************************************* 25 | 26 | Electronic Theatre Controls 27 | 28 | lighthack - Box 1 29 | 30 | (c) 2017 by ETC 31 | 32 | 33 | This code implements a Pan/Tilt module using two encoders and three 34 | buttons. The two encoders function as pan and tilt controllers with one 35 | button being reserved for controlling fine/coarse mode. The other two 36 | buttons are assigned to Next and Last which make it easy to switch between 37 | channels. 38 | 39 | ******************************************************************************* 40 | 41 | NOTE: UPDATE VERSION_STRING IN DEFINITIONS BELOW WHEN VERSION NUMBER CHANGES 42 | 43 | Revision History 44 | 45 | yyyy-mm-dd Vxx By_Who Comment 46 | 47 | 2017-07-21 1.0.0.1 Ethan Oswald Massey Original creation 48 | 49 | 2017-10-19 1.0.0.2 Sam Kearney Fix build errors on some 50 | Arduino platforms. Change 51 | OSC subscribe parameters 52 | 53 | 2017-10-24 1.0.0.3 Sam Kearney Add ability to scale encoder 54 | output 55 | 56 | 2017-11-22 1.0.0.4 Hans Hinrichsen Add splash msg before Eos 57 | connects 58 | 59 | 2017-12-07 1.0.0.5 Hans Hinrichsen Added timeout to disconnect 60 | and show splash screen again 61 | 62 | ******************************************************************************/ 63 | 64 | /******************************************************************************* 65 | Includes 66 | ******************************************************************************/ 67 | #include 68 | #include 69 | #include 70 | #include 71 | #include 72 | #include 73 | #include 74 | #ifdef BOARD_HAS_USB_SERIAL 75 | #include 76 | SLIPEncodedUSBSerial SLIPSerial(thisBoardsSerialUSB); 77 | #else 78 | #include 79 | SLIPEncodedSerial SLIPSerial(Serial); 80 | #endif 81 | #include 82 | 83 | /******************************************************************************* 84 | Macros and Constants 85 | ******************************************************************************/ 86 | 87 | 88 | #define ONE_BTN 11 89 | #define TWO_BTN 12 90 | #define THREE_BTN 13 91 | #define SHIFT_BTN 2 92 | 93 | 94 | 95 | 96 | 97 | #define SUBSCRIBE ((int32_t)1) 98 | #define UNSUBSCRIBE ((int32_t)0) 99 | 100 | #define EDGE_DOWN ((int32_t)1) 101 | #define EDGE_UP ((int32_t)0) 102 | 103 | #define FORWARD 0 104 | #define REVERSE 1 105 | 106 | // Change these values to switch which direction increase/decrease pan/tilt 107 | #define ENC1_DIR FORWARD 108 | #define ENC2_DIR FORWARD 109 | #define ENC3_DIR FORWARD 110 | #define ENC4_DIR FORWARD 111 | #define ENC5_DIR FORWARD 112 | 113 | // Use these values to make the encoder more coarse or fine. This controls 114 | // the number of wheel "ticks" the device sends to Eos for each tick of the 115 | // encoder. 1 is the default and the most fine setting. Must be an integer. 116 | //changed to an int so they can be modified at run time. 117 | int ENC1_SCALE = 1; 118 | int ENC2_SCALE = 1; 119 | int ENC3_SCALE = 1; 120 | int ENC4_SCALE = 1; 121 | int ENC5_SCALE = 1; 122 | 123 | 124 | int sensorPin = A0; 125 | float sensorValue = 0.000; 126 | float outputValue = 0.000; 127 | float sensorVal = 0.000; 128 | float sensorValstring = 0.000; 129 | 130 | 131 | 132 | //added variables to set global "coarse" and "normal" encoder modes 133 | int encNorm = 1; 134 | int encCoarse = 8; 135 | 136 | #define SIG_DIGITS 2 // Number of significant digits displayed 137 | 138 | #define OSC_BUF_MAX_SIZE 512 139 | 140 | const String HANDSHAKE_QUERY = "ETCOSC?"; 141 | const String HANDSHAKE_REPLY = "OK"; 142 | 143 | const String EOS_KEY = "/eos/key/"; 144 | 145 | 146 | 147 | 148 | //See displayScreen() below - limited to 10 chars (after 6 prefix chars) 149 | const String VERSION_STRING = "1.0.0.5C"; 150 | 151 | // Change these values to alter how long we wait before sending an OSC ping 152 | // to see if Eos is still there, and then finally how long before we 153 | // disconnect and show the splash screen 154 | // Values are in milliseconds 155 | #define PING_AFTER_IDLE_INTERVAL 5000 156 | #define TIMEOUT_AFTER_IDLE_INTERVAL 15000 157 | 158 | 159 | char currentChannel[255]; 160 | int mode = 1; 161 | 162 | static uint32_t debounceTime1 = 0; 163 | static uint32_t debounceTime2 = 0; 164 | static uint32_t debounceTime3 = 0; 165 | 166 | 167 | /******************************************************************************* 168 | Local Types 169 | ******************************************************************************/ 170 | enum WHEEL_TYPE { ENC1, ENC2, ENC3, ENC4, ENC5 }; 171 | 172 | enum WHEEL_MODE { COARSE, FINE }; 173 | 174 | struct Encoder 175 | { 176 | uint8_t pinA; 177 | uint8_t pinB; 178 | int pinAPrevious; 179 | int pinBPrevious; 180 | float pos; 181 | uint8_t direction; 182 | }; 183 | struct Encoder enc1Wheel; 184 | struct Encoder enc2Wheel; 185 | struct Encoder enc3Wheel; 186 | struct Encoder enc4Wheel; 187 | struct Encoder enc5Wheel; 188 | 189 | /******************************************************************************* 190 | Global Variables 191 | ******************************************************************************/ 192 | 193 | 194 | bool connectedToEos = false; 195 | unsigned long lastMessageRxTime = 0; 196 | bool timeoutPingSent = false; 197 | 198 | /******************************************************************************* 199 | Local Functions 200 | ******************************************************************************/ 201 | 202 | /******************************************************************************* 203 | Issues all our subscribes to Eos. When subscribed, Eos will keep us updated 204 | with the latest values for a given parameter. 205 | 206 | Parameters: none 207 | 208 | Return Value: void 209 | 210 | ******************************************************************************/ 211 | void issueSubscribes() 212 | { 213 | // Add a filter so we don't get spammed with unwanted OSC messages from Eos 214 | OSCMessage filter("/eos/filter/add"); 215 | filter.add("/eos/out/param/*"); 216 | filter.add("/eos/out/ping"); 217 | SLIPSerial.beginPacket(); 218 | filter.send(SLIPSerial); 219 | SLIPSerial.endPacket(); 220 | // subscribe to Eos pan & tilt updates 221 | OSCMessage subPan("/eos/subscribe/param/pan/tilt/zoom/edge"); 222 | subPan.add(SUBSCRIBE); 223 | SLIPSerial.beginPacket(); 224 | subPan.send(SLIPSerial); 225 | SLIPSerial.endPacket(); 226 | 227 | OSCMessage faderSetup("eos/fader/1/config/1/10"); 228 | SLIPSerial.beginPacket(); 229 | faderSetup.send(SLIPSerial); 230 | SLIPSerial.endPacket(); 231 | 232 | 233 | } 234 | 235 | /******************************************************************************* 236 | Given a valid OSCMessage (relevant to Pan/Tilt), we update our Encoder struct 237 | with the new position information. 238 | 239 | Parameters: 240 | msg - The OSC message we will use to update our internal data 241 | addressOffset - Unused (allows for multiple nested roots) 242 | 243 | Return Value: void 244 | 245 | ******************************************************************************/ 246 | void parseNull(OSCMessage& msg, int addressOffset) 247 | { 248 | 249 | } 250 | 251 | 252 | /******************************************************************************* 253 | Given an unknown OSC message we check to see if it's a handshake message. 254 | If it's a handshake we issue a subscribe, otherwise we begin route the OSC 255 | message to the appropriate function. 256 | 257 | Parameters: 258 | msg - The OSC message of unknown importance 259 | 260 | Return Value: void 261 | 262 | ******************************************************************************/ 263 | void parseOSCMessage(String& msg) 264 | { 265 | // check to see if this is the handshake string 266 | if (msg.indexOf(HANDSHAKE_QUERY) != -1) 267 | { 268 | // handshake string found! 269 | SLIPSerial.beginPacket(); 270 | SLIPSerial.write((const uint8_t*)HANDSHAKE_REPLY.c_str(), (size_t)HANDSHAKE_REPLY.length()); 271 | SLIPSerial.endPacket(); 272 | 273 | // Let Eos know we want updates on some things 274 | issueSubscribes(); 275 | 276 | // Make our splash screen go away 277 | connectedToEos = true; 278 | } 279 | else 280 | { 281 | // prepare the message for routing by filling an OSCMessage object with our message string 282 | OSCMessage oscmsg; 283 | oscmsg.fill((uint8_t*)msg.c_str(), (int)msg.length()); 284 | 285 | } 286 | } 287 | 288 | /******************************************************************************* 289 | Initializes a given encoder struct to the requested parameters. 290 | 291 | Parameters: 292 | encoder - Pointer to the encoder we will be initializing 293 | pinA - Where the A pin is connected to the Arduino 294 | pinB - Where the B pin is connected to the Arduino 295 | direction - Determines if clockwise or counterclockwise is "forward" 296 | 297 | Return Value: void 298 | 299 | ******************************************************************************/ 300 | void initEncoder(struct Encoder* encoder, uint8_t pinA, uint8_t pinB, uint8_t direction) 301 | { 302 | encoder->pinA = pinA; 303 | encoder->pinB = pinB; 304 | encoder->pos = 0; 305 | encoder->direction = direction; 306 | 307 | pinMode(pinA, INPUT_PULLUP); 308 | pinMode(pinB, INPUT_PULLUP); 309 | 310 | encoder->pinAPrevious = digitalRead(pinA); 311 | encoder->pinBPrevious = digitalRead(pinB); 312 | } 313 | 314 | /******************************************************************************* 315 | Checks if the encoder has moved by comparing the previous state of the pins 316 | with the current state. If they are different, we know there is movement. 317 | In the event of movement we update the current state of our pins. 318 | 319 | Parameters: 320 | encoder - Pointer to the encoder we will be checking for motion 321 | 322 | Return Value: 323 | encoderMotion - Returns the 0 if the encoder has not moved 324 | 1 for forward motion 325 | -1 for reverse motion 326 | 327 | ******************************************************************************/ 328 | int8_t updateEncoder(struct Encoder* encoder) 329 | { 330 | int8_t encoderMotion = 0; 331 | int pinACurrent = digitalRead(encoder->pinA); 332 | int pinBCurrent = digitalRead(encoder->pinB); 333 | 334 | // has the encoder moved at all? 335 | if (encoder->pinAPrevious != pinACurrent) 336 | { 337 | // Since it has moved, we must determine if the encoder has moved forwards or backwards 338 | encoderMotion = (encoder->pinAPrevious == encoder->pinBPrevious) ? -1 : 1; 339 | 340 | // If we are in reverse mode, flip the direction of the encoder motion 341 | if (encoder->direction == REVERSE) 342 | encoderMotion = -encoderMotion; 343 | } 344 | encoder->pinAPrevious = pinACurrent; 345 | encoder->pinBPrevious = pinBCurrent; 346 | 347 | return encoderMotion; 348 | } 349 | 350 | /******************************************************************************* 351 | Sends a message to Eos informing them of a wheel movement. 352 | 353 | Parameters: 354 | type - the type of wheel that's moving (i.e. pan or tilt) 355 | ticks - the direction and intensity of the movement 356 | 357 | Return Value: void 358 | 359 | ******************************************************************************/ 360 | void sendWheelMove(WHEEL_TYPE type, float ticks) 361 | { 362 | String wheelMsg("/eos/active/wheel"); 363 | 364 | if (digitalRead(SHIFT_BTN) == LOW) 365 | wheelMsg.concat("/fine"); 366 | else 367 | wheelMsg.concat("/coarse"); 368 | 369 | if (type == ENC1) { 370 | wheelMsg.concat("/1"); 371 | } 372 | else if (type == ENC2) { 373 | wheelMsg.concat("/2"); 374 | } 375 | else if (type == ENC3) { 376 | wheelMsg.concat("/3"); 377 | } 378 | else if (type == ENC4) { 379 | wheelMsg.concat("/4"); 380 | } 381 | else if (type == ENC5) { 382 | wheelMsg.concat("/5"); 383 | } 384 | else 385 | // something has gone very wrong 386 | return; 387 | 388 | OSCMessage wheelUpdate(wheelMsg.c_str()); 389 | wheelUpdate.add(ticks); 390 | SLIPSerial.beginPacket(); 391 | wheelUpdate.send(SLIPSerial); 392 | SLIPSerial.endPacket(); 393 | } 394 | 395 | /******************************************************************************* 396 | Sends a message to Eos informing them of a key press. 397 | 398 | Parameters: 399 | down - whether a key has been pushed down (true) or released (false) 400 | key - the key that has moved 401 | 402 | Return Value: void 403 | 404 | ******************************************************************************/ 405 | void sendKeyPress(bool down, String key) 406 | { 407 | key = "/eos/key/" + key; 408 | OSCMessage keyMsg(key.c_str()); 409 | 410 | // if (down) 411 | // keyMsg.add(EDGE_DOWN); 412 | // else 413 | // keyMsg.add(EDGE_UP); 414 | 415 | SLIPSerial.beginPacket(); 416 | keyMsg.send(SLIPSerial); 417 | SLIPSerial.endPacket(); 418 | } 419 | 420 | 421 | 422 | /******************************************************************************* 423 | Checks the status of all the buttons relevant to Eos (i.e. Next & Last) 424 | 425 | NOTE: This does not check the shift key. The shift key is used in tandem with 426 | the encoder to determine coarse/fine mode and thus does not report to Eos 427 | directly. 428 | 429 | Parameters: none 430 | 431 | Return Value: void 432 | 433 | ******************************************************************************/ 434 | void checkButtons() 435 | { 436 | static int oneKeyState = HIGH; 437 | static int twoKeyState = HIGH; 438 | static int threeKeyState = HIGH; 439 | 440 | 441 | 442 | 443 | // Has the button state changed 444 | if (digitalRead(ONE_BTN) != oneKeyState) 445 | { 446 | oneKeyState = digitalRead(ONE_BTN); 447 | // Notify Eos of this key press 448 | if (oneKeyState == LOW) 449 | { 450 | debounceTime1 = millis(); 451 | } 452 | else 453 | { 454 | debounceTime1 = 0; 455 | } 456 | } 457 | 458 | if (debounceTime1 > 0 && (millis() - debounceTime1 > 10)) { 459 | // ... set the time stamp to 0 to say we have finished debouncing 460 | debounceTime1 = 0; 461 | OSCMessage LoadMsg("/eos/fader/1/1/load"); 462 | SLIPSerial.beginPacket(); 463 | LoadMsg.send(SLIPSerial); 464 | SLIPSerial.endPacket(); 465 | } 466 | 467 | 468 | if (digitalRead(TWO_BTN) != twoKeyState) 469 | { 470 | twoKeyState = digitalRead(TWO_BTN); 471 | if (twoKeyState == LOW) 472 | { 473 | debounceTime2 = millis(); 474 | 475 | } 476 | else 477 | { 478 | debounceTime2 = 0; 479 | 480 | } 481 | } 482 | 483 | if (debounceTime2 > 0 && (millis() - debounceTime2 > 10)) { 484 | // ... set the time stamp to 0 to say we have finished debouncing 485 | debounceTime2 = 0; 486 | OSCMessage StopMsg("/eos/fader/1/1/stop"); 487 | SLIPSerial.beginPacket(); 488 | StopMsg.send(SLIPSerial); 489 | SLIPSerial.endPacket(); 490 | } 491 | 492 | if (digitalRead(THREE_BTN) != threeKeyState) 493 | { 494 | threeKeyState = digitalRead(THREE_BTN); 495 | if (threeKeyState == LOW) 496 | { 497 | debounceTime3 = millis(); 498 | 499 | } 500 | else 501 | { 502 | debounceTime3 = 0; 503 | 504 | } 505 | } 506 | 507 | if (debounceTime3 > 0 && (millis() - debounceTime3 > 10)) { 508 | // ... set the time stamp to 0 to say we have finished debouncing 509 | debounceTime3 = 0; 510 | OSCMessage FireMsg("/eos/fader/1/1/fire"); 511 | SLIPSerial.beginPacket(); 512 | FireMsg.send(SLIPSerial); 513 | SLIPSerial.endPacket(); 514 | } 515 | 516 | } 517 | 518 | 519 | void checkFaders() 520 | { 521 | sensorValue = analogRead(sensorPin); 522 | outputValue = sensorValue; 523 | outputValue = constrain(outputValue, 0, 1000); 524 | // String sensorValstring = String(outputValue/10); 525 | sensorValstring = outputValue / 1000; 526 | // sensorValstring = sensorValstring + '.' + (outputValue % 1000); 527 | 528 | 529 | if (sensorVal == sensorValue) 530 | // if( abs(sensorValstring2 - outputValue) < THRESHOLD) 531 | //value has really changed - do something with the new value 532 | { 533 | 534 | } 535 | else if (sensorVal > sensorValue + 3 or sensorVal < sensorValue - 3) 536 | { 537 | OSCMessage msg("/eos/fader/1/1"); 538 | 539 | SLIPSerial.beginPacket(); 540 | msg.add(sensorValstring); 541 | msg.send(SLIPSerial); 542 | SLIPSerial.endPacket(); 543 | 544 | 545 | msg.empty(); 546 | } 547 | 548 | 549 | 550 | delay(10); 551 | sensorVal = sensorValue; 552 | } 553 | 554 | 555 | /******************************************************************************* 556 | Here we setup our encoder, lcd, and various input devices. We also prepare 557 | to communicate OSC with Eos by setting up SLIPSerial. Once we are done with 558 | setup() we pass control over to loop() and never call setup() again. 559 | 560 | NOTE: This function is the entry function. This is where control over the 561 | Arduino is passed to us (the end user). 562 | 563 | Parameters: none 564 | 565 | Return Value: void 566 | 567 | ******************************************************************************/ 568 | void setup() 569 | { 570 | SLIPSerial.begin(115200); 571 | // This is a hack around an Arduino bug. It was taken from the OSC library 572 | //examples 573 | //#ifdef BOARD_HAS_USB_SERIAL 574 | // while (!SerialUSB); 575 | //#else 576 | // while (!Serial); 577 | //#endif 578 | 579 | // This is necessary for reconnecting a device because it needs some time 580 | // for the serial port to open, but meanwhile the handshake message was 581 | // sent from Eos 582 | SLIPSerial.beginPacket(); 583 | SLIPSerial.write((const uint8_t*)HANDSHAKE_REPLY.c_str(), (size_t)HANDSHAKE_REPLY.length()); 584 | SLIPSerial.endPacket(); 585 | // Let Eos know we want updates on some things 586 | issueSubscribes(); 587 | 588 | initEncoder(&enc1Wheel, A1, A2, ENC1_DIR); 589 | initEncoder(&enc2Wheel, A3, A4, ENC2_DIR); 590 | initEncoder(&enc3Wheel, 5, 6, ENC3_DIR); 591 | initEncoder(&enc4Wheel, 7, 8, ENC4_DIR); 592 | initEncoder(&enc5Wheel, 9, 10, ENC5_DIR); 593 | 594 | 595 | 596 | pinMode(ONE_BTN, INPUT_PULLUP); 597 | pinMode(TWO_BTN, INPUT_PULLUP); 598 | pinMode(THREE_BTN, INPUT_PULLUP); 599 | pinMode(SHIFT_BTN, INPUT_PULLUP); 600 | 601 | 602 | 603 | 604 | 605 | 606 | } 607 | 608 | /******************************************************************************* 609 | Here we service, monitor, and otherwise control all our peripheral devices. 610 | First, we retrieve the status of our encoders and buttons and update Eos. 611 | Next, we check if there are any OSC messages for us. 612 | Finally, we update our display (if an update is necessary) 613 | 614 | NOTE: This function is our main loop and thus this function will be called 615 | repeatedly forever 616 | 617 | Parameters: none 618 | 619 | Return Value: void 620 | 621 | ******************************************************************************/ 622 | void loop() 623 | { 624 | static String curMsg; 625 | int size; 626 | // get the updated state of each encoder 627 | int32_t enc1Motion = updateEncoder(&enc1Wheel); 628 | int32_t enc2Motion = updateEncoder(&enc2Wheel); 629 | int32_t enc3Motion = updateEncoder(&enc3Wheel); 630 | int32_t enc4Motion = updateEncoder(&enc4Wheel); 631 | int32_t enc5Motion = updateEncoder(&enc5Wheel); 632 | 633 | // Scale the result by a scaling factor 634 | enc1Motion *= ENC1_SCALE; 635 | enc2Motion *= ENC2_SCALE; 636 | enc3Motion *= ENC3_SCALE; 637 | enc4Motion *= ENC4_SCALE; 638 | enc4Motion *= ENC5_SCALE; 639 | 640 | // check for next/last updates 641 | checkButtons(); 642 | checkFaders(); 643 | // now update our wheels 644 | if (enc1Motion != 0) 645 | sendWheelMove(ENC1, enc1Motion); 646 | 647 | if (enc2Motion != 0) 648 | sendWheelMove(ENC2, enc2Motion); 649 | 650 | if (enc3Motion != 0) 651 | sendWheelMove(ENC3, enc3Motion); 652 | 653 | if (enc4Motion != 0) 654 | sendWheelMove(ENC4, enc4Motion); 655 | 656 | if (enc5Motion != 0) 657 | sendWheelMove(ENC5, enc5Motion); 658 | 659 | // Then we check to see if any OSC commands have come from Eos 660 | // and update the display accordingly. 661 | size = SLIPSerial.available(); 662 | if (size > 0) 663 | { 664 | // Fill the msg with all of the available bytes 665 | while (size--) 666 | curMsg += (char)(SLIPSerial.read()); 667 | } 668 | if (SLIPSerial.endofPacket()) 669 | { 670 | parseOSCMessage(curMsg); 671 | lastMessageRxTime = millis(); 672 | // We only care about the ping if we haven't heard recently 673 | // Clear flag when we get any traffic 674 | timeoutPingSent = false; 675 | curMsg = String(); 676 | } 677 | 678 | if (lastMessageRxTime > 0) 679 | { 680 | unsigned long diff = millis() - lastMessageRxTime; 681 | //We first check if it's been too long and we need to time out 682 | if (diff > TIMEOUT_AFTER_IDLE_INTERVAL) 683 | { 684 | connectedToEos = false; 685 | lastMessageRxTime = 0; 686 | timeoutPingSent = false; 687 | } 688 | 689 | //It could be the console is sitting idle. Send a ping once to 690 | // double check that it's still there, but only once after 2.5s have passed 691 | if (!timeoutPingSent && diff > PING_AFTER_IDLE_INTERVAL) 692 | { 693 | OSCMessage ping("/eos/ping"); 694 | ping.add("5Encoder"); // This way we know who is sending the ping 695 | SLIPSerial.beginPacket(); 696 | ping.send(SLIPSerial); 697 | SLIPSerial.endPacket(); 698 | timeoutPingSent = true; 699 | } 700 | } 701 | 702 | 703 | } 704 | 705 | -------------------------------------------------------------------------------- /faders_OSC_V2.ino: -------------------------------------------------------------------------------- 1 | #include // needed for Arduino versions later than 0018 2 | #include 3 | #include // UDP library from: bjoern@cs.stanford.edu 12/30/2008 4 | #include 5 | #include 6 | #include 7 | 8 | LiquidTWI lcd(0); 9 | 10 | int analogvalue1; 11 | int analogvalue2; 12 | int analogvalue3; 13 | int analogvalue4; 14 | 15 | 16 | int lastanalogvalue1; 17 | int lastanalogvalue2; 18 | int lastanalogvalue3; 19 | int lastanalogvalue4; 20 | 21 | float fadervalue1; 22 | float fadervalue2; 23 | float fadervalue3; 24 | float fadervalue4; 25 | 26 | 27 | //setup 28 | char oscMsg1[32]; 29 | char oscMsg2[32]; 30 | char oscMsg3[32]; 31 | char oscMsg4[32]; 32 | 33 | int fader1 = A0; 34 | int fader2 = A1; 35 | int fader3 = A2; 36 | int fader4 = A3; 37 | int fader5 = A4; 38 | 39 | 40 | byte myMac[6] = { 41 | 42 | }; 43 | byte myNM[4] = { 44 | 45 | }; 46 | byte myIP[4] = { 47 | 48 | }; 49 | byte myGW[4] = { 50 | 51 | }; 52 | byte RemIP[4] = { 53 | 54 | }; 55 | 56 | int RemPort = 0; // remote port to transmit to 57 | 58 | 59 | EthernetUDP Udp; 60 | 61 | void setup() 62 | { 63 | // set up the LCD's number of rows and columns: 64 | lcd.begin(16, 2); 65 | lcd.print("Int Iris"); 66 | 67 | ShieldSetup ();//setup ethernet shield 68 | 69 | pinMode(10, OUTPUT); 70 | 71 | Udp.begin(RemPort); 72 | 73 | 74 | } 75 | 76 | 77 | void ShieldSetup() 78 | { 79 | Serial.begin(9600); 80 | 81 | 82 | if (!SD.begin(4)) Serial.println(F("SD fail")); 83 | else Serial.println(F("SD ok")); 84 | 85 | File fh = SD.open("settings.txt", FILE_READ); 86 | char netBuffer[32]; 87 | 88 | if (!fh) 89 | { 90 | Serial.println(F("SD open fail")); 91 | return; 92 | } 93 | 94 | int chPos = 0; 95 | int lineNo = 0; 96 | 97 | while (fh.available()) 98 | { 99 | char ch = fh.read(); 100 | if (ch == '\n') { 101 | chPos = 0; 102 | 103 | switch (lineNo) { 104 | case 0: 105 | if (getMAC(netBuffer, myMac)) Serial.println(F("mac ok")); 106 | break; 107 | 108 | case 2: 109 | if (getIP(netBuffer, myIP)) Serial.println(F("ip ok")); 110 | break; 111 | 112 | case 4: 113 | if (getIP(netBuffer, myNM)) Serial.println(F("NM ok")); 114 | break; 115 | 116 | case 6: 117 | if (getIP(netBuffer, myGW)) Serial.println(F("GW ok")); 118 | break; 119 | 120 | case 8: 121 | if (getIP(netBuffer, RemIP)) Serial.println(F("CNSL ok")); 122 | break; 123 | 124 | case 10: 125 | RemPort = atoi(&netBuffer[0]); 126 | Serial.print(F("Port ")); 127 | Serial.println(RemPort); 128 | break; 129 | 130 | case 12: 131 | strcpy( oscMsg1, netBuffer ); 132 | Serial.print(F("OSC Command1: ")); 133 | Serial.println(oscMsg1); 134 | break; 135 | 136 | case 14: 137 | strcpy( oscMsg2, netBuffer ); 138 | Serial.print(F("OSC Command2: ")); 139 | Serial.println(oscMsg2); 140 | break; 141 | 142 | case 16: 143 | strcpy( oscMsg3, netBuffer ); 144 | Serial.print(F("OSC Command3: ")); 145 | Serial.println(oscMsg3); 146 | break; 147 | 148 | 149 | case 18: 150 | strcpy( oscMsg4, netBuffer ); 151 | Serial.print(F("OSC Command4: ")); 152 | Serial.println(oscMsg4); 153 | break; 154 | 155 | } 156 | 157 | lineNo++; 158 | } 159 | else if (ch == '\r') { 160 | // do nothing 161 | } 162 | else if (chPos < 32) { 163 | netBuffer[chPos] = ch; 164 | chPos++; 165 | netBuffer[chPos] = 0; 166 | } 167 | } 168 | 169 | fh.close(); 170 | 171 | int x; 172 | 173 | Serial.print("\r\nmac "); 174 | for (x = 0; x < 6; x++) { 175 | Serial.print(myMac[x], HEX); 176 | if (x < 5) Serial.print(":"); 177 | } 178 | 179 | Serial.print("\r\nip "); 180 | for (x = 0; x < 4; x++) { 181 | Serial.print(myIP[x], DEC); 182 | if (x < 3) Serial.print("."); 183 | } 184 | 185 | Serial.print("\r\nnetmask "); 186 | for (x = 0; x < 4; x++) { 187 | Serial.print(myNM[x], DEC); 188 | if (x < 3) Serial.print("."); 189 | } 190 | 191 | Serial.print("\r\ngateway "); 192 | for (x = 0; x < 4; x++) { 193 | Serial.print(myGW[x], DEC); 194 | if (x < 3) Serial.print("."); 195 | } 196 | 197 | Serial.print("\r\nconsole "); 198 | for (x = 0; x < 4; x++) { 199 | Serial.print(RemIP[x], DEC); 200 | if (x < 3) Serial.print("."); 201 | } 202 | 203 | 204 | Serial.println(F("\r\nStarting ethernet")); 205 | Ethernet.begin(myMac, myIP, myGW, myGW, myNM); 206 | 207 | Serial.println(Ethernet.localIP()); 208 | 209 | 210 | } 211 | 212 | 213 | 214 | 215 | void loop() 216 | { 217 | 218 | 219 | //begin fader1 220 | 221 | 222 | analogvalue1 = analogRead(fader1); 223 | fadervalue1 = analogvalue1; 224 | if (fadervalue1 == lastanalogvalue1) { 225 | ; 226 | // Serial.println("Null"); 227 | } 228 | 229 | else if (fadervalue1 > lastanalogvalue1 + 2) { 230 | ; 231 | 232 | Serial.println(analogvalue1); 233 | fadervalue1 = map(fadervalue1, 0, 1023, 0, 1000); 234 | // fadervalue1 = fadervalue1 / 4; 235 | fadervalue1 = fadervalue1 / 10; 236 | 237 | lcd.setCursor(0, 1); 238 | lcd.print(fadervalue1); 239 | fadervalue1 = fadervalue1 / 100; 240 | 241 | OSCMessage outMessage(oscMsg1); 242 | outMessage.add(fadervalue1); 243 | // outMessage.send(Udp,RemIP,RemPort); 244 | Udp.beginPacket(RemIP, RemPort); 245 | outMessage.send(Udp); 246 | Udp.endPacket(); 247 | Serial.println(oscMsg1); 248 | delay(10); 249 | lastanalogvalue1 = analogvalue1; 250 | 251 | 252 | } 253 | 254 | else if (fadervalue1 < lastanalogvalue1 - 2) { 255 | ; 256 | 257 | Serial.println(analogvalue1); 258 | fadervalue1 = map(fadervalue1, 0, 1023, 0, 1000); 259 | // fadervalue1 = fadervalue1 / 4; 260 | fadervalue1 = fadervalue1 / 10; 261 | 262 | lcd.setCursor(0, 1); 263 | lcd.print(fadervalue1); 264 | fadervalue1 = fadervalue1 / 100; 265 | OSCMessage outMessage(oscMsg1); 266 | outMessage.add(fadervalue1); 267 | 268 | // outMessage.send(Udp,RemIP,RemPort); 269 | Udp.beginPacket(RemIP, RemPort); 270 | outMessage.send(Udp); 271 | Udp.endPacket(); 272 | Serial.println(oscMsg1); 273 | delay(10); 274 | lastanalogvalue1 = analogvalue1; 275 | 276 | 277 | } 278 | 279 | 280 | //begin fader2 281 | 282 | analogvalue2 = analogRead(fader2); 283 | fadervalue2 = analogvalue2; 284 | if (fadervalue2 == lastanalogvalue2) { 285 | ; 286 | // Serial.println("Null"); 287 | } 288 | 289 | else if (fadervalue2 > lastanalogvalue2 + 2) { 290 | ; 291 | 292 | Serial.println(analogvalue2); 293 | fadervalue2 = map(fadervalue2, 0, 1023, 0, 1000); 294 | // fadervalue2 = fadervalue2 / 4; 295 | fadervalue2 = fadervalue2 / 10; 296 | 297 | lcd.setCursor(10, 1); 298 | lcd.print(fadervalue2); 299 | fadervalue2 = fadervalue2 / 100; 300 | 301 | OSCMessage outMessage(oscMsg2); 302 | outMessage.add(fadervalue2); 303 | // outMessage.send(Udp,RemIP,RemPort); 304 | Udp.beginPacket(RemIP, RemPort); 305 | outMessage.send(Udp); 306 | Udp.endPacket(); 307 | Serial.println(oscMsg2); 308 | delay(10); 309 | lastanalogvalue2 = analogvalue2; 310 | 311 | 312 | } 313 | 314 | else if (fadervalue2 < lastanalogvalue2 - 2) { 315 | ; 316 | 317 | Serial.println(analogvalue2); 318 | fadervalue2 = map(fadervalue2, 0, 1023, 0, 1000); 319 | // fadervalue2 = fadervalue2 / 4; 320 | fadervalue2 = fadervalue2 / 10; 321 | 322 | lcd.setCursor(10, 1); 323 | lcd.print(fadervalue2); 324 | fadervalue2 = fadervalue2 / 100; 325 | 326 | OSCMessage outMessage(oscMsg2); 327 | outMessage.add(fadervalue2); 328 | // outMessage.send(Udp,RemIP,RemPort); 329 | Udp.beginPacket(RemIP, RemPort); 330 | outMessage.send(Udp); 331 | Udp.endPacket(); 332 | Serial.println(oscMsg2); 333 | delay(10); 334 | lastanalogvalue2 = analogvalue2; 335 | 336 | 337 | } 338 | 339 | //begin fader3 340 | 341 | analogvalue3 = analogRead(fader3); 342 | fadervalue3 = analogvalue3; 343 | if (fadervalue3 == lastanalogvalue3) { 344 | ; 345 | // Serial.println("Null"); 346 | } 347 | 348 | else if (fadervalue3 > lastanalogvalue3) { 349 | ; 350 | 351 | Serial.println(analogvalue3); 352 | fadervalue3 = map(fadervalue3, 0, 1023, 0, 1000); 353 | // fadervalue3 = fadervalue3 / 4; 354 | fadervalue3 = fadervalue3 / 1000; 355 | OSCMessage outMessage(oscMsg3); 356 | outMessage.add(fadervalue3); 357 | // outMessage.send(Udp,RemIP,RemPort); 358 | Udp.beginPacket(RemIP, RemPort); 359 | outMessage.send(Udp); 360 | Udp.endPacket(); 361 | Serial.println(oscMsg3); 362 | delay(10); 363 | lastanalogvalue3 = analogvalue3; 364 | 365 | 366 | } 367 | 368 | else if (fadervalue3 < lastanalogvalue3) { 369 | ; 370 | 371 | Serial.println(analogvalue3); 372 | fadervalue3 = map(fadervalue3, 0, 1023, 0, 1000); 373 | // fadervalue3 = fadervalue3 / 4; 374 | fadervalue3 = fadervalue3 / 1000; 375 | OSCMessage outMessage(oscMsg3); 376 | outMessage.add(fadervalue3); 377 | // outMessage.send(Udp,RemIP,RemPort); 378 | Udp.beginPacket(RemIP, RemPort); 379 | outMessage.send(Udp); 380 | Udp.endPacket(); 381 | Serial.println(oscMsg3); 382 | delay(10); 383 | lastanalogvalue3 = analogvalue3; 384 | 385 | 386 | } 387 | 388 | 389 | //begin fader4 390 | 391 | 392 | analogvalue4 = analogRead(fader4); 393 | fadervalue4 = analogvalue4; 394 | if (fadervalue4 == lastanalogvalue4) { 395 | ; 396 | // Serial.println("Null"); 397 | } 398 | 399 | else if (fadervalue4 > lastanalogvalue4) { 400 | ; 401 | 402 | Serial.println(analogvalue4); 403 | fadervalue4 = map(fadervalue4, 0, 1023, 0, 1000); 404 | // fadervalue4 = fadervalue4 / 4; 405 | fadervalue4 = fadervalue4 / 1000; 406 | OSCMessage outMessage(oscMsg4); 407 | outMessage.add(fadervalue4); 408 | // outMessage.send(Udp,RemIP,RemPort); 409 | Udp.beginPacket(RemIP, RemPort); 410 | outMessage.send(Udp); 411 | Udp.endPacket(); 412 | delay(10); 413 | lastanalogvalue4 = analogvalue4; 414 | 415 | 416 | } 417 | 418 | else if (fadervalue4 < lastanalogvalue4) { 419 | ; 420 | 421 | Serial.println(analogvalue4); 422 | fadervalue4 = map(fadervalue4, 0, 1023, 0, 1000); 423 | // fadervalue4 = fadervalue4 / 4; 424 | fadervalue4 = fadervalue4 / 1000; 425 | OSCMessage outMessage(oscMsg4); 426 | outMessage.add(fadervalue4); 427 | // outMessage.send(Udp,RemIP,RemPort); 428 | Udp.beginPacket(RemIP, RemPort); 429 | outMessage.send(Udp); 430 | Udp.endPacket(); 431 | delay(10); 432 | lastanalogvalue4 = analogvalue4; 433 | 434 | 435 | } 436 | 437 | 438 | delay(10); 439 | } 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | byte getMAC(char* macBuf, byte* thisMAC) { 451 | byte thisLen = strlen(macBuf); 452 | byte thisOctet = 1; 453 | 454 | thisMAC[0] = strtol(&macBuf[0], NULL, 16); 455 | 456 | for (int x = 0; x < thisLen; x++) { 457 | if (macBuf[x] == ':') { 458 | thisMAC[thisOctet] = strtol(&macBuf[x + 1], NULL, 16); 459 | thisOctet++; 460 | } 461 | } 462 | 463 | if (thisOctet == 6) return (1); 464 | else return (0); 465 | 466 | } 467 | 468 | byte getIP(char* ipBuf, byte* thisIP) { 469 | byte thisLen = strlen(ipBuf); 470 | byte thisOctet = 1; 471 | 472 | thisIP[0] = atoi(&ipBuf[0]); 473 | 474 | for (int x = 0; x < thisLen; x++) { 475 | if (ipBuf[x] == '.') { 476 | thisIP[thisOctet] = atoi(&ipBuf[x + 1]); 477 | thisOctet++; 478 | } 479 | } 480 | 481 | if (thisOctet == 4) return (1); 482 | else return (0); 483 | } 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | -------------------------------------------------------------------------------- /five_encoder_USB_OSC_No_Display.ino: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Electronic Theatre Controls, Inc., http://www.etcconnect.com 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 22 | /******************************************************************************* 23 | * 24 | * Electronic Theatre Controls 25 | * 26 | * LightHack_ - Two Encoder Three Button Module 27 | * 28 | * (c) 2017 by ETC 29 | * 30 | * 31 | * This code implements a Pan/Tilt module using two encoders and three 32 | * buttons. The two encoders function as pan and tilt controllers with one 33 | * button being reserved for controlling fine/coarse mode. The other two 34 | * buttons are assigned to Next and Last which make it easy to switch between 35 | * channels. 36 | * 37 | ******************************************************************************* 38 | * 39 | * Revision History 40 | * 41 | * yyyy-mm-dd Vxx By_Who Comment 42 | * 43 | * 2017-07-21 V1.000 Ethan Oswald Massey Original creation 44 | * 45 | ******************************************************************************/ 46 | 47 | /******************************************************************************* 48 | * Includes 49 | ******************************************************************************/ 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include 57 | #ifdef BOARD_HAS_USB_SERIAL 58 | #include 59 | SLIPEncodedUSBSerial SLIPSerial(thisBoardsSerialUSB); 60 | #else 61 | #include 62 | SLIPEncodedSerial SLIPSerial(Serial); 63 | #endif 64 | #include 65 | #include 66 | 67 | /******************************************************************************* 68 | * Macros and Constants 69 | ******************************************************************************/ 70 | #define LCD_CHARS 40 71 | #define LCD_LINES 2 // Currently assume at least 2 lines 72 | 73 | #define PAN_POS 4 74 | #define TILT_POS 5 75 | #define ZOOM_POS 0 76 | #define EDGE_POS 0 77 | #define NEXT_BTN 31 78 | #define LAST_BTN 32 79 | #define SHIFT_BTN 30 80 | 81 | #define SUBSCRIBE 1 82 | #define UNSUBSCRIBE 0 83 | 84 | #define EDGE_DOWN 1 85 | #define EDGE_UP 0 86 | 87 | // These define which direction is "forward" for an encoder 88 | #define FORWARD 0 89 | #define REVERSE 1 90 | 91 | // Change these values to switch which direction increase/decrease pan/tilt 92 | #define PAN_DIR FORWARD 93 | #define TILT_DIR FORWARD 94 | #define ZOOM_DIR FORWARD 95 | #define EDGE_DIR FORWARD 96 | 97 | #define SIG_DIGITS 2 // Number of significant digits displayed 98 | 99 | #define OSC_BUF_MAX_SIZE 512 100 | 101 | const String HANDSHAKE_QUERY = "ETCOSC?"; 102 | const String HANDSHAKE_REPLY = "OK"; 103 | 104 | const String EOS_KEY = "/eos/key/"; 105 | const String EOS_NEXT_KEY = "NEXT"; 106 | const String EOS_LAST_KEY = "LAST"; 107 | 108 | const String EOS_WHEEL = "/eos/wheel"; 109 | const String EOS_PT_ADDRESS = "/eos/out/pantilt"; 110 | const String EOS_ZOOM_ADDRESS = "/eos/out/param/zoom"; 111 | const String EOS_EDGE_ADDRESS = "/eos/out/param/edge"; 112 | 113 | /******************************************************************************* 114 | * Local Types 115 | ******************************************************************************/ 116 | enum WHEEL_TYPE { TILT, PAN, ZOOM, EDGE }; 117 | enum WHEEL_MODE { COARSE, FINE }; 118 | 119 | struct Encoder 120 | { 121 | uint8_t pinA; 122 | uint8_t pinB; 123 | uint8_t buttonPin; 124 | uint8_t buttonState; 125 | int pinAPrevious; 126 | int pinBPrevious; 127 | float pos; 128 | uint8_t direction; 129 | }; 130 | struct Encoder panWheel; 131 | struct Encoder tiltWheel; 132 | struct Encoder zoomWheel; 133 | struct Encoder edgeWheel; 134 | 135 | /******************************************************************************* 136 | * Global Variables 137 | ******************************************************************************/ 138 | 139 | // initialize the library with the numbers of the interface pins 140 | LiquidCrystal lcd(2, 3, 5, 6, 7, 8, 9); 141 | 142 | bool updateDisplay = false; 143 | 144 | 145 | /******************************************************************************* 146 | * Local Functions 147 | ******************************************************************************/ 148 | 149 | /******************************************************************************* 150 | * Issues all our subscribes to Eos. When subscribed, Eos will keep us updated 151 | * with the latest values for a given parameter. 152 | * 153 | * Parameters: none 154 | * 155 | * Return Value: void 156 | * 157 | ******************************************************************************/ 158 | void issueSubscribes() 159 | { 160 | // Add a filter so we don't get spammed with unwanted OSC messages from Eos 161 | OSCMessage filter("/eos/filter/add"); 162 | filter.add("/eos/out/pantilt*"); 163 | filter.add("/eos/out/param/zoom*"); 164 | filter.add("/eos/out/param/edge*"); 165 | // filter.add("/eos/out/param*"); 166 | SLIPSerial.beginPacket(); 167 | filter.send(SLIPSerial); 168 | SLIPSerial.endPacket(); 169 | 170 | 171 | 172 | 173 | // subscribe to Eos pan & tilt updates 174 | OSCMessage subPan("/eos/subscribe/param/pan"); 175 | subPan.add(SUBSCRIBE); 176 | SLIPSerial.beginPacket(); 177 | subPan.send(SLIPSerial); 178 | SLIPSerial.endPacket(); 179 | 180 | OSCMessage subTilt("/eos/subscribe/param/tilt"); 181 | subTilt.add(SUBSCRIBE); 182 | SLIPSerial.beginPacket(); 183 | subTilt.send(SLIPSerial); 184 | SLIPSerial.endPacket(); 185 | 186 | OSCMessage subZoom("/eos/subscribe/param/zoom"); 187 | subZoom.add(SUBSCRIBE); 188 | SLIPSerial.beginPacket(); 189 | subZoom.send(SLIPSerial); 190 | SLIPSerial.endPacket(); 191 | 192 | OSCMessage subEdge("/eos/subscribe/param/edge"); 193 | subEdge.add(SUBSCRIBE); 194 | SLIPSerial.beginPacket(); 195 | subEdge.send(SLIPSerial); 196 | SLIPSerial.endPacket(); 197 | 198 | 199 | } 200 | 201 | /******************************************************************************* 202 | * Given a valid OSCMessage (relavent to Pan/Tilt), we update our Encoder struct 203 | * with the new position information. 204 | * 205 | * Parameters: 206 | * msg - The OSC message we will use to update our internal data 207 | * addressOffset - Unused (allows for mulitple nested roots) 208 | * 209 | * Return Value: void 210 | * 211 | ******************************************************************************/ 212 | void parseWheelUpdate(OSCMessage& msg, int addressOffset) 213 | { 214 | panWheel.pos = msg.getOSCData(PAN_POS)->getFloat(); 215 | tiltWheel.pos = msg.getOSCData(TILT_POS)->getFloat(); 216 | 217 | 218 | updateDisplay = true; 219 | } 220 | 221 | void parseZoomUpdate(OSCMessage& msg, int addressOffset) 222 | { 223 | 224 | zoomWheel.pos = msg.getOSCData(ZOOM_POS)->getFloat(); 225 | 226 | updateDisplay = true; 227 | } 228 | 229 | void parseEdgeUpdate(OSCMessage& msg, int addressOffset) 230 | { 231 | 232 | edgeWheel.pos = msg.getOSCData(EDGE_POS)->getFloat(); 233 | 234 | updateDisplay = true; 235 | } 236 | 237 | /******************************************************************************* 238 | * Given an unknown OSC message we check to see if it's a handshake message. 239 | * If it's a handshake we issue a subscribe, otherwise we begin route the OSC 240 | * message to the appropriate function. 241 | * 242 | * Parameters: 243 | * msg - The OSC message of unknown importance 244 | * 245 | * Return Value: void 246 | * 247 | ******************************************************************************/ 248 | void parseOSCMessage(String& msg) 249 | { 250 | // check to see if this is the handshake string 251 | if (msg.indexOf(HANDSHAKE_QUERY) != -1) 252 | { 253 | // handshake string found! 254 | SLIPSerial.beginPacket(); 255 | SLIPSerial.write((const uint8_t*)HANDSHAKE_REPLY.c_str(), (size_t)HANDSHAKE_REPLY.length()); 256 | SLIPSerial.endPacket(); 257 | 258 | // Let Eos know we want updates on some things 259 | issueSubscribes(); 260 | } 261 | else 262 | { 263 | // prepare the message for routing by filling an OSCMessage object with our message string 264 | OSCMessage oscmsg; 265 | oscmsg.fill((uint8_t*)msg.c_str(), (int)msg.length()); 266 | // route pan/tilt messages to the parseWheelUpdate function 267 | oscmsg.route(EOS_PT_ADDRESS.c_str(), parseWheelUpdate); 268 | oscmsg.route(EOS_ZOOM_ADDRESS.c_str(), parseZoomUpdate); 269 | oscmsg.route(EOS_EDGE_ADDRESS.c_str(), parseEdgeUpdate); 270 | 271 | } 272 | } 273 | 274 | /******************************************************************************* 275 | * Updates the display with the latest pan and tilt positions. 276 | * 277 | * Parameters: none 278 | * 279 | * Return Value: void 280 | * 281 | ******************************************************************************/ 282 | void displayStatus() 283 | { 284 | // lcd.clear(); 285 | // put the cursor at the begining of the first line 286 | lcd.setCursor(0, 0); 287 | lcd.print(" Pan"); 288 | lcd.setCursor(0, 1); 289 | // lcd.print(" "); 290 | lcd.print(panWheel.pos, SIG_DIGITS); 291 | lcd.print(" "); 292 | 293 | // put the cursor at the begining of the first line 294 | lcd.setCursor(11, 0); 295 | lcd.print(" Tilt"); 296 | lcd.setCursor(11, 1); 297 | // lcd.print(" "); 298 | lcd.print(tiltWheel.pos, SIG_DIGITS); 299 | lcd.print(" "); 300 | 301 | // put the cursor at the begining of the second line 302 | lcd.setCursor(21, 0); 303 | lcd.print(" Edge"); 304 | lcd.setCursor(21, 1); 305 | // lcd.print(" "); 306 | lcd.print(edgeWheel.pos, SIG_DIGITS); 307 | lcd.print(" "); 308 | 309 | // put the cursor at the begining of the second line 310 | lcd.setCursor(31, 0); 311 | lcd.print(" Zoom"); 312 | lcd.setCursor(31, 1); 313 | // lcd.print(" "); 314 | lcd.print(zoomWheel.pos, SIG_DIGITS); 315 | lcd.print(" "); 316 | 317 | updateDisplay = false; 318 | } 319 | 320 | /******************************************************************************* 321 | * Initalizes a given encoder struct to the requested parameters. 322 | * 323 | * Parameters: 324 | * encoder - Pointer to the encoder we will be inializing 325 | * pinA - Where the A pin is connected to the arduino 326 | * pinB - Where the B pin is connected to the arduino 327 | * buttonPin - Where the button pin is connected to the arduino 328 | * direction - Determines if clockwise or counterclockwise is "forward" 329 | * 330 | * Return Value: void 331 | * 332 | ******************************************************************************/ 333 | void initEncoder(struct Encoder* encoder, uint8_t pinA, uint8_t pinB, uint8_t buttonPin, uint8_t direction) 334 | { 335 | encoder->pinA = pinA; 336 | encoder->pinB = pinB; 337 | encoder->buttonPin = buttonPin; 338 | encoder->pos = 0; 339 | encoder->direction = direction; 340 | 341 | pinMode(pinA, INPUT_PULLUP); 342 | pinMode(pinB, INPUT_PULLUP); 343 | pinMode(buttonPin, INPUT_PULLUP); 344 | 345 | encoder->pinAPrevious = digitalRead(pinA); 346 | encoder->pinBPrevious = digitalRead(pinB); 347 | encoder->buttonState = digitalRead(buttonPin); 348 | } 349 | 350 | /******************************************************************************* 351 | * Checks if the encoder has moved by comparing the previous state of the pins 352 | * with the current state. If they are different, we know there is movement. 353 | * In the event of movement we update the current state of our pins. 354 | * 355 | * Parameters: 356 | * encoder - Pointer to the encoder we will be checking for motion 357 | * 358 | * Return Value: 359 | * encoderMotion - Returns the 0 if the encoder has not moved 360 | * 1 for forward motion 361 | * -1 for reverse motion 362 | * 363 | ******************************************************************************/ 364 | int8_t updateEncoder(struct Encoder* encoder) 365 | { 366 | int8_t encoderMotion = 0; 367 | int pinACurrent = digitalRead(encoder->pinA); 368 | int pinBCurrent = digitalRead(encoder->pinB); 369 | 370 | // has the encoder moved at all? 371 | if (encoder->pinAPrevious != pinACurrent) 372 | { 373 | // Since it has moved, we must determine if the encoder has moved forwards or backwards 374 | encoderMotion = (encoder->pinAPrevious == encoder->pinBPrevious) ? -1 : 1; 375 | 376 | // If we are in reverse mode, flip the direction of the encoder motion 377 | if (encoder->direction == REVERSE) 378 | encoderMotion = -encoderMotion; 379 | } 380 | encoder->pinAPrevious = pinACurrent; 381 | encoder->pinBPrevious = pinBCurrent; 382 | 383 | return encoderMotion; 384 | } 385 | 386 | /******************************************************************************* 387 | * Sends a message to Eos informing them of a wheels movement. 388 | * 389 | * Parameters: 390 | * type - the type of wheel that's moving (i.e. pan or tilt) 391 | * ticks - the direction and intensity of the movement 392 | * 393 | * Return Value: void 394 | * 395 | ******************************************************************************/ 396 | void sendWheelMove(WHEEL_TYPE type, float ticks) 397 | { 398 | String wheelMsg(EOS_WHEEL); 399 | 400 | if (digitalRead(SHIFT_BTN) == LOW) 401 | wheelMsg.concat("/fine"); 402 | else 403 | wheelMsg.concat("/coarse"); 404 | 405 | if (type == PAN) 406 | wheelMsg.concat("/pan"); 407 | else if (type == TILT) 408 | wheelMsg.concat("/tilt"); 409 | else if (type == ZOOM) 410 | wheelMsg.concat("/zoom"); 411 | else if (type == EDGE) 412 | wheelMsg.concat("/edge"); 413 | else 414 | // something has gone very wrong 415 | return; 416 | 417 | OSCMessage wheelUpdate(wheelMsg.c_str()); 418 | wheelUpdate.add(ticks); 419 | SLIPSerial.beginPacket(); 420 | wheelUpdate.send(SLIPSerial); 421 | SLIPSerial.endPacket(); 422 | } 423 | 424 | /******************************************************************************* 425 | * Sends a message to Eos informing them of a keys press. 426 | * 427 | * Parameters: 428 | * down - whether a key has been pushed down (true) or released (false) 429 | * key - the key that has moved 430 | * 431 | * Return Value: void 432 | * 433 | ******************************************************************************/ 434 | void sendKeyPress(bool down, String key) 435 | { 436 | key = EOS_KEY + key; 437 | OSCMessage keyMsg(key.c_str()); 438 | 439 | if (down) 440 | keyMsg.add(EDGE_DOWN); 441 | else 442 | keyMsg.add(EDGE_UP); 443 | 444 | SLIPSerial.beginPacket(); 445 | keyMsg.send(SLIPSerial); 446 | SLIPSerial.endPacket(); 447 | } 448 | 449 | /******************************************************************************* 450 | * Checks the status of all the buttons relavent to Eos (i.e. Next & Last) 451 | * 452 | * NOTE: This does not check the shift key. The shift key is used in tandom with 453 | * the encoder to determine coarse/fine mode and thus does not report to Eos 454 | * directly. 455 | * 456 | * Parameters: none 457 | * 458 | * Return Value: void 459 | * 460 | ******************************************************************************/ 461 | void checkButtons() 462 | { 463 | static int nextKeyState = HIGH; 464 | static int lastKeyState = HIGH; 465 | 466 | // Has the button state changed 467 | if (digitalRead(NEXT_BTN) != nextKeyState) 468 | { 469 | // Notify Eos of this key press 470 | if (nextKeyState == LOW) 471 | { 472 | sendKeyPress(false, EOS_NEXT_KEY); 473 | nextKeyState = HIGH; 474 | } 475 | else 476 | { 477 | sendKeyPress(true, EOS_NEXT_KEY); 478 | nextKeyState = LOW; 479 | } 480 | } 481 | 482 | if (digitalRead(LAST_BTN) != lastKeyState) 483 | { 484 | if (lastKeyState == LOW) 485 | { 486 | sendKeyPress(false, EOS_LAST_KEY); 487 | lastKeyState = HIGH; 488 | } 489 | else 490 | { 491 | sendKeyPress(true, EOS_LAST_KEY); 492 | lastKeyState = LOW; 493 | } 494 | } 495 | } 496 | 497 | /******************************************************************************* 498 | * Here we setup our encoder, lcd, and various input devices. We also prepare 499 | * to comunicate OSC with Eos by setting up SLIPSerial. Once we are done with 500 | * setup() we pass control over to loop() and never call setup() again. 501 | * 502 | * NOTE: This function is the entry function. This is where control over the 503 | * arduino is passed to us (the end user). 504 | * 505 | * Parameters: none 506 | * 507 | * Return Value: void 508 | * 509 | ******************************************************************************/ 510 | void setup() 511 | { 512 | SLIPSerial.begin(115200); 513 | // This is a hack around an arduino bug. It was taken from the OSC library examples 514 | // quoted out for Teensy implementation 515 | // #ifdef BOARD_HAS_USB_SERIAL 516 | // while (!SerialUSB); 517 | // #else 518 | // while (!Serial); 519 | // #endif 520 | 521 | // this is necessary for reconnecting a device because it need some timme for the serial port to get open, but meanwhile the handshake message was send from eos 522 | SLIPSerial.beginPacket(); 523 | SLIPSerial.write((const uint8_t*)HANDSHAKE_REPLY.c_str(), (size_t)HANDSHAKE_REPLY.length()); 524 | SLIPSerial.endPacket(); 525 | // Let Eos know we want updates on some things 526 | issueSubscribes(); 527 | 528 | initEncoder(&panWheel, A6, A7, 11, PAN_DIR); 529 | initEncoder(&tiltWheel, A4, A5, 11, TILT_DIR); 530 | initEncoder(&zoomWheel, A0, A1, 11, ZOOM_DIR); 531 | initEncoder(&edgeWheel, A2, A3, 11, EDGE_DIR); 532 | 533 | lcd.begin(LCD_CHARS, LCD_LINES); 534 | 535 | lcd.clear(); 536 | 537 | lcd.setCursor(10,0); 538 | lcd.print("|"); 539 | lcd.setCursor(10,1); 540 | lcd.print("|"); 541 | lcd.setCursor(20,0); 542 | lcd.print("|"); 543 | lcd.setCursor(20,1); 544 | lcd.print("|"); 545 | lcd.setCursor(30,0); 546 | lcd.print("|"); 547 | lcd.setCursor(30,1); 548 | lcd.print("|"); 549 | 550 | 551 | pinMode(NEXT_BTN, INPUT_PULLUP); 552 | pinMode(LAST_BTN, INPUT_PULLUP); 553 | pinMode(SHIFT_BTN, INPUT_PULLUP); 554 | 555 | displayStatus(); 556 | } 557 | 558 | /******************************************************************************* 559 | * Here we service, monitor, and otherwise control all our peripheral devices. 560 | * First, we retrieve the status of our encoders and buttons and update Eos. 561 | * Next, we check if there are any OSC message for us. 562 | * Finally, we update our display (if an update is necessary) 563 | * 564 | * NOTE: This function is our main loop and thus we will loop here forever. 565 | * 566 | * Parameters: none 567 | * 568 | * Return Value: void 569 | * 570 | ******************************************************************************/ 571 | void loop() 572 | { 573 | static String curMsg; 574 | int size; 575 | // get the updated state of each encoder 576 | int32_t panMotion = updateEncoder(&panWheel); 577 | int32_t tiltMotion = updateEncoder(&tiltWheel); 578 | int32_t zoomMotion = updateEncoder(&zoomWheel); 579 | int32_t edgeMotion = updateEncoder(&edgeWheel); 580 | 581 | // check for next/last updates 582 | checkButtons(); 583 | 584 | // now update our wheels 585 | if (tiltMotion != 0) 586 | sendWheelMove(TILT, tiltMotion); 587 | 588 | if (panMotion != 0) 589 | sendWheelMove(PAN, panMotion); 590 | 591 | if (zoomMotion != 0) 592 | sendWheelMove(ZOOM, zoomMotion); 593 | 594 | if (edgeMotion != 0) 595 | sendWheelMove(EDGE, edgeMotion); 596 | 597 | 598 | // Then we check to see if any OSC commands have come from Eos 599 | // and update the display accordingly. 600 | size = SLIPSerial.available(); 601 | if (size > 0) 602 | { 603 | // Fill the msg with all of the available bytes 604 | while (size--) 605 | curMsg += (char)(SLIPSerial.read()); 606 | } 607 | if (SLIPSerial.endofPacket()) 608 | { 609 | parseOSCMessage(curMsg); 610 | curMsg = String(); 611 | } 612 | 613 | if (updateDisplay) 614 | displayStatus(); 615 | } 616 | 617 | -------------------------------------------------------------------------------- /four_encoder_USB_OSC_40X2_Display.ino: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2017 Electronic Theatre Controls, Inc., http://www.etcconnect.com 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a copy 4 | // of this software and associated documentation files (the "Software"), to deal 5 | // in the Software without restriction, including without limitation the rights 6 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | // copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | // THE SOFTWARE. 20 | 21 | 22 | /******************************************************************************* 23 | * 24 | * Electronic Theatre Controls 25 | * 26 | * LightHack_ - Two Encoder Three Button Module 27 | * 28 | * (c) 2017 by ETC 29 | * 30 | * 31 | * This code implements a Pan/Tilt module using two encoders and three 32 | * buttons. The two encoders function as pan and tilt controllers with one 33 | * button being reserved for controlling fine/coarse mode. The other two 34 | * buttons are assigned to Next and Last which make it easy to switch between 35 | * channels. 36 | * 37 | ******************************************************************************* 38 | * 39 | * Revision History 40 | * 41 | * yyyy-mm-dd Vxx By_Who Comment 42 | * 43 | * 2017-07-21 V1.000 Ethan Oswald Massey Original creation 44 | * 45 | ******************************************************************************/ 46 | 47 | /******************************************************************************* 48 | * Includes 49 | ******************************************************************************/ 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include 57 | #ifdef BOARD_HAS_USB_SERIAL 58 | #include 59 | SLIPEncodedUSBSerial SLIPSerial(thisBoardsSerialUSB); 60 | #else 61 | #include 62 | SLIPEncodedSerial SLIPSerial(Serial); 63 | #endif 64 | #include 65 | #include 66 | 67 | /******************************************************************************* 68 | * Macros and Constants 69 | ******************************************************************************/ 70 | #define LCD_CHARS 40 71 | #define LCD_LINES 2 // Currently assume at least 2 lines 72 | 73 | #define PAN_POS 4 74 | #define TILT_POS 5 75 | #define ZOOM_POS 0 76 | #define EDGE_POS 0 77 | #define NEXT_BTN 31 78 | #define LAST_BTN 32 79 | #define SHIFT_BTN 30 80 | 81 | #define SUBSCRIBE 1 82 | #define UNSUBSCRIBE 0 83 | 84 | #define EDGE_DOWN 1 85 | #define EDGE_UP 0 86 | 87 | // These define which direction is "forward" for an encoder 88 | #define FORWARD 0 89 | #define REVERSE 1 90 | 91 | // Change these values to switch which direction increase/decrease pan/tilt 92 | #define PAN_DIR FORWARD 93 | #define TILT_DIR FORWARD 94 | #define ZOOM_DIR FORWARD 95 | #define EDGE_DIR FORWARD 96 | 97 | #define SIG_DIGITS 2 // Number of significant digits displayed 98 | 99 | #define OSC_BUF_MAX_SIZE 512 100 | 101 | const String HANDSHAKE_QUERY = "ETCOSC?"; 102 | const String HANDSHAKE_REPLY = "OK"; 103 | 104 | const String EOS_KEY = "/eos/key/"; 105 | const String EOS_NEXT_KEY = "NEXT"; 106 | const String EOS_LAST_KEY = "LAST"; 107 | 108 | const String EOS_WHEEL = "/eos/wheel"; 109 | const String EOS_PT_ADDRESS = "/eos/out/pantilt"; 110 | const String EOS_ZOOM_ADDRESS = "/eos/out/param/zoom"; 111 | const String EOS_EDGE_ADDRESS = "/eos/out/param/edge"; 112 | 113 | /******************************************************************************* 114 | * Local Types 115 | ******************************************************************************/ 116 | enum WHEEL_TYPE { TILT, PAN, ZOOM, EDGE }; 117 | enum WHEEL_MODE { COARSE, FINE }; 118 | 119 | struct Encoder 120 | { 121 | uint8_t pinA; 122 | uint8_t pinB; 123 | uint8_t buttonPin; 124 | uint8_t buttonState; 125 | int pinAPrevious; 126 | int pinBPrevious; 127 | float pos; 128 | uint8_t direction; 129 | }; 130 | struct Encoder panWheel; 131 | struct Encoder tiltWheel; 132 | struct Encoder zoomWheel; 133 | struct Encoder edgeWheel; 134 | 135 | /******************************************************************************* 136 | * Global Variables 137 | ******************************************************************************/ 138 | 139 | // initialize the library with the numbers of the interface pins 140 | LiquidCrystal lcd(2, 3, 5, 6, 7, 8, 9); 141 | 142 | bool updateDisplay = false; 143 | 144 | 145 | /******************************************************************************* 146 | * Local Functions 147 | ******************************************************************************/ 148 | 149 | /******************************************************************************* 150 | * Issues all our subscribes to Eos. When subscribed, Eos will keep us updated 151 | * with the latest values for a given parameter. 152 | * 153 | * Parameters: none 154 | * 155 | * Return Value: void 156 | * 157 | ******************************************************************************/ 158 | void issueSubscribes() 159 | { 160 | // Add a filter so we don't get spammed with unwanted OSC messages from Eos 161 | OSCMessage filter("/eos/filter/add"); 162 | filter.add("/eos/out/pantilt*"); 163 | filter.add("/eos/out/param/zoom*"); 164 | filter.add("/eos/out/param/edge*"); 165 | // filter.add("/eos/out/param*"); 166 | SLIPSerial.beginPacket(); 167 | filter.send(SLIPSerial); 168 | SLIPSerial.endPacket(); 169 | 170 | 171 | 172 | 173 | // subscribe to Eos pan & tilt updates 174 | OSCMessage subPan("/eos/subscribe/param/pan"); 175 | subPan.add(SUBSCRIBE); 176 | SLIPSerial.beginPacket(); 177 | subPan.send(SLIPSerial); 178 | SLIPSerial.endPacket(); 179 | 180 | OSCMessage subTilt("/eos/subscribe/param/tilt"); 181 | subTilt.add(SUBSCRIBE); 182 | SLIPSerial.beginPacket(); 183 | subTilt.send(SLIPSerial); 184 | SLIPSerial.endPacket(); 185 | 186 | OSCMessage subZoom("/eos/subscribe/param/zoom"); 187 | subZoom.add(SUBSCRIBE); 188 | SLIPSerial.beginPacket(); 189 | subZoom.send(SLIPSerial); 190 | SLIPSerial.endPacket(); 191 | 192 | OSCMessage subEdge("/eos/subscribe/param/edge"); 193 | subEdge.add(SUBSCRIBE); 194 | SLIPSerial.beginPacket(); 195 | subEdge.send(SLIPSerial); 196 | SLIPSerial.endPacket(); 197 | 198 | 199 | } 200 | 201 | /******************************************************************************* 202 | * Given a valid OSCMessage (relavent to Pan/Tilt), we update our Encoder struct 203 | * with the new position information. 204 | * 205 | * Parameters: 206 | * msg - The OSC message we will use to update our internal data 207 | * addressOffset - Unused (allows for mulitple nested roots) 208 | * 209 | * Return Value: void 210 | * 211 | ******************************************************************************/ 212 | void parseWheelUpdate(OSCMessage& msg, int addressOffset) 213 | { 214 | panWheel.pos = msg.getOSCData(PAN_POS)->getFloat(); 215 | tiltWheel.pos = msg.getOSCData(TILT_POS)->getFloat(); 216 | 217 | 218 | updateDisplay = true; 219 | } 220 | 221 | void parseZoomUpdate(OSCMessage& msg, int addressOffset) 222 | { 223 | 224 | zoomWheel.pos = msg.getOSCData(ZOOM_POS)->getFloat(); 225 | 226 | updateDisplay = true; 227 | } 228 | 229 | void parseEdgeUpdate(OSCMessage& msg, int addressOffset) 230 | { 231 | 232 | edgeWheel.pos = msg.getOSCData(EDGE_POS)->getFloat(); 233 | 234 | updateDisplay = true; 235 | } 236 | 237 | /******************************************************************************* 238 | * Given an unknown OSC message we check to see if it's a handshake message. 239 | * If it's a handshake we issue a subscribe, otherwise we begin route the OSC 240 | * message to the appropriate function. 241 | * 242 | * Parameters: 243 | * msg - The OSC message of unknown importance 244 | * 245 | * Return Value: void 246 | * 247 | ******************************************************************************/ 248 | void parseOSCMessage(String& msg) 249 | { 250 | // check to see if this is the handshake string 251 | if (msg.indexOf(HANDSHAKE_QUERY) != -1) 252 | { 253 | // handshake string found! 254 | SLIPSerial.beginPacket(); 255 | SLIPSerial.write((const uint8_t*)HANDSHAKE_REPLY.c_str(), (size_t)HANDSHAKE_REPLY.length()); 256 | SLIPSerial.endPacket(); 257 | 258 | // Let Eos know we want updates on some things 259 | issueSubscribes(); 260 | } 261 | else 262 | { 263 | // prepare the message for routing by filling an OSCMessage object with our message string 264 | OSCMessage oscmsg; 265 | oscmsg.fill((uint8_t*)msg.c_str(), (int)msg.length()); 266 | // route pan/tilt messages to the parseWheelUpdate function 267 | oscmsg.route(EOS_PT_ADDRESS.c_str(), parseWheelUpdate); 268 | oscmsg.route(EOS_ZOOM_ADDRESS.c_str(), parseZoomUpdate); 269 | oscmsg.route(EOS_EDGE_ADDRESS.c_str(), parseEdgeUpdate); 270 | 271 | } 272 | } 273 | 274 | /******************************************************************************* 275 | * Updates the display with the latest pan and tilt positions. 276 | * 277 | * Parameters: none 278 | * 279 | * Return Value: void 280 | * 281 | ******************************************************************************/ 282 | void displayStatus() 283 | { 284 | // lcd.clear(); 285 | // put the cursor at the begining of the first line 286 | lcd.setCursor(0, 0); 287 | lcd.print(" Pan"); 288 | lcd.setCursor(0, 1); 289 | // lcd.print(" "); 290 | lcd.print(panWheel.pos, SIG_DIGITS); 291 | lcd.print(" "); 292 | 293 | // put the cursor at the begining of the first line 294 | lcd.setCursor(11, 0); 295 | lcd.print(" Tilt"); 296 | lcd.setCursor(11, 1); 297 | // lcd.print(" "); 298 | lcd.print(tiltWheel.pos, SIG_DIGITS); 299 | lcd.print(" "); 300 | 301 | // put the cursor at the begining of the second line 302 | lcd.setCursor(21, 0); 303 | lcd.print(" Edge"); 304 | lcd.setCursor(21, 1); 305 | // lcd.print(" "); 306 | lcd.print(edgeWheel.pos, SIG_DIGITS); 307 | lcd.print(" "); 308 | 309 | // put the cursor at the begining of the second line 310 | lcd.setCursor(31, 0); 311 | lcd.print(" Zoom"); 312 | lcd.setCursor(31, 1); 313 | // lcd.print(" "); 314 | lcd.print(zoomWheel.pos, SIG_DIGITS); 315 | lcd.print(" "); 316 | 317 | updateDisplay = false; 318 | } 319 | 320 | /******************************************************************************* 321 | * Initalizes a given encoder struct to the requested parameters. 322 | * 323 | * Parameters: 324 | * encoder - Pointer to the encoder we will be inializing 325 | * pinA - Where the A pin is connected to the arduino 326 | * pinB - Where the B pin is connected to the arduino 327 | * buttonPin - Where the button pin is connected to the arduino 328 | * direction - Determines if clockwise or counterclockwise is "forward" 329 | * 330 | * Return Value: void 331 | * 332 | ******************************************************************************/ 333 | void initEncoder(struct Encoder* encoder, uint8_t pinA, uint8_t pinB, uint8_t buttonPin, uint8_t direction) 334 | { 335 | encoder->pinA = pinA; 336 | encoder->pinB = pinB; 337 | encoder->buttonPin = buttonPin; 338 | encoder->pos = 0; 339 | encoder->direction = direction; 340 | 341 | pinMode(pinA, INPUT_PULLUP); 342 | pinMode(pinB, INPUT_PULLUP); 343 | pinMode(buttonPin, INPUT_PULLUP); 344 | 345 | encoder->pinAPrevious = digitalRead(pinA); 346 | encoder->pinBPrevious = digitalRead(pinB); 347 | encoder->buttonState = digitalRead(buttonPin); 348 | } 349 | 350 | /******************************************************************************* 351 | * Checks if the encoder has moved by comparing the previous state of the pins 352 | * with the current state. If they are different, we know there is movement. 353 | * In the event of movement we update the current state of our pins. 354 | * 355 | * Parameters: 356 | * encoder - Pointer to the encoder we will be checking for motion 357 | * 358 | * Return Value: 359 | * encoderMotion - Returns the 0 if the encoder has not moved 360 | * 1 for forward motion 361 | * -1 for reverse motion 362 | * 363 | ******************************************************************************/ 364 | int8_t updateEncoder(struct Encoder* encoder) 365 | { 366 | int8_t encoderMotion = 0; 367 | int pinACurrent = digitalRead(encoder->pinA); 368 | int pinBCurrent = digitalRead(encoder->pinB); 369 | 370 | // has the encoder moved at all? 371 | if (encoder->pinAPrevious != pinACurrent) 372 | { 373 | // Since it has moved, we must determine if the encoder has moved forwards or backwards 374 | encoderMotion = (encoder->pinAPrevious == encoder->pinBPrevious) ? -1 : 1; 375 | 376 | // If we are in reverse mode, flip the direction of the encoder motion 377 | if (encoder->direction == REVERSE) 378 | encoderMotion = -encoderMotion; 379 | } 380 | encoder->pinAPrevious = pinACurrent; 381 | encoder->pinBPrevious = pinBCurrent; 382 | 383 | return encoderMotion; 384 | } 385 | 386 | /******************************************************************************* 387 | * Sends a message to Eos informing them of a wheels movement. 388 | * 389 | * Parameters: 390 | * type - the type of wheel that's moving (i.e. pan or tilt) 391 | * ticks - the direction and intensity of the movement 392 | * 393 | * Return Value: void 394 | * 395 | ******************************************************************************/ 396 | void sendWheelMove(WHEEL_TYPE type, float ticks) 397 | { 398 | String wheelMsg(EOS_WHEEL); 399 | 400 | if (digitalRead(SHIFT_BTN) == LOW) 401 | wheelMsg.concat("/fine"); 402 | else 403 | wheelMsg.concat("/coarse"); 404 | 405 | if (type == PAN) 406 | wheelMsg.concat("/pan"); 407 | else if (type == TILT) 408 | wheelMsg.concat("/tilt"); 409 | else if (type == ZOOM) 410 | wheelMsg.concat("/zoom"); 411 | else if (type == EDGE) 412 | wheelMsg.concat("/edge"); 413 | else 414 | // something has gone very wrong 415 | return; 416 | 417 | OSCMessage wheelUpdate(wheelMsg.c_str()); 418 | wheelUpdate.add(ticks); 419 | SLIPSerial.beginPacket(); 420 | wheelUpdate.send(SLIPSerial); 421 | SLIPSerial.endPacket(); 422 | } 423 | 424 | /******************************************************************************* 425 | * Sends a message to Eos informing them of a keys press. 426 | * 427 | * Parameters: 428 | * down - whether a key has been pushed down (true) or released (false) 429 | * key - the key that has moved 430 | * 431 | * Return Value: void 432 | * 433 | ******************************************************************************/ 434 | void sendKeyPress(bool down, String key) 435 | { 436 | key = EOS_KEY + key; 437 | OSCMessage keyMsg(key.c_str()); 438 | 439 | if (down) 440 | keyMsg.add(EDGE_DOWN); 441 | else 442 | keyMsg.add(EDGE_UP); 443 | 444 | SLIPSerial.beginPacket(); 445 | keyMsg.send(SLIPSerial); 446 | SLIPSerial.endPacket(); 447 | } 448 | 449 | /******************************************************************************* 450 | * Checks the status of all the buttons relavent to Eos (i.e. Next & Last) 451 | * 452 | * NOTE: This does not check the shift key. The shift key is used in tandom with 453 | * the encoder to determine coarse/fine mode and thus does not report to Eos 454 | * directly. 455 | * 456 | * Parameters: none 457 | * 458 | * Return Value: void 459 | * 460 | ******************************************************************************/ 461 | void checkButtons() 462 | { 463 | static int nextKeyState = HIGH; 464 | static int lastKeyState = HIGH; 465 | 466 | // Has the button state changed 467 | if (digitalRead(NEXT_BTN) != nextKeyState) 468 | { 469 | // Notify Eos of this key press 470 | if (nextKeyState == LOW) 471 | { 472 | sendKeyPress(false, EOS_NEXT_KEY); 473 | nextKeyState = HIGH; 474 | } 475 | else 476 | { 477 | sendKeyPress(true, EOS_NEXT_KEY); 478 | nextKeyState = LOW; 479 | } 480 | } 481 | 482 | if (digitalRead(LAST_BTN) != lastKeyState) 483 | { 484 | if (lastKeyState == LOW) 485 | { 486 | sendKeyPress(false, EOS_LAST_KEY); 487 | lastKeyState = HIGH; 488 | } 489 | else 490 | { 491 | sendKeyPress(true, EOS_LAST_KEY); 492 | lastKeyState = LOW; 493 | } 494 | } 495 | } 496 | 497 | /******************************************************************************* 498 | * Here we setup our encoder, lcd, and various input devices. We also prepare 499 | * to comunicate OSC with Eos by setting up SLIPSerial. Once we are done with 500 | * setup() we pass control over to loop() and never call setup() again. 501 | * 502 | * NOTE: This function is the entry function. This is where control over the 503 | * arduino is passed to us (the end user). 504 | * 505 | * Parameters: none 506 | * 507 | * Return Value: void 508 | * 509 | ******************************************************************************/ 510 | void setup() 511 | { 512 | SLIPSerial.begin(115200); 513 | // This is a hack around an arduino bug. It was taken from the OSC library examples 514 | // quoted out for Teensy implementation 515 | // #ifdef BOARD_HAS_USB_SERIAL 516 | // while (!SerialUSB); 517 | // #else 518 | // while (!Serial); 519 | // #endif 520 | 521 | // this is necessary for reconnecting a device because it need some timme for the serial port to get open, but meanwhile the handshake message was send from eos 522 | SLIPSerial.beginPacket(); 523 | SLIPSerial.write((const uint8_t*)HANDSHAKE_REPLY.c_str(), (size_t)HANDSHAKE_REPLY.length()); 524 | SLIPSerial.endPacket(); 525 | // Let Eos know we want updates on some things 526 | issueSubscribes(); 527 | 528 | initEncoder(&panWheel, A6, A7, 11, PAN_DIR); 529 | initEncoder(&tiltWheel, A4, A5, 11, TILT_DIR); 530 | initEncoder(&zoomWheel, A0, A1, 11, ZOOM_DIR); 531 | initEncoder(&edgeWheel, A2, A3, 11, EDGE_DIR); 532 | 533 | lcd.begin(LCD_CHARS, LCD_LINES); 534 | 535 | lcd.clear(); 536 | 537 | lcd.setCursor(10,0); 538 | lcd.print("|"); 539 | lcd.setCursor(10,1); 540 | lcd.print("|"); 541 | lcd.setCursor(20,0); 542 | lcd.print("|"); 543 | lcd.setCursor(20,1); 544 | lcd.print("|"); 545 | lcd.setCursor(30,0); 546 | lcd.print("|"); 547 | lcd.setCursor(30,1); 548 | lcd.print("|"); 549 | 550 | 551 | pinMode(NEXT_BTN, INPUT_PULLUP); 552 | pinMode(LAST_BTN, INPUT_PULLUP); 553 | pinMode(SHIFT_BTN, INPUT_PULLUP); 554 | 555 | displayStatus(); 556 | } 557 | 558 | /******************************************************************************* 559 | * Here we service, monitor, and otherwise control all our peripheral devices. 560 | * First, we retrieve the status of our encoders and buttons and update Eos. 561 | * Next, we check if there are any OSC message for us. 562 | * Finally, we update our display (if an update is necessary) 563 | * 564 | * NOTE: This function is our main loop and thus we will loop here forever. 565 | * 566 | * Parameters: none 567 | * 568 | * Return Value: void 569 | * 570 | ******************************************************************************/ 571 | void loop() 572 | { 573 | static String curMsg; 574 | int size; 575 | // get the updated state of each encoder 576 | int32_t panMotion = updateEncoder(&panWheel); 577 | int32_t tiltMotion = updateEncoder(&tiltWheel); 578 | int32_t zoomMotion = updateEncoder(&zoomWheel); 579 | int32_t edgeMotion = updateEncoder(&edgeWheel); 580 | 581 | // check for next/last updates 582 | checkButtons(); 583 | 584 | // now update our wheels 585 | if (tiltMotion != 0) 586 | sendWheelMove(TILT, tiltMotion); 587 | 588 | if (panMotion != 0) 589 | sendWheelMove(PAN, panMotion); 590 | 591 | if (zoomMotion != 0) 592 | sendWheelMove(ZOOM, zoomMotion); 593 | 594 | if (edgeMotion != 0) 595 | sendWheelMove(EDGE, edgeMotion); 596 | 597 | 598 | // Then we check to see if any OSC commands have come from Eos 599 | // and update the display accordingly. 600 | size = SLIPSerial.available(); 601 | if (size > 0) 602 | { 603 | // Fill the msg with all of the available bytes 604 | while (size--) 605 | curMsg += (char)(SLIPSerial.read()); 606 | } 607 | if (SLIPSerial.endofPacket()) 608 | { 609 | parseOSCMessage(curMsg); 610 | curMsg = String(); 611 | } 612 | 613 | if (updateDisplay) 614 | displayStatus(); 615 | } 616 | 617 | -------------------------------------------------------------------------------- /name.c: -------------------------------------------------------------------------------- 1 | // To give your project a unique name, this code must be 2 | // placed into a .c file (its own tab). It can not be in 3 | // a .cpp file or your main sketch (the .ino file). 4 | 5 | #include "usb_names.h" 6 | 7 | // Edit these lines to create your own name. The length must 8 | // match the number of characters in your custom name. 9 | 10 | #define MIDI_NAME {'M','I','D','I',' ','C','C',' ','T','o',' ','N','O','T','E'} 11 | #define MIDI_NAME_LEN 15 12 | 13 | // Do not change this part. This exact format is required by USB. 14 | 15 | struct usb_string_descriptor_struct usb_string_product_name = { 16 | 2 + MIDI_NAME_LEN * 2, 17 | 3, 18 | MIDI_NAME 19 | }; 20 | -------------------------------------------------------------------------------- /settings.txt: -------------------------------------------------------------------------------- 1 | F2:9E:45:B9:05:9D 2 | Mac Address 3 | 10.10.90.145 4 | IP Address 5 | 255.255.255.0 6 | Subnet Mask 7 | 10.101.90.101 8 | Gateway Address 9 | 10.101.90.101 10 | Server Address(Console) 11 | 8001 12 | OSC UDP Port 13 | /eos/wheel/pan 14 | Encoder 1 15 | /eos/wheel/tilt 16 | Encoder 2 17 | /eos/key/go_0 18 | Encoder 1 button 19 | /eos/key/stop 20 | Encoder 2 button 21 | --------------------------------------------------------------------------------