OSC.Mod 51 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570
  1. (* Copyright 2005-2006, Markus Heule, ETH Zurich *)
  2. MODULE OSC; (** AUTHOR "heulemar"; PURPOSE "OpenSoundControl Basetypes"; *)
  3. (*
  4. This Module contains the needed Objecttypes to represent OSCMessages and OSCBundles.
  5. OSCPacket is a common supertype of OSCMessage and OSCBundle, as an OSCPacket received from or sent to the network
  6. can either be a OSCMessage or a OSCBundle. There are also some 'abstract functions' to support easier access
  7. to the corresponding functions in OSCMessage or OSCBundle.
  8. The Objecttypes OSCParam* represent each one Type of OSCArgument. OSCParamObject is a common supertype of all OSCParameter to
  9. support building an array of parameters.
  10. It's rather easy to build a OSCPacket or an OSCBundle:
  11. VAR
  12. message1: OSCMessage;
  13. message2: OSCMessage;
  14. bundle: OSCBundle;
  15. timetag: OSCTimeTag;
  16. paramint: OSCParamInteger;
  17. paramfloat: OSCParamFloat;
  18. BEGIN
  19. NEW(message1, Strings.NewString('/osc/address/message1'));
  20. NEW(paramint, 34);
  21. message1.AddArgument(paramint);
  22. NEW(message2, Strings.NewString('/osc/address/message2'));
  23. NEW(paramfloat, 1.234);
  24. message2.AddArgument(paramfloat);
  25. NEW(paramint, 20);
  26. message2.AddArgument(paramfloat);
  27. NEW(timetag);
  28. timetag.SetLow(2006,01,01,15,35,00,00); (* year, month, day, hour, minute, second, miliseconds *)
  29. NET(bundle, timetag);
  30. bundle.AddPacket(message1);
  31. bundle.AddPacket(message2);
  32. * now
  33. message1 is an OSCMessage to '/osc/address/message1' with one 32bit integer of the value 34
  34. message2 is an OSCMessage to '/osc/address/message2' with one 32bit float, which has the value 1.234 and one 32bit integer,
  35. which has the value 20.
  36. bundle is an OSCBundle with the given timestamp and two messages message1 and message2.
  37. Note: bundles can also contain bundles.
  38. If you get a parsed packet from the network, then you can access all the needed information of a packet via the member variables of a packet.
  39. OSCMessage m:
  40. m.address: OSCAddress of OSCMessage m
  41. m.argumentcount: # of arguments of OSCMessage m
  42. m.arguments[i]: argument with index i (0<=i<argumentcount). This reference contains always a subclass of OSCPacketObject.
  43. m.noTypeTagString: Is TRUE iff the recieved packet hasn't got a OSC Type Tag String. In this case, all the received argumentdata
  44. of length LEN(m.argumentData) is stored in m.argumentData.
  45. OSCBundle b:
  46. b.timetag: OSCTimeTag of the bundle
  47. b.messagescount: # of messages or bundles contained in the bundle
  48. b.messages[i]: packet with index i (0<=i<messagescount)
  49. *)
  50. IMPORT
  51. SYSTEM (* Int64 -> Byte[] *),
  52. Dates, Strings, KernelLog,
  53. Network (* PutNet4: Little/Big-endian conversion *),
  54. Reals (* Real -> Byte[] *),
  55. WMGraphics (* RGBA Color *),
  56. Clock, Kernel (* Systemtime in ms *);
  57. CONST
  58. OSCMessageDefaultArgsCount = 4;
  59. OSCBundleDefaultMsgCount = 4;
  60. One32Zero = 100000000H;
  61. OSCTimeTagOneMS = 418937H; (* := 100000000H DIV 1000 *)
  62. (* this assumes little endianness, used in the exportfunction of OSCParamInt64 *)
  63. H = 4; L = 0;
  64. WrngClassUsedOrFunNotOverl* = 99; (* this trap is executed, if a 'abstract' function wasn't overloaded *)
  65. Trace* = FALSE;
  66. VAR
  67. MonthToDays : ARRAY 13 OF INTEGER; (* copied from Dates.Mod *)
  68. SysStartSeconds-: LONGINT; (* stores the current bootuptimestamp (secs sincs 1st Jan 1900), when an overflow of Objects.ticks is detected,
  69. the timestamp will be adjusted *)
  70. TicksArePositive-: BOOLEAN;
  71. TYPE
  72. String* = Strings.String;
  73. VAR
  74. OSCBundleIdent: String; (* stores '#bundle' *)
  75. TYPE
  76. Blob* = POINTER TO ARRAY OF CHAR;
  77. (* The following classes are to store the different types of OSC Parameters *)
  78. OSCParamObject* = OBJECT (* abstract *)
  79. VAR
  80. tag-: CHAR;
  81. (* Returns the number of bytes that this Parameter uses in the argument data.
  82. This function will be called for every stored argument to calculate the size of the OSCPacket *)
  83. PROCEDURE GetSize*(): LONGINT; BEGIN HALT(WrngClassUsedOrFunNotOverl); END GetSize;
  84. (* Exports the argumentdata to packet[pos..pos+GetSize()-1]. In packet all data is stored in network byteorder. *)
  85. PROCEDURE export(VAR packet: ARRAY OF CHAR; VAR pos: LONGINT); BEGIN HALT(WrngClassUsedOrFunNotOverl); END export;
  86. (* Dumps the current parameter (with stored values) to the kernel log. *)
  87. PROCEDURE dump*(indent: LONGINT);
  88. BEGIN
  89. indentDump(indent); KernelLog.String('OSCParamObject { }'); KernelLog.Ln;
  90. END dump;
  91. END OSCParamObject;
  92. ParamArray* = POINTER TO ARRAY OF OSCParamObject;
  93. (* This 'abstract' class stored the shared functionality of OSCParamInteger and OSCParamRGBAColor *)
  94. OSCParamAbsInteger = OBJECT(OSCParamObject)
  95. VAR (* 32bit on IA32 *)
  96. integer-: LONGINT;
  97. PROCEDURE GetSize*(): LONGINT;
  98. BEGIN
  99. RETURN 4;
  100. END GetSize;
  101. PROCEDURE export(VAR packet: ARRAY OF CHAR; VAR pos: LONGINT);
  102. BEGIN
  103. Network.PutNet4(packet, pos, integer);
  104. INC(pos, 4);
  105. END export;
  106. PROCEDURE dump*(indent: LONGINT);
  107. BEGIN
  108. indentDump(indent); KernelLog.String('OSCParamAbsInteger{ }'); KernelLog.Ln;
  109. END dump;
  110. END OSCParamAbsInteger;
  111. (* int32: OSC Type Tag 'i' *)
  112. OSCParamInteger* = OBJECT(OSCParamAbsInteger)
  113. PROCEDURE &InitInteger*(i: LONGINT);
  114. BEGIN
  115. integer := i;
  116. tag := 'i';
  117. END InitInteger;
  118. PROCEDURE dump*(indent: LONGINT);
  119. BEGIN
  120. indentDump(indent); KernelLog.String('OSCParamInt { ');
  121. KernelLog.Int(integer, 1); KernelLog.String(' ('); KernelLog.Hex(integer, 1); KernelLog.String(') }'); KernelLog.Ln;
  122. END dump;
  123. END OSCParamInteger;
  124. (* float32: OSC Type Tag 'f' *)
  125. OSCParamFloat* = OBJECT(OSCParamObject)
  126. VAR (* 32bit on IA32 *)
  127. float-: REAL;
  128. PROCEDURE &InitFloat*(f: REAL);
  129. BEGIN
  130. float := f;
  131. tag := 'f';
  132. END InitFloat;
  133. PROCEDURE GetSize*(): LONGINT;
  134. BEGIN
  135. RETURN 4;
  136. END GetSize;
  137. PROCEDURE export(VAR packet: ARRAY OF CHAR; VAR pos: LONGINT);
  138. BEGIN
  139. Network.PutNet4(packet, pos, Reals.Int(float));
  140. INC(pos, 4);
  141. END export;
  142. PROCEDURE dump*(indent: LONGINT);
  143. VAR
  144. l, hi, lo: LONGINT;
  145. BEGIN
  146. indentDump(indent); KernelLog.String('OSCParamFloat { ');
  147. l := Reals.RoundL(float*1000);
  148. hi := l DIV 1000;
  149. lo := l - hi*1000;
  150. KernelLog.Int(hi, 1); KernelLog.String('.'); KernelLog.Int(lo, 4);
  151. (* KernelLog.Float(float, 1); KernelLog.String(' ('); KernelLog.Hex(integer, 1); *) KernelLog.String(' }'); KernelLog.Ln;
  152. END dump;
  153. END OSCParamFloat;
  154. (* This 'abstract' class contains the shared functionality of OSCParamString and OSCParamAltString *)
  155. OSCParamAbsString = OBJECT(OSCParamObject)
  156. VAR
  157. string-: String;
  158. PROCEDURE GetSize*(): LONGINT;
  159. BEGIN
  160. RETURN(padsize(Strings.Length(string^)+1));
  161. END GetSize;
  162. PROCEDURE export(VAR packet: ARRAY OF CHAR; VAR pos: LONGINT);
  163. BEGIN
  164. ASSERT(string # NIL);
  165. exportString(string, packet, pos);
  166. END export;
  167. PROCEDURE dump*(indent: LONGINT);
  168. BEGIN
  169. indentDump(indent); KernelLog.String('OSCParamAbsString { '); KernelLog.String(' }'); KernelLog.Ln;
  170. END dump;
  171. END OSCParamAbsString;
  172. (* OSC-String: OSC Type Tag 's' *)
  173. OSCParamString* = OBJECT(OSCParamAbsString)
  174. PROCEDURE &InitString*(s: String);
  175. BEGIN
  176. ASSERT(s # NIL);
  177. string := s;
  178. tag := 's';
  179. END InitString;
  180. PROCEDURE dump*(indent: LONGINT);
  181. BEGIN
  182. indentDump(indent); KernelLog.String('OSCParamString{ ');
  183. KernelLog.String(string^); KernelLog.String(' }'); KernelLog.Ln;
  184. END dump;
  185. END OSCParamString;
  186. (* OSC-Blob: OSC Type Tag 'b' *)
  187. OSCParamBlob* = OBJECT(OSCParamObject)
  188. VAR
  189. blob-: Blob;
  190. size-: LONGINT;
  191. PROCEDURE &InitBlob*(b: Blob; s: LONGINT);
  192. BEGIN
  193. ASSERT(b # NIL);
  194. blob := b;
  195. size := s;
  196. tag := 'b';
  197. END InitBlob;
  198. PROCEDURE GetSize*(): LONGINT;
  199. BEGIN
  200. RETURN(padsize(size)+4);
  201. END GetSize;
  202. PROCEDURE export(VAR packet: ARRAY OF CHAR; VAR pos: LONGINT);
  203. VAR i: LONGINT;
  204. BEGIN
  205. Network.PutNet4(packet, pos, size); INC(pos, 4);
  206. FOR i:=0 TO size-1 DO
  207. packet[pos+i] := blob[i];
  208. END;
  209. INC(pos, size);
  210. WHILE (i MOD 4) # 0 DO
  211. packet[pos] := 0X; INC(pos);
  212. END;
  213. END export;
  214. PROCEDURE dump*(indent: LONGINT);
  215. BEGIN
  216. indentDump(indent); KernelLog.String('OSCParamBlob { '); KernelLog.Buffer(blob^, 0, size); KernelLog.String(' }'); KernelLog.Ln;
  217. END dump;
  218. END OSCParamBlob;
  219. (* Additional Types:
  220. h: 64bit Integer
  221. t: OSC-Timetag
  222. d: 64bit IEE754 float
  223. S: alternate string
  224. c: ASCII-charakter sent as 32bit
  225. r: 32bit RBGA color
  226. m 4byte midi message
  227. T: TRUE (* no bytes in argument data *)
  228. F: FALSE (* dito *)
  229. N: NIL (* dito *)
  230. I: Infinitum (* dito *)
  231. [, ]: begin & end of data <= *** This type isn't yet implemented *** *)
  232. (* int64: OSC Type Tag 'h' *)
  233. OSCParamInteger64* = OBJECT(OSCParamObject)
  234. VAR
  235. integer: HUGEINT;
  236. PROCEDURE &InitInt64*(i: HUGEINT);
  237. BEGIN
  238. integer := i;
  239. tag := 'h';
  240. END InitInt64;
  241. PROCEDURE GetSize*(): LONGINT;
  242. BEGIN
  243. RETURN 8;
  244. END GetSize;
  245. PROCEDURE export(VAR packet: ARRAY OF CHAR; VAR pos: LONGINT);
  246. VAR
  247. l, h: LONGINT;
  248. BEGIN
  249. SYSTEM.GET(ADDRESSOF(integer)+H, h);
  250. Network.PutNet4(packet, pos, h); INC(pos, 4);
  251. SYSTEM.GET(ADDRESSOF(integer)+L, l);
  252. Network.PutNet4(packet, pos, l); INC(pos, 4);
  253. END export;
  254. PROCEDURE dump*(indent: LONGINT);
  255. BEGIN
  256. indentDump(indent); KernelLog.String('OSCParamInteger64 { '); KernelLog.HIntHex(integer, 16); KernelLog.String(' }'); KernelLog.Ln;
  257. END dump;
  258. END OSCParamInteger64;
  259. (* OSC-Timetag: OSC Type Tag 't' *)
  260. OSCParamTT* = OBJECT(OSCParamObject)
  261. VAR
  262. tt: OSCTimeTag;
  263. PROCEDURE &InitTT*(tt: OSCTimeTag);
  264. BEGIN
  265. ASSERT(tt # NIL);
  266. tag := 't';
  267. END InitTT;
  268. PROCEDURE GetSize*(): LONGINT;
  269. BEGIN
  270. RETURN tt.GetSize();
  271. END GetSize;
  272. PROCEDURE export(VAR packet: ARRAY OF CHAR; VAR pos: LONGINT);
  273. BEGIN
  274. tt.export(packet, pos);
  275. END export;
  276. PROCEDURE dump*(indent: LONGINT);
  277. BEGIN
  278. indentDump(indent); KernelLog.String('OSCParamTT { '); KernelLog.Ln;
  279. tt.dump(indent+1);
  280. indentDump(indent); KernelLog.String(' }'); KernelLog.Ln;
  281. END dump;
  282. END OSCParamTT;
  283. (* 64 double IEE754: OSC Type Tag 'd' *)
  284. OSCParamFloat64* = OBJECT(OSCParamObject)
  285. VAR
  286. float: LONGREAL;
  287. PROCEDURE &InitFloat64*(f: LONGREAL);
  288. BEGIN
  289. float := f;
  290. tag := 'd';
  291. END InitFloat64;
  292. PROCEDURE GetSize*(): LONGINT;
  293. BEGIN
  294. RETURN 8;
  295. END GetSize;
  296. PROCEDURE export(VAR packet: ARRAY OF CHAR; VAR pos: LONGINT);
  297. VAR
  298. l, h: LONGINT;
  299. BEGIN
  300. Reals.IntL(float, h, l);
  301. Network.PutNet4(packet, pos, h); INC(pos, 4);
  302. Network.PutNet4(packet, pos, l); INC(pos, 4);
  303. END export;
  304. PROCEDURE dump*(indent: LONGINT);
  305. BEGIN
  306. indentDump(indent); KernelLog.String('OSCParamFloat64 { '); KernelLog.String(' }'); KernelLog.Ln;
  307. END dump;
  308. END OSCParamFloat64;
  309. (* alternate type represented as OSC-string: OSC Type Tag 'S' *)
  310. OSCParamAltString* = OBJECT(OSCParamString)
  311. PROCEDURE &InitAltString*(s: String);
  312. BEGIN
  313. ASSERT(s # NIL);
  314. string := s;
  315. tag := 'S';
  316. END InitAltString;
  317. PROCEDURE dump*(indent: LONGINT);
  318. BEGIN
  319. indentDump(indent); KernelLog.String('OSCParamAltString { '); KernelLog.String(string^); KernelLog.String(' }'); KernelLog.Ln;
  320. END dump;
  321. END OSCParamAltString;
  322. (* an ASCII-Char: OSC Type Tag 'c' *)
  323. OSCParamChar* = OBJECT(OSCParamObject)
  324. VAR
  325. char: CHAR;
  326. PROCEDURE &InitChar*(c: CHAR);
  327. BEGIN
  328. char := c;
  329. tag := 'c';
  330. END InitChar;
  331. PROCEDURE GetSize*(): LONGINT;
  332. BEGIN
  333. RETURN 4;
  334. END GetSize;
  335. PROCEDURE export(VAR packet: ARRAY OF CHAR; VAR pos: LONGINT);
  336. BEGIN
  337. Network.PutNet4(packet, pos, ORD(char)); INC(pos, 4);
  338. END export;
  339. PROCEDURE dump*(indent: LONGINT);
  340. BEGIN
  341. indentDump(indent); KernelLog.String('OSCParamChar { '); KernelLog.Char(char); KernelLog.String(' }'); KernelLog.Ln;
  342. END dump;
  343. END OSCParamChar;
  344. (* 32bit RGBA color: OSC Type Tag 'r' *)
  345. OSCParamRGBAColor* = OBJECT(OSCParamAbsInteger);
  346. PROCEDURE &InitRGBAColor*(c: WMGraphics.Color);
  347. BEGIN
  348. tag := 'r';
  349. integer := c;
  350. END InitRGBAColor;
  351. PROCEDURE dump*(indent: LONGINT);
  352. BEGIN
  353. indentDump(indent); KernelLog.String('OSCParamRGBAColor { '); KernelLog.Int(integer, 4); KernelLog.String(' }'); KernelLog.Ln;
  354. END dump;
  355. END OSCParamRGBAColor;
  356. (* This 'abstract' class contains shared code for all types without argument data *)
  357. OSCParamEmpty = OBJECT(OSCParamObject)
  358. PROCEDURE GetSize*(): LONGINT;
  359. BEGIN
  360. RETURN 0;
  361. END GetSize;
  362. PROCEDURE export(VAR packet: ARRAY OF CHAR; VAR pos: LONGINT);
  363. END export;
  364. PROCEDURE dump*(indent: LONGINT);
  365. BEGIN
  366. indentDump(indent); KernelLog.String('OSCParamEmpty { }'); KernelLog.Ln;
  367. END dump;
  368. END OSCParamEmpty;
  369. (* True: OSC Type Tag 'T' *)
  370. OSCParamTrue* = OBJECT(OSCParamEmpty)
  371. PROCEDURE &InitTrue*;
  372. BEGIN
  373. tag := 'T';
  374. END InitTrue;
  375. PROCEDURE dump*(indent: LONGINT);
  376. BEGIN
  377. indentDump(indent); KernelLog.String('OSCParamTrue { }'); KernelLog.Ln;
  378. END dump;
  379. END OSCParamTrue;
  380. (* False: OSC Type Tag 'F' *)
  381. OSCParamFalse* = OBJECT(OSCParamEmpty)
  382. PROCEDURE &InitFalse*;
  383. BEGIN
  384. tag := 'F';
  385. END InitFalse;
  386. PROCEDURE dump*(indent: LONGINT);
  387. BEGIN
  388. indentDump(indent); KernelLog.String('OSCParamFalse { }'); KernelLog.Ln;
  389. END dump;
  390. END OSCParamFalse;
  391. (* Nil: OSC Type Tag 'N' *)
  392. OSCParamNil* = OBJECT(OSCParamEmpty)
  393. PROCEDURE &InitNil*;
  394. BEGIN
  395. tag := 'N';
  396. END InitNil;
  397. PROCEDURE dump*(indent: LONGINT);
  398. BEGIN
  399. indentDump(indent); KernelLog.String('OSCParamNil { }'); KernelLog.Ln;
  400. END dump;
  401. END OSCParamNil;
  402. (* Infinitum: OSC Type Tag 'I' *)
  403. OSCParamInf* = OBJECT(OSCParamEmpty)
  404. PROCEDURE &InitInf*;
  405. BEGIN
  406. tag := 'I';
  407. END InitInf;
  408. PROCEDURE dump*(indent: LONGINT);
  409. BEGIN
  410. indentDump(indent); KernelLog.String('OSCParamNil { }'); KernelLog.Ln;
  411. END dump;
  412. END OSCParamInf;
  413. (* OSCTimeTag: Stores a OSC Time Tag
  414. IF imm is TRUE then this timetag represents the special case "immediately",
  415. otherwise the seconds since midnight January 1, 1900 are stored in seconds and the number of miliseconds (added to seconds)
  416. is stored in miliseconds.
  417. The Timetag can be set with the Set(..), SetLow(...) and the SetImmediatly-Functions. It can be read through the
  418. read-only members seconds, miliseconds and imm.
  419. The smallest precision of a OSC Time Tag is one milisecond, this is mainly due to restrictions of kerneltimers and networkingtimeouts.
  420. *)
  421. OSCTimeTag* = OBJECT
  422. VAR
  423. seconds-: LONGINT; (* seconds from 1st Jan 1900 *)
  424. miliseconds-: LONGINT; (* 0...999 *)
  425. imm-: BOOLEAN; (* immediate-flag *)
  426. PROCEDURE &Init*;
  427. BEGIN
  428. seconds := 0; miliseconds := 0; imm := FALSE;
  429. END Init;
  430. PROCEDURE GetSize*(): LONGINT; BEGIN RETURN 8; END GetSize;
  431. (* Sets the OSCTimeTag to the special case 'immediately' *)
  432. PROCEDURE SetImmediately*; BEGIN imm := TRUE; END SetImmediately;
  433. (* Sets the OSCTimeTag to the time described by seconds since January 1, 1900 and the miliseconds offset *)
  434. PROCEDURE Set*(sec, msec: LONGINT);
  435. BEGIN
  436. seconds := sec; miliseconds := msec MOD 1000; imm := FALSE;
  437. END Set;
  438. (* Sets the OSCTimeTag to the time represented with a Year, Month, ...
  439. Note: This function doesn't check if the date is really valid *)
  440. PROCEDURE SetLow*(year (* >=1900 *), month (* 1..12 *), day (* 1..31 *),
  441. hour (* 0..23 *), min (* 0..59 *), sec (* 0..59 *), msec (* 0..999 *): INTEGER);
  442. BEGIN
  443. seconds := TTGetSecondsLow(year, month, day, hour, min, sec);
  444. miliseconds := msec;
  445. END SetLow;
  446. (* Outputs the stored timetag *)
  447. PROCEDURE dump*(indent: LONGINT);
  448. BEGIN
  449. IF imm THEN
  450. indentDump(indent); KernelLog.String('TT { imm: TRUE } '); KernelLog.Ln;
  451. ELSE
  452. indentDump(indent); KernelLog.String('TT { sec: ');
  453. KernelLog.Int(seconds, 12); KernelLog.String('('); KernelLog.Hex(seconds, 1); KernelLog.String(') ');
  454. KernelLog.String(' msec: '); KernelLog.Int(miliseconds, 4); KernelLog.String(' }'); KernelLog.Ln;
  455. END;
  456. END dump;
  457. PROCEDURE export(VAR packet: ARRAY OF CHAR; VAR pos: LONGINT);
  458. VAR
  459. i: LONGINT;
  460. fraction: LONGINT;
  461. BEGIN
  462. IF imm THEN
  463. FOR i := 0 TO 6 DO
  464. packet[pos+i] := 0X;
  465. END;
  466. packet[pos+7] := CHR(1);
  467. ELSE
  468. Network.PutNet4(packet, pos, seconds);
  469. fraction := miliseconds * OSCTimeTagOneMS;
  470. Network.PutNet4(packet, pos+4, fraction);
  471. END;
  472. INC(pos, 8);
  473. END export;
  474. END OSCTimeTag;
  475. (* Common superclass of OSCMessage and OSCBundle.
  476. Used to build arrays, which elements are either a OSCMessage or an OSCBundle.
  477. Contains also code to support shared functionality.
  478. When a packet is received from the network, the responsible networkplugin registers a handler
  479. to return a packet to the sender with the SetReturner(..) procedure. When a returner is registred
  480. it's possible to send packets back to the sender with the Return(..) procedure.
  481. Note: Although its possible, you should never inctance an object of this type! *)
  482. OSCPacket* = OBJECT
  483. VAR
  484. bytearray: String;
  485. returner: OSCReturnProc;
  486. returnerdata: OBJECT; (* The networkplugin can register also some data with the returner, which is included in the call to
  487. the returner *)
  488. PROCEDURE &Init*;
  489. BEGIN
  490. bytearray := NIL;
  491. returner := NIL; returnerdata:= NIL;
  492. END Init;
  493. (* This 'abstract' function is used to calculate the size of the binary representation of OSCPackets. *)
  494. PROCEDURE GetSize*(): LONGINT; BEGIN HALT(WrngClassUsedOrFunNotOverl); END GetSize;
  495. PROCEDURE export(VAR packet: ARRAY OF CHAR; VAR position: LONGINT); BEGIN HALT(WrngClassUsedOrFunNotOverl); END export;
  496. PROCEDURE GetBytes*(): String; (* returns the binary representation of this OSCPacket. *)
  497. BEGIN
  498. assemble();
  499. RETURN bytearray;
  500. END GetBytes;
  501. PROCEDURE IsReturnable*(): BOOLEAN; (* returns true, iff it's possible to return a OSCPacket to the sender *)
  502. BEGIN
  503. RETURN returner # NIL;
  504. END IsReturnable;
  505. PROCEDURE Return*(p: OSCPacket): WORD; (* returns the packet p to the sender of the current packet *)
  506. BEGIN
  507. IF returner # NIL THEN
  508. RETURN returner(p, returnerdata);
  509. ELSE
  510. RETURN -1;
  511. END;
  512. END Return;
  513. (* registers a returner, overloaded in OSCBundle to register it also to all members of an OSCBundle *)
  514. PROCEDURE SetReturner*(s: OSCReturnProc; data: OBJECT);
  515. BEGIN
  516. returner := s;
  517. returnerdata := data;
  518. END SetReturner;
  519. PROCEDURE dump*(indent: LONGINT);
  520. BEGIN
  521. indentDump(indent); KernelLog.String('OSCPacket { bytearray: ');
  522. KernelLog.Buffer(bytearray^, 0, LEN(bytearray^)); KernelLog.String(' }'); KernelLog.Ln;
  523. END dump;
  524. PROCEDURE assemble;
  525. VAR
  526. p: LONGINT;
  527. BEGIN
  528. NEW(bytearray, GetSize());
  529. ASSERT(bytearray # NIL);
  530. p := 0;
  531. export(bytearray^, p);
  532. END assemble;
  533. END OSCPacket;
  534. OSCPacketArray* = POINTER TO ARRAY OF OSCPacket;
  535. (* signature of return procedures *)
  536. OSCReturnProc* = PROCEDURE {DELEGATE} (p: OSCPacket; data: OBJECT): WORD;
  537. (* OSCMessage stores a single OSCMessage *)
  538. OSCMessage* = OBJECT(OSCPacket)
  539. VAR
  540. address-: String;
  541. argumentcount-: INTEGER;
  542. arguments-: ParamArray;
  543. noTypeTagString-: BOOLEAN; (* is TRUE, iff the received packet doesn't contain an OSC Type Tag String *)
  544. argumentData-: Blob; (* this holds all the argument data, if noTypeTagString is TRUE *)
  545. PROCEDURE &InitMessage*(adr: String);
  546. BEGIN
  547. Init();
  548. address := adr;
  549. NEW(arguments, OSCMessageDefaultArgsCount);
  550. argumentcount := 0;
  551. noTypeTagString := FALSE;
  552. argumentData := NIL;
  553. END InitMessage;
  554. (* Used internally to increase the size of the arguments-array. *)
  555. PROCEDURE grow;
  556. VAR
  557. newargs: ParamArray;
  558. i: INTEGER;
  559. BEGIN
  560. NEW(newargs, LEN(arguments)*2);
  561. FOR i:=0 TO argumentcount-1 DO
  562. newargs[i] := arguments[i];
  563. END;
  564. arguments := newargs;
  565. END grow;
  566. (* GetSize() returns the length of the binary representation of this OSCMessage in bytes.
  567. The binary representation of this OSCMessage consists of:
  568. adr: OSCString;
  569. osctypetagstring: OSCString;
  570. "the argument data"
  571. or if noTypeTagString = TRUE
  572. adr: OSCString;
  573. "the argument data"
  574. *)
  575. PROCEDURE GetSize*(): LONGINT;
  576. VAR
  577. i, argsize: LONGINT;
  578. BEGIN
  579. argsize := 0;
  580. FOR i:=0 TO argumentcount-1 DO
  581. argsize := argsize + arguments[i].GetSize();
  582. END;
  583. IF noTypeTagString THEN
  584. ASSERT(argumentData # NIL);
  585. RETURN oscStrSize(address)+LEN(argumentData);
  586. ELSE
  587. RETURN
  588. oscStrSize(address)+
  589. padsize(1+argumentcount+1)+
  590. argsize;
  591. END;
  592. END GetSize;
  593. (* AddArgument adds a new Argument to the OSCMessage *)
  594. PROCEDURE AddArgument*(a: OSCParamObject);
  595. BEGIN
  596. IF argumentcount = LEN(arguments) THEN grow; END;
  597. arguments[argumentcount] := a;
  598. INC(argumentcount);
  599. END AddArgument;
  600. (* exports the binary representation of this OSCMessage to packet[pos..pos+GetSize()-1] *)
  601. PROCEDURE export(VAR packet: ARRAY OF CHAR; VAR pos: LONGINT);
  602. VAR
  603. i: LONGINT;
  604. BEGIN
  605. exportString(address, packet, pos);
  606. IF noTypeTagString THEN
  607. FOR i:=0 TO LEN(argumentData)-1 DO
  608. packet[pos+i] := argumentData[i];
  609. END;
  610. INC(pos, LEN(argumentData));
  611. RETURN;
  612. END;
  613. (* ,arg-tags*)
  614. packet[pos] := ','; INC(pos);
  615. FOR i:=0 TO argumentcount-1 DO
  616. ASSERT(arguments[i] # NIL);
  617. packet[pos] := arguments[i].tag; INC(pos);
  618. END;
  619. i := argumentcount+1;
  620. WHILE (i MOD 4) # 0 DO
  621. packet[pos] := 0X; INC(i); INC(pos);
  622. END;
  623. (* arguments *)
  624. FOR i := 0 TO argumentcount-1 DO
  625. arguments[i].export(packet, pos);
  626. END;
  627. END export;
  628. PROCEDURE dump*(indent: LONGINT);
  629. VAR i: LONGINT;
  630. BEGIN
  631. indentDump(indent); KernelLog.String('OSCMessage { address: '); KernelLog.String(address^); KernelLog.String(' noTypeTagString: ');
  632. KernelLog.Boolean(noTypeTagString); KernelLog.Ln;
  633. FOR i:=0 TO argumentcount-1 DO
  634. arguments[i].dump(indent+1);
  635. END;
  636. IF noTypeTagString THEN
  637. indentDump(indent); KernelLog.String(' argumentData: '); KernelLog.Buffer(argumentData^, 0, LEN(argumentData^));
  638. END;
  639. indentDump(indent); KernelLog.String('}'); KernelLog.Ln;
  640. END dump;
  641. END OSCMessage;
  642. (* OSC Bundle stores a bundle of OSC Messages *)
  643. OSCBundle* = OBJECT(OSCPacket)
  644. VAR
  645. timetag-: OSCTimeTag;
  646. messages-: OSCPacketArray;
  647. messagescount-: INTEGER;
  648. PROCEDURE &InitBundle*(tt: OSCTimeTag; msgs: OSCPacketArray; msgcount: INTEGER);
  649. BEGIN
  650. Init();
  651. timetag := tt;
  652. messages := msgs;
  653. IF messages = NIL THEN
  654. NEW(messages, OSCBundleDefaultMsgCount);
  655. messagescount := 0;
  656. ELSE
  657. messagescount := msgcount;
  658. END;
  659. END InitBundle;
  660. PROCEDURE AddPacket*(p: OSCPacket);
  661. BEGIN
  662. IF LEN(messages) = messagescount THEN grow; END;
  663. messages[messagescount] := p;
  664. INC(messagescount);
  665. END AddPacket;
  666. PROCEDURE GetSize*(): LONGINT;
  667. VAR
  668. s: LONGINT;
  669. i: INTEGER;
  670. BEGIN (* '#bundle' 8, timetag: 8, bundle elements ( := size + packet ) *)
  671. s := 16;
  672. FOR i:= 0 TO messagescount-1 DO
  673. INC(s, messages[i].GetSize()+4);
  674. END;
  675. RETURN s;
  676. END GetSize;
  677. PROCEDURE IsBeforeEqual*(rhs: OSCBundle): BOOLEAN;
  678. BEGIN
  679. RETURN TTSmaller(SELF.timetag, rhs.timetag) OR TTEqual(SELF.timetag, rhs.timetag);
  680. END IsBeforeEqual;
  681. PROCEDURE IsBefore*(rhs: OSCBundle): BOOLEAN;
  682. BEGIN
  683. RETURN TTSmaller(SELF.timetag, rhs.timetag);
  684. END IsBefore;
  685. (* Note: This function uses Objects.ticks to get a 'exact' systemtime.
  686. It calculates the seconds since midnight Jan 1, 1900 with SysStartSeconds plus the offset with Objects.ticks.
  687. If the Timeout of a packet in miliseconds is greather then it can be expressed in an positive LONGINT, a
  688. maximal timeout of MAX(LONGINT) DIV 1000 is used. *)
  689. PROCEDURE GetTimeout*(): LONGINT; (* timeout in ms from now *)
  690. VAR
  691. nowseconds, nowms: LONGINT;
  692. ticks: LONGINT;
  693. diff, diffms: LONGINT;
  694. overflowdiff: LONGINT;
  695. timeout: LONGINT;
  696. BEGIN
  697. IF timetag.imm THEN RETURN 0 END;
  698. ticks := Kernel.GetTicks ();
  699. IF (ticks > 0) # TicksArePositive THEN updateBootup; END;
  700. nowseconds := SysStartSeconds + (ticks DIV Kernel.Second);
  701. IF Trace THEN KernelLog.String('GetTimeout.nowseconds '); KernelLog.Hex(nowseconds, 4); KernelLog.Ln; END;
  702. nowms := ((ticks MOD Kernel.Second) * 1000) DIV Kernel.Second;
  703. IF Trace THEN KernelLog.String('GetTimeout.nowms '); KernelLog.Int(nowms, 4); KernelLog.Ln;END;
  704. overflowdiff := MAX(LONGINT) DIV 1000;
  705. diff := timetag.seconds - nowseconds;
  706. diffms := timetag.miliseconds - nowms;
  707. IF diff < 0 THEN RETURN 0; END;
  708. IF Trace THEN KernelLog.String('GetTimeout.diff '); KernelLog.Int(diff, 4); KernelLog.Ln;END;
  709. IF Trace THEN KernelLog.String('GetTimeout.diffms '); KernelLog.Int(diffms, 4); KernelLog.Ln;END;
  710. IF(diffms < 0) THEN DEC(diff); diffms := diffms MOD 1000; END;
  711. IF (diff >= overflowdiff-1) THEN
  712. diff := overflowdiff-1;
  713. END;
  714. IF Trace THEN KernelLog.String('GetTimeout.diff '); KernelLog.Int(diff, 4); KernelLog.Ln;END;
  715. IF Trace THEN KernelLog.String('GetTimeout.diffms '); KernelLog.Int(diffms, 4); KernelLog.Ln;END;
  716. timeout := diff*1000+diffms;
  717. IF timeout < 0 THEN RETURN 0; END;
  718. RETURN diff*1000+diffms;
  719. END GetTimeout;
  720. (* registers the returner also to all submessages or subbundles *)
  721. PROCEDURE SetReturner*(s: OSCReturnProc; data: OBJECT);
  722. VAR
  723. i: LONGINT;
  724. BEGIN
  725. SetReturner^(s, data);
  726. FOR i:=0 TO messagescount-1 DO
  727. messages[i].SetReturner(s, data);
  728. END;
  729. END SetReturner;
  730. PROCEDURE dump*(indent: LONGINT);
  731. VAR
  732. i: LONGINT;
  733. BEGIN
  734. indentDump(indent); KernelLog.String('OSCBundle { timetag: '); timetag.dump(indent+1); KernelLog.String(' packets(');
  735. KernelLog.Int(messagescount, 1); KernelLog.String(')'); KernelLog.Ln;
  736. FOR i:=0 TO messagescount-1 DO
  737. messages[i].dump(indent+1);
  738. END;
  739. indentDump(indent); KernelLog.String('}'); KernelLog.Ln;
  740. END dump;
  741. PROCEDURE export(VAR packet: ARRAY OF CHAR; VAR pos: LONGINT);
  742. VAR
  743. i: INTEGER;
  744. BEGIN
  745. exportString(OSCBundleIdent, packet, pos);
  746. timetag.export(packet, pos);
  747. FOR i := 0 TO messagescount-1 DO
  748. Network.PutNet4(packet, pos, messages[i].GetSize()); INC(pos, 4);
  749. messages[i].export(packet, pos);
  750. END;
  751. END export;
  752. (* Used internally to increase the size of the messages-array. *)
  753. PROCEDURE grow;
  754. VAR
  755. newmsgs: OSCPacketArray;
  756. i: LONGINT;
  757. BEGIN
  758. NEW(newmsgs, 2*LEN(messages));
  759. FOR i:=0 TO LEN(messages)-1 DO
  760. newmsgs[i] := messages[i];
  761. END;
  762. messages := newmsgs;
  763. END grow;
  764. END OSCBundle;
  765. (* helper for indentation of the dump()-function *)
  766. PROCEDURE indentDump(i: LONGINT);
  767. VAR
  768. a: LONGINT;
  769. BEGIN
  770. FOR a:=1 TO i DO KernelLog.String(' '); END;
  771. END indentDump;
  772. (* Helper for the usage of OSCTimeTag objects *)
  773. (* Returns the number of seconds since midnight January 1, 1900 until now
  774. Note: This function doesn't honor the users current timezone.
  775. Note: The timezone of a timetag isn't specified in the OSC specification v 1.0 by Matt Wright*)
  776. PROCEDURE TTGetSecondsNow*(): LONGINT;
  777. VAR year, month, day, hour,minute, second: INTEGER;
  778. date, time: LONGINT;
  779. BEGIN
  780. Clock.Get(time, date);
  781. hour := SHORT((time DIV 4096) MOD 32);
  782. minute := SHORT((time DIV 64) MOD 64);
  783. second := SHORT(time MOD 64);
  784. year := 1900+SHORT(date DIV 512);
  785. month := SHORT((date DIV 32) MOD 16);
  786. day := SHORT(date MOD 32);
  787. IF Trace THEN KernelLog.String('TTGetSecondsNow(');KernelLog.Int(year, 4); KernelLog.Int(month, 4); KernelLog.Int(day, 4); KernelLog.Int(hour, 4);
  788. KernelLog.Int(minute, 4); KernelLog.Int(second, 4); KernelLog.String(')'); KernelLog.Ln; END;
  789. RETURN TTGetSecondsLow(year, month, day, hour, minute, second);
  790. END TTGetSecondsNow;
  791. (* Returns the number of seconds from midnight January 1, 1900 to the specified date and time *)
  792. PROCEDURE TTGetSecondsLow*(year (* >=1900 *), month (* 1..12 *), day (* 1..31 *),
  793. hour (* 0..23 *), min (* 0..59 *), sec (* 0..59 *): INTEGER): LONGINT;
  794. VAR
  795. days, seconds: LONGINT;
  796. i: INTEGER;
  797. BEGIN
  798. days := 0;
  799. FOR i := 1900 TO year-1 DO
  800. IF Dates.LeapYear(i) THEN INC(days); END;
  801. END;
  802. INC(days, (LONG(year)-1900)*365); (* years *)
  803. INC(days, MonthToDays[month-1]); (* months *)
  804. IF Dates.LeapYear(year) & (month > 2) THEN INC(days); END;
  805. INC(days, day-1); (* days *)
  806. seconds := ((days*24 + hour)*60 + min)*60 + sec;
  807. RETURN seconds;
  808. END TTGetSecondsLow;
  809. (* tests if the timetags of a and b are equal *)
  810. PROCEDURE TTEqual*(a,b: OSCTimeTag): BOOLEAN;
  811. BEGIN
  812. ASSERT(a # NIL); ASSERT(b # NIL);
  813. IF (a.imm = TRUE) & (b.imm = TRUE) THEN RETURN TRUE; END;
  814. IF (a.imm = TRUE) OR (b.imm = TRUE) THEN RETURN FALSE; END;
  815. RETURN (a.seconds = b.seconds) & (a.miliseconds = b.miliseconds);
  816. END TTEqual;
  817. (* returns TRUE iff the timetag of a is smaller than the timetag of b *)
  818. PROCEDURE TTSmaller*(a,b: OSCTimeTag): BOOLEAN;
  819. BEGIN
  820. ASSERT(a # NIL); ASSERT(b # NIL);
  821. IF (a.imm = TRUE) & (b.imm = FALSE) THEN RETURN TRUE; END;
  822. IF b.imm = TRUE THEN RETURN FALSE; END;
  823. RETURN (a.seconds < b.seconds) OR ((a.seconds = b.seconds) & (a.miliseconds < b.miliseconds));
  824. END TTSmaller;
  825. (* returns TRUE iff the timetag of a is greather than the timetag of b *)
  826. PROCEDURE TTGreather*(a,b: OSCTimeTag): BOOLEAN;
  827. BEGIN
  828. RETURN TTSmaller(b,a);
  829. END TTGreather;
  830. (* The following ParseOSC*-functions are used to parse an OSCPacket or an OSCMessage.
  831. The newtorkplugins use this function to translate a binary represenation of a packet to a corresponding
  832. object.
  833. Note: This is the only parsing function which is accessible from other modules.
  834. This function parses the packet in data[0..endofs-1]. It returns the corresponding object or NIL if a
  835. parse error occured. *)
  836. PROCEDURE ParseOSCPacket*(VAR data: ARRAY OF CHAR; endofs: LONGINT): OSCPacket;
  837. VAR
  838. ofs: LONGINT;
  839. BEGIN
  840. IF Trace THEN
  841. KernelLog.String('ParseOSCPacket started'); KernelLog.Ln;
  842. KernelLog.Buffer(data, 0, endofs); KernelLog.Ln;
  843. END;
  844. ofs := 0;
  845. RETURN parseOSCPacketInt(data, ofs, endofs);
  846. END ParseOSCPacket;
  847. (* parses a packet in data[ofs..endofs-1] (the size of the packet is endofs-ofs).
  848. Note: Since ofs is a VAR parameter, it will also be adjusted in calling functions! *)
  849. PROCEDURE parseOSCPacketInt(VAR data: ARRAY OF CHAR; VAR ofs: LONGINT; endofs: LONGINT): OSCPacket;
  850. VAR
  851. p: OSCPacket;
  852. BEGIN
  853. IF Trace THEN KernelLog.String('parseOSCPacketInt: '); KernelLog.Int(ofs, 4); KernelLog.Int(endofs, 4); KernelLog.Ln; END;
  854. (* size not a multiple of 4 *)
  855. IF (endofs-ofs) MOD 4 # 0 THEN RETURN NIL; END;
  856. IF Trace THEN KernelLog.String('size MOD 4 = 0 is ok'); KernelLog.Ln; END;
  857. IF Strings.StartsWith(OSCBundleIdent^, ofs, data) THEN
  858. p := parseOSCBundle(data, ofs, endofs);
  859. ELSE
  860. p := parseOSCMessage(data, ofs, endofs);
  861. END;
  862. IF Trace THEN KernelLog.String('parseOSCPacketInt: '); IF p = NIL THEN KernelLog.String(' parsing message of bundle failed '); END;
  863. KernelLog.String(' ofs is now:'); KernelLog.Int(ofs, 4); KernelLog.Ln; END;
  864. (* Not all data parsed *)
  865. IF ofs # endofs THEN RETURN NIL; END;
  866. RETURN p;
  867. END parseOSCPacketInt;
  868. PROCEDURE parseOSCBundle(VAR data: ARRAY OF CHAR; VAR ofs: LONGINT; endofs: LONGINT): OSCBundle;
  869. VAR
  870. b: OSCBundle;
  871. p: OSCPacket;
  872. tt: OSCTimeTag;
  873. packetsize: LONGINT;
  874. packetendofs: LONGINT;
  875. i: LONGINT;
  876. BEGIN
  877. IF Trace THEN KernelLog.String('parseOSCBundle: '); KernelLog.Int(ofs, 4); KernelLog.Int(endofs, 4); KernelLog.Ln; END;
  878. (* #bundle || tt || { size || message } *)
  879. IF endofs-ofs < 16 THEN RETURN NIL; END;
  880. IF ~ skipAndCheckOSCString(data, ofs, ofs+8) THEN RETURN NIL END;
  881. tt := parseOSCTT(data, ofs);
  882. NEW(b, tt, NIL, 0);
  883. WHILE (ofs+4) < endofs DO
  884. packetsize := Network.GetNet4(data, ofs); INC(ofs, 4);
  885. packetendofs := ofs+packetsize;
  886. IF packetendofs > endofs THEN RETURN NIL END;
  887. p := parseOSCPacketInt(data, ofs, packetendofs);
  888. IF p = NIL THEN RETURN NIL END;
  889. ASSERT(ofs = packetendofs);
  890. b.AddPacket(p);
  891. END;
  892. IF ofs # endofs THEN RETURN NIL; END;
  893. (* Check bundle TimeTags *)
  894. FOR i:=0 TO b.messagescount-1 DO
  895. p := b.messages[i];
  896. IF p IS OSCBundle THEN
  897. WITH p: OSCBundle DO
  898. IF TTSmaller(p.timetag, b.timetag) THEN
  899. IF Trace THEN KernelLog.String('parseOSCBundle: Timetag in a enclosed bundle is smaller then the enclosing timetag');
  900. KernelLog.Ln; END;
  901. RETURN NIL;
  902. END;
  903. END;
  904. END;
  905. END;
  906. RETURN b;
  907. END parseOSCBundle;
  908. PROCEDURE parseOSCTT(VAR data: ARRAY OF CHAR; VAR ofs: LONGINT): OSCTimeTag;
  909. VAR
  910. tt: OSCTimeTag;
  911. sec, fraction, msec: LONGINT;
  912. BEGIN
  913. IF Trace THEN KernelLog.String('parseOSCTT: '); KernelLog.Int(ofs, 4); KernelLog.Ln; END;
  914. NEW(tt);
  915. sec := Network.GetNet4(data, ofs);
  916. fraction := Network.GetNet4(data, ofs+4);
  917. INC(ofs, 8);
  918. (* fraction is signed :( *)
  919. IF (sec = 0) & (fraction = 1) THEN
  920. tt.SetImmediately(); RETURN tt;
  921. END;
  922. msec := 0;
  923. IF fraction < 0 THEN
  924. fraction := - fraction;
  925. msec := 1000 - (fraction DIV OSCTimeTagOneMS);
  926. IF msec = 1000 THEN INC(sec); msec := 0; END;
  927. ELSE
  928. msec := fraction DIV OSCTimeTagOneMS;
  929. END;
  930. tt.Set(sec, msec);
  931. RETURN tt;
  932. END parseOSCTT;
  933. PROCEDURE parseOSCParamInteger(VAR data: ARRAY OF CHAR; VAR ofs: LONGINT; endofs: LONGINT): OSCParamInteger;
  934. VAR
  935. p: OSCParamInteger;
  936. BEGIN
  937. IF Trace THEN KernelLog.String('parseOSCParamInteger: '); KernelLog.Int(ofs, 4); KernelLog.Int(endofs, 4); KernelLog.Ln; END;
  938. IF (ofs+4) > endofs THEN RETURN NIL END;
  939. NEW(p, Network.GetNet4(data, ofs)); INC(ofs, 4);
  940. RETURN p;
  941. END parseOSCParamInteger;
  942. PROCEDURE parseOSCParamFloat(VAR data: ARRAY OF CHAR; VAR ofs: LONGINT; endofs: LONGINT): OSCParamFloat;
  943. VAR
  944. p: OSCParamFloat;
  945. i: LONGINT;
  946. BEGIN
  947. IF (ofs+4) > endofs THEN RETURN NIL END;
  948. i := Network.GetNet4(data, ofs); INC(ofs, 4);
  949. NEW(p, Reals.Real(i));
  950. RETURN p;
  951. END parseOSCParamFloat;
  952. PROCEDURE parseOSCParamString(VAR data: ARRAY OF CHAR; VAR ofs: LONGINT; endofs: LONGINT): OSCParamString;
  953. VAR
  954. p: OSCParamString;
  955. s: String;
  956. BEGIN
  957. IF Trace THEN KernelLog.String('parseOSCParamString: '); KernelLog.Int(ofs, 4); KernelLog.Int(endofs, 4); KernelLog.Ln; END;
  958. s := importString(data, ofs, endofs);
  959. IF s = NIL THEN RETURN NIL END;
  960. NEW(p, s);
  961. RETURN p;
  962. END parseOSCParamString;
  963. PROCEDURE parseOSCParamBlob(VAR data: ARRAY OF CHAR; VAR ofs: LONGINT; endofs: LONGINT): OSCParamBlob;
  964. VAR
  965. p: OSCParamBlob;
  966. b: Blob;
  967. size, i: LONGINT;
  968. BEGIN
  969. IF Trace THEN KernelLog.String('parseOSCParamBlob: '); KernelLog.Int(ofs, 4); KernelLog.Int(endofs, 4); KernelLog.Ln; END;
  970. IF (ofs+4) > endofs THEN RETURN NIL END;
  971. size := Network.GetNet4(data, ofs); INC(ofs, 4);
  972. IF (ofs+size) > endofs THEN RETURN NIL END;
  973. NEW(b, size);
  974. FOR i:=0 TO size-1 DO b[i] := data[ofs+i]; END; INC(ofs, size);
  975. NEW(p, b, size);
  976. RETURN p;
  977. END parseOSCParamBlob;
  978. PROCEDURE parseOSCParamInteger64(VAR data: ARRAY OF CHAR; VAR ofs: LONGINT; endofs: LONGINT): OSCParamInteger64;
  979. VAR
  980. p: OSCParamInteger64;
  981. h, l: LONGINT;
  982. bigint: HUGEINT;
  983. BEGIN
  984. IF Trace THEN KernelLog.String('parseOSCParamInteger64: '); KernelLog.Int(ofs, 4); KernelLog.Int(endofs, 4); KernelLog.Ln; END;
  985. IF (ofs+8) > endofs THEN RETURN NIL END;
  986. h := Network.GetNet4(data, ofs); INC(ofs, 4);
  987. l := Network.GetNet4(data, ofs); INC(ofs, 4);
  988. SYSTEM.PUT(ADDRESSOF(bigint)+H, h);
  989. SYSTEM.PUT(ADDRESSOF(bigint)+L, l);
  990. NEW(p, bigint);
  991. RETURN p;
  992. END parseOSCParamInteger64;
  993. PROCEDURE parseOSCParamTT(VAR data: ARRAY OF CHAR; VAR ofs: LONGINT; endofs: LONGINT): OSCParamTT;
  994. VAR
  995. tt: OSCTimeTag;
  996. p: OSCParamTT;
  997. BEGIN
  998. IF Trace THEN KernelLog.String('parseOSCParamTT: '); KernelLog.Int(ofs, 4); KernelLog.Int(endofs, 4); KernelLog.Ln; END;
  999. IF (ofs+8) > endofs THEN RETURN NIL END;
  1000. tt := parseOSCTT(data, ofs);
  1001. IF tt = NIL THEN RETURN NIL; END;
  1002. NEW(p, tt);
  1003. RETURN p;
  1004. END parseOSCParamTT;
  1005. PROCEDURE parseOSCParamFloat64(VAR data: ARRAY OF CHAR; VAR ofs: LONGINT; endofs: LONGINT): OSCParamFloat64;
  1006. VAR
  1007. p: OSCParamFloat64;
  1008. h,l: LONGINT;
  1009. f: LONGREAL;
  1010. BEGIN
  1011. IF Trace THEN KernelLog.String('parseOSCParamFloat64: '); KernelLog.Int(ofs, 4); KernelLog.Int(endofs, 4); KernelLog.Ln; END;
  1012. IF (ofs+8) > endofs THEN RETURN NIL END;
  1013. h := Network.GetNet4(data, ofs); INC(ofs, 4);
  1014. l := Network.GetNet4(data, ofs); INC(ofs, 4);
  1015. f := Reals.RealL(h, l);
  1016. NEW(p, f);
  1017. RETURN p;
  1018. END parseOSCParamFloat64;
  1019. PROCEDURE parseOSCParamAltString(VAR data: ARRAY OF CHAR; VAR ofs: LONGINT; endofs: LONGINT): OSCParamString;
  1020. VAR
  1021. p: OSCParamAltString;
  1022. s: String;
  1023. BEGIN
  1024. IF Trace THEN KernelLog.String('parseOSCParamAltString: '); KernelLog.Int(ofs, 4); KernelLog.Int(endofs, 4); KernelLog.Ln; END;
  1025. s := importString(data, ofs, endofs);
  1026. IF s = NIL THEN RETURN NIL END;
  1027. NEW(p, s);
  1028. RETURN p;
  1029. END parseOSCParamAltString;
  1030. PROCEDURE parseOSCParamChar(VAR data: ARRAY OF CHAR; VAR ofs: LONGINT; endofs: LONGINT): OSCParamChar;
  1031. VAR
  1032. p: OSCParamChar;
  1033. i: LONGINT;
  1034. BEGIN
  1035. IF Trace THEN KernelLog.String('parseOSCParamChar: '); KernelLog.Int(ofs, 4); KernelLog.Int(endofs, 4); KernelLog.Ln; END;
  1036. IF (ofs+4) > endofs THEN RETURN NIL END;
  1037. i := Network.GetNet4(data, ofs); INC(ofs, 4);
  1038. NEW(p, CHR(i));
  1039. RETURN p;
  1040. END parseOSCParamChar;
  1041. PROCEDURE parseOSCParamRGBAColor(VAR data: ARRAY OF CHAR; VAR ofs: LONGINT; endofs: LONGINT): OSCParamRGBAColor;
  1042. VAR
  1043. p: OSCParamRGBAColor;
  1044. BEGIN
  1045. IF Trace THEN KernelLog.String('parseOSCParamRGBAColor: '); KernelLog.Int(ofs, 4); KernelLog.Int(endofs, 4); KernelLog.Ln; END;
  1046. IF (ofs + 4) > endofs THEN RETURN NIL END;
  1047. NEW(p, Network.GetNet4(data, ofs)); INC(ofs, 4);
  1048. RETURN p;
  1049. END parseOSCParamRGBAColor;
  1050. PROCEDURE parseOSCParams(adr: String; VAR data: ARRAY OF CHAR; VAR ofs: LONGINT; endofs: LONGINT): OSCMessage;
  1051. VAR
  1052. argstrofs: LONGINT;
  1053. m: OSCMessage;
  1054. param: OSCParamObject;
  1055. T: OSCParamTrue;
  1056. F: OSCParamFalse;
  1057. N: OSCParamNil;
  1058. I: OSCParamInf;
  1059. BEGIN
  1060. IF Trace THEN KernelLog.String('parseOSCParams: '); KernelLog.Int(ofs, 4); KernelLog.Int(endofs, 4); KernelLog.Ln; END;
  1061. NEW(m, adr);
  1062. (* check argumentstring *)
  1063. argstrofs := ofs;
  1064. IF ~ skipAndCheckOSCString(data, ofs, endofs) THEN RETURN NIL END;
  1065. INC(argstrofs); (* skip , *)
  1066. IF Trace THEN KernelLog.String('first parametertype at index: '); KernelLog.Int(argstrofs, 4); KernelLog.Ln; END;
  1067. WHILE data[argstrofs] # 0X DO
  1068. CASE data[argstrofs] OF
  1069. 'i': param := parseOSCParamInteger(data, ofs, endofs);
  1070. | 'f': param := parseOSCParamFloat(data, ofs, endofs);
  1071. | 's': param := parseOSCParamString(data, ofs, endofs);
  1072. | 'b': param := parseOSCParamBlob(data, ofs, endofs);
  1073. | 'h': param := parseOSCParamInteger64(data, ofs, endofs);
  1074. | 't': param := parseOSCParamTT(data, ofs, endofs);
  1075. | 'd': param := parseOSCParamFloat64(data, ofs, endofs);
  1076. | 'S': param := parseOSCParamAltString(data, ofs, endofs);
  1077. | 'c': param := parseOSCParamChar(data, ofs, endofs);
  1078. | 'r': param := parseOSCParamRGBAColor(data, ofs, endofs);
  1079. | 'T': NEW(T); param := T;
  1080. | 'F': NEW(F); param := F;
  1081. | 'N': NEW(N); param := N;
  1082. | 'I': NEW(I); param := I;
  1083. ELSE
  1084. (* discard message *)
  1085. KernelLog.String('Unknown OSC-Argumenttype: '); KernelLog.Char(data[argstrofs]); KernelLog.Ln;
  1086. RETURN NIL;
  1087. END;
  1088. IF param = NIL THEN RETURN NIL; END;
  1089. m.AddArgument(param);
  1090. INC(argstrofs);
  1091. END;
  1092. IF Trace THEN KernelLog.String('parseOSCParams ended with ofs '); KernelLog.Int(ofs, 4); KernelLog.Ln; END;
  1093. RETURN m;
  1094. END parseOSCParams;
  1095. PROCEDURE parseOSCMessage(VAR data: ARRAY OF CHAR; VAR ofs: LONGINT; endofs: LONGINT): OSCMessage;
  1096. VAR
  1097. adr: String;
  1098. argumentofs: LONGINT;
  1099. m: OSCMessage;
  1100. i: LONGINT;
  1101. BEGIN
  1102. IF Trace THEN KernelLog.String('parseOSCMessage: '); KernelLog.Int(ofs, 4); KernelLog.Int(endofs, 4); KernelLog.Ln; END;
  1103. (* address [ || typetagstring ] || argumentdata *)
  1104. adr := importString(data, ofs, endofs);
  1105. IF adr = NIL THEN RETURN NIL END;
  1106. IF ~ CheckOSCAdrPattern(adr) THEN RETURN NIL END;
  1107. IF Trace THEN KernelLog.String('address parsed: '); KernelLog.String(adr^); KernelLog.Ln; END;
  1108. (* check if typetagstring is there *)
  1109. IF (data[ofs] = ',') THEN
  1110. (* there seems to be a typetagstring *)
  1111. argumentofs := ofs;
  1112. m := parseOSCParams(adr, data, argumentofs, endofs);
  1113. (* if there is something parsed, return it *)
  1114. IF (m # NIL) & (argumentofs = endofs) THEN
  1115. ofs := argumentofs; (* argumentofs was used as positional parameter, therfore also adjust ofs now *)
  1116. RETURN m
  1117. END;
  1118. IF Trace THEN KernelLog.String('parseOSCParams falied... returned ofs: '); KernelLog.Int(argumentofs, 4); KernelLog.Ln;
  1119. IF m = NIL THEN KernelLog.String('but returned message is NIL'); KernelLog.Ln; END; END;
  1120. END;
  1121. IF Trace THEN KernelLog.String('parsing of typetag failed (or no typetag there)'); KernelLog.Ln; END;
  1122. (* parsing of typetagstring failed or no typetagstring available *)
  1123. NEW(m, adr);
  1124. m.noTypeTagString := TRUE;
  1125. NEW(m.argumentData, endofs-ofs);
  1126. FOR i:=0 TO (endofs-ofs)-1 DO
  1127. m.argumentData[i] := data[ofs+i];
  1128. END;
  1129. ofs := endofs;
  1130. RETURN m;
  1131. END parseOSCMessage;
  1132. (* helpers *)
  1133. PROCEDURE CheckOSCAdr*(adr: String): BOOLEAN;
  1134. VAR
  1135. i: LONGINT;
  1136. BEGIN
  1137. ASSERT(adr # NIL);
  1138. i := 0;
  1139. WHILE (i < LEN(adr)) & (adr[i] # 0X) DO
  1140. IF (ORD(adr[i]) < 32) OR (ORD(adr[i]) > 126) THEN RETURN FALSE; END;
  1141. CASE ORD(adr[i]) OF
  1142. 32, 35, 42, 44, 63, 91, 93, 123, 125:
  1143. RETURN FALSE;
  1144. ELSE
  1145. (* do nothing *)
  1146. END;
  1147. INC(i);
  1148. END;
  1149. IF i = LEN(adr) THEN RETURN FALSE; END;
  1150. IF adr[0] # '/' THEN RETURN FALSE; END;
  1151. RETURN TRUE;
  1152. END CheckOSCAdr;
  1153. PROCEDURE CheckOSCAdrPattern*(adr: String): BOOLEAN;
  1154. VAR
  1155. i: LONGINT;
  1156. BEGIN
  1157. ASSERT(adr # NIL);
  1158. i := 0;
  1159. WHILE (i < LEN(adr)) & (adr[i] # 0X) DO
  1160. IF (ORD(adr[i]) < 32) OR (ORD(adr[i]) > 126) THEN RETURN FALSE; END;
  1161. CASE ORD(adr[i]) OF
  1162. 32, 35:
  1163. RETURN FALSE;
  1164. ELSE
  1165. (* do nothing *)
  1166. END;
  1167. INC(i);
  1168. END;
  1169. IF i = LEN(adr) THEN RETURN FALSE; END;
  1170. IF adr[0] # '/' THEN RETURN FALSE; END;
  1171. RETURN TRUE;
  1172. END CheckOSCAdrPattern;
  1173. PROCEDURE skipAndCheckOSCString(VAR data: ARRAY OF CHAR; VAR ofs: LONGINT; endofs: LONGINT): BOOLEAN;
  1174. BEGIN
  1175. IF Trace THEN KernelLog.String('skipAndCheckOSCString: '); KernelLog.Int(ofs, 4); KernelLog.Int(endofs, 4); KernelLog.Ln; END;
  1176. WHILE (ofs < endofs) & (data[ofs] # 0X) DO INC(ofs); END;
  1177. (* string too long! *)
  1178. IF ofs = endofs THEN IF Trace THEN KernelLog.String('string is too long!'); KernelLog.Ln; END; RETURN FALSE; END;
  1179. INC(ofs);
  1180. (* check and skip pad bytes *)
  1181. WHILE (ofs MOD 4) # 0 DO
  1182. IF data[ofs] # 0X THEN RETURN FALSE; END;
  1183. INC(ofs);
  1184. END;
  1185. IF Trace THEN KernelLog.String('offset after padding: '); KernelLog.Int(ofs,4); KernelLog.Ln; END;
  1186. RETURN TRUE;
  1187. END skipAndCheckOSCString;
  1188. (* helper function to import an OSCString - checks also the extra padding 0X characters *)
  1189. PROCEDURE importString(VAR data: ARRAY OF CHAR; VAR ofs: LONGINT; endofs: LONGINT): String;
  1190. VAR
  1191. pos: LONGINT;
  1192. s: String;
  1193. BEGIN
  1194. IF Trace THEN KernelLog.String('importString: '); KernelLog.Int(ofs, 4); KernelLog.Int(endofs, 4); KernelLog.Ln; END;
  1195. pos := ofs;
  1196. WHILE (pos < endofs) & (data[pos] # 0X) DO
  1197. INC(pos);
  1198. END;
  1199. IF data[pos] # 0X THEN RETURN NIL END;
  1200. IF Trace THEN KernelLog.String('end of string: '); KernelLog.Int(pos, 4); KernelLog.Ln; END;
  1201. NEW(s, pos-ofs+1);
  1202. Strings.Copy(data, ofs, pos-ofs+1, s^);
  1203. IF Trace THEN KernelLog.String('copied string: '); KernelLog.String(s^); KernelLog.Ln; END;
  1204. ofs := pos+1;
  1205. WHILE (ofs MOD 4) # 0 DO
  1206. IF data[ofs] # 0X THEN RETURN NIL END;
  1207. INC(ofs);
  1208. END;
  1209. IF Trace THEN KernelLog.String('ofset after padding: '); KernelLog.Int(ofs, 4); KernelLog.Ln; END;
  1210. RETURN s;
  1211. END importString;
  1212. PROCEDURE padsize(i: LONGINT): LONGINT;
  1213. BEGIN
  1214. CASE i MOD 4 OF
  1215. 0: RETURN i; (* size is ok *)
  1216. | 1: RETURN i+3;
  1217. | 2: RETURN i+2;
  1218. | 3: RETURN i+1;
  1219. END;
  1220. END padsize;
  1221. (* returns the length of the exported OSCString of s *)
  1222. PROCEDURE oscStrSize(s: String): LONGINT;
  1223. BEGIN
  1224. ASSERT(s # NIL );
  1225. RETURN padsize(Strings.Length(s^)+1);
  1226. END oscStrSize;
  1227. (* exports an string s to packet[pos..pos+oscstrlen(s)-1] *)
  1228. PROCEDURE exportString(s: String; VAR packet: ARRAY OF CHAR; VAR pos: LONGINT);
  1229. VAR
  1230. i, length: LONGINT;
  1231. BEGIN
  1232. length := oscStrSize(s);
  1233. i := 0;
  1234. WHILE (i < length) & (s[i] # 0X) DO
  1235. packet[pos+i] := s[i];
  1236. INC(i);
  1237. END;
  1238. FOR i := i TO length-1 DO
  1239. packet[pos+i] := 0X;
  1240. END;
  1241. INC(pos, length);
  1242. END exportString;
  1243. (* This function have been used for testing during the development of this module *)
  1244. PROCEDURE Test*;
  1245. VAR
  1246. a: ParamArray;
  1247. b: OSCParamInteger;
  1248. c: OSCParamString;
  1249. BEGIN
  1250. NEW(a, 4);
  1251. KernelLog.Int(LEN(a), 4); KernelLog.Ln;
  1252. NEW(b, 10);
  1253. KernelLog.Int(b.integer, 4); KernelLog.Ln;
  1254. NEW(c, Strings.NewString('abc'));
  1255. KernelLog.Int(c.GetSize(), 4); KernelLog.Ln;
  1256. NEW(c, Strings.NewString('abcd'));
  1257. KernelLog.Int(c.GetSize(), 4); KernelLog.Ln;
  1258. NEW(c, Strings.NewString('abcde'));
  1259. KernelLog.Int(c.GetSize(), 4); KernelLog.Ln;
  1260. NEW(c, Strings.NewString('abcdef'));
  1261. KernelLog.Int(c.GetSize(), 4); KernelLog.Ln;
  1262. NEW(c, Strings.NewString('abcdefgh'));
  1263. KernelLog.Int(c.GetSize(), 4); KernelLog.Ln;
  1264. KernelLog.String('OSC.Test done'); KernelLog.Ln;
  1265. END Test;
  1266. PROCEDURE TestGetSize*;
  1267. VAR
  1268. pi: OSCParamInteger;
  1269. pf: OSCParamFloat;
  1270. ps: OSCParamString;
  1271. m: OSCMessage;
  1272. BEGIN
  1273. NEW(pi, 15);
  1274. KernelLog.Int(pi.GetSize(), 4); KernelLog.Ln;
  1275. NEW(pf, 1.52);
  1276. KernelLog.Int(pf.GetSize(), 4); KernelLog.Ln;
  1277. NEW(ps, Strings.NewString('12345'));
  1278. KernelLog.Int(ps.GetSize(), 4);
  1279. NEW(m, Strings.NewString('/abc/def/ghi'));
  1280. m.AddArgument(pi);
  1281. m.AddArgument(pf);
  1282. m.AddArgument(ps);
  1283. KernelLog.Int(m.GetSize(), 4); KernelLog.Ln;
  1284. KernelLog.String('OSC.TestGetSize done'); KernelLog.Ln;
  1285. END TestGetSize;
  1286. PROCEDURE TestAssemble*;
  1287. VAR
  1288. pi: OSCParamInteger;
  1289. pf: OSCParamFloat;
  1290. m: OSCMessage;
  1291. pli: OSCParamInteger64;
  1292. plf: OSCParamFloat64;
  1293. b: OSCBundle;
  1294. tt: OSCTimeTag;
  1295. BEGIN
  1296. NEW(m, Strings.NewString('/abc/def/ghi'));
  1297. m.assemble();
  1298. KernelLog.Buffer(m.bytearray^, 0, LEN(m.bytearray^));KernelLog.Ln;KernelLog.Ln;KernelLog.Ln;
  1299. NEW(pi, 12345678H); m.AddArgument(pi);
  1300. NEW(pi, 12345679H); m.AddArgument(pi);
  1301. NEW(pi, 1234567AH); m.AddArgument(pi);
  1302. NEW(pf, 1.25); m.AddArgument(pf);
  1303. NEW(plf, 5); m.AddArgument(plf);
  1304. NEW(pli, 123456789ABCDEF0H); m.AddArgument(pli);
  1305. m.assemble();
  1306. KernelLog.Buffer(m.bytearray^, 0, LEN(m.bytearray^));KernelLog.Ln;KernelLog.Ln;KernelLog.Ln;
  1307. NEW(tt); tt.SetLow(2005,12,26,12,1,1,123);
  1308. NEW(b, tt, NIL, 0);
  1309. b.AddPacket(m);
  1310. NEW(m, Strings.NewString('/abc/xxx'));
  1311. m.AddArgument(pi);
  1312. b.AddPacket(m);
  1313. b.assemble();
  1314. KernelLog.Buffer(b.bytearray^, 0, LEN(b.bytearray^));KernelLog.Ln;KernelLog.Ln;KernelLog.Ln;
  1315. tt.SetImmediately();
  1316. b.assemble();
  1317. KernelLog.Buffer(b.bytearray^, 0, LEN(b.bytearray^));KernelLog.Ln;KernelLog.Ln;KernelLog.Ln;
  1318. KernelLog.String('OSC.TestAssemble done');
  1319. END TestAssemble;
  1320. PROCEDURE TestTT*;
  1321. VAR
  1322. t: OSCTimeTag;
  1323. BEGIN
  1324. KernelLog.String('OSC.TestTT'); KernelLog.Ln;
  1325. NEW(t);
  1326. t.SetLow(2005, 12, 26, 12, 1, 1, 123);
  1327. KernelLog.String('2005/12/26/12/01/01.123: '); KernelLog.Hex(t.seconds, 10); KernelLog.Int(t.miliseconds, 4); KernelLog.Ln;
  1328. END TestTT;
  1329. PROCEDURE TestBundleTimeout*;
  1330. VAR
  1331. tt: OSCTimeTag;
  1332. b: OSCBundle;
  1333. BEGIN
  1334. KernelLog.String('Bootup: '); KernelLog.Hex(SysStartSeconds, 10); KernelLog.Ln;
  1335. KernelLog.String('Ticks: '); KernelLog.Hex(Kernel.GetTicks (), 10); KernelLog.Ln; KernelLog.Boolean(TicksArePositive); KernelLog.Ln;
  1336. KernelLog.String('TTGetSecondsNow'); KernelLog.Hex(TTGetSecondsNow(), 10); KernelLog.Ln;
  1337. NEW(tt); tt.Set(TTGetSecondsNow()+1000, 0);
  1338. NEW(b,tt, NIL, 0);
  1339. KernelLog.String('GetTimeout: '); KernelLog.Int(b.GetTimeout(), 10); KernelLog.Ln;
  1340. NEW(tt); tt.SetLow(2006,01,25,10, 28,0,0);
  1341. NEW(b,tt, NIL, 0);
  1342. KernelLog.String('GetTimeout: '); KernelLog.Int(b.GetTimeout(), 10); KernelLog.Ln;
  1343. NEW(tt); tt.SetLow(2005,12,31,13, 28,0,0);
  1344. NEW(b,tt, NIL, 0);
  1345. KernelLog.String('GetTimeout: '); KernelLog.Int(b.GetTimeout(), 10); KernelLog.Ln;
  1346. END TestBundleTimeout;
  1347. PROCEDURE TestParser*;
  1348. VAR
  1349. pi: OSCParamInteger;
  1350. pf: OSCParamFloat;
  1351. m: OSCMessage;
  1352. pli: OSCParamInteger64;
  1353. plf: OSCParamFloat64;
  1354. b: OSCBundle;
  1355. tt: OSCTimeTag;
  1356. p: OSCPacket;
  1357. BEGIN
  1358. NEW(m, Strings.NewString('/abc/def/ghi'));
  1359. m.assemble();
  1360. KernelLog.String('Parsing: ');KernelLog.Ln;
  1361. KernelLog.Buffer(m.bytearray^, 0, LEN(m.bytearray^));KernelLog.Ln;KernelLog.Ln;KernelLog.Ln;
  1362. p := ParseOSCPacket(m.bytearray^, LEN(m.bytearray^));
  1363. IF p # NIL THEN KernelLog.String('parsing ok'); ELSE KernelLog.String('parsing failed'); END; KernelLog.Ln;
  1364. NEW(pi, 12345678H); m.AddArgument(pi);
  1365. NEW(pi, 12345679H); m.AddArgument(pi);
  1366. NEW(pi, 1234567AH); m.AddArgument(pi);
  1367. NEW(pf, 1.25); m.AddArgument(pf);
  1368. NEW(plf, 5); m.AddArgument(plf);
  1369. NEW(pli, 123456789ABCDEF0H); m.AddArgument(pli);
  1370. m.assemble();
  1371. KernelLog.String('Parsing: ');KernelLog.Ln;
  1372. KernelLog.Buffer(m.bytearray^, 0, LEN(m.bytearray^));KernelLog.Ln;KernelLog.Ln;KernelLog.Ln;
  1373. p := ParseOSCPacket(m.bytearray^, LEN(m.bytearray^));
  1374. IF p # NIL THEN KernelLog.String('parsing ok'); ELSE KernelLog.String('parsing failed'); END; KernelLog.Ln;
  1375. NEW(tt); tt.SetLow(2005,12,26,12,1,1,123);
  1376. NEW(b, tt, NIL, 0);
  1377. b.AddPacket(m);
  1378. NEW(m, Strings.NewString('/abc/xxx'));
  1379. m.AddArgument(pi);
  1380. b.AddPacket(m);
  1381. b.assemble();
  1382. KernelLog.String('Parsing: ');KernelLog.Ln;
  1383. KernelLog.Buffer(b.bytearray^, 0, LEN(b.bytearray^));KernelLog.Ln;KernelLog.Ln;KernelLog.Ln;
  1384. p := ParseOSCPacket(b.bytearray^, LEN(b.bytearray^));
  1385. IF p # NIL THEN KernelLog.String('parsing ok'); ELSE KernelLog.String('parsing failed'); END; KernelLog.Ln;
  1386. tt.SetImmediately();
  1387. b.assemble();
  1388. KernelLog.String('Parsing: ');KernelLog.Ln;
  1389. KernelLog.Buffer(b.bytearray^, 0, LEN(b.bytearray^));KernelLog.Ln;KernelLog.Ln;KernelLog.Ln;
  1390. p := ParseOSCPacket(b.bytearray^, LEN(b.bytearray^));
  1391. IF p # NIL THEN KernelLog.String('parsing ok'); ELSE KernelLog.String('parsing failed'); END; KernelLog.Ln;
  1392. KernelLog.String('OSC.TestAssemble done');
  1393. END TestParser;
  1394. (* Calculates the 'bootup'-timestamp with the current timestamp and the elapsed ticks since bootup.
  1395. This function is called from the module initializer. *)
  1396. PROCEDURE calculateBootup;
  1397. VAR
  1398. nowseconds: LONGINT;
  1399. ticks: LONGINT;
  1400. BEGIN
  1401. ticks := Kernel.GetTicks ();
  1402. nowseconds := TTGetSecondsNow();
  1403. TicksArePositive := ticks > 0;
  1404. SysStartSeconds := nowseconds - (ticks DIV Kernel.Second);
  1405. END calculateBootup;
  1406. (* This function will be called from GetTimeout() to detect overflows of Objects.ticks *)
  1407. PROCEDURE updateBootup;
  1408. VAR
  1409. ticks: LONGINT;
  1410. BEGIN
  1411. ticks := Kernel.GetTicks ();
  1412. IF ticks > 0 THEN
  1413. TicksArePositive := TRUE;
  1414. ELSIF (ticks < 0) & TicksArePositive THEN
  1415. (* Update Bootup *)
  1416. IF Trace THEN KernelLog.String('updateBootup: SysStartSeconds now: '); KernelLog.Int(SysStartSeconds, 10);
  1417. KernelLog.Hex(SysStartSeconds, 1); KernelLog.Ln; END;
  1418. SysStartSeconds := SysStartSeconds + (1073741824 DIV (Kernel.Second DIV 4)); (* := INC(SysStartSeconds, 2**32/Seconds) *)
  1419. TicksArePositive := FALSE;
  1420. IF Trace THEN KernelLog.String('updateBootup: After update SysStartSeconds: '); KernelLog.Int(SysStartSeconds, 10);
  1421. KernelLog.Hex(SysStartSeconds, 1); KernelLog.Ln; END;
  1422. END;
  1423. END updateBootup;
  1424. BEGIN
  1425. MonthToDays[0] := 0; MonthToDays[1] := 31; MonthToDays[2] := 59; MonthToDays[3] := 90; MonthToDays[4] := 120;
  1426. MonthToDays[5] := 151; MonthToDays[6] := 181; MonthToDays[7] := 212; MonthToDays[8] := 243;
  1427. MonthToDays[9] := 273; MonthToDays[10] := 304; MonthToDays[11] := 334; MonthToDays[12] := 365;
  1428. OSCBundleIdent := Strings.NewString('#bundle');
  1429. calculateBootup;
  1430. END OSC.
  1431. PC.Compile OSCStrings.Mod OSC.Mod OSCRegistry.Mod OSCQueue.Mod OSCService.Mod OSCNet.Mod OSCExample.Mod OSCEval.Mod~
  1432. System.Free OSCEval OSCExample OSCNet OSCService OSCQueue OSCRegistry OSC OSCUtilities ~
  1433. OSC.Test ~
  1434. OSC.TestGetSize ~
  1435. OSC.TestAssemble ~
  1436. OSC.TestTT ~
  1437. OSC.TestParser ~