PIC24 Support Libraries
pic24_stdio_uart.c
Go to the documentation of this file.
1 /*
2  * "Copyright (c) 2009 David Weaver ("AUTHORS")"
3  * All rights reserved.
4  *
5  * Permission to use, copy, modify, and distribute this software and its
6  * documentation for any purpose, without fee, and without written agreement is
7  * hereby granted, provided that the above copyright notice, the following
8  * two paragraphs and the authors appear in all copies of this software.
9  *
10  * IN NO EVENT SHALL THE "AUTHORS" BE LIABLE TO ANY PARTY FOR
11  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
12  * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE "AUTHORS"
13  * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14  *
15  * THE "AUTHORS" SPECIFICALLY DISCLAIMS ANY WARRANTIES,
16  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
17  * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
18  * ON AN "AS IS" BASIS, AND THE "AUTHORS" HAS NO OBLIGATION TO
19  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
20  *
21  * Please maintain this header in its entirety when copying/modifying
22  * these files.
23  *
24  *
25  */
26 
27 
28 // Documentation for this file. If the \file tag isn't present,
29 // this file won't be documented.
30 /** \file
31  * STDIO UART support functions
32  *\par
33  * This file provided courtesy of David Weaver who has given permission for it
34  * to be included in the code archive.
35  *\par
36  * Provides standard I/O functions compatible with our single character library functions.
37  * See chap10/reverse_string_stdio.c or chap10/stdio_test.c for examples using \em scanf().
38  *\par
39  * See libc documentation for definitions of open(), close(), read(), write(), and lseek().
40  * Exceptions and limitations imposed by this implementation are documented here.
41  *\par
42  * Use of stdio functions is memory intensive especially for floating point!
43  *\par
44  *\em fopen() access specifiers work as docummented in libc.
45  * Translation mode may be set seperately for reading
46  * and writing as in example 1. If using read+write access, remember to seek during
47  * transitions from write to read and read to write. Use \em fseek() or \em rewind(). See example 2.
48  *\par Example 1:
49  *\code
50  * file1 = fopen("uart1", "r"); // uart1 open for reading text using file1
51  * file2 = fopen("uart1", "wb"); // uart1 open for writing binary using file2
52  * fprintf(file2, "Enter string:\n"); // binary - no "\n" substituion allowed - see open()
53  * fscanf(file1, "%s", buffer);\endcode
54  *\par Example 2:
55  *\code
56  * file3 = fopen("uart1", "r+"); // uart1 open for reading and writing text using file3
57  * fseek(file3, 0, SEEK_END); // move to end of file for output - or use rewind()
58  * fprintf(file3, "Enter string:\n"); // text - may substitute for "\n" - see open()
59  * fseek(file3, 0, SEEK_SET); // move to start of file for input - or use rewind()
60  * fscanf(file3, "%s", buffer);\endcode
61  */
62 
63 #include "pic24_all.h"
64 #include <stdio.h>
65 
66 // These definitions for translation mode
67 // Also see SERIAL_EOL_DEFAULT setting in pic_24libconfig.h for output translation
68 #define SERIAL_BREAK_CR // Break input stream on CR if specified
69 #define SERIAL_BREAK_NL // Break input stream on NL if specified
70 
71 // These definitions are for libc placement and compatibility
72 #define _LIBC_FUNCTION __attribute__((__weak__, __section__(".libc")))
73 #define SUCCESS 0
74 #define FAIL -1
75 #define CHAR_ACCESS 0x4000
76 #define DATA_ACCESS 0x8000 //this flag assumed if CHAR_ACCESS not set
77 #define READ_ACCESS 0x0
78 #define WRITE_ACCESS 0x1
79 #define READ_WRITE_ACCESS 0x2
80 #define ACCESS_RW_MASK 0x3 // bits set to 0 or 2 for read and 1 or 2 for write
81 #define ACCESS_SET_OPEN DATA_ACCESS // expedient - reuse bit position to indicate open
82 
83 //set default baudrate as needed for each of four UARTs
84 #ifndef DEFAULT_BAUDRATE1
85 #define DEFAULT_BAUDRATE1 DEFAULT_BAUDRATE
86 #endif
87 #ifndef DEFAULT_BAUDRATE2
88 #define DEFAULT_BAUDRATE2 DEFAULT_BAUDRATE
89 #endif
90 #ifndef DEFAULT_BAUDRATE3
91 #define DEFAULT_BAUDRATE3 DEFAULT_BAUDRATE
92 #endif
93 #ifndef DEFAULT_BAUDRATE4
94 #define DEFAULT_BAUDRATE4 DEFAULT_BAUDRATE
95 #endif
96 
97 #define MAX_ALLOWED_HANDLES (NUM_UART_MODS+3) // number of handles allowed
98 #define RANGECK_HANDLE(xxhandlexx) ((xxhandlexx >= 0) && (xxhandlexx < MAX_ALLOWED_HANDLES))
99 enum ALLOWED_HANDLES {
100  HANDLE_STDIN=0,
101  HANDLE_STDOUT=1,
102  HANDLE_STDERR=2,
103  HANDLE_UART1,
104  HANDLE_UART2,
105  HANDLE_UART3,
106  HANDLE_UART4
107 };
108 
109 struct {
110  void (*pfnv_outChar)(uint8_t);
111  uint8_t (*pfn_inChar)();
112  uint16_t u16_read_access;
113  uint16_t u16_write_access;
114 } FILES[MAX_ALLOWED_HANDLES] = {
115  { 0, 0 }, //stdin
116  { 0, 0 }, //stdout
117  { 0, 0 }, //stderr
118 #if (NUM_UART_MODS >= 1)
119  { &outChar1, &inChar1 },
120 #endif
121 #if (NUM_UART_MODS >= 2)
122  { &outChar2, &inChar2 },
123 #endif
124 #if (NUM_UART_MODS >= 3)
125  { &outChar3, &inChar3 },
126 #endif
127 #if (NUM_UART_MODS >= 4)
128  { &outChar4, &inChar4 }
129 #endif
130 };
131 
132 /**********************************
133  * Functions private to this file *
134  **********************************/
135 
136 /**
137 * Check __C30_UART for the UART to use. If set to 1, for example, then
138 * set up \em stdin, \em stdout, and \em stderr for UART1 and
139 * call \em configUART1() if not currently enabled.
140 *\return \em SUCCESS or \em FAIL.
141 *
142 */
143 static int16_t stdioOpen(void) {
144 #if (NUM_UART_MODS >= 1)
145  if (__C30_UART == 1) {
146  FILES[HANDLE_STDERR].pfnv_outChar = (void *)&outChar1;
147  FILES[HANDLE_STDOUT].pfnv_outChar = (void *)&outChar1;
148  FILES[HANDLE_STDIN].pfn_inChar = &inChar1;
149  if (!U1MODEbits.UARTEN) {
150  configUART1(DEFAULT_BAUDRATE1);
151  }
152  return SUCCESS;
153  }
154 #endif
155 #if (NUM_UART_MODS >= 2)
156  if (__C30_UART == 2) {
157  FILES[HANDLE_STDERR].pfnv_outChar = (void *)&outChar2;
158  FILES[HANDLE_STDOUT].pfnv_outChar = (void *)&outChar2;
159  FILES[HANDLE_STDIN].pfn_inChar = &inChar2;
160  if (!U2MODEbits.UARTEN) {
161  configUART2(DEFAULT_BAUDRATE2);
162  }
163  return SUCCESS;
164  }
165 #endif
166 #if (NUM_UART_MODS >= 3)
167  if (__C30_UART == 3) {
168  FILES[HANDLE_STDERR].pfnv_outChar = (void *)&outChar3;
169  FILES[HANDLE_STDOUT].pfnv_outChar = (void *)&outChar3;
170  FILES[HANDLE_STDIN].pfn_inChar = &inChar3;
171  if (!U3MODEbits.UARTEN) {
172  configUART3(DEFAULT_BAUDRATE3);
173  }
174  return SUCCESS;
175  }
176 #endif
177 #if (NUM_UART_MODS >= 4)
178  if (__C30_UART == 4) {
179  FILES[HANDLE_STDERR].pfnv_outChar = (void *)&outChar4;
180  FILES[HANDLE_STDOUT].pfnv_outChar = (void *)&outChar4;
181  FILES[HANDLE_STDIN].pfn_inChar = &inChar4;
182  if (!U4MODEbits.UARTEN) {
183  configUART4(DEFAULT_BAUDRATE4);
184  }
185  return SUCCESS;
186  }
187 #endif
188  return FAIL;
189 }
190 
191 /*********************************************************
192  * Public functions intended to be called by other files *
193  *********************************************************/
194 
195 /**
196 * Initiate I/O on UART specified by \em name
197 *\param name of file (UART) to open.
198 *Limited to "stdin", "stdout", "stderr", "uart1", "uart2", "uart3", and "uart4".
199 *\n
200 *UART number specified by \em __C30_UART is reserved and can only be opened
201 *as \em stdin, \em stdout, and \em stderr.
202 *\param access is a bit field. Default, 0x0, is for binary read.
203 *Set it to include \em 0x4000 for character translation mode:
204 *\n
205 *input - possible break on '\\r' and '\\n' - See \em SERIAL_BREAK_NL and \em SERIAL_BREAK_CR.
206 *\n
207 *output - possible substitutions for '\\n' - See \em SERIAL_EOL_CR and \em SERIAL_EOL_CR_LF.
208 *\n
209 *If desired, OR it with 0x1 for write, or 0x2 for read and write.
210 *\param mode not used
211 *\return \em handle or \em FAIL.
212 *
213 */
214 int _LIBC_FUNCTION
215 open(const char *name, int access, int mode) {
216  enum ALLOWED_HANDLES ie_handle;
217  uint16_t u16_masked_access;
218  uint16_t u16_set_access;
219 
220  switch (name[4]) { // Expedient - name[4] is unique for the allowed file names
221  case 'n': //stdin
222  if (stdioOpen()) return FAIL;
223  ie_handle = HANDLE_STDIN;
224  break;
225  case 'u': //stdout
226  if (stdioOpen()) return FAIL;
227  ie_handle = HANDLE_STDOUT;
228  break;
229  case 'r': //stderr
230  if (stdioOpen()) return FAIL;
231  ie_handle = HANDLE_STDERR;
232  break;
233 #if (NUM_UART_MODS >= 1)
234  case '1': //uart1
235  if (__C30_UART == 1) return FAIL;
236  if (!U1MODEbits.UARTEN) {
237  configUART1(DEFAULT_BAUDRATE1);
238  }
239  ie_handle = HANDLE_UART1;
240  break;
241 #endif
242 #if (NUM_UART_MODS >= 2)
243  case '2': //uart2
244  if (__C30_UART == 2) return FAIL;
245  if (!U2MODEbits.UARTEN) {
246  configUART2(DEFAULT_BAUDRATE2);
247  }
248  ie_handle = HANDLE_UART2;
249  break;
250 #endif
251 #if (NUM_UART_MODS >= 3)
252  case '3': //uart3
253  if (__C30_UART == 3) return FAIL;
254  if (!U3MODEbits.UARTEN) {
255  configUART3(DEFAULT_BAUDRATE3);
256  }
257  ie_handle = HANDLE_UART3;
258  break;
259 #endif
260 #if (NUM_UART_MODS >= 4)
261  case '4': //uart4
262  if (__C30_UART == 4) return FAIL;
263  if (!U4MODEbits.UARTEN) {
264  configUART4(DEFAULT_BAUDRATE4);
265  }
266  ie_handle = HANDLE_UART4;
267  break;
268 #endif
269  default:
270  return FAIL; // name not recognized
271  }
272 
273  u16_masked_access = access & ACCESS_RW_MASK;
274  u16_set_access = ACCESS_SET_OPEN | access;
275  if ((u16_masked_access == READ_ACCESS) || (u16_masked_access == READ_WRITE_ACCESS)) {
276  FILES[ie_handle].u16_read_access = u16_set_access;
277  }
278  if ((u16_masked_access == WRITE_ACCESS) || (u16_masked_access == READ_WRITE_ACCESS)) {
279  FILES[ie_handle].u16_write_access = u16_set_access;
280  }
281  return ie_handle;
282 }
283 
284 /**
285 *Input \em len characters from UART specified for \em handle to \em buffer.
286 *Uses \em mode specified via \em open().
287 *If \em handle is for \em stdin, calls \em open() with character translation read \em access as needed.
288 *\param handle specifies UART to read from.
289 *\param buffer storage for read characters.
290 *\param len maximum number of characters to read.
291 *\return number of charaters in \em buffer or \em FAIL.
292 *
293 */
294 int _LIBC_FUNCTION
295 read(int handle, void *buffer, unsigned int len) {
296  uint16_t u16_char_count;
297 
298  if(!RANGECK_HANDLE(handle)) return FAIL; // invalid handle
299  if ((handle == HANDLE_STDIN) && !(FILES[HANDLE_STDIN].u16_read_access & ACCESS_SET_OPEN)) {
300  open("stdin", (CHAR_ACCESS | READ_ACCESS), 0);
301  }
302  if (!FILES[handle].u16_read_access) return FAIL; // not open
303  for (u16_char_count = 0; u16_char_count < len; u16_char_count++) {
304  ((unsigned char *)buffer)[u16_char_count] = (*FILES[handle].pfn_inChar)();
305 #ifdef SERIAL_BREAK_NL
306  if ((FILES[handle].u16_read_access & CHAR_ACCESS) && (((unsigned char *)buffer)[u16_char_count] == '\n')) {
307  ++u16_char_count;
308  break;
309  }
310 #endif
311 #ifdef SERIAL_BREAK_CR
312  if ((FILES[handle].u16_read_access & CHAR_ACCESS) && (((unsigned char *)buffer)[u16_char_count] == '\r')) {
313  ++u16_char_count;
314  break;
315  }
316 #endif
317  }
318 
319  return u16_char_count;
320 }
321 
322 /**
323 *Output \em len characters from \em buffer to UART specified for \em handle.
324 *Uses \em mode specified via \em open().
325 * If \em handle is for \em stdout or \em stderr, calls \em open() with character translation write \em access as needed.
326 *\param handle specifies UART to write to.
327 *\param buffer contains characters to write.
328 *\param len number of characters to write.
329 *\return number of charaters written from buffer or \em FAIL.
330 *
331 */
332 int _LIBC_FUNCTION
333 write(int handle, void *buffer, unsigned int len) {
334  uint16_t u16_char_count;
335 
336  if(!RANGECK_HANDLE(handle)) return FAIL; // invalid handle
337  if ((handle == HANDLE_STDOUT) && !(FILES[HANDLE_STDOUT].u16_write_access & ACCESS_SET_OPEN)) {
338  open("stdout", (CHAR_ACCESS | WRITE_ACCESS), 0);
339  }
340  if ((handle == HANDLE_STDERR) && !(FILES[HANDLE_STDERR].u16_write_access & ACCESS_SET_OPEN)) {
341  open("stderr", (CHAR_ACCESS | WRITE_ACCESS), 0);
342  }
343  if (!FILES[handle].u16_write_access) return FAIL; // not open
344  for (u16_char_count = 0; u16_char_count < len; u16_char_count++) {
345  if ((FILES[handle].u16_write_access & CHAR_ACCESS) && (((unsigned char *)buffer)[u16_char_count] == '\n')) {
346 #if (SERIAL_EOL_DEFAULT==SERIAL_EOL_CR)
347  (*FILES[handle].pfv_outChar)('\r');
348  continue;
349 #endif
350 #if (SERIAL_EOL_DEFAULT==SERIAL_EOL_CR_LF)
351  (*FILES[handle].pfv_outChar)('\r');
352 #endif
353  (*FILES[handle].pfnv_outChar)('\n');
354  continue;
355  }
356  (*FILES[handle].pfnv_outChar)(((unsigned char *)buffer)[u16_char_count]);
357  }
358 
359  return u16_char_count;
360 }
361 
362 /**
363 *Stub required by \em fclose().
364 *\param handle not used.
365 *\return \em SUCCESS.
366 *
367 */
368 int _LIBC_FUNCTION
369 close(int handle) {
370  return SUCCESS;
371 }
372 
373 /**
374 *Stub required by \em rewind() and \em fseek().
375 *\param handle not used.
376 *\param offset not used.
377 *\param origin not used.
378 *\return \em SUCCESS.
379 *
380 */
381 long _LIBC_FUNCTION
382 lseek(int handle, long offset, int origin) {
383  return SUCCESS;
384 }
long _LIBC_FUNCTION lseek(int handle, long offset, int origin)
static int16_t stdioOpen(void)
int _LIBC_FUNCTION open(const char *name, int access, int mode)
int _LIBC_FUNCTION close(int handle)
#define FAIL
Definition: all_generic.h:412
uint8_t inChar1(void)
Definition: pic24_uart.c:214
int _LIBC_FUNCTION write(int handle, void *buffer, unsigned int len)
void configUART1(uint32_t u32_baudRate)
Definition: pic24_uart.c:250
void outChar1(uint8_t u8_c)
Definition: pic24_uart.c:145
int _LIBC_FUNCTION read(int handle, void *buffer, unsigned int len)
unsigned char uint8_t
An abbreviation for an 8-bit unsigned integer.
Definition: dataXferImpl.h:194