1 /*
2 Copyright (c) 2018, MIPI Alliance, Inc.
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11
12 * Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in
14 the documentation and/or other materials provided with the
15 distribution.
16
17 * Neither the name of the copyright holder nor the names of its
18 contributors may be used to endorse or promote products derived
19 from this software without specific prior written permission.
20
21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 /*
35 * Contributors:
36 * Norbert Schulz (Intel Corporation) - Initial API and implementation
37 */
38
39
40 /* Example platform adaptation
41 * This "platform" shows how to implement a SyS-T library platform module
42 * to simulate MIPI STP data protocol generation for SyS-T messages.
43 */
44 #if defined(_WIN32)
45 #include <windows.h>
46 #else
47 #include <sys/time.h>
48 #endif
49 #include <stdio.h>
50 #include <string.h>
51
52 #include "mipi_syst.h"
53
54 #if defined(_WIN32)
55 static CRITICAL_SECTION lockPlat;
56 #define LOCKING_INIT() InitializeCriticalSection(&lockPlat)
57 #define LOCKING_DESTROY() DeleteCriticalSection(&lockPlat)
58 #define LOCK() EnterCriticalSection(&lockPlat)
59 #define UNLOCK() LeaveCriticalSection(&lockPlat)
60
61 #else
62
63 #include <pthread.h>
64 static pthread_mutex_t lockPlat;
65
66 #define LOCKING_INIT() pthread_mutex_init(&lockPlat, NULL)
67 #define LOCKING_DESTROY() pthread_mutex_destroy(&lockPlat)
68 #define LOCK() pthread_mutex_lock(&lockPlat)
69 #define UNLOCK() pthread_mutex_unlock(&lockPlat)
70
71 #endif
72
mipi_syst_get_epoch_us()73 MIPI_SYST_EXPORT mipi_syst_u64 MIPI_SYST_CALLCONV mipi_syst_get_epoch_us()
74 {
75 mipi_syst_u64 epoch;
76 #if defined(MIPI_SYST_UNIT_TEST)
77 epoch = 0x12345678aabbccddull;
78 #elif defined(_WIN32)
79 // windows does not offer epoch time API directly.
80 // Search for the 116444... constant below on
81 // msdn for an explanation of this computation:
82 //
83 FILETIME ft;
84 GetSystemTimeAsFileTime(&ft);
85 epoch = ft.dwHighDateTime;
86 epoch = ((epoch<<32) | ft.dwLowDateTime) / 10 - 11644473600000000ULL;
87 #else
88 struct timeval tv;
89 gettimeofday(&tv, NULL);
90 epoch = tv.tv_sec;
91 epoch *= 1000000;
92 epoch += tv.tv_usec;
93 #endif
94 return epoch;
95 }
96
97 #if defined(MIPI_SYST_PCFG_ENABLE_HEAP_MEMORY)
98 MIPI_SYST_EXPORT
mipi_syst_platform_alloc(size_t s)99 void * MIPI_SYST_CALLCONV mipi_syst_platform_alloc(size_t s)
100 {
101 return malloc(s);
102 }
103
104 MIPI_SYST_EXPORT
mipi_syst_platform_free(void * p)105 void MIPI_SYST_CALLCONV mipi_syst_platform_free(void * p)
106 {
107 free(p);
108 }
109
110 #endif /* defined(MIPI_SYST_PCFG_ENABLE_HEAP_MEMORY) */
111
112 /* helper class for generating STP protocol data
113 */
114 struct stp_writer_data {
115 FILE * fp; /* output */
116 mipi_syst_u8 byteDone; /* true = byte complete */
117 mipi_syst_u8 current; /* current byte value */
118 mipi_syst_u16 master; /* current master */
119 mipi_syst_u16 channel; /* current channel */
120 mipi_syst_u64 recordCount; /* count stp packets */
121
122 mipi_syst_u64 timestamp; /* first timestamp */
123 };
124
125
126 static struct stp_writer_data writer_state;
127
stp_write_putNibble(struct stp_writer_data * p,mipi_syst_u8 n)128 void stp_write_putNibble(struct stp_writer_data* p, mipi_syst_u8 n)
129 {
130 p->current |= (n<<4);
131 p->byteDone = ! p->byteDone;
132
133 if (p->byteDone) { /* push it out .. */
134 fputc(p->current, p->fp);
135 p->current = 0;
136 } else { /* first nibble, shift it down to b0..3 */
137 p->current >>= 4;
138 }
139 }
140
stp_write_flush(struct stp_writer_data * p)141 void stp_write_flush(struct stp_writer_data* p) {
142 if (!p->byteDone) {
143 stp_write_putNibble(p, 0);
144 }
145
146 fflush(p->fp);
147 }
stp_write_d4(struct stp_writer_data * p,mipi_syst_u8 v)148 void stp_write_d4(struct stp_writer_data* p, mipi_syst_u8 v) {
149 stp_write_putNibble(p, v);
150 }
151
stp_write_payload8(struct stp_writer_data * p,mipi_syst_u8 v)152 void stp_write_payload8(struct stp_writer_data* p, mipi_syst_u8 v) {
153 stp_write_d4(p, v);
154 stp_write_d4(p, v>>4);
155 }
156
stp_write_payload16(struct stp_writer_data * p,mipi_syst_u16 v)157 void stp_write_payload16(struct stp_writer_data* p, mipi_syst_u16 v) {
158 stp_write_payload8(p, (mipi_syst_u8)v);
159 stp_write_payload8(p, (mipi_syst_u8)(v>>8));
160 }
161
stp_write_payload32(struct stp_writer_data * p,mipi_syst_u32 v)162 void stp_write_payload32(struct stp_writer_data* p, mipi_syst_u32 v) {
163 stp_write_payload16(p, (mipi_syst_u16)v);
164 stp_write_payload16(p, (mipi_syst_u16)(v>>16));
165 }
166
stp_write_payload64(struct stp_writer_data * p,mipi_syst_u64 v)167 void stp_write_payload64(struct stp_writer_data* p, mipi_syst_u64 v) {
168 stp_write_payload32(p, (mipi_syst_u32)v);
169 stp_write_payload32(p, (mipi_syst_u32)(v>>32));
170 }
171
deltaTime(struct stp_writer_data * p)172 mipi_syst_u64 deltaTime(struct stp_writer_data* p)
173 {
174 mipi_syst_u64 delta;
175
176 delta = mipi_syst_get_epoch_us() - p->timestamp;
177 return delta * 60; /* simluate 60Mhz clock */
178 }
stp_write_d32mts(struct stp_writer_data * p,mipi_syst_u32 v)179 void stp_write_d32mts(struct stp_writer_data* p, mipi_syst_u32 v) {
180 stp_write_d4(p, 0xA);
181 stp_write_payload32(p, v);
182
183 stp_write_d4(p, 0xE);
184 stp_write_payload64(p, deltaTime(p));
185 }
186
stp_write_d64mts(struct stp_writer_data * p,mipi_syst_u64 v)187 void stp_write_d64mts(struct stp_writer_data* p, mipi_syst_u64 v) {
188 stp_write_d4(p, 0xB);
189 stp_write_payload64(p, v);
190
191 stp_write_d4(p, 0xE);
192 stp_write_payload64(p, deltaTime(p));
193 }
stp_write_d32ts(struct stp_writer_data * p,mipi_syst_u32 v)194 void stp_write_d32ts(struct stp_writer_data* p, mipi_syst_u32 v) {
195 stp_write_d4(p, 0xF);
196 stp_write_d4(p, 0x6);
197
198 stp_write_payload32(p, v);
199
200 stp_write_d4(p, 0xE);
201 stp_write_payload64(p, deltaTime(p));
202 }
203
stp_write_d8(struct stp_writer_data * p,mipi_syst_u8 v)204 void stp_write_d8(struct stp_writer_data* p, mipi_syst_u8 v) {
205 stp_write_d4(p, 0x4);
206 stp_write_payload8(p, v);
207 }
208
stp_write_d16(struct stp_writer_data * p,mipi_syst_u16 v)209 void stp_write_d16(struct stp_writer_data* p, mipi_syst_u16 v) {
210 stp_write_d4(p, 0x5);
211 stp_write_payload16(p, v);
212 }
213
214
stp_write_d32(struct stp_writer_data * p,mipi_syst_u32 v)215 void stp_write_d32(struct stp_writer_data* p, mipi_syst_u32 v) {
216 stp_write_d4(p, 0x6);
217 stp_write_payload32(p, v);
218 }
219
220
stp_write_d64(struct stp_writer_data * p,mipi_syst_u64 v)221 void stp_write_d64(struct stp_writer_data* p, mipi_syst_u64 v)
222 {
223 stp_write_d4(p, 0x7);
224 stp_write_payload64(p, v);
225 }
226
stp_write_flag(struct stp_writer_data * p)227 void stp_write_flag(struct stp_writer_data* p)
228 {
229 stp_write_d4(p, 0xF);
230 stp_write_d4(p, 0xE);
231 }
232
stp_write_async(struct stp_writer_data * p)233 void stp_write_async(struct stp_writer_data* p)
234 {
235 int i;
236 for(i=0; i < 21; ++i) {
237 stp_write_d4(p, 0xF);
238 }
239 stp_write_d4(p, 0x0);
240 }
241
stp_write_version(struct stp_writer_data * p)242 void stp_write_version(struct stp_writer_data* p)
243 {
244 stp_write_d4(p, 0xF);
245 stp_write_d4(p, 0x0);
246 stp_write_d4(p, 0x0);
247
248 stp_write_d4(p, 0x3); /* STPv2NAT */
249
250 p->master = p->channel = 0;
251 }
252
stp_write_freq(struct stp_writer_data * p)253 void stp_write_freq(struct stp_writer_data* p)
254 {
255 stp_write_d4(p, 0xF);
256 stp_write_d4(p, 0x0);
257 stp_write_d4(p, 0x8);
258 stp_write_payload32(p, 60 * 1000 * 1000 ); // 60 Mhz
259 }
260
stp_write_setMC(struct stp_writer_data * p,mipi_syst_u16 master,mipi_syst_u16 channel)261 void stp_write_setMC(struct stp_writer_data* p,
262 mipi_syst_u16 master,
263 mipi_syst_u16 channel)
264 {
265 /* re-send async after 20 packets */
266 if (!(p->recordCount++ % 20) ) {
267 stp_write_async(p);
268 stp_write_version(p);
269 stp_write_freq(p);
270 }
271
272 if (p->master != master ) {
273 stp_write_d4(p, 0xF);
274 stp_write_d4(p, 0x1);
275 stp_write_payload16(p, master);
276
277 p->master = master;
278 p->channel = 0;
279 }
280
281 if (p->channel != channel) {
282 stp_write_d4(p, 0xF);
283 stp_write_d4(p, 0x3);
284 stp_write_payload16(p, channel);
285
286 p->channel = channel;
287 }
288 }
289
290
291
292 /* output stream for STP data
293 */
294 static FILE * fp;
295 static mipi_syst_u16 master = 128; /* Default MIPI STP master:channel */
296 static mipi_syst_u16 channel = 1;
297
298
299 /* low level "driver" output routines */
300 static void sth_write_d32ts(struct mipi_syst_handle* systh, mipi_syst_u32 v);
301 static void sth_write_d32mts(struct mipi_syst_handle* systh, mipi_syst_u32 v);
302 static void sth_write_d64mts(struct mipi_syst_handle* systh, mipi_syst_u64 v);
303 static void sth_write_d8(struct mipi_syst_handle* systh, mipi_syst_u8 v);
304 static void sth_write_d16(struct mipi_syst_handle* systh, mipi_syst_u16 v);
305 static void sth_write_d32(struct mipi_syst_handle* systh, mipi_syst_u32 v);
306 #if defined(MIPI_SYST_PCFG_ENABLE_64BIT_IO)
307 static void sth_write_d64(struct mipi_syst_handle* systh, mipi_syst_u64 vp);
308 #endif
309 static void sth_write_user8ts(struct mipi_syst_handle* systh, mipi_syst_u8 v);
310 static void sth_write_flag(struct mipi_syst_handle* systh);
311
312 /*
313 * Platform specific SyS-T handle initialization hook function
314 *
315 * @param systh pointer to the new SyS-T handle structure
316 */
platform_handle_init(struct mipi_syst_handle * systh)317 static void platform_handle_init(struct mipi_syst_handle* systh)
318 {
319 LOCK();
320
321 /* Simply increment channels on each handle request and advance
322 * to next master if all consumed.
323 */
324 if (channel > 127) {
325 ++master;
326 channel = 1;
327 }
328
329 systh->systh_platform.channel = channel++;
330 systh->systh_platform.master = master;
331
332 UNLOCK();
333 }
334
335 /**
336 * Platform specific SyS-T handle initialization hook function
337 *
338 * @param systh pointer to the new SyS-T handle structure
339 */
platform_handle_release(struct mipi_syst_handle * systh)340 static void platform_handle_release(struct mipi_syst_handle* systh)
341 {
342 LOCK();
343
344 /* add any race protected cleanup code here
345 */
346
347 UNLOCK();
348 }
349
350 MIPI_SYST_EXPORT void MIPI_SYST_CALLCONV
mipi_syst_platform_init(struct mipi_syst_header * systh,const void * platform_data)351 mipi_syst_platform_init(struct mipi_syst_header* systh, const void * platform_data)
352 {
353 const char * filename;
354
355 LOCKING_INIT();
356
357 /* Platform data is expected to be UTF-8 string with the STP output
358 * file name.
359 */
360 filename = (const char *)platform_data;
361
362 if (filename == NULL ||!strcmp(filename, "-"))
363 {
364 fp = stdout;
365 } else {
366 fp = fopen((char*)platform_data, "wb");
367
368 if (fp == NULL) {
369 fprintf(stderr, "Unable to open file '%s'.\n", (char*)platform_data);
370 exit(-1);
371 }
372 }
373
374 /* create the STP output writer
375 */
376 writer_state.byteDone = 0;
377 writer_state.fp = fp;
378 writer_state.current = 0;
379 writer_state.master = 0;
380 writer_state.channel = 0;
381 writer_state.recordCount=0;
382 writer_state.timestamp = mipi_syst_get_epoch_us();
383
384 systh->systh_platform.stpWriter = & writer_state;
385
386 /* Set handle init hook that performs per SyS-T handle initialization
387 * and destruction
388 */
389 systh->systh_inith = platform_handle_init;
390 systh->systh_releaseh = platform_handle_release;
391
392 /* Initialize platform specific data in global SyS-T state
393 * This platform example puts its low level output function
394 * pointers here. A real implementation may have these "inlined"
395 * for performance reasons.
396 */
397 systh->systh_platform.write_d32ts = sth_write_d32ts;
398 systh->systh_platform.write_d32mts = sth_write_d32mts;
399 systh->systh_platform.write_d64mts = sth_write_d64mts;
400 systh->systh_platform.write_d8 = sth_write_d8;
401 systh->systh_platform.write_d16 = sth_write_d16;
402 systh->systh_platform.write_d32 = sth_write_d32;
403 #if defined(MIPI_SYST_PCFG_ENABLE_64BIT_IO)
404 systh->systh_platform.write_d64 = sth_write_d64;
405 #endif
406 systh->systh_platform.write_flag = sth_write_flag;
407 }
408
409 MIPI_SYST_EXPORT void MIPI_SYST_CALLCONV
mipi_syst_platform_destroy(struct mipi_syst_header * systh)410 mipi_syst_platform_destroy(struct mipi_syst_header* systh)
411 {
412 if (systh->systh_platform.stpWriter != NULL &&
413 systh->systh_platform.stpWriter->fp != NULL)
414 {
415 fflush(systh->systh_platform.stpWriter->fp);
416
417 if (systh->systh_platform.stpWriter->fp != stdout)
418 {
419 fclose(systh->systh_platform.stpWriter->fp);
420 systh->systh_platform.stpWriter->fp = NULL;
421 }
422 }
423
424 LOCKING_DESTROY();
425 }
426
427 #if !defined(MIPI_SYST_STATIC)
428
429 /*
430 * This example platform uses SyS-T as a shared library inside an
431 * application. The platform init hook is called during a shared library
432 * constructor call.
433 */
434 static MIPI_SYST_SHAREDLIB_CONSTRUCTOR
shared_library_init()435 void shared_library_init()
436 {
437 const char * filename;
438
439 filename = getenv("SYSTCAT_OUTPUT");
440 if (filename == NULL) {
441 filename = "syst_stp_data.bin";
442 }
443
444 MIPI_SYST_INIT(mipi_syst_platform_init, filename);
445
446 if (filename[0] != '-' && filename[1] != 0 ) {
447 printf("writing STP data into '%s' ...\n", filename);
448 }
449 }
450
451 /*
452 * This example platform uses SyS-T as a shared library inside an
453 * application. The platform destroy hook is called during a shared library
454 * destructor call.
455 */
shared_library_exit()456 static MIPI_SYST_SHAREDLIB_DESTRUCTOR void shared_library_exit()
457 {
458 MIPI_SYST_SHUTDOWN(mipi_syst_platform_destroy);
459 }
460
461 #if defined(_WIN32)
462 /*
463 * Windows DLL main routine, needed to run the global initialization and
464 * destruction handlers.
465 */
DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpReserved)466 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved )
467 {
468 switch(fdwReason) {
469 case DLL_PROCESS_ATTACH:
470 shared_library_init();
471 break;
472 case DLL_PROCESS_DETACH:
473 shared_library_exit();
474 break;
475 }
476 return TRUE;
477 }
478 #endif
479
480 #endif /* #if !defined(MIPI_SYST_STATIC) */
481
482
483 /* C code low level driver output routine wrappers for SyS-T
484 */
sth_write_d32ts(struct mipi_syst_handle * systh,mipi_syst_u32 v)485 static void sth_write_d32ts(struct mipi_syst_handle* systh, mipi_syst_u32 v)
486 {
487 struct stp_writer_data * writer = systh->systh_header->systh_platform.stpWriter;
488
489 /* Each message starts with d32ts. We use this as an */
490 /* indicator to lock the output writer until we wrote the */
491 /* end of record flag pattern. */
492 LOCK();
493
494
495 stp_write_setMC(writer,
496 systh->systh_platform.master, systh->systh_platform.channel );
497 stp_write_d32ts(writer, v);
498 }
499
500 /* short single 32 bit payload message */
sth_write_d32mts(struct mipi_syst_handle * systh,mipi_syst_u32 v)501 static void sth_write_d32mts(struct mipi_syst_handle* systh, mipi_syst_u32 v)
502 {
503 struct stp_writer_data * writer = systh->systh_header->systh_platform.stpWriter;
504
505 LOCK();
506
507 stp_write_setMC(writer,
508 systh->systh_platform.master,systh->systh_platform.channel );
509 stp_write_d32mts(writer, v);
510
511 UNLOCK();
512 }
513 /* short single 64 bit payload message */
sth_write_d64mts(struct mipi_syst_handle * systh,mipi_syst_u64 v)514 static void sth_write_d64mts(struct mipi_syst_handle* systh, mipi_syst_u64 v)
515 {
516 struct stp_writer_data * writer = systh->systh_header->systh_platform.stpWriter;
517
518 LOCK();
519
520 stp_write_setMC(writer,
521 systh->systh_platform.master,systh->systh_platform.channel );
522 stp_write_d64mts(writer, v);
523
524 UNLOCK();
525 }
sth_write_d8(struct mipi_syst_handle * systh,mipi_syst_u8 v)526 static void sth_write_d8(struct mipi_syst_handle* systh, mipi_syst_u8 v)
527 {
528 struct stp_writer_data * writer = systh->systh_header->systh_platform.stpWriter;
529 stp_write_d8(writer, v);
530 }
531
sth_write_d16(struct mipi_syst_handle * systh,mipi_syst_u16 v)532 static void sth_write_d16(struct mipi_syst_handle* systh, mipi_syst_u16 v)
533 {
534 struct stp_writer_data * writer = systh->systh_header->systh_platform.stpWriter;
535 stp_write_d16(writer, v);
536 }
537
sth_write_d32(struct mipi_syst_handle * systh,mipi_syst_u32 v)538 static void sth_write_d32(struct mipi_syst_handle* systh, mipi_syst_u32 v)
539 {
540 struct stp_writer_data * writer = systh->systh_header->systh_platform.stpWriter;
541 stp_write_d32(writer, v);
542 }
543
544 #if defined(MIPI_SYST_PCFG_ENABLE_64BIT_IO)
sth_write_d64(struct mipi_syst_handle * systh,mipi_syst_u64 v)545 static void sth_write_d64(struct mipi_syst_handle* systh, mipi_syst_u64 v)
546 {
547 struct stp_writer_data * writer = systh->systh_header->systh_platform.stpWriter;
548 stp_write_d64(writer, v);
549 }
550 #endif
551
sth_write_flag(struct mipi_syst_handle * systh)552 static void sth_write_flag(struct mipi_syst_handle* systh)
553 {
554 struct stp_writer_data * writer = systh->systh_header->systh_platform.stpWriter;
555
556 stp_write_flag(writer);
557 stp_write_flush(writer);
558
559 /* atomic record write done - matching lock was in sth_write_d32ts() */
560 UNLOCK();
561 }