PlatformIO package of the Teensy core framework compatible with GCC 10 & C++20
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

3 роки тому
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  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 "OSCBundle.h"
  22. #include <stdlib.h>
  23. /*=============================================================================
  24. CONSTRUCTORS / DESTRUCTOR
  25. =============================================================================*/
  26. OSCBundle::OSCBundle(osctime_t _timetag){
  27. setTimetag(_timetag);
  28. numMessages = 0;
  29. error = OSC_OK;
  30. messages = NULL;
  31. incomingBuffer = NULL;
  32. incomingBufferSize = 0;
  33. decodeState = STANDBY;
  34. }
  35. OSCBundle::~OSCBundle(){
  36. for (int i = 0; i < numMessages; i++){
  37. OSCMessage * msg = getOSCMessage(i);
  38. delete msg;
  39. }
  40. free(messages);
  41. free(incomingBuffer);
  42. }
  43. //clears all of the OSCMessages inside
  44. OSCBundle& OSCBundle::empty(){
  45. error = OSC_OK;
  46. for (int i = 0; i < numMessages; i++){
  47. OSCMessage * msg = getOSCMessage(i);
  48. delete msg;
  49. }
  50. free(messages);
  51. messages = NULL;
  52. clearIncomingBuffer();
  53. numMessages = 0;
  54. return *this;
  55. }
  56. /*=============================================================================
  57. SETTERS
  58. =============================================================================*/
  59. OSCMessage & OSCBundle::add(const char * _address){
  60. OSCMessage * msg = new OSCMessage(_address);
  61. if (!msg->hasError()){
  62. //realloc the array to fit the message
  63. OSCMessage ** messageMem = (OSCMessage **) realloc(messages, sizeof(OSCMessage *) * (numMessages + 1));
  64. if (messageMem != NULL){
  65. messages = messageMem;
  66. messages[numMessages] = msg;
  67. numMessages++;
  68. } else {
  69. error = ALLOCFAILED;
  70. }
  71. }
  72. return *msg;
  73. }
  74. OSCMessage & OSCBundle::add(){
  75. OSCMessage * msg = new OSCMessage();
  76. //realloc the array to fit the message
  77. OSCMessage ** messageMem = (OSCMessage **) realloc(messages, sizeof(OSCMessage *) * (numMessages + 1));
  78. if (messageMem != NULL){
  79. messages = messageMem;
  80. messages[numMessages] = msg;
  81. numMessages++;
  82. } else {
  83. error = ALLOCFAILED;
  84. }
  85. return *msg;
  86. }
  87. OSCMessage & OSCBundle::add(OSCMessage & _msg){
  88. OSCMessage * msg = new OSCMessage(&_msg);
  89. if (!msg->hasError()){
  90. //realloc the array to fit the message
  91. OSCMessage ** messageMem = (OSCMessage **) realloc(messages, sizeof(OSCMessage *) * (numMessages + 1));
  92. if (messageMem != NULL){
  93. messages = messageMem;
  94. messages[numMessages] = msg;
  95. numMessages++;
  96. } else {
  97. error = ALLOCFAILED;
  98. }
  99. }
  100. return *msg;
  101. }
  102. /*=============================================================================
  103. GETTERS
  104. =============================================================================*/
  105. //returns the first fullMatch.
  106. OSCMessage * OSCBundle::getOSCMessage( char * addr){
  107. for (int i = 0; i < numMessages; i++){
  108. OSCMessage * msg = getOSCMessage(i);
  109. if (msg->fullMatch(addr)){
  110. return msg;
  111. }
  112. }
  113. return NULL;
  114. }
  115. //the position is the same as the order they were declared in
  116. OSCMessage * OSCBundle::getOSCMessage(int pos){
  117. if (pos < numMessages){
  118. return messages[pos];
  119. }
  120. return NULL;
  121. }
  122. /*=============================================================================
  123. PATTERN MATCHING
  124. =============================================================================*/
  125. bool OSCBundle::dispatch(const char * pattern, void (*callback)(OSCMessage&), int initial_offset){
  126. bool called = false;
  127. for (int i = 0; i < numMessages; i++){
  128. OSCMessage msg = getOSCMessage(i);
  129. called = msg.dispatch(pattern, callback, initial_offset) || called ;
  130. }
  131. return called;
  132. }
  133. bool OSCBundle::route(const char * pattern, void (*callback)(OSCMessage&, int), int initial_offset){
  134. bool called = false;
  135. for (int i = 0; i < numMessages; i++){
  136. OSCMessage msg = getOSCMessage(i);
  137. called = msg.route(pattern, callback, initial_offset) || called;
  138. }
  139. return called;
  140. }
  141. /*=============================================================================
  142. SIZE
  143. =============================================================================*/
  144. int OSCBundle::size(){
  145. return numMessages;
  146. }
  147. /*=============================================================================
  148. ERROR HANDLING
  149. =============================================================================*/
  150. bool OSCBundle::hasError(){
  151. bool retError = error != OSC_OK;
  152. //test each of the data
  153. for (int i = 0; i < numMessages; i++){
  154. OSCMessage * msg = getOSCMessage(i);
  155. retError |= msg->hasError();
  156. }
  157. return retError;
  158. }
  159. OSCErrorCode OSCBundle::getError(){
  160. return error;
  161. }
  162. /*=============================================================================
  163. SENDING
  164. =============================================================================*/
  165. OSCBundle& OSCBundle::send(Print &p){
  166. //don't send a bundle with errors
  167. if (hasError()){
  168. return *this;
  169. }
  170. //write the bundle header
  171. static uint8_t header[] = {'#', 'b', 'u', 'n', 'd', 'l', 'e', 0};
  172. p.write(header, 8);
  173. //write the timetag
  174. {
  175. osctime_t time = timetag;
  176. uint32_t d = BigEndian(time.seconds);
  177. uint8_t * ptr = (uint8_t *) &d;
  178. p.write(ptr, 4);
  179. d = BigEndian(time.fractionofseconds);
  180. ptr = (uint8_t *) &d;
  181. p.write(ptr, 4);
  182. }
  183. //send the messages
  184. for (int i = 0; i < numMessages; i++){
  185. OSCMessage * msg = getOSCMessage(i);
  186. int msgSize = msg->bytes();
  187. //turn the message size into a pointer
  188. uint32_t s32 = BigEndian((uint32_t) msgSize);
  189. uint8_t * sptr = (uint8_t *) &s32;
  190. //write the messsage size
  191. p.write(sptr, 4);
  192. msg->send(p);
  193. }
  194. return *this;
  195. }
  196. /*=============================================================================
  197. FILLING
  198. =============================================================================*/
  199. OSCBundle& OSCBundle::fill(uint8_t incomingByte){
  200. decode(incomingByte);
  201. return *this;
  202. }
  203. OSCBundle& OSCBundle::fill(uint8_t * incomingBytes, int length){
  204. while (length--){
  205. decode(*incomingBytes++);
  206. }
  207. return *this;
  208. }
  209. /*=============================================================================
  210. DECODING
  211. =============================================================================*/
  212. void OSCBundle::decodeTimetag(){
  213. //parse the incoming buffer as a uint64
  214. setTimetag(incomingBuffer);
  215. //make sure the endianness is right
  216. //xxx time tag timetag = BigEndian(timetag);
  217. decodeState = MESSAGE_SIZE;
  218. clearIncomingBuffer();
  219. }
  220. void OSCBundle::decodeHeader(){
  221. const char * header = "#bundle";
  222. if (strcmp(header, (char *) incomingBuffer)!=0){
  223. //otherwise go back to the top and wait for a new bundle header
  224. decodeState = STANDBY;
  225. error = INVALID_OSC;
  226. } else {
  227. decodeState = TIMETAG;
  228. }
  229. clearIncomingBuffer();
  230. }
  231. void OSCBundle::decodeMessage(uint8_t incomingByte){
  232. //get the current message
  233. if (numMessages > 0){
  234. OSCMessage * lastMessage = messages[numMessages - 1];
  235. //put the bytes in there
  236. lastMessage->fill(incomingByte);
  237. //if it's all done
  238. if (incomingBufferSize == incomingMessageSize){
  239. //move onto the next message
  240. decodeState = MESSAGE_SIZE;
  241. clearIncomingBuffer();
  242. } else if (incomingBufferSize > incomingMessageSize){
  243. error = INVALID_OSC;
  244. }
  245. }
  246. }
  247. //does not validate the incoming OSC for correctness
  248. void OSCBundle::decode(uint8_t incomingByte){
  249. addToIncomingBuffer(incomingByte);
  250. switch (decodeState){
  251. case STANDBY:
  252. if (incomingByte == '#'){
  253. decodeState = HEADER;
  254. } else if (incomingByte == '/'){
  255. decodeState = MESSAGE;
  256. }
  257. break;
  258. case HEADER:
  259. if (incomingBufferSize == 8){
  260. decodeHeader();
  261. decodeState = TIMETAG;
  262. }
  263. break;
  264. case TIMETAG:
  265. if (incomingBufferSize == 8){
  266. decodeTimetag();
  267. decodeState = MESSAGE_SIZE;
  268. }
  269. break;
  270. case MESSAGE_SIZE:
  271. if (incomingBufferSize == 4){
  272. //make sure the message size is valid
  273. int32_t msgSize;
  274. memcpy(&msgSize, incomingBuffer, 4);
  275. msgSize = BigEndian(msgSize);
  276. if (msgSize % 4 != 0 || msgSize == 0){
  277. error = INVALID_OSC;
  278. } else {
  279. //add a message to the buffer
  280. decodeState = MESSAGE;
  281. incomingMessageSize = msgSize;
  282. clearIncomingBuffer();
  283. //add a new empty message
  284. add();
  285. }
  286. }
  287. break;
  288. case MESSAGE:
  289. decodeMessage(incomingByte);
  290. break;
  291. }
  292. }
  293. /*=============================================================================
  294. INCOMING BUFFER MANAGEMENT
  295. =============================================================================*/
  296. void OSCBundle::addToIncomingBuffer(uint8_t incomingByte){
  297. //realloc some space for the new byte and stick it on the end
  298. incomingBuffer = (uint8_t *) realloc ( incomingBuffer, incomingBufferSize + 1);
  299. if (incomingBuffer != NULL){
  300. incomingBuffer[incomingBufferSize++] = incomingByte;
  301. } else {
  302. error = ALLOCFAILED;
  303. }
  304. }
  305. void OSCBundle::clearIncomingBuffer(){
  306. incomingBufferSize = 0;
  307. free(incomingBuffer);
  308. incomingBuffer = NULL;
  309. }