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 }