UDPOscuino.ino 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  1. // UDP OSCuino
  2. // system, analog and digital pin control and monitoring for Arduino
  3. // Yotam Mann and Adrian Freed
  4. #include <Ethernet.h>
  5. #include <EthernetUdp.h>
  6. #include <SPI.h>
  7. #include <OSCBundle.h>
  8. #include <OSCBoards.h>
  9. EthernetUDP Udp;
  10. //the Arduino's IP
  11. IPAddress ip(128, 32, 122, 252);
  12. //port numbers
  13. const unsigned int inPort = 8888;
  14. const unsigned int outPort = 9999;
  15. //everything on the network needs a unique MAC
  16. #if defined(__MK20DX128__) || defined(__MK20DX256__) || defined(__MKL26Z64__) || defined(__MK66FX1M0__)
  17. // Teensy 3 has MAC burned in
  18. static byte mac[6];
  19. void read(uint8_t word, uint8_t *mac, uint8_t offset) {
  20. FTFL_FCCOB0 = 0x41; // Selects the READONCE command
  21. FTFL_FCCOB1 = word; // read the given word of read once area
  22. // launch command and wait until complete
  23. FTFL_FSTAT = FTFL_FSTAT_CCIF;
  24. while(!(FTFL_FSTAT & FTFL_FSTAT_CCIF));
  25. *(mac+offset) = FTFL_FCCOB5; // collect only the top three bytes,
  26. *(mac+offset+1) = FTFL_FCCOB6; // in the right orientation (big endian).
  27. *(mac+offset+2) = FTFL_FCCOB7; // Skip FTFL_FCCOB4 as it's always 0.
  28. }
  29. void read_mac() {
  30. read(0xe,mac,0);
  31. read(0xf,mac,3);
  32. }
  33. #else
  34. void read_mac() {}
  35. byte mac[] = {
  36. 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; // you can find this written on the board of some Arduino Ethernets or shields
  37. #endif
  38. //outgoing messages
  39. OSCBundle bundleOUT;
  40. //converts the pin to an osc address
  41. char * numToOSCAddress( int pin){
  42. static char s[10];
  43. int i = 9;
  44. s[i--]= '\0';
  45. do
  46. {
  47. s[i] = "0123456789"[pin % 10];
  48. --i;
  49. pin /= 10;
  50. }
  51. while(pin && i);
  52. s[i] = '/';
  53. return &s[i];
  54. }
  55. /**
  56. * ROUTES
  57. *
  58. * these are where the routing functions go
  59. *
  60. */
  61. /**
  62. * DIGITAL
  63. *
  64. * called when address matched "/d"
  65. * expected format:
  66. * /d/(pin)
  67. * /u = digitalRead with pullup
  68. * (no value) = digitalRead without pullup
  69. * (value) = digital write on that pin
  70. *
  71. */
  72. void routeDigital(OSCMessage &msg, int addrOffset ){
  73. //match input or output
  74. for(byte pin = 0; pin < NUM_DIGITAL_PINS; pin++){
  75. //match against the pin number strings
  76. int pinMatched = msg.match(numToOSCAddress(pin), addrOffset);
  77. if(pinMatched){
  78. //if it has an int, then it's a digital write
  79. if (msg.isInt(0)){
  80. pinMode(pin, OUTPUT);
  81. digitalWrite(pin, (msg.getInt(0)>0) ? HIGH:LOW);
  82. } //otherwise it's an analog read
  83. else if(msg.isFloat(0)){
  84. analogWrite(pin, (int)(msg.getFloat(0)*255.0f));
  85. }
  86. //otherwise it's an digital read
  87. //with a pullup?
  88. else if (msg.fullMatch("/u", pinMatched+addrOffset)){
  89. //set the pullup
  90. pinMode(pin, INPUT_PULLUP);
  91. //setup the output address which should be /d/(pin)/u
  92. char outputAddress[9];
  93. strcpy(outputAddress, "/d");
  94. strcat(outputAddress, numToOSCAddress(pin));
  95. strcat(outputAddress,"/u");
  96. //do the digital read and send the results
  97. bundleOUT.add(outputAddress).add(digitalRead(pin));
  98. } //else without a pullup
  99. else {
  100. //set the pinmode
  101. pinMode(pin, INPUT);
  102. //setup the output address which should be /d/(pin)
  103. char outputAddress[6];
  104. strcpy(outputAddress, "/d");
  105. strcat(outputAddress, numToOSCAddress(pin));
  106. //do the digital read and send the results
  107. bundleOUT.add(outputAddress).add(digitalRead(pin));
  108. }
  109. }
  110. }
  111. }
  112. /**
  113. * ANALOG
  114. *
  115. * called when the address matches "/a"
  116. *
  117. * format:
  118. * /a/(pin)
  119. * /u = analogRead with pullup
  120. * (no value) = analogRead without pullup
  121. * (digital value) = digital write on that pin
  122. * (float value) = analogWrite on that pin
  123. *
  124. **/
  125. void routeAnalog(OSCMessage &msg, int addrOffset ){
  126. //iterate through all the analog pins
  127. for(byte pin = 0; pin < NUM_ANALOG_INPUTS; pin++){
  128. //match against the pin number strings
  129. int pinMatched = msg.match(numToOSCAddress(pin), addrOffset);
  130. if(pinMatched){
  131. //if it has an int, then it's a digital write
  132. if (msg.isInt(0)){
  133. pinMode(analogInputToDigitalPin(pin), OUTPUT);
  134. digitalWrite(analogInputToDigitalPin(pin), (msg.getInt(0) > 0)? HIGH: LOW);
  135. } //otherwise it's an analog read
  136. else if(msg.isFloat(0)){
  137. analogWrite(pin, (int)(msg.getFloat(0)*255.0f));
  138. }
  139. #ifdef BOARD_HAS_ANALOG_PULLUP
  140. //with a pullup?
  141. else if (msg.fullMatch("/u", pinMatched+addrOffset)){
  142. //set the pullup
  143. pinMode(analogInputToDigitalPin(pin), INPUT_PULLUP);
  144. //setup the output address which should be /a/(pin)/u
  145. char outputAddress[9];
  146. strcpy(outputAddress, "/a");
  147. strcat(outputAddress, numToOSCAddress(pin));
  148. strcat(outputAddress,"/u");
  149. strcat(outputAddress,"/u");
  150. //do the analog read and send the results
  151. bundleOUT.add(outputAddress).add((int32_t)analogRead(pin));
  152. } //else without a pullup
  153. #endif
  154. else {
  155. //set the pinmode
  156. pinMode(analogInputToDigitalPin(pin), INPUT);
  157. //setup the output address which should be /a/(pin)
  158. char outputAddress[6];
  159. strcpy(outputAddress, "/a");
  160. strcat(outputAddress, numToOSCAddress(pin));
  161. //do the analog read and send the results
  162. bundleOUT.add(outputAddress).add((int32_t)analogRead(pin));
  163. }
  164. }
  165. }
  166. }
  167. #ifdef BOARD_HAS_TONE
  168. /**
  169. * TONE
  170. *
  171. * square wave output "/tone"
  172. *
  173. * format:
  174. * /tone/pin
  175. *
  176. * (digital value) (float value) = frequency in Hz
  177. * (no value) disable tone
  178. *
  179. **/
  180. void routeTone(OSCMessage &msg, int addrOffset ){
  181. //iterate through all the analog pins
  182. for(byte pin = 0; pin < NUM_DIGITAL_PINS; pin++){
  183. //match against the pin number strings
  184. int pinMatched = msg.match(numToOSCAddress(pin), addrOffset);
  185. if(pinMatched){
  186. unsigned int frequency = 0;
  187. //if it has an int, then it's an integers frequency in Hz
  188. if (msg.isInt(0)){
  189. frequency = msg.getInt(0);
  190. } //otherwise it's a floating point frequency in Hz
  191. else if(msg.isFloat(0)){
  192. frequency = msg.getFloat(0);
  193. }
  194. else
  195. noTone(pin);
  196. if(frequency>0)
  197. {
  198. if(msg.isInt(1))
  199. tone(pin, frequency, msg.getInt(1));
  200. else
  201. tone(pin, frequency);
  202. }
  203. }
  204. }
  205. }
  206. #endif
  207. #ifdef BOARD_HAS_CAPACITANCE_SENSING
  208. #if defined(__MKL26Z64__)
  209. // teensy 3.0LC
  210. #define NTPINS 11
  211. const int cpins[NTPINS] = {22,23,19,18,17,16,15,0,1,3,4 };
  212. #elif defined(__MK66FX1M0__)
  213. // teensy 3.6
  214. #define NTPINS 12
  215. const int cpins[NTPINS] = {0,1,14,15,16,17,18,19,22,23,29,30 };
  216. #else
  217. //Teensy 3.1 3.2
  218. #define NTPINS 12
  219. const int cpins[NTPINS] = {22,23,19,18,17,16,15,0,1,25,32, 33 };
  220. #endif
  221. void routeTouch(OSCMessage &msg, int addrOffset )
  222. {
  223. for(int i=0;i<NTPINS;++i)
  224. {
  225. const char *name = numToOSCAddress(cpins[i]);
  226. int pinMatched = msg.match(name, addrOffset);
  227. if(pinMatched)
  228. {
  229. char outputAddress[9];
  230. strcpy(outputAddress, "/c");
  231. strcat(outputAddress, name);
  232. bundleOUT.add(outputAddress).add(touchRead(cpins[i]));
  233. }
  234. }
  235. }
  236. #endif
  237. /**
  238. * SYSTEM MESSAGES
  239. *
  240. * expected format:
  241. * /s
  242. * /m = microseconds
  243. * /d = number of digital pins
  244. * /a = number of analog pins
  245. * /l integer = set the led
  246. * /t = temperature
  247. * /s = power supply voltage
  248. */
  249. //
  250. void routeSystem(OSCMessage &msg, int addrOffset ){
  251. #ifdef BOARD_HAS_DIE_TEMPERATURE_SENSOR
  252. if (msg.fullMatch("/t", addrOffset)){
  253. bundleOUT.add("/s/t").add(getTemperature());
  254. }
  255. #endif
  256. #ifdef BOARD_HAS_DIE_POWER_SUPPLY_MEASUREMENT
  257. if (msg.fullMatch("/s", addrOffset)){
  258. bundleOUT.add("/s/s").add(getSupplyVoltage());
  259. }
  260. #endif
  261. if (msg.fullMatch("/m", addrOffset)){
  262. bundleOUT.add("/s/m").add((int32_t)micros());
  263. }
  264. if (msg.fullMatch("/d", addrOffset)){
  265. bundleOUT.add("/s/d").add(NUM_DIGITAL_PINS);
  266. }
  267. if (msg.fullMatch("/a", addrOffset)){
  268. bundleOUT.add("/s/a").add(NUM_ANALOG_INPUTS);
  269. }
  270. // this is disabled because many ethernet boards use the
  271. // LED pin for ethernet pin 13
  272. #if LED_BUILTIN!=13
  273. if (msg.fullMatch("/l", addrOffset)){
  274. if (msg.isInt(0)){
  275. pinMode(LED_BUILTIN, OUTPUT);
  276. int i = msg.getInt(0);
  277. pinMode(LED_BUILTIN, OUTPUT);
  278. digitalWrite(LED_BUILTIN, (i > 0)? HIGH: LOW);
  279. bundleOUT.add("/s/l").add(i);
  280. }
  281. }
  282. #endif
  283. }
  284. /**
  285. * MAIN METHODS
  286. *
  287. * setup and loop, bundle receiving/sending, initial routing
  288. */
  289. void setup() {
  290. //setup ethernet port
  291. read_mac();
  292. Ethernet.begin(mac,ip);
  293. Udp.begin(inPort);
  294. }
  295. //reads and routes the incoming messages
  296. void loop(){
  297. OSCBundle bundleIN;
  298. int size;
  299. if( (size = Udp.parsePacket())>0)
  300. {
  301. // unsigned int outPort = Udp.remotePort();
  302. while(size--)
  303. bundleIN.fill(Udp.read());
  304. if(!bundleIN.hasError())
  305. {
  306. bundleIN.route("/s", routeSystem);
  307. bundleIN.route("/a", routeAnalog);
  308. bundleIN.route("/d", routeDigital);
  309. #ifdef BOARD_HAS_TONE
  310. bundleIN.route("/tone", routeTone);
  311. #endif
  312. #ifdef TOUCHSUPPORT
  313. bundleIN.route("/c", routeTouch);
  314. #endif
  315. }
  316. // send the response bundle back to where the request came from
  317. Udp.beginPacket(Udp.remoteIP(),outPort);
  318. bundleOUT.send(Udp);
  319. Udp.endPacket();
  320. bundleOUT.empty(); // empty the bundle ready to use for new messages
  321. }
  322. }