Difference between revisions of "Embedded Studio Library IO"

From SEGGER Wiki
Jump to: navigation, search
m (fixed typo)
 
(7 intermediate revisions by 3 users not shown)
Line 1: Line 1:
 
The debugger and the Runtime Library of Embedded Studio support different mechanisms for debug input and output.
 
The debugger and the Runtime Library of Embedded Studio support different mechanisms for debug input and output.
 
The mechanism to be used in a project can easily be selected in the project options at Library -> Library I/O and does not require any additional file or configuration.
 
The mechanism to be used in a project can easily be selected in the project options at Library -> Library I/O and does not require any additional file or configuration.
  +
  +
'''Note:''' Embedded Studio versions prior to V6 included two versions of the runtime library:
  +
The legacy "Embedded Studio Runtime Library" and the "SEGGER Runtime Library".
  +
This article is about the SEGGER Runtime Library, which is used by Embedded Studio V6 and most projects created with Embedded Studio V5.50 or later.
   
 
== Library I/O Mechanisms ==
 
== Library I/O Mechanisms ==
Line 14: Line 18:
   
 
Available on all Cortex-M based systems.
 
Available on all Cortex-M based systems.
  +
  +
'''Note:'''
  +
Older projects might include SEGGER_RTT_Syscalls_SES.c or a similar file to override printf().
  +
When using the SEGGER Runtime Library, this file should be removed from the project,
  +
or its content should be encapsulated with <code>#if !defined(__SEGGER_RTL_VERSION) ... #endif</code>
  +
  +
SEGGER Embedded Studio provides RTT <code>printf();</code> functionality automatically.
  +
  +
To use the full RTT API, the RTT Target Package needs to be added to the Embedded Studio project: [https://wiki.segger.com/RTT_in_Embedded_Studio RTT in Embedded Studio]
   
 
=== SWO ===
 
=== SWO ===
Line 42: Line 55:
   
 
==== User-supplied I/O ====
 
==== User-supplied I/O ====
''Note: This section applies to Embedded Studio V6.10 and later.''
+
''Note: This section applies to Embedded Studio V6.12 and later.''
   
 
When no standard I/O mechanism is implemented, the user can supply an implementation of the low-level routines to do output and optionally input.
 
When no standard I/O mechanism is implemented, the user can supply an implementation of the low-level routines to do output and optionally input.
Line 53: Line 66:
 
int __SEGGER_RTL_X_file_unget(__SEGGER_RTL_FILE *stream, int c); // Push character back to stream. >= 0: OK. < 0: Error.
 
int __SEGGER_RTL_X_file_unget(__SEGGER_RTL_FILE *stream, int c); // Push character back to stream. >= 0: OK. < 0: Error.
   
  +
A Embedded Studio project for the emPower board that exposes I/O of a UART port can be downloaded here: [[File:RTL-UART-IO.zip]]
   
  +
A minimal implementation of the I/O functions could look like the below:
The default implementations are:
 
   
  +
<source lang="C">
int __SEGGER_RTL_X_file_stat(__SEGGER_RTL_FILE *stream) {
 
  +
/*********************************************************************
return 0; // Assume only stdout/stdin/stderr is used and always valid.
 
  +
* (c) SEGGER Microcontroller GmbH *
}
 
  +
* The Embedded Experts *
  +
* www.segger.com *
  +
**********************************************************************
   
  +
-------------------------- END-OF-HEADER -----------------------------
int __SEGGER_RTL_X_file_bufsize(__SEGGER_RTL_FILE *stream) {
 
  +
Purpose : Implementation of low-level functions for I/O with the
return 1; // 1 for unbuffered I/O. Otherwise 80.
 
  +
SEGGER Runtime Library
}
 
  +
using a UART (SEGGER's BSP UART module)
  +
*/
   
  +
/*********************************************************************
int __SEGGER_RTL_X_file_read(__SEGGER_RTL_FILE * stream, char * s, unsigned len) {
 
  +
*
return EOF; // Read not implemented
 
  +
* #include section
}
 
  +
*
  +
**********************************************************************
  +
*/
   
  +
#include "__SEGGER_RTL_Int.h"
int __SEGGER_RTL_X_file_write(__SEGGER_RTL_FILE *stream, const char *s, unsigned len) {
 
  +
#include "stdio.h"
while (len > 0) {
 
  +
#include "BSP_UART.h"
UART_SendByte(*s++); // Output any stream to UART.
 
--len;
 
}
 
return 0;
 
}
 
   
  +
/*********************************************************************
int __SEGGER_RTL_X_file_unget(__SEGGER_RTL_FILE *stream, int c) {
 
  +
*
return EOF; // Unget not implemented.
 
  +
* Prototypes
}
 
  +
*
  +
**********************************************************************
  +
*/
  +
void RTL_UART_Init(unsigned int Unit, unsigned long Baudrate, unsigned char NumDataBits, unsigned char Parity, unsigned char NumStopBits);
   
  +
/*********************************************************************
A Embedded Studio project for the emPower board that exposes I/O of a UART port can be downloaded here: (FIXME)
 
  +
*
  +
* Local types
  +
*
  +
**********************************************************************
  +
*/
   
  +
struct __SEGGER_RTL_FILE_impl { // NOTE: Provides implementation for FILE
A minimal implementation of the I/O functions could look like the below:
 
  +
int stub; // only needed so impl has size != 0.
  +
};
   
  +
/*********************************************************************
  +
*
  +
* Static data
  +
*
  +
**********************************************************************
  +
*/
   
  +
static FILE __SEGGER_RTL_stdin_file = { 0 }; // stdin reads from UART
/*********************************************************************
 
  +
static FILE __SEGGER_RTL_stdout_file = { 0 }; // stdout writes to UART
* (c) SEGGER Microcontroller GmbH *
 
  +
static FILE __SEGGER_RTL_stderr_file = { 0 }; // stderr writes to UART
* The Embedded Experts *
 
  +
* www.segger.com *
 
  +
static unsigned int _UART_Port = 0;
**********************************************************************
 
  +
static int _stdin_ungot = EOF;
 
  +
-------------------------- END-OF-HEADER -----------------------------
 
  +
/*********************************************************************
Purpose : Implementation of low-level functions for I/O with the
 
  +
*
SEGGER Runtime Library
 
  +
* Public data
using a UART (SEGGER's BSP UART module)
 
*/
+
*
  +
**********************************************************************
 
  +
*/
/*********************************************************************
 
  +
*
 
  +
FILE *stdin = &__SEGGER_RTL_stdin_file; // NOTE: Provide implementation of stdin for RTL.
* #include section
 
  +
FILE *stdout = &__SEGGER_RTL_stdout_file; // NOTE: Provide implementation of stdout for RTL.
*
 
  +
FILE *stderr = &__SEGGER_RTL_stderr_file; // NOTE: Provide implementation of stderr for RTL.
**********************************************************************
 
  +
*/
 
  +
/*********************************************************************
 
  +
*
#include "__SEGGER_RTL_Int.h"
 
  +
* Static code
#include "stdio.h"
 
  +
*
#include "BSP_UART.h"
 
  +
**********************************************************************
 
  +
*/
/*********************************************************************
 
  +
*
 
  +
/*********************************************************************
* Prototypes
 
*
+
*
  +
* _stdin_getc()
**********************************************************************
 
*/
+
*
  +
* Function description
void RTL_UART_Init(unsigned int Unit, unsigned long Baudrate, unsigned char NumDataBits, unsigned char Parity, unsigned char NumStopBits);
 
  +
* Get character from standard input.
 
  +
*
/*********************************************************************
 
  +
* Return value
*
 
  +
* Character received.
* Local types
 
*
+
*
  +
* Additional information
**********************************************************************
 
  +
* This function never fails to deliver a character.
*/
 
  +
*/
 
  +
static char _stdin_getc(void) {
struct __SEGGER_RTL_FILE_impl { // NOTE: Provides implementation for FILE
 
  +
unsigned char c;
int stub; // only needed so impl has size != 0.
 
  +
};
 
  +
if (_stdin_ungot != EOF) {
 
  +
c = _stdin_ungot;
/*********************************************************************
 
  +
_stdin_ungot = EOF;
*
 
  +
} else {
* Static data
 
  +
BSP_UART_ReadBlocking(_UART_Port, &c, sizeof(c));
*
 
**********************************************************************
 
*/
 
 
static FILE __SEGGER_RTL_stdin_file = { 0 }; // stdin reads from UART
 
static FILE __SEGGER_RTL_stdout_file = { 0 }; // stdout writes to UART
 
static FILE __SEGGER_RTL_stderr_file = { 0 }; // stderr writes to UART
 
 
static unsigned int _UART_Port = 0;
 
static int _stdin_ungot = EOF;
 
 
/*********************************************************************
 
*
 
* Public data
 
*
 
**********************************************************************
 
*/
 
 
FILE *stdin = &__SEGGER_RTL_stdin_file; // NOTE: Provide implementation of stdin for RTL.
 
FILE *stdout = &__SEGGER_RTL_stdout_file; // NOTE: Provide implementation of stdout for RTL.
 
FILE *stderr = &__SEGGER_RTL_stderr_file; // NOTE: Provide implementation of stderr for RTL.
 
 
/*********************************************************************
 
*
 
* Static code
 
*
 
**********************************************************************
 
*/
 
 
/*********************************************************************
 
*
 
* _stdin_getc()
 
*
 
* Function description
 
* Get character from standard input.
 
*
 
* Return value
 
* Character received.
 
*
 
* Additional information
 
* This function never fails to deliver a character.
 
*/
 
static char _stdin_getc(void) {
 
unsigned char c;
 
 
if (_stdin_ungot != EOF) {
 
c = _stdin_ungot;
 
_stdin_ungot = EOF;
 
} else {
 
BSP_UART_ReadBlocking(_UART_Port, &c, sizeof(c));
 
}
 
return c;
 
 
}
 
}
  +
return c;
 
  +
}
/*********************************************************************
 
  +
*
 
  +
/*********************************************************************
* Public code
 
*
+
*
  +
* Public code
**********************************************************************
 
*/
+
*
  +
**********************************************************************
 
  +
*/
/*********************************************************************
 
  +
*
 
  +
/*********************************************************************
* RTL_UART_Init()
 
*
+
*
  +
* RTL_UART_Init()
* Function description
 
  +
*
* Initialize RTL to use given UART for stdio.
 
  +
* Function description
*
 
  +
* Initialize RTL to use given UART for stdio.
* Parameters
 
  +
*
* Unit : UART unit number (typically zero-based).
 
  +
* Parameters
* Baudrate : Baud rate to configure [Hz].
 
  +
* Unit : UART unit number (typically zero-based).
* NumDataBits: Number of data bits to use.
 
* Parity : One of the following values:
+
* Baudrate : Baud rate to configure [Hz].
  +
* NumDataBits: Number of data bits to use.
* * BSP_UART_PARITY_NONE
 
* * BSP_UART_PARITY_ODD
+
* Parity : One of the following values:
* * BSP_UART_PARITY_EVEN
+
* * BSP_UART_PARITY_NONE
  +
* * BSP_UART_PARITY_ODD
* NumStopBits: Number of stop bits to use.
 
  +
* * BSP_UART_PARITY_EVEN
*
 
  +
* NumStopBits: Number of stop bits to use.
* Additional description
 
  +
*
* Parameters are same as for BSP_UART_Init().
 
  +
* Additional description
* This also sets appropriate RX and TX interrupt handlers.
 
  +
* Parameters are same as for BSP_UART_Init().
*/
 
  +
* This also sets appropriate RX and TX interrupt handlers.
void RTL_UART_Init(unsigned int Unit, unsigned long Baudrate, unsigned char NumDataBits, unsigned char Parity, unsigned char NumStopBits) {
 
  +
*/
_UART_Port = Unit;
 
BSP_UART_Init(_UART_Port, Baudrate, NumDataBits, Parity, NumStopBits);
+
void RTL_UART_Init(unsigned int Unit, unsigned long Baudrate, unsigned char NumDataBits, unsigned char Parity, unsigned char NumStopBits) {
  +
_UART_Port = Unit;
  +
BSP_UART_Init(_UART_Port, Baudrate, NumDataBits, Parity, NumStopBits);
  +
}
  +
  +
/*********************************************************************
  +
*
  +
* __SEGGER_RTL_X_file_stat()
  +
*
  +
* Function description
  +
* Get file status.
  +
*
  +
* Parameters
  +
* stream - Pointer to file.
  +
*
  +
* Additional information
  +
* Low-overhead test to determine if stream is valid. If stream
  +
* is a valid pointer and the stream is open, this function must
  +
* succeed. If stream is a valid pointer and the stream is closed,
  +
* this function must fail.
  +
*
  +
* The implementation may optionally determine whether stream is
  +
* a valid pointer: this may not always be possible and is not
  +
* required, but may assist debugging when clients provide wild
  +
* pointers.
  +
*
  +
* Return value
  +
* < 0 - Failure, stream is not a valid file.
  +
* >= 0 - Success, stream is a valid file.
  +
*/
  +
int __SEGGER_RTL_X_file_stat(FILE *stream) {
  +
if (stream == stdin || stream == stdout || stream == stderr) {
  +
return 0; // NOTE: stdin, stdout, and stderr are assumed to be valid.
  +
} else {
  +
return EOF;
 
}
 
}
  +
}
 
  +
/*********************************************************************
 
  +
/*********************************************************************
*
 
  +
*
* __SEGGER_RTL_X_file_stat()
 
  +
* __SEGGER_RTL_X_file_bufsize()
*
 
  +
*
* Function description
 
  +
* Function description
* Get file status.
 
  +
* Get stream buffer size.
*
 
  +
*
* Parameters
 
  +
* Parameters
* stream - Pointer to file.
 
  +
* stream - Pointer to file.
*
 
  +
*
* Additional information
 
  +
* Additional information
* Low-overhead test to determine if stream is valid. If stream
 
  +
* Returns the number of characters to use for buffered I/O on
* is a valid pointer and the stream is open, this function must
 
* succeed. If stream is a valid pointer and the stream is closed,
+
* the file stream. The I/O buffer is allocated on the stack
  +
* for the duration of the I/O call, therefore this value should
* this function must fail.
 
  +
* not be set arbitrarily large.
*
 
  +
*
* The implementation may optionally determine whether stream is
 
  +
* For unbuffered I/O, return 1.
* a valid pointer: this may not always be possible and is not
 
  +
*
* required, but may assist debugging when clients provide wild
 
  +
* Return value
* pointers.
 
  +
* Nonzero number of characters to use for buffered I/O; for
*
 
  +
* unbuffered I/O, return 1.
* Return value
 
  +
*/
* < 0 - Failure, stream is not a valid file.
 
  +
int __SEGGER_RTL_X_file_bufsize(FILE *stream) {
* >= 0 - Success, stream is a valid file.
 
  +
(void)stream;
*/
 
  +
return 1;
int __SEGGER_RTL_X_file_stat(FILE *stream) {
 
  +
}
if (stream == stdin || stream == stdout || stream == stderr) {
 
  +
return 0; // NOTE: stdin, stdout, and stderr are assumed to be valid.
 
  +
/*********************************************************************
} else {
 
  +
*
return EOF;
 
  +
* __SEGGER_RTL_X_file_read()
  +
*
  +
* Function description
  +
* Read data from file.
  +
*
  +
* Parameters
  +
* stream - Pointer to file to read from.
  +
* s - Pointer to object that receives the input.
  +
* len - Number of characters to read from file.
  +
*
  +
* Return value
  +
* >= 0 - Success, amount of data read.
  +
* < 0 - Failure.
  +
*
  +
* Additional information
  +
* Reading from any stream other than stdin results in an error.
  +
*/
  +
int __SEGGER_RTL_X_file_read(FILE *stream, char *s, unsigned len) {
  +
int c;
  +
  +
if (stream == stdin) {
  +
c = 0;
  +
while (len > 0) {
  +
*s = _stdin_getc();
  +
++s;
  +
++c;
  +
--len;
 
}
 
}
  +
} else {
  +
c = EOF;
 
}
 
}
  +
return c;
 
  +
}
/*********************************************************************
 
  +
*
 
  +
/*********************************************************************
* __SEGGER_RTL_X_file_bufsize()
 
*
+
*
  +
* __SEGGER_RTL_X_file_write()
* Function description
 
  +
*
* Get stream buffer size.
 
  +
* Function description
*
 
  +
* Write data to file.
* Parameters
 
  +
*
* stream - Pointer to file.
 
  +
* Parameters
*
 
  +
* stream - Pointer to file to write to.
* Additional information
 
* Returns the number of characters to use for buffered I/O on
+
* s - Pointer to object to write to file.
* the file stream. The I/O buffer is allocated on the stack
+
* len - Number of characters to write to the file.
  +
*
* for the duration of the I/O call, therefore this value should
 
  +
* Return value
* not be set arbitrarily large.
 
  +
* >= 0 - Success.
*
 
* For unbuffered I/O, return 1.
+
* < 0 - Failure.
*
+
*
  +
* Additional information
* Return value
 
  +
* this version is NOT reentrant!
* Nonzero number of characters to use for buffered I/O; for
 
  +
* stdout and stderr are directed to UART;
* unbuffered I/O, return 1.
 
  +
* writing to any stream other than stdout or stderr results in an error
*/
 
  +
*/
int __SEGGER_RTL_X_file_bufsize(FILE *stream) {
 
  +
int __SEGGER_RTL_X_file_write(FILE *stream, const char *s, unsigned len) {
(void)stream;
 
  +
if ((stream == stdout) || (stream == stderr)) {
return 1;
 
  +
BSP_UART_WriteBlocking(_UART_Port, (const unsigned char*) s, len);
  +
return len;
  +
} else {
  +
return EOF;
 
}
 
}
  +
}
 
  +
/*********************************************************************
 
  +
/*********************************************************************
*
 
  +
*
* __SEGGER_RTL_X_file_read()
 
  +
* __SEGGER_RTL_X_file_unget()
*
 
  +
*
* Function description
 
  +
* Function description
* Read data from file.
 
  +
* Push character back to stream.
*
 
  +
*
* Parameters
 
  +
* Parameters
* stream - Pointer to file to read from.
 
* s - Pointer to object that receives the input.
+
* stream - Pointer to file to push back to.
* len - Number of characters to read from file.
+
* c - Character to push back.
*
+
*
* Return value
+
* Return value
* >= 0 - Success, amount of data read.
+
* >= 0 - Success.
* < 0 - Failure.
+
* < 0 - Failure.
*
+
*
* Additional information
+
* Additional information
  +
* Push-back is only supported for standard input, and
* Reading from any stream other than stdin results in an error.
 
  +
* only a single-character pushback buffer is implemented.
*/
 
  +
*/
int __SEGGER_RTL_X_file_read(FILE *stream, char *s, unsigned len) {
 
  +
int __SEGGER_RTL_X_file_unget(FILE *stream, int c) {
int c;
 
  +
if (stream == stdin) {
 
if (stream == stdin) {
+
if (c != EOF && _stdin_ungot == EOF) {
c = 0;
+
_stdin_ungot = c;
while (len > 0) {
 
*s = _stdin_getc();
 
++s;
 
++c;
 
--len;
 
}
 
 
} else {
 
} else {
 
c = EOF;
 
c = EOF;
 
}
 
}
return c;
+
} else {
  +
c = EOF;
 
}
 
}
  +
return c;
 
  +
}
/*********************************************************************
 
  +
*
 
  +
/*************************** End of file ****************************/
* __SEGGER_RTL_X_file_write()
 
  +
*
 
  +
</source>
* Function description
 
* Write data to file.
 
*
 
* Parameters
 
* stream - Pointer to file to write to.
 
* s - Pointer to object to write to file.
 
* len - Number of characters to write to the file.
 
*
 
* Return value
 
* >= 0 - Success.
 
* < 0 - Failure.
 
*
 
* Additional information
 
* this version is NOT reentrant!
 
* stdout and stderr are directed to UART;
 
* writing to any stream other than stdout or stderr results in an error
 
*/
 
int __SEGGER_RTL_X_file_write(FILE *stream, const char *s, unsigned len) {
 
if ((stream == stdout) || (stream == stderr)) {
 
BSP_UART_WriteBlocking(_UART_Port, (const unsigned char*) s, len);
 
return len;
 
} else {
 
return EOF;
 
}
 
}
 
 
/*********************************************************************
 
*
 
* __SEGGER_RTL_X_file_unget()
 
*
 
* Function description
 
* Push character back to stream.
 
*
 
* Parameters
 
* stream - Pointer to file to push back to.
 
* c - Character to push back.
 
*
 
* Return value
 
* >= 0 - Success.
 
* < 0 - Failure.
 
*
 
* Additional information
 
* Push-back is only supported for standard input, and
 
* only a single-character pushback buffer is implemented.
 
*/
 
int __SEGGER_RTL_X_file_unget(FILE *stream, int c) {
 
if (stream == stdin) {
 
if (c != EOF && _stdin_ungot == EOF) {
 
_stdin_ungot = c;
 
} else {
 
c = EOF;
 
}
 
} else {
 
c = EOF;
 
}
 
return c;
 
}
 
 
/*************************** End of file ****************************/
 

Latest revision as of 17:37, 1 April 2022

The debugger and the Runtime Library of Embedded Studio support different mechanisms for debug input and output. The mechanism to be used in a project can easily be selected in the project options at Library -> Library I/O and does not require any additional file or configuration.

Note: Embedded Studio versions prior to V6 included two versions of the runtime library: The legacy "Embedded Studio Runtime Library" and the "SEGGER Runtime Library". This article is about the SEGGER Runtime Library, which is used by Embedded Studio V6 and most projects created with Embedded Studio V5.50 or later.

Library I/O Mechanisms

There are different mechanisms for different application requirements.

RTT

Use SEGGER Real-Time Transfer (RTT), which enables super fast output without halting the system. The target application writes the output string to a buffer in RAM. The J-Link reads the buffer while the target is running.

Suitable for applications with real-time requirements.

Available on all Cortex-M based systems.

Note: Older projects might include SEGGER_RTT_Syscalls_SES.c or a similar file to override printf(). When using the SEGGER Runtime Library, this file should be removed from the project, or its content should be encapsulated with #if !defined(__SEGGER_RTL_VERSION) ... #endif

SEGGER Embedded Studio provides RTT printf(); functionality automatically.

To use the full RTT API, the RTT Target Package needs to be added to the Embedded Studio project: RTT in Embedded Studio

SWO

The target application writes the output string to the ITM stimulus ports. The J-Link reads the SWO pin while the target is running.

Suitable for applications with real-time requirements.

Available on all Cortex-M based systems with a SWO pin.

SEMIHOST

Halt the target CPU for I/O operations. On halt, the debugger reads and executes the operation command and parameters.

Available on all targets (Cortex-M, Cortex-A, Cortex-R, RISC-V)

SEMIHOST host-formatted

With host formatting printf output is processed by the debugger instead of on the target. The debugger reads the format string and the parameters from the target and feeds it to its formatter to be printed. No code for formatting is required on the target, saving 1 - 3 kiloBytes of ROM.

Recommended for minimum size.

None

No I/O mechanism implemented. Use user-supplied I/O mechanisms, such as output on a UART.

User-supplied I/O

Note: This section applies to Embedded Studio V6.12 and later.

When no standard I/O mechanism is implemented, the user can supply an implementation of the low-level routines to do output and optionally input.

The functions to be implemented are:

 int __SEGGER_RTL_X_file_stat(__SEGGER_RTL_FILE *stream);                                // Get file status.               >= 0: OK. < 0: Invalid file stream.
 int __SEGGER_RTL_X_file_bufsize(__SEGGER_RTL_FILE *stream);                             // Get stream buffer size.        == 1: Unbuffered I/O. > 1: Size of buffer.
 int __SEGGER_RTL_X_file_read(__SEGGER_RTL_FILE * stream, char * s, unsigned len);       // Read data from file stream.    >= 0: OK. < 0: Failed to read.
 int __SEGGER_RTL_X_file_write(__SEGGER_RTL_FILE *stream, const char *s, unsigned len);  // Write data to file stream.     >= 0: OK. < 0: Error.
 int __SEGGER_RTL_X_file_unget(__SEGGER_RTL_FILE *stream, int c);                        // Push character back to stream. >= 0: OK. < 0: Error.

A Embedded Studio project for the emPower board that exposes I/O of a UART port can be downloaded here: File:RTL-UART-IO.zip

A minimal implementation of the I/O functions could look like the below:

/*********************************************************************
*                   (c) SEGGER Microcontroller GmbH                  *
*                        The Embedded Experts                        *
*                           www.segger.com                           *
**********************************************************************

-------------------------- END-OF-HEADER -----------------------------
Purpose : Implementation of low-level functions for I/O with the
          SEGGER Runtime Library
          using a UART (SEGGER's BSP UART module)
*/

/*********************************************************************
*
*       #include section
*
**********************************************************************
*/

#include "__SEGGER_RTL_Int.h"
#include "stdio.h"
#include "BSP_UART.h"

/*********************************************************************
*
*       Prototypes
*
**********************************************************************
*/
void RTL_UART_Init(unsigned int Unit, unsigned long Baudrate, unsigned char NumDataBits, unsigned char Parity, unsigned char NumStopBits);

/*********************************************************************
*
*       Local types
*
**********************************************************************
*/

struct __SEGGER_RTL_FILE_impl {         // NOTE: Provides implementation for FILE
  int stub; // only needed so impl has size != 0.
};

/*********************************************************************
*
*       Static data
*
**********************************************************************
*/

static FILE __SEGGER_RTL_stdin_file  = { 0 };  // stdin reads from UART
static FILE __SEGGER_RTL_stdout_file = { 0 };  // stdout writes to UART
static FILE __SEGGER_RTL_stderr_file = { 0 };  // stderr writes to UART

static unsigned int _UART_Port    = 0;
static int          _stdin_ungot  = EOF;

/*********************************************************************
*
*       Public data
*
**********************************************************************
*/

FILE *stdin  = &__SEGGER_RTL_stdin_file;  // NOTE: Provide implementation of stdin for RTL.
FILE *stdout = &__SEGGER_RTL_stdout_file; // NOTE: Provide implementation of stdout for RTL.
FILE *stderr = &__SEGGER_RTL_stderr_file; // NOTE: Provide implementation of stderr for RTL.

/*********************************************************************
*
*       Static code
*
**********************************************************************
*/

/*********************************************************************
*
*       _stdin_getc()
*
*  Function description
*    Get character from standard input.
*
*  Return value
*    Character received.
*
*  Additional information
*    This function never fails to deliver a character.
*/
static char _stdin_getc(void) {
  unsigned char c;

  if (_stdin_ungot != EOF) {
    c = _stdin_ungot;
    _stdin_ungot = EOF;
  } else {
    BSP_UART_ReadBlocking(_UART_Port, &c, sizeof(c));
  }
  return c;
}

/*********************************************************************
*
*       Public code
*
**********************************************************************
*/

/*********************************************************************
*
*       RTL_UART_Init()
*
*  Function description
*    Initialize RTL to use given UART for stdio.
*
*  Parameters
*    Unit       : UART unit number (typically zero-based).
*    Baudrate   : Baud rate to configure [Hz].
*    NumDataBits: Number of data bits to use.
*    Parity     : One of the following values:
*                   * BSP_UART_PARITY_NONE
*                   * BSP_UART_PARITY_ODD
*                   * BSP_UART_PARITY_EVEN
*    NumStopBits: Number of stop bits to use.
*
*  Additional description
*    Parameters are same as for BSP_UART_Init().
*    This also sets appropriate RX and TX interrupt handlers.
*/
void RTL_UART_Init(unsigned int Unit, unsigned long Baudrate, unsigned char NumDataBits, unsigned char Parity, unsigned char NumStopBits) {
  _UART_Port = Unit;
  BSP_UART_Init(_UART_Port, Baudrate, NumDataBits, Parity, NumStopBits);
}

/*********************************************************************
*
*       __SEGGER_RTL_X_file_stat()
*
*  Function description
*    Get file status.
*
*  Parameters
*    stream - Pointer to file.
*
*  Additional information
*    Low-overhead test to determine if stream is valid.  If stream
*    is a valid pointer and the stream is open, this function must
*    succeed.  If stream is a valid pointer and the stream is closed,
*    this function must fail.
*
*    The implementation may optionally determine whether stream is
*    a valid pointer: this may not always be possible and is not
*    required, but may assist debugging when clients provide wild
*    pointers.
*
*  Return value
*    <  0 - Failure, stream is not a valid file.
*    >= 0 - Success, stream is a valid file.
*/
int __SEGGER_RTL_X_file_stat(FILE *stream) {
  if (stream == stdin || stream == stdout || stream == stderr) {
    return 0;       // NOTE: stdin, stdout, and stderr are assumed to be valid.
  } else {
    return EOF;
  }
}

/*********************************************************************
*
*       __SEGGER_RTL_X_file_bufsize()
*
*  Function description
*    Get stream buffer size.
*
*  Parameters
*    stream - Pointer to file.
*
*  Additional information
*    Returns the number of characters to use for buffered I/O on
*    the file stream.  The I/O buffer is allocated on the stack
*    for the duration of the I/O call, therefore this value should
*    not be set arbitrarily large.
*
*    For unbuffered I/O, return 1.
*
*  Return value
*    Nonzero number of characters to use for buffered I/O; for
*    unbuffered I/O, return 1.
*/
int __SEGGER_RTL_X_file_bufsize(FILE *stream) {
  (void)stream;
  return 1;
}

/*********************************************************************
*
*       __SEGGER_RTL_X_file_read()
*
*  Function description
*    Read data from file.
*
*  Parameters
*    stream - Pointer to file to read from.
*    s      - Pointer to object that receives the input.
*    len    - Number of characters to read from file.
*
*  Return value
*    >= 0 - Success, amount of data read.
*    <  0 - Failure.
*
*  Additional information
*    Reading from any stream other than stdin results in an error.
*/
int __SEGGER_RTL_X_file_read(FILE *stream, char *s, unsigned len) {
  int c;

  if (stream == stdin) {
    c = 0;
    while (len > 0) {
      *s = _stdin_getc();
      ++s;
      ++c;
      --len;
    }
  } else {
    c = EOF;
  }
  return c;
}

/*********************************************************************
*
*       __SEGGER_RTL_X_file_write()
*
*  Function description
*    Write data to file.
*
*  Parameters
*    stream - Pointer to file to write to.
*    s      - Pointer to object to write to file.
*    len    - Number of characters to write to the file.
*
*  Return value
*    >= 0 - Success.
*    <  0 - Failure.
*
*  Additional information
*    this version is NOT reentrant!
*    stdout and stderr are directed to UART;
*    writing to any stream other than stdout or stderr results in an error
*/
int __SEGGER_RTL_X_file_write(FILE *stream, const char *s, unsigned len) {
  if ((stream == stdout) || (stream == stderr)) {
    BSP_UART_WriteBlocking(_UART_Port, (const unsigned char*) s, len);
    return len;
  } else {
    return EOF;
  }
}

/*********************************************************************
*
*       __SEGGER_RTL_X_file_unget()
*
*  Function description
*    Push character back to stream.
*
*  Parameters
*    stream - Pointer to file to push back to.
*    c      - Character to push back.
*
*  Return value
*    >= 0 - Success.
*    <  0 - Failure.
*
*  Additional information
*    Push-back is only supported for standard input, and
*    only a single-character pushback buffer is implemented.
*/
int __SEGGER_RTL_X_file_unget(FILE *stream, int c) {
  if (stream == stdin) {
    if (c != EOF && _stdin_ungot == EOF) {
      _stdin_ungot = c;
    } else {
      c = EOF;
    }
  } else {
    c = EOF;
  }
  return c;
}

/*************************** End of file ****************************/