PlatformIO package of the Teensy core framework compatible with GCC 10 & C++20
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

738 lines
21KB

  1. /*
  2. Written by Yotam Mann, The Center for New Music and Audio Technologies,
  3. University of California, Berkeley. Copyright (c) 2012, The Regents of
  4. the University of California (Regents).
  5. Permission to use, copy, modify, distribute, and distribute modified versions
  6. of this software and its documentation without fee and without a signed
  7. licensing agreement, is hereby granted, provided that the above copyright
  8. notice, this paragraph and the following two paragraphs appear in all copies,
  9. modifications, and distributions.
  10. IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
  11. SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
  12. OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
  13. BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  14. REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  15. THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  16. PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
  17. HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
  18. MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  19. For bug reports and feature requests please email me at yotam@cnmat.berkeley.edu
  20. */
  21. #include "OSCMessage.h"
  22. #include "OSCMatch.h"
  23. #include "OSCTiming.h"
  24. extern osctime_t zerotime;
  25. /*=============================================================================
  26. CONSTRUCTORS / DESTRUCTOR
  27. =============================================================================*/
  28. //constructor with address
  29. OSCMessage::OSCMessage(const char * _address){
  30. setupMessage();
  31. setAddress(_address);
  32. }
  33. //constructor with nothing
  34. //just a placeholder since the message is invalid
  35. OSCMessage::OSCMessage(){
  36. setupMessage();
  37. error = INVALID_OSC;
  38. }
  39. //variable length constructor
  40. //for example OSCMessage msg("/address", "isf", 1, "two", 3.0);
  41. /*
  42. OSCMessage::OSCMessage(const char * _address, char * types, ... ){
  43. setupMessage(_address);
  44. }
  45. */
  46. //sets up a new message
  47. void OSCMessage::setupMessage(){
  48. address = NULL;
  49. //setup the attributes
  50. dataCount = 0;
  51. error = OSC_OK;
  52. //setup the space for data
  53. data = NULL;
  54. //setup for filling the message
  55. incomingBuffer = NULL;
  56. incomingBufferSize = 0;
  57. incomingBufferFree = 0;
  58. clearIncomingBuffer();
  59. //set the decode state
  60. decodeState = STANDBY;
  61. }
  62. //DESTRUCTOR
  63. OSCMessage::~OSCMessage(){
  64. //free everything that needs to be freed
  65. //free the address
  66. free(address);
  67. //free the data
  68. empty();
  69. //free the filling buffer
  70. free(incomingBuffer);
  71. }
  72. OSCMessage& OSCMessage::empty(){
  73. error = OSC_OK;
  74. //free each of hte data in the array
  75. for (int i = 0; i < dataCount; i++){
  76. OSCData * datum = getOSCData(i);
  77. //explicitly destruct the data
  78. //datum->~OSCData();
  79. delete datum;
  80. }
  81. //and free the array
  82. free(data);
  83. data = NULL;
  84. dataCount = 0;
  85. decodeState = STANDBY;
  86. clearIncomingBuffer();
  87. return *this;
  88. }
  89. //COPY
  90. OSCMessage::OSCMessage(OSCMessage * msg){
  91. //start with a message with the same address
  92. setupMessage();
  93. setAddress(msg->address);
  94. //add each of the data to the other message
  95. for (int i = 0; i < msg->dataCount; i++){
  96. add(msg->data[i]);
  97. }
  98. }
  99. /*=============================================================================
  100. GETTING DATA
  101. =============================================================================*/
  102. OSCData * OSCMessage::getOSCData(int position){
  103. if (position < dataCount){
  104. OSCData * datum = data[position];
  105. return datum;
  106. } else {
  107. error = INDEX_OUT_OF_BOUNDS;
  108. return NULL;
  109. }
  110. }
  111. int32_t OSCMessage::getInt(int position){
  112. OSCData * datum = getOSCData(position);
  113. if (!hasError()){
  114. return datum->getInt();
  115. } else {
  116. #ifndef ESP8266
  117. return (int32_t)NULL;
  118. #else
  119. return -1;
  120. #endif
  121. }
  122. }
  123. osctime_t OSCMessage::getTime(int position){
  124. OSCData * datum = getOSCData(position);
  125. if (!hasError()){
  126. return datum->getTime();
  127. } else {
  128. return zerotime;
  129. }
  130. }
  131. float OSCMessage::getFloat(int position){
  132. OSCData * datum = getOSCData(position);
  133. if (!hasError()){
  134. return datum->getFloat();
  135. } else {
  136. #ifndef ESP8266
  137. return (float)NULL;
  138. #else
  139. return -1;
  140. #endif
  141. }
  142. }
  143. double OSCMessage::getDouble(int position){
  144. OSCData * datum = getOSCData(position);
  145. if (!hasError()){
  146. return datum->getDouble();
  147. } else {
  148. #ifndef ESP8266
  149. return (double)NULL;
  150. #else
  151. return -1;
  152. #endif
  153. }
  154. }
  155. bool OSCMessage::getBoolean(int position){
  156. OSCData * datum = getOSCData(position);
  157. if (!hasError()){
  158. return datum->getBoolean();
  159. } else {
  160. #ifndef ESP8266
  161. return NULL;
  162. #else
  163. return -1;
  164. #endif
  165. }
  166. }
  167. int OSCMessage::getString(int position, char * buffer, int bufferSize){
  168. OSCData * datum = getOSCData(position);
  169. if (!hasError()){
  170. //the number of bytes to copy is the smaller between the buffer size and the datum's byte length
  171. int copyBytes = bufferSize < datum->bytes? bufferSize : datum->bytes;
  172. return datum->getString(buffer, copyBytes);
  173. } else {
  174. #ifndef ESP8266
  175. return (int)NULL;
  176. #else
  177. return -1;
  178. #endif
  179. }
  180. }
  181. int OSCMessage::getBlob(int position, uint8_t * buffer, int bufferSize){
  182. OSCData * datum = getOSCData(position);
  183. if (!hasError()){
  184. //the number of bytes to copy is the smaller between the buffer size and the datum's byte length
  185. int copyBytes = bufferSize < datum->bytes? bufferSize : datum->bytes;
  186. return datum->getBlob(buffer, copyBytes);
  187. } else {
  188. #ifndef ESP8266
  189. return (int)NULL;
  190. #else
  191. return -1;
  192. #endif
  193. }
  194. }
  195. char OSCMessage::getType(int position){
  196. OSCData * datum = getOSCData(position);
  197. if (!hasError()){
  198. return datum->type;
  199. } else {
  200. #ifndef ESP8266
  201. return (int)NULL;
  202. #else
  203. return '\0';
  204. #endif
  205. }
  206. }
  207. int OSCMessage::getDataLength(int position){
  208. OSCData * datum = getOSCData(position);
  209. if (!hasError()){
  210. return datum->bytes;
  211. } else {
  212. return 0;
  213. }
  214. }
  215. /*=============================================================================
  216. TESTING DATA
  217. =============================================================================*/
  218. bool OSCMessage::testType(int position, char type){
  219. OSCData * datum = getOSCData(position);
  220. if (!hasError()){
  221. return datum->type == type;
  222. } else {
  223. return false;
  224. }
  225. }
  226. bool OSCMessage::isInt(int position){
  227. return testType(position, 'i');
  228. }
  229. bool OSCMessage::isTime(int position){
  230. return testType(position, 't');
  231. }
  232. bool OSCMessage::isFloat(int position){
  233. return testType(position, 'f');
  234. }
  235. bool OSCMessage::isBlob(int position){
  236. return testType(position, 'b');
  237. }
  238. bool OSCMessage::isChar(int position){
  239. return testType(position, 'c');
  240. }
  241. bool OSCMessage::isString(int position){
  242. return testType(position, 's');
  243. }
  244. bool OSCMessage::isDouble(int position){
  245. return testType(position, 'd');
  246. }
  247. bool OSCMessage::isBoolean(int position){
  248. return testType(position, 'T') || testType(position, 'F');
  249. }
  250. /*=============================================================================
  251. PATTERN MATCHING
  252. =============================================================================*/
  253. int OSCMessage::match(const char * pattern, int addr_offset){
  254. int pattern_offset;
  255. int address_offset;
  256. int ret = osc_match(address + addr_offset, pattern, &pattern_offset, &address_offset);
  257. char * next = (char *) (address + addr_offset + pattern_offset);
  258. if (ret==3){
  259. return pattern_offset;
  260. } else if (pattern_offset > 0 && *next == '/'){
  261. return pattern_offset;
  262. } else {
  263. return 0;
  264. }
  265. }
  266. bool OSCMessage::fullMatch( const char * pattern, int addr_offset){
  267. int pattern_offset;
  268. int address_offset;
  269. int ret = osc_match(address + addr_offset, pattern, &address_offset, &pattern_offset);
  270. return (ret==3);
  271. }
  272. bool OSCMessage::dispatch(const char * pattern, void (*callback)(OSCMessage &), int addr_offset){
  273. if (fullMatch(pattern, addr_offset)){
  274. callback(*this);
  275. return true;
  276. } else {
  277. return false;
  278. }
  279. }
  280. bool OSCMessage::route(const char * pattern, void (*callback)(OSCMessage &, int), int initial_offset){
  281. int match_offset = match(pattern, initial_offset);
  282. if (match_offset>0){
  283. callback(*this, match_offset + initial_offset);
  284. return true;
  285. } else {
  286. return false;
  287. }
  288. }
  289. /*=============================================================================
  290. ADDRESS
  291. =============================================================================*/
  292. int OSCMessage::getAddress(char * buffer, int offset){
  293. strcpy(buffer, address+offset);
  294. return strlen(buffer);
  295. }
  296. int OSCMessage::getAddress(char * buffer, int offset, int len){
  297. strncpy(buffer, address+offset, len);
  298. return strlen(buffer);
  299. }
  300. OSCMessage& OSCMessage::setAddress(const char * _address){
  301. //free the previous address
  302. free(address); // are we sure address was allocated?
  303. //copy the address
  304. char * addressMemory = (char *) malloc( (strlen(_address) + 1) * sizeof(char) );
  305. if (addressMemory == NULL){
  306. error = ALLOCFAILED;
  307. address = NULL;
  308. } else {
  309. strcpy(addressMemory, _address);
  310. address = addressMemory;
  311. }
  312. return *this;
  313. }
  314. /*=============================================================================
  315. SIZE
  316. =============================================================================*/
  317. #ifdef SLOWpadcalculation
  318. int OSCMessage::padSize(int _bytes){
  319. int space = (_bytes + 3) / 4;
  320. space *= 4;
  321. return space - _bytes;
  322. }
  323. #else
  324. static inline int padSize(int bytes) { return (4- (bytes&03))&3; }
  325. #endif
  326. //returns the number of OSCData in the OSCMessage
  327. int OSCMessage::size(){
  328. return dataCount;
  329. }
  330. int OSCMessage::bytes(){
  331. int messageSize = 0;
  332. //send the address
  333. int addrLen = strlen(address) + 1;
  334. messageSize += addrLen;
  335. //padding amount
  336. int addrPad = padSize(addrLen);
  337. messageSize += addrPad;
  338. //add the comma seperator
  339. messageSize += 1;
  340. //add the types
  341. messageSize += dataCount;
  342. //pad the types
  343. int typePad = padSize(dataCount + 1); //for the comma
  344. if (typePad == 0){
  345. typePad = 4; // to make sure the type string is null terminated
  346. }
  347. messageSize+=typePad;
  348. //then the data
  349. for (int i = 0; i < dataCount; i++){
  350. OSCData * datum = getOSCData(i);
  351. messageSize+=datum->bytes;
  352. messageSize += padSize(datum->bytes);
  353. }
  354. return messageSize;
  355. }
  356. /*=============================================================================
  357. ERROR HANDLING
  358. =============================================================================*/
  359. bool OSCMessage::hasError(){
  360. bool retError = error != OSC_OK;
  361. //test each of the data
  362. for (int i = 0; i < dataCount; i++){
  363. OSCData * datum = getOSCData(i);
  364. retError |= datum->error != OSC_OK;
  365. }
  366. return retError;
  367. }
  368. OSCErrorCode OSCMessage::getError(){
  369. return error;
  370. }
  371. /*=============================================================================
  372. SENDING
  373. =============================================================================*/
  374. OSCMessage& OSCMessage::send(Print &p){
  375. //don't send a message with errors
  376. if (hasError()){
  377. return *this;
  378. }
  379. uint8_t nullChar = '\0';
  380. //send the address
  381. int addrLen = strlen(address) + 1;
  382. //padding amount
  383. int addrPad = padSize(addrLen);
  384. //write it to the stream
  385. p.write((uint8_t *) address, addrLen);
  386. //add the padding
  387. while(addrPad--){
  388. p.write(nullChar);
  389. }
  390. //add the comma seperator
  391. p.write((uint8_t) ',');
  392. //add the types
  393. #ifdef PAULSSUGGESTION
  394. // Paul suggested buffering on the stack
  395. // to improve performance. The problem is this could exhaust the stack
  396. // for long complex messages
  397. {
  398. uint8_t typstr[dataCount];
  399. for (int i = 0; i < dataCount; i++){
  400. typstr[i] = getType(i);
  401. }
  402. p.write(typstr,dataCount);
  403. }
  404. #else
  405. for (int i = 0; i < dataCount; i++){
  406. p.write((uint8_t) getType(i));
  407. }
  408. #endif
  409. //pad the types
  410. int typePad = padSize(dataCount + 1); // 1 is for the comma
  411. if (typePad == 0){
  412. typePad = 4; // This is because the type string has to be null terminated
  413. }
  414. while(typePad--){
  415. p.write(nullChar);
  416. }
  417. //write the data
  418. for (int i = 0; i < dataCount; i++){
  419. OSCData * datum = getOSCData(i);
  420. if ((datum->type == 's') || (datum->type == 'b')){
  421. p.write(datum->data.b, datum->bytes);
  422. int dataPad = padSize(datum->bytes);
  423. while(dataPad--){
  424. p.write(nullChar);
  425. }
  426. } else if (datum->type == 'd'){
  427. double d = BigEndian(datum->data.d);
  428. uint8_t * ptr = (uint8_t *) &d;
  429. p.write(ptr, 8);
  430. } else if (datum->type == 't'){
  431. osctime_t time = datum->data.time;
  432. uint32_t d = BigEndian(time.seconds);
  433. uint8_t * ptr = (uint8_t *) &d;
  434. p.write(ptr, 4);
  435. d = BigEndian(time.fractionofseconds);
  436. ptr = (uint8_t *) &d;
  437. p.write(ptr, 4);
  438. } else if (datum->type == 'T' || datum->type == 'F')
  439. { }
  440. else { // float or int
  441. uint32_t i = BigEndian(datum->data.i);
  442. uint8_t * ptr = (uint8_t *) &i;
  443. p.write(ptr, datum->bytes);
  444. }
  445. }
  446. return *this;
  447. }
  448. /*=============================================================================
  449. FILLING
  450. =============================================================================*/
  451. OSCMessage& OSCMessage::fill(uint8_t incomingByte){
  452. decode(incomingByte);
  453. return *this;
  454. }
  455. OSCMessage& OSCMessage::fill(uint8_t * incomingBytes, int length){
  456. while (length--){
  457. decode(*incomingBytes++);
  458. }
  459. return *this;
  460. }
  461. /*=============================================================================
  462. DECODING
  463. =============================================================================*/
  464. void OSCMessage::decodeAddress(){
  465. setAddress((char *) incomingBuffer);
  466. //change the error from invalide message
  467. error = OSC_OK;
  468. clearIncomingBuffer();
  469. }
  470. void OSCMessage::decodeType(uint8_t incomingByte){
  471. char type = incomingByte;
  472. add(type);
  473. }
  474. void OSCMessage::decodeData(uint8_t incomingByte){
  475. //get the first OSCData to re-set
  476. for (int i = 0; i < dataCount; i++){
  477. OSCData * datum = getOSCData(i);
  478. if (datum->error == INVALID_OSC){
  479. //set the contents of datum with the data received
  480. switch (datum->type){
  481. case 'i':
  482. if (incomingBufferSize == 4){
  483. //parse the buffer as an int
  484. union {
  485. int32_t i;
  486. uint8_t b[4];
  487. } u;
  488. memcpy(u.b, incomingBuffer, 4);
  489. int32_t dataVal = BigEndian(u.i);
  490. set(i, dataVal);
  491. clearIncomingBuffer();
  492. }
  493. break;
  494. case 'f':
  495. if (incomingBufferSize == 4){
  496. //parse the buffer as a float
  497. union {
  498. float f;
  499. uint8_t b[4];
  500. } u;
  501. memcpy(u.b, incomingBuffer, 4);
  502. float dataVal = BigEndian(u.f);
  503. set(i, dataVal);
  504. clearIncomingBuffer();
  505. }
  506. break;
  507. case 'd':
  508. if (incomingBufferSize == 8){
  509. //parse the buffer as a double
  510. union {
  511. double d;
  512. uint8_t b[8];
  513. } u;
  514. memcpy(u.b, incomingBuffer, 8);
  515. double dataVal = BigEndian(u.d);
  516. set(i, dataVal);
  517. clearIncomingBuffer();
  518. }
  519. break;
  520. case 't':
  521. if (incomingBufferSize == 8){
  522. //parse the buffer as a timetag
  523. union {
  524. osctime_t t;
  525. uint8_t b[8];
  526. } u;
  527. memcpy(u.b, incomingBuffer, 8);
  528. u.t.seconds = BigEndian(u.t.seconds);
  529. u.t.fractionofseconds = BigEndian(u.t.fractionofseconds);
  530. set(i, u.t);
  531. clearIncomingBuffer();
  532. }
  533. break;
  534. case 's':
  535. if (incomingByte == 0){
  536. char * str = (char *) incomingBuffer;
  537. set(i, str);
  538. clearIncomingBuffer();
  539. decodeState = DATA_PADDING;
  540. }
  541. break;
  542. case 'b':
  543. if (incomingBufferSize > 4){
  544. //compute the expected blob size
  545. union {
  546. uint32_t i;
  547. uint8_t b[4];
  548. } u;
  549. memcpy(u.b, incomingBuffer, 4);
  550. uint32_t blobLength = BigEndian(u.i);
  551. if (incomingBufferSize == (int)(blobLength + 4)){
  552. set(i, incomingBuffer + 4, blobLength);
  553. clearIncomingBuffer();
  554. decodeState = DATA_PADDING;
  555. }
  556. }
  557. break;
  558. }
  559. //break out of the for loop once we've selected the first invalid message
  560. break;
  561. }
  562. }
  563. }
  564. //does not validate the incoming OSC for correctness
  565. void OSCMessage::decode(uint8_t incomingByte){
  566. addToIncomingBuffer(incomingByte);
  567. switch (decodeState){
  568. case STANDBY:
  569. if (incomingByte == '/'){
  570. decodeState = ADDRESS;
  571. }
  572. break;
  573. case ADDRESS:
  574. if (incomingByte == 0){
  575. //end of the address
  576. //decode the address
  577. decodeAddress();
  578. //next state
  579. decodeState = ADDRESS_PADDING;
  580. }
  581. break;
  582. case ADDRESS_PADDING:
  583. //it does not count the padding
  584. if (incomingByte==','){
  585. //next state
  586. decodeState = TYPES;
  587. clearIncomingBuffer();
  588. }
  589. break;
  590. case TYPES:
  591. if (incomingByte != 0){
  592. //next state
  593. decodeType(incomingByte);
  594. } else {
  595. decodeState = TYPES_PADDING;
  596. }
  597. //FALL THROUGH to test if it should go to the data state
  598. case TYPES_PADDING: {
  599. //compute the padding size for the types
  600. //to determine the start of the data section
  601. int typePad = padSize(dataCount + 1); // 1 is the comma
  602. if (typePad == 0){
  603. typePad = 4; // to make sure it will be null terminated
  604. }
  605. if (incomingBufferSize == (typePad + dataCount)){
  606. clearIncomingBuffer();
  607. decodeState = DATA;
  608. }
  609. }
  610. break;
  611. case DATA:
  612. decodeData(incomingByte);
  613. break;
  614. case DATA_PADDING:{
  615. //get the last valid data
  616. for (int i = dataCount - 1; i >= 0; i--){
  617. OSCData * datum = getOSCData(i);
  618. if (datum->error == OSC_OK){
  619. //compute the padding size for the data
  620. int dataPad = padSize(datum->bytes);
  621. // if there is no padding required, switch back to DATA, and don't clear the incomingBuffer because it holds next data
  622. if (dataPad == 0){
  623. decodeState = DATA;
  624. }
  625. else if (incomingBufferSize == dataPad){
  626. clearIncomingBuffer();
  627. decodeState = DATA;
  628. }
  629. break;
  630. }
  631. }
  632. }
  633. break;
  634. case DONE:
  635. break; // TODO: is this correct? - was missing from original code, it did this by default
  636. }
  637. }
  638. /*=============================================================================
  639. INCOMING BUFFER MANAGEMENT
  640. =============================================================================*/
  641. #define OSCPREALLOCATEIZE 16
  642. void OSCMessage::addToIncomingBuffer(uint8_t incomingByte){
  643. //realloc some space for the new byte and stick it on the end
  644. if(incomingBufferFree>0)
  645. {
  646. incomingBuffer[incomingBufferSize++] = incomingByte;
  647. incomingBufferFree--;
  648. }
  649. else
  650. {
  651. incomingBuffer = (uint8_t *) realloc ( incomingBuffer, incomingBufferSize + 1 + OSCPREALLOCATEIZE);
  652. if (incomingBuffer != NULL){
  653. incomingBuffer[incomingBufferSize++] = incomingByte;
  654. incomingBufferFree = OSCPREALLOCATEIZE;
  655. } else {
  656. error = ALLOCFAILED;
  657. }
  658. }
  659. }
  660. void OSCMessage::clearIncomingBuffer(){
  661. incomingBuffer = (uint8_t *) realloc ( incomingBuffer, OSCPREALLOCATEIZE);
  662. if (incomingBuffer != NULL){
  663. incomingBufferFree = OSCPREALLOCATEIZE;
  664. } else {
  665. error = ALLOCFAILED;
  666. incomingBuffer = NULL;
  667. }
  668. incomingBufferSize = 0;
  669. }