/* * Copyright (c) 2023, Erich Styger * * SPDX-License-Identifier: BSD-3-Clause */ #ifndef MCUSEMIHOST_H_ #define MCUSEMIHOST_H_ #include "McuSemihost_config.h" #include #include #include "McuTimeDate.h" #include "McuShell.h" #ifdef __cplusplus extern "C" { #endif #define McuSemihost_STDIN 0 /*!< handle for standard input */ #define McuSemihost_STDOUT 1 /*!< handle for standard output */ #define McuSemihost_STDERR 2 /*!< handle for standard error */ extern int McuSemihost_Read(int handle, unsigned char *data, size_t nofBytes); extern uint8_t McuSemihost_DefaultShellBuffer[McuShell_DEFAULT_SHELL_BUFFER_SIZE]; /*!< default buffer which can be used by the application or shell */ extern McuShell_ConstStdIOType McuSemihost_stdio; /*!< Default standard I/O handler, can be used for a shell intergration */ /*! * \brief Return the SWO stdio handle * \return Standard I/O handle */ McuShell_ConstStdIOTypePtr McuSemihost_GetStdio(void); /*! * \brief Flush the standard I/O output. Needed if using McuSemihost_CONFIG_BUFFER_IO_FLUSH. */ void McuSemihost_StdIOFlush(void); /*! * \brief Write a character to the stdout console. * \param ch Character to write * \return always zero for success */ int McuSemihost_WriteChar(char ch); /*! * \brief Return the current system time * \return System time in seconds since 1970 */ int McuSemihost_SysHostTime(void); /*! * \brief Return the number of centi-seconds the executable is running * \return -1 for error, otherwise the number of centi-seconds of the execution */ int McuSemihost_SysHostClock(void); /* File modes for McuSemihost_FileOpen() */ #define SYS_FILE_MODE_READ 0 /* Open the file for reading "r" */ #define SYS_FILE_MODE_READBINARY 1 /* Open the file for reading "rb" */ #define SYS_FILE_MODE_READWRITE 2 /* Open the file for reading and writing "r+" */ #define SYS_FILE_MODE_READWRITEBINARY 3 /* Open the file for reading and writing "r+b" */ #define SYS_FILE_MODE_WRITE 4 /* Open and truncate or create the file for writing "w" */ #define SYS_FILE_MODE_WRITEBINARY 5 /* Open and truncate or create the file for writing "wb" */ #define SYS_FILE_MODE_WRITEREAD 6 /* Open and truncate or create the file for writing and reading "w+" */ #define SYS_FILE_MODE_WRITEREADBINARY 7 /* Open and truncate or create the file for writing and reading "w+b" */ #define SYS_FILE_MODE_APPEND 8 /* Open or create the file for writing "a" */ #define SYS_FILE_MODE_APPENDBINARY 9 /* Open or create the file for writing "ab" */ #define SYS_FILE_MODE_APPENDREAD 10 /* Open or create the file for writing and reading "a+" */ #define SYS_FILE_MODE_APPENDREADBINARY 11 /* Open or create the file for writing and reading "a+b" */ /*! * \brief Open a file on the host * \param filename * \param mode * \return -1 if failed, otherwise file handle */ int McuSemihost_SysFileOpen(const unsigned char *filename, int mode); /*! * \brief Closes a file handle * \param fh File handle previously opened * \return 0: ok, otherwise -1 if failed */ int McuSemihost_SysFileClose(int fh); /*! * \brief Read from a file * \param fh File handle * \param data Pointer where to store the data * \param nofBytes Number of bytes to read * \return 0: success. If it is nofBytes, then the call has failed and the end of the file has been reached. If smaller than nofBytes, then the buffer has not been filled. */ int McuSemihost_SysFileRead(int fh, unsigned char *data, size_t nofBytes); /*! * \brief Write data to a file * \param fh File handle * \param data Pointer to data * \param nofBytes Number of data bytes to write * \return 0 for success, in error case the number of bytes not written */ int McuSemihost_SysFileWrite(int fh, const unsigned char *data, size_t nofBytes); #if McuSemihost_CONFIG_HAS_SYS_REMOVE /*! * \brief Remove a file on the host * \param filePath Name and path of the file to remove */ int McuSemihost_SysFileRemove(const unsigned char *filePath); #endif #if McuSemihost_CONFIG_HAS_SYS_RENAME /*! * \brief Rename a file on the host * \param filePath Name and path of the source file * \param fileNewPath Name and path of new file */ int McuSemihost_SysFileRename(const unsigned char *filePath, const unsigned char *fileNewPath); #endif /*! * \brief Return the length of a file * \param fh File handle * \return Current length of the file, -1 for an error */ int McuSemihost_SysFileLen(int fh); /*! * \brief Seeks for a specified position in a file * \param fh File handle * \param pos Target position. Seeking outside of the size of the file is undefined * \return 0 for success, negative for an error. McuSemihost_Op_SYS_ERRNO can be used to read the error value. */ int McuSemihost_SysFileSeek(int fh, int pos); #if McuSemihost_CONFIG_HAS_SYS_TMPNAME /*! * \brief Returns a temporary name for a file identified by a system file identifier. * \param fileID target identifier for the file name. Must be in the range 0..255 * \param buffer Pointer where to store the file name * \param bufSize Buffer size in bytes * \return 0 for success, -1 for an error */ int McuSemihost_SysTmpName(uint8_t fileID, unsigned char *buffer, size_t bufSize); #endif /*! * \brief Read a character using SYS_READC * \return The character read */ int McuSemihost_SysReadC(void); /*! * \brief Write a character using the SYS_WRITEC call. * \param ch Character to write * \return zero for success */ int McuSemihost_SysWriteC(char ch); /*! * \brief Decides if a file handle is a standard io handle or not. * \param fg File handle * \return 1 if it a interactive device, 0 if not, any other value is an error */ int McuSemihost_SysIsTTY(int fh); /*! * \brief Determines whether the return code from another semihosting call is an error status or not. * \param errorCode Return code from a previous semihosting call * \return 0 if it is not an error, non-zero if it is an error */ int McuSemihost_SysIsError(int32_t errorCode); /*! * \brief Returns the value of the C library errno variable associated with the host implementation of the semihosting. * The errno variable gets set by calls file operations, but others too. * \return The value of the host errno variable. */ int McuSemihost_SysErrNo(void); /*! * \brief Returns the command line used for the call to the executable, that is, argc and argv. * \return 0 for success, -1 for error */ int McuSemihost_SysGetCmdLine(unsigned char *cmd, size_t cmdSize); typedef struct McuSemihost_HeapInfo_t { uint32_t heap_base; uint32_t heap_limit; uint32_t stack_base; uint32_t stack_limit; } McuSemihost_HeapInfo_t; /*! * \brief Returns the system stack and heap parameters. * \param heapInfo Pointer to heap info to be filled in * \return 0 for success, non-zero otherwise */ int McuSemihost_SysHeapInfo(McuSemihost_HeapInfo_t *heapInfo); /*! * \brief Sets the processor to supervisor mode and disables all interrupts * \return address to be called to return to user mode. */ int McuSemihost_SysEnterSVC(void); typedef enum McuSemihost_Exception_e { McuSemihost_ADP_Stopped_ApplicationExit = 0x20026, /* exit target application */ } McuSemihost_Exception_e; /*! * \brief Raises one of predefined excetptions to the debugger * \param exception Exception to be raised * \return 0 for success, non-zero otherwise */ int McuSemihost_SysException(McuSemihost_Exception_e exception); /*! * \brief Return the tick frequency * \return Tick frequency, -1 if debugger does not know the value of one tick */ int McuSemihost_SysTickFreq(void); /*! * \brief Reads a line from user input. Call is blocking, and user has to press enter. * Buffer will be always zero terminated. A '\r' at the end will be converted to '\n'. * Backspace ('\b') in the input will be converted and handled. * Buffer will have a '\n' at the end with a zero byte, so buffer needs to have at least a size of 2. * \param buf Buffer to store the user input. If buffer is too small, excess characters are not stored in it and discarded. * \param bufSize Size of the buffer * \param echo If characters shall be printed as echo * \return Number of characters stored in the buffer. */ int McuSemihost_ReadLine(unsigned char *buf, size_t bufSize, bool echo); /*! * \brief Write a zero byte terminated character array (string) to stdout, using buffering. * \param str String, zero byte terminated * \return 0: ok, -1 error */ int McuSemihost_WriteString(const unsigned char *str); /*! * \brief Write a zero byte terminated character array without buffering directly to the debugger. * \param str String, zero byte terminated * \return 0: ok, -1 error */ int McuSemihost_WriteString0(const unsigned char *str); /*! * \brief Sending a character to the SWO/ITM console * \param ch Character to send */ void McuSemihost_StdIOSendChar(uint8_t ch); /*! * \brief Reads a character from the standard input * \param ch Pointer where to store the character, stores '\0' if no character was received */ void McuSemihost_StdIOReadChar(uint8_t *ch); /*! * \brief Checks if there is input from SWO/ITM console * \return true if there is input, false otherwise */ bool McuSemihost_StdIOKeyPressed(void); /*! * \brief 'printf'-style writing with semihosting * \param fmt Format string * \return Number of characters written */ unsigned McuSemihost_printf(const char *fmt, ...); /*! * \brief Get the date and time from the host * \param time Pointer to where to store the time information * \param date Pointer to where to store the date information * \param offsetHour Pass -1 if during wintertime * \return ERR_OK if ok, error code otherwise */ uint8_t McuSemihost_GetTimeDateFromHost(TIMEREC *time, DATEREC *date, int offsetHour); /*! * \brief Testing the semihost functionality and API * \return 0 for success, -1 for error */ int McuSemiHost_Test(void); /*! * \brief Module de-initialization */ void McuSemiHost_Deinit(void); /*! * \brief Module initialization */ void McuSemiHost_Init(void); #ifdef __cplusplus } /* extern "C" */ #endif #endif /* MCUSEMIHOST_H_ */