PIC24 Support Libraries
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pic24_serial.c
Go to the documentation of this file.
1 /*
2  * "Copyright (c) 2008 Robert B. Reese, Bryan A. Jones, J. W. Bruce ("AUTHORS")"
3  * All rights reserved.
4  * (R. Reese, reese_AT_ece.msstate.edu, Mississippi State University)
5  * (B. A. Jones, bjones_AT_ece.msstate.edu, Mississippi State University)
6  * (J. W. Bruce, jwbruce_AT_ece.msstate.edu, Mississippi State University)
7  *
8  * Permission to use, copy, modify, and distribute this software and its
9  * documentation for any purpose, without fee, and without written agreement is
10  * hereby granted, provided that the above copyright notice, the following
11  * two paragraphs and the authors appear in all copies of this software.
12  *
13  * IN NO EVENT SHALL THE "AUTHORS" BE LIABLE TO ANY PARTY FOR
14  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
15  * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE "AUTHORS"
16  * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
17  *
18  * THE "AUTHORS" SPECIFICALLY DISCLAIMS ANY WARRANTIES,
19  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
20  * AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
21  * ON AN "AS IS" BASIS, AND THE "AUTHORS" HAS NO OBLIGATION TO
22  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS."
23  *
24  * Please maintain this header in its entirety when copying/modifying
25  * these files.
26  *
27  *
28  */
29 
30 
31 // Documentation for this file. If the \file tag isn't present,
32 // this file won't be documented.
33 /** \file
34  * Implementation of serial I/O functions prototyped in pic24_serial.h
35  */
36 
37 #include "pic24_serial.h"
38 #include "pic24_uart.h"
39 #include "pic24_unittest.h"
40 #include <libpic30.h>
41 
42 /*********************************************************
43  * Public functions intended to be called by other files *
44  *********************************************************/
45 
46 #ifdef BUILT_ON_ESOS
47 #define outChar esos_PutUint8ToCommOut
48 #else
49 /** Write a character to the serial port.
50  * This function blocks until a character is
51  * written. The UART used
52  * is determined by the __C30_UART variable, which
53  * defaults to 1.
54  * \param u8_c Character to write
55  */
56 void outChar(uint8_t u8_c) {
57  switch (__C30_UART) {
58 #if (NUM_UART_MODS >= 1)
59  case 1 :
60  outChar1(u8_c);
61  break;
62 #endif
63 #if (NUM_UART_MODS >= 2)
64  case 2 :
65  outChar2(u8_c);
66  break;
67 #endif
68 #if (NUM_UART_MODS >= 3)
69  case 3 :
70  outChar3(u8_c);
71  break;
72 #endif
73 #if (NUM_UART_MODS >= 4)
74  case 4 :
75  outChar4(u8_c);
76  break;
77 #endif
78  default :
79  REPORT_ERROR("Invalid UART");
80  }
81 }
82 #endif
83 
84 /** Write a null-terminated string to the serial port.
85 See file documentation for End-of-line behavior when passed a "\n" (newline).
86 \param psz_s Pointer to null-terminated string to print.
87 */
88 void outString(const char* psz_s) {
89  while (*psz_s) {
90 
91 #if (SERIAL_EOL_DEFAULT==SERIAL_EOL_CR_LF)
92  if (*psz_s == '\n') outChar(0x0D);
93  outChar(*psz_s);
94 #endif
95 #if (SERIAL_EOL_DEFAULT==SERIAL_EOL_CR)
96  if (*psz_s == '\n') outChar(0x0D);
97  else outChar(*psz_s);
98 #endif
99 #if (SERIAL_EOL_DEFAULT==SERIAL_EOL_LF)
100 //no translation
101  outChar(*psz_s);
102 #endif
103  psz_s++;
104  }
105 }
106 
107 
108 
109 
110 static uint16_t inStringInternal (char *psz_buff, uint16_t u16_maxCount, uint8_t echoFlag) {
111  uint8_t u8_c;
112  uint16_t u16_i;
113 
114  if (!u16_maxCount) return 0;
115  u16_i = 0;
116  for (u16_i = 0; u16_i < u16_maxCount; u16_i++) {
117  if (echoFlag) u8_c = inCharEcho();
118  else u8_c = inChar();
119  if (u8_c == '\n' ||u8_c == '\r' ) break; //terminate loop
120  *psz_buff = u8_c; //save character
121  psz_buff++;
122  }
123  //stop reading, terminate, return characters read.
124  *psz_buff = 0;
125  return(u16_i);
126 }
127 
128 /**
129 Reads a string into psz_buff, assumes psz_buff can
130 hold at least u16_maxCount+1 characters. String reading
131 halts when either a newline or carriage return is read, or u16_maxCount
132 characters is read. The return string is always null-terminated.
133 The return count does not includes the null terminator.
134 An input string of just '\n' returns a null string.
135 \param psz_buff pointer to buffer for storing string read from console
136 \param u16_maxCount maximum number of characters to read from console.
137 */
138 uint16_t inString (char *psz_buff, int16_t u16_maxCount) {
139  return inStringInternal(psz_buff,u16_maxCount,0);
140 }
141 
142 /**
143 Same as inString(), except echoes characters to console as they are read.
144 */
145 uint16_t inStringEcho (char *psz_buff, int16_t u16_maxCount) {
146  return inStringInternal(psz_buff,u16_maxCount,1);
147 }
148 
149 
150 void outUint8NoLeader(uint8_t u8_x) {
151  uint8_t u8_c;
152  u8_c = (u8_x>>4)& 0xf;
153  if (u8_c > 9) outChar('A'+u8_c-10);
154  else outChar('0'+u8_c);
155  //LSDigit
156  u8_c= u8_x & 0xf;
157  if (u8_c > 9) outChar('A'+u8_c-10);
158  else outChar('0'+u8_c);
159 }
160 
161 /**
162 Output u8_x as formatted hex value with leading "0x".
163 \param u8_x value to output.
164 */
165 void outUint8(uint8_t u8_x) {
166  outString("0x");
167  outUint8NoLeader(u8_x);
168 }
169 
170 /**
171 Output u16_x as formatted hex value with leading "0x".
172 \param u16_x value to output.
173 */
174 void outUint16(uint16_t u16_x) {
175  uint8_t u8_c;
176 
177  outString("0x");
178  u8_c = (u16_x >> 8);
179  outUint8NoLeader(u8_c);
180  u8_c = (uint8_t) u16_x;
181  outUint8NoLeader(u8_c);
182 }
183 
184 /**
185 Output u32_x as formatted hex value with leading "0x".
186 \param u32_x value to output.
187 */
188 void outUint32(uint32_t u32_x) {
189  uint8_t u8_c;
190  outString("0x");
191  u8_c = (u32_x >> 24);
192  outUint8NoLeader(u8_c);
193  u8_c = (u32_x >> 16);
194  outUint8NoLeader(u8_c);
195  u8_c = (u32_x >> 8);
196  outUint8NoLeader(u8_c);
197  u8_c = u32_x;
198  outUint8NoLeader(u8_c);
199 }
200 
201 /**
202 Output u8_x as decimal value.
203 \param u8_x value to output.
204 */
205 void outUint8Decimal( uint8_t u8_x ) {
206  static const uint8_t u8_d[]= {50, 30, 20, 10, 5, 3, 2, 1 };
207  static const uint8_t u8_f[]= {5, 3, 2, 1, 5, 3, 2, 1 };
208 
209  char psz_out[5];
210  uint8_t u8_i, u8_destroy;
211 
212  u8_i = 0;
213  u8_destroy = u8_x;
214  psz_out[0] = '0';
215  psz_out[1] = '0';
216  psz_out[2] = '0';
217  psz_out[3] = 0;
218  if (u8_destroy >= 200) {
219  psz_out[0] += 2;
220  u8_destroy -= 200;
221  } // end if()
222  if (u8_destroy >= 100) {
223  psz_out[0] += 1;
224  u8_destroy -= 100;
225  } // end if()
226  for (u8_i=0; u8_i<8; u8_i++) {
227  if (u8_destroy >= u8_d[u8_i]) {
228  psz_out[1+(u8_i/4)] += u8_f[u8_i];
229  u8_destroy -= u8_d[u8_i];
230  }
231  } //end for()
232  psz_out[3] = 0;
233  outString( psz_out );
234 }
235 
236 /**
237 Output u16_x as decimal value.
238 \param u16_x value to output.
239 */
240 void outUint16Decimal( uint16_t u16_x ) {
241  static const uint16_t u16_d[]= {50000, 30000, 20000, 10000, 5000, 3000, 2000, 1000, \
242  500, 300, 200, 100, 50, 30, 20, 10, 5, 3, 2, 1
243  };
244  static const uint8_t u8_f[]= {5, 3, 2, 1 };
245 
246  uint8_t u8_i;
247  uint16_t u16_destroy;
248  char psz_out[5];
249 
250  u8_i = 0;
251  u16_destroy = u16_x;
252  psz_out[0] = '0';
253  psz_out[1] = '0';
254  psz_out[2] = '0';
255  psz_out[3] = '0';
256  psz_out[4] = '0';
257 
258  for (u8_i=0; u8_i<20; u8_i++) {
259  if (u16_destroy >= u16_d[u8_i]) {
260  psz_out[u8_i/4] += u8_f[u8_i % 4];
261  u16_destroy -= u16_d[u8_i];
262  }
263  } //end for()
264  psz_out[5] = 0;
265  outString( psz_out );
266 }
267 
268 /** Read a character from the serial port.
269  * This function blocks until a character is
270  * read.
271  * The serial port used is selected by the
272  * __C30_UART variable, which defaults to 1.
273  * \return Character read from the serial port.
274  */
276  switch (__C30_UART) {
277 #if (NUM_UART_MODS >= 1)
278  case 1 :
279  return inChar1();
280 #endif
281 #if (NUM_UART_MODS >= 2)
282  case 2 :
283  return inChar2();
284 #endif
285 #if (NUM_UART_MODS >= 3)
286  case 3 :
287  return inChar3();
288 #endif
289 #if (NUM_UART_MODS >= 4)
290  case 4 :
291  return inChar4();
292 #endif
293  default :
294  REPORT_ERROR("Invalid UART");
295  return 0;
296  }
297 }
298 
299 /**
300 Same as inChar(), except echo character that is back to console
301 */
302 
304  uint8_t u8_c;
305  u8_c = inChar(); //get character
306  outChar(u8_c); //echo
307  return u8_c;
308 }
309 
310 /** Determine if a character is ready to be read
311  * from the serial port.
312  * \return non-zero value if character is ready, zero otherwise..
313  */
315  switch (__C30_UART) {
316 #if (NUM_UART_MODS >= 1)
317  case 1 :
318  return isCharReady1();
319 #endif
320 #if (NUM_UART_MODS >= 2)
321  case 2 :
322  return isCharReady2();
323 #endif
324 #if (NUM_UART_MODS >= 3)
325  case 3 :
326  return isCharReady3();
327 #endif
328 #if (NUM_UART_MODS >= 4)
329  case 4 :
330  return isCharReady4();
331 #endif
332  default :
333  REPORT_ERROR("Invalid UART");
334  return 0;
335  }
336 }
337 
338 
339 
340 /** Configures a UART based compiler setting of DEFAULT_UART
341  * and sets __C30_UART to the default UART.
342  * If you want to configure a different UART, then call the configUARTx function explicitly.
343  * \param u32_baudRate The baud rate to use.
344  */
345 void configDefaultUART(uint32_t u32_baudRate) {
346  switch (DEFAULT_UART) {
347 #if (NUM_UART_MODS >= 1)
348  case 1 :
349  __C30_UART = 1; //this is the default UART
350  configUART1(u32_baudRate);
351  break;
352 #endif
353 #if (NUM_UART_MODS >= 2)
354  case 2 :
355  __C30_UART = 2; //this is the default UART
356  configUART2(u32_baudRate);
357  break;
358 #endif
359 #if (NUM_UART_MODS >= 3)
360  case 3 :
361  __C30_UART = 3; //this is the default UART
362  configUART3(u32_baudRate);
363  break;
364 #endif
365 #if (NUM_UART_MODS >= 4)
366  case 4 :
367  __C30_UART = 4; //this is the default UART
368  configUART4(u32_baudRate);
369  break;
370 #endif
371  default :
372  REPORT_ERROR("Invalid UART");
373  }
374 }
375