5aa1086647fa09a59f37a2e3b938bb60b5885bf4
1 /******************************************************************************
2 @file stream_common.c
4 @brief TIMAC 2.0 API Common/shared code for all stream types
6 Group: WCS LPC
7 $Target Devices: Linux: AM335x, Embedded Devices: CC1310, CC1350$
9 ******************************************************************************
10 $License: BSD3 2016 $
12 Copyright (c) 2015, Texas Instruments Incorporated
13 All rights reserved.
15 Redistribution and use in source and binary forms, with or without
16 modification, are permitted provided that the following conditions
17 are met:
19 * Redistributions of source code must retain the above copyright
20 notice, this list of conditions and the following disclaimer.
22 * Redistributions in binary form must reproduce the above copyright
23 notice, this list of conditions and the following disclaimer in the
24 documentation and/or other materials provided with the distribution.
26 * Neither the name of Texas Instruments Incorporated nor the names of
27 its contributors may be used to endorse or promote products derived
28 from this software without specific prior written permission.
30 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
31 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
32 THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
33 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
34 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
35 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
36 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
37 OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
38 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
39 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
40 EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41 ******************************************************************************
42 $Release Name: TI-15.4Stack Linux x64 SDK$
43 $Release Date: July 14, 2016 (2.00.00.30)$
44 *****************************************************************************/
46 #include "compiler.h"
47 #include "stream.h"
48 #include "log.h"
49 #include "timer.h"
50 #include "void_ptr.h"
52 #define _STREAM_IMPLIMENTOR_ 1
53 #include "stream_private.h"
55 #include <string.h>
56 #include <stdarg.h>
57 #include <stdlib.h>
59 /*
60 * Globals defined in stream.h
61 */
62 intptr_t STREAM_stdout;
63 intptr_t STREAM_stderr;
64 intptr_t STREAM_stdin;
65 intptr_t STREAM_debug_stdin;
66 intptr_t STREAM_debug_stdout;
68 /* used to verify a stream pointer */
69 static const int stream_check = 'S' + 'C';
71 /*
72 * Destroy a pseudo-private stream internal structure
73 *
74 * Pseudo-private to stream implimentations, see stream_private.h
75 */
76 void STREAM_destroyPrivate(struct io_stream *pIO)
77 {
78 if(pIO == NULL)
79 {
80 return;
81 }
82 /* we have nothing to release */
83 memset((void *)(pIO), 0, sizeof(*pIO));
84 free((void *)(pIO));
85 }
87 /*
88 * Create a pseudo-private stream internal structure
89 *
90 * Pseudo-private to streams, see stream_private.h
91 */
92 struct io_stream *STREAM_createPrivate(const struct io_stream_funcs *pFuncs,
93 intptr_t opaque)
94 {
95 struct io_stream *pIO;
97 pIO = calloc(1, sizeof(*pIO));
98 if(pIO)
99 {
100 pIO->check_ptr = &stream_check;
101 pIO->pFuncs = pFuncs;
102 pIO->opaque_ptr = opaque;
103 }
104 return (pIO);
105 }
107 /*
108 * Determine if a stream is currently marked as "in-error"
109 *
110 * Public function defined in stream.h
111 */
112 bool STREAM_isError(intptr_t h)
113 {
114 bool b;
115 struct io_stream *pIO;
117 b = true;
118 if(h)
119 {
120 pIO = STREAM_hToStruct(h);
121 if(pIO)
122 {
123 b = pIO->is_error;
124 }
125 }
126 return (b);
127 }
129 /*
130 * Convert a stream structure into a stream handle
131 *
132 * Pseudo-private to stream implimentations, see stream_private.h
133 */
134 intptr_t STREAM_structToH(struct io_stream *pIO)
135 {
136 return (intptr_t)(pIO);
137 }
139 /*
140 * Convert a stream handle into a stream structure
141 *
142 * Pseudo-private to stream implimentations, see stream_private.h
143 */
144 struct io_stream *STREAM_hToStruct(intptr_t h)
145 {
146 struct io_stream *pIO;
148 pIO = (struct io_stream *)(h);
149 if(pIO)
150 {
151 if(pIO->check_ptr != &stream_check)
152 {
153 pIO = NULL;
154 }
155 }
156 if(pIO == NULL)
157 {
158 LOG_printf(LOG_ERROR, "not-a-stream: %p\n", (void *)(h));
159 }
160 return (pIO);
161 }
163 /*
164 * Initialize the stream module as a whole
165 *
166 * Public function defined in stream.h
167 */
168 void STREAM_init(void)
169 {
170 STREAM_FILE_init();
171 }
173 /*
174 * Get the type name of a stream
175 *
176 * Public function defined in stream.h
177 */
178 const char *STREAM_getTypeName(intptr_t s)
179 {
180 const struct io_stream *pIO;
182 pIO = STREAM_hToStruct(s);
183 if(pIO == NULL)
184 {
185 return ("(unknown)");
186 }
188 return (pIO->pFuncs->name);
189 }
191 /*
192 * printf() to a stream
193 *
194 * Public function defined in stream.h
195 */
196 int STREAM_printf(intptr_t s, _Printf_format_string_ const char *fmt, ...)
197 {
198 int r;
199 va_list ap;
201 va_start(ap,fmt);
202 r = STREAM_vprintf(s, fmt, ap);
203 va_end(ap);
204 return (r);
205 }
207 /*
208 * Building block for STREAM_printf()
209 *
210 * Public function defined in stream.h
211 */
212 int STREAM_vprintf(intptr_t s, const char *fmt, va_list ap)
213 {
214 int r;
215 /* Depending upon the internal "printf()" implimentation
216 * this function could be written many ways...
217 * this is a simple and fast method that works
218 * note we are on linux, we have plenty of stack space */
219 char buf[1024];
221 r = vsnprintf(buf, sizeof(buf), fmt, ap);
222 /* forcably terminate */
223 buf[ sizeof(buf)-1 ] = 0;
225 /* something go wrong/ */
226 if(r <= 0)
227 {
228 return (r);
229 }
231 /* in case users string is larger then expected */
232 if(r > 1024)
233 {
234 /* truncate */
235 r = 1024;
236 }
238 /* send it off */
239 return (STREAM_wrBytes(s, buf, r, -1));
240 }
242 /*
243 * Unix fputc() for a stream.
244 *
245 * Public function defined in stream.h
246 */
247 int STREAM_fputc(int c, intptr_t s)
248 {
249 uint8_t b;
250 int r;
252 b = (uint8_t)(c);
254 r = STREAM_wrBytes(s, &b, 1, -1);
255 if(r == 1)
256 {
257 c = c & 0x0ff;
258 }
259 else
260 {
261 c = EOF;
262 }
263 return (c);
264 }
266 /*
267 * Unix ungetc() against a stream
268 *
269 * Public function defined in stream.h
270 */
271 int STREAM_ungetc(int c, intptr_t s)
272 {
273 struct io_stream *pIO;
275 pIO = STREAM_hToStruct(s);
276 if(pIO == NULL)
277 {
278 return (-1);
279 }
280 pIO->unget_buf = (c & 0x0ff) | 0x0100;
281 return (0);
282 }
284 /*
285 * Unix fgetc() against a stream
286 *
287 * Public function defined in stream.h
288 */
289 int STREAM_fgetc(intptr_t s)
290 {
291 struct io_stream *pIO;
292 char c;
293 int r;
295 pIO = STREAM_hToStruct(s);
296 if(pIO == NULL)
297 {
298 return (-1);
299 }
301 if(pIO->unget_buf)
302 {
303 c = (char)(pIO->unget_buf);
304 pIO->unget_buf = 0;
305 return ((int)(c) & 0x0ff);
306 }
307 r = STREAM_rdBytes(s, &c, 1, -1);
308 if(r > 0)
309 {
310 r = c;
311 r = r & 0x0ff;
312 }
313 else if(r == 0)
314 {
315 /* we read nothing, thus we return EOF */
316 r = EOF;
317 }
318 else
319 {
320 pIO->is_error = true;
321 r = EOF;
322 }
323 return (r);
324 }
326 /*
327 * Unix fgets() against a stream
328 *
329 * Public function defined in stream.h
330 */
331 char *STREAM_fgets(char *buf, int size, intptr_t h)
332 {
333 /* read a line of ascii until a universal line ending is found. */
334 /* universal means: UNIX, DOS, or MAC - or MIXED formats are ok. */
335 int c;
336 int n;
338 /* for debug reasons */
339 buf[0] = 0;
340 /* always terminate */
341 buf[size-1] = 0;
343 /* always insure space for a null byte */
344 size--;
346 /* incase the string is zero length (can't really happen) */
347 /* but visual studio warnings thinks it can happen.. */
348 c = 0;
350 /* read till terminator */
351 for(n = 0 ; n < size ; )
352 {
353 c = STREAM_fgetc(h);
354 if(c < 0)
355 {
356 /* EOF or err */
357 break;
358 }
359 buf[n+1] = 0;
360 buf[n+0] = (char)(c & 0x0ff);
361 n++;
362 /* any type of line ending? */
363 if((c == '\n') || (c=='\r'))
364 {
365 /* Unix line endings */
366 break;
367 }
368 }
370 if(c == '\r')
371 {
372 /* we have 2 possible cases: */
373 /* MAC line endings: text<CR>text */
374 /* DOS line endings: text<CR><LF>text */
375 /* ----- */
376 /* Peek ahead look for the DOS <lf> */
377 c = STREAM_fgetc(h);
378 if(c < 0)
379 {
380 /* odd situation */
381 /* could be EOF, or ERROR */
382 /* we are not going to unget this. */
383 }
384 else if(c != '\n')
385 {
386 /* Undo! this is a MAC end of line */
387 STREAM_ungetc(c, h);
388 }
389 else
390 {
391 /* we need to store the <lf> */
392 if(n >= size)
393 {
394 /* ERROR: Edge condition, No room for the LF */
395 /* so we silently throw it away */
396 }
397 else
398 {
399 /* we have room for the LF */
400 buf[n+0] = ((char)(c));
401 buf[n+1] = 0;
402 n++;
403 }
404 }
405 }
406 if(n)
407 {
408 /* we got something */
409 /* we return buf (below); */
410 }
411 else
412 {
413 /* We must have an EOF */
414 buf = NULL;
415 }
416 return (buf);
417 }
419 /*
420 * Unix fputs() against a stream
421 *
422 * Public function defined in stream.h
423 */
424 int STREAM_fputs(const char *s, intptr_t h)
425 {
426 int r;
427 /* write an ascii string to the file */
428 r = STREAM_wrBytes(h, s, strlen(s),-1);
429 return (r);
430 }
432 /*
433 * Write bytes into a stream
434 *
435 * Public function defined in stream.h
436 */
437 int STREAM_wrBytes(intptr_t h,
438 const void *databytes,
439 size_t nbytes,
440 int timeout_mSecs)
441 {
442 struct io_stream *pIO;
444 /* write bytes (raw) to the file */
445 pIO = STREAM_hToStruct(h);
446 if(pIO == NULL)
447 {
448 return (-1);
449 }
451 return ((*(pIO->pFuncs->wr_fn))(pIO, databytes, nbytes, timeout_mSecs));
452 }
454 /*
455 * Read bytes from a stream
456 *
457 * Public function defined in stream.h
458 */
459 int STREAM_rdBytes(intptr_t h,
460 void *databytes,
461 size_t nbytes,
462 int timeout_mSecs)
463 {
464 /* read (raw) from file and honor the ungetc case. */
465 struct io_stream *pIO;
466 int n;
467 int r;
469 if(nbytes == 0)
470 {
471 return (0);
472 }
474 pIO = STREAM_hToStruct(h);
475 if(pIO == NULL)
476 {
477 return (-1);
478 }
480 n = 0;
481 /* do we have an unget case? */
482 if(pIO->unget_buf)
483 {
484 /* we have an unget byte! */
485 ((char *)(databytes))[0] = (char)(pIO->unget_buf & 0x0ff);
486 pIO->unget_buf = 0;
487 nbytes -= 1;
488 databytes = void_ptr_add(databytes, 1);
489 n = 1;
490 /* Do we have great success! */
491 if(nbytes == 0)
492 {
493 return (1);
494 }
495 }
497 /* call specific */
498 r = (*(pIO->pFuncs->rd_fn))(pIO, databytes, nbytes, timeout_mSecs);
500 /* if UNGET did not occur */
501 /* just return what we got. */
502 if(n == 0)
503 {
504 return (r);
505 }
507 /* we did an UNGET */
508 /* But maybe the read call failed? */
509 if(r >= 0)
510 {
511 /* no it did not, return succes */
512 r += n;
513 return (r);
514 }
516 /* we had a failure */
517 /* But we got something from the undo buffer. */
518 /* So... it is success (posix rules!) */
519 return (1);
520 }
522 /*
523 * Return positive number if bytes are available from a stream
524 *
525 * Note: it may return 1, when there are hundreds of bytes available.
526 * Some streams cannot perform 'deep' inspection.
527 *
528 * Public function defined in stream.h
529 */
530 int STREAM_rxAvail(intptr_t h, int timeout_mSec)
531 {
532 /* do we have bytes available? */
533 struct io_stream *pIO;
535 pIO = STREAM_hToStruct(h);
536 if(pIO == NULL)
537 {
538 /* we have nothing available. */
539 return (0);
540 }
541 /* yes we do have at least 1 */
542 if(pIO->unget_buf)
543 {
544 return (1);
545 }
547 /* call handler otherwise */
548 return ((*(pIO->pFuncs->poll_fn))(pIO,timeout_mSec));
549 }
551 /*
552 * Flush (write-commit) all data in a stream to the output device
553 *
554 * Public function defined in stream.h
555 */
556 int STREAM_flush(intptr_t h)
557 {
558 /* write/commit data */
559 struct io_stream *pIO;
561 pIO = STREAM_hToStruct(h);
562 if(pIO == NULL)
563 {
564 return (-1);
565 }
567 return ((*(pIO->pFuncs->flush_fn))(pIO));
568 }
570 /*
571 * Close a stream (does not always destroy the stream)
572 * In some cases this requires additional steps that are
573 * stream specific
574 *
575 * Public function defined in sream.h
576 */
577 void STREAM_close(intptr_t h)
578 {
579 /* close the stream */
580 struct io_stream *pIO;
582 pIO = STREAM_hToStruct(h);
583 if(pIO)
584 {
585 (*(pIO->pFuncs->close_fn))(pIO);
586 }
587 }
589 /*
590 * Clear stream error flag
591 *
592 * Public function defined in sream.h
593 */
594 void STREAM_clearErrors(intptr_t h)
595 {
596 struct io_stream *pIO;
598 pIO = STREAM_hToStruct(h);
599 if(pIO)
600 {
601 (*(pIO->pFuncs->clear_fn))(pIO);
602 pIO->is_error = false;
603 }
604 }
606 /*
607 * Dump (flush) all incomming data for a stream
608 *
609 * Public function defined in stream.h
610 */
611 void STREAM_rdDump(intptr_t h, int timeout_mSecs)
612 {
613 int r;
614 timertoken_t tstart;
615 uint8_t buf[256];
616 int total;
618 tstart = TIMER_timeoutStart();
620 total = 0;
621 for(;;)
622 {
623 r = STREAM_rdBytes(h, &buf, sizeof(buf), 0);
624 if(r > 0)
625 {
626 total += r;
627 if( total > __1K ){
628 BUG_HERE("target has crashed, and is spewing bytes\n");
629 }
630 continue;
631 }
632 if(r < 0)
633 {
634 /* io error? */
635 break;
636 }
637 if(TIMER_timeoutIsExpired(tstart, timeout_mSecs))
638 {
639 break;
640 }
641 }
642 }
644 /*
645 * ========================================
646 * Texas Instruments Micro Controller Style
647 * ========================================
648 * Local Variables:
649 * mode: c
650 * c-file-style: "bsd"
651 * tab-width: 4
652 * c-basic-offset: 4
653 * indent-tabs-mode: nil
654 * End:
655 * vim:set filetype=c tabstop=4 shiftwidth=4 expandtab=true
656 */