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 # include "esos.h"
48 # define outChar __esos_unsafe_PutUint8
49 #else
50 /** Write a character to the serial port.
51  * This function blocks until a character is
52  * written. The UART used
53  * is determined by the __C30_UART variable, which
54  * defaults to 1.
55  * \param u8_c Character to write
56  */
57 void outChar(uint8_t u8_c) {
58  switch (__C30_UART) {
59 #if (NUM_UART_MODS >= 1)
60  case 1 :
61  outChar1(u8_c);
62  break;
63 #endif
64 #if (NUM_UART_MODS >= 2)
65  case 2 :
66  outChar2(u8_c);
67  break;
68 #endif
69 #if (NUM_UART_MODS >= 3)
70  case 3 :
71  outChar3(u8_c);
72  break;
73 #endif
74 #if (NUM_UART_MODS >= 4)
75  case 4 :
76  outChar4(u8_c);
77  break;
78 #endif
79  default :
80  REPORT_ERROR("Invalid UART");
81  }
82 }
83 #endif
84 
85 /** Write a null-terminated string to the serial port.
86 See file documentation for End-of-line behavior when passed a "\n" (newline).
87 \param psz_s Pointer to null-terminated string to print.
88 */
89 void outString(const char* psz_s) {
90  while (*psz_s) {
91 
92 #if (SERIAL_EOL_DEFAULT == SERIAL_EOL_CR_LF)
93  if (*psz_s == '\n') outChar(0x0D);
94  outChar(*psz_s);
95 #endif
96 #if (SERIAL_EOL_DEFAULT == SERIAL_EOL_CR)
97  if (*psz_s == '\n') outChar(0x0D);
98  else outChar(*psz_s);
99 #endif
100 #if (SERIAL_EOL_DEFAULT == SERIAL_EOL_LF)
101 //no translation
102  outChar(*psz_s);
103 #endif
104  psz_s++;
105  }
106 }
107 
108 
109 
110 
111 static uint16_t inStringInternal(char *psz_buff, uint16_t u16_maxCount, uint8_t echoFlag) {
112  uint8_t u8_c;
113  uint16_t u16_i;
114 
115  if (!u16_maxCount) return 0;
116  u16_i = 0;
117  for (u16_i = 0; u16_i < u16_maxCount; u16_i++) {
118  if (echoFlag) u8_c = inCharEcho();
119  else u8_c = inChar();
120  if (u8_c == '\n' ||u8_c == '\r' ) break; //terminate loop
121  *psz_buff = u8_c; //save character
122  psz_buff++;
123  }
124  //stop reading, terminate, return characters read.
125  *psz_buff = 0;
126  return(u16_i);
127 }
128 
129 /**
130 Reads a string into psz_buff, assumes psz_buff can
131 hold at least u16_maxCount+1 characters. String reading
132 halts when either a newline or carriage return is read, or u16_maxCount
133 characters is read. The return string is always null-terminated.
134 The return count does not includes the null terminator.
135 An input string of just '\n' returns a null string.
136 \param psz_buff pointer to buffer for storing string read from console
137 \param u16_maxCount maximum number of characters to read from console.
138 */
139 uint16_t inString(char *psz_buff, int16_t u16_maxCount) {
140  return inStringInternal(psz_buff,u16_maxCount,0);
141 }
142 
143 /**
144 Same as inString(), except echoes characters to console as they are read.
145 */
146 uint16_t inStringEcho (char *psz_buff, int16_t u16_maxCount) {
147  return inStringInternal(psz_buff,u16_maxCount,1);
148 }
149 
150 
151 void outUint8NoLeader(uint8_t u8_x) {
152  uint8_t u8_c;
153  u8_c = (u8_x>>4)& 0xf;
154  if (u8_c > 9) outChar('A'+u8_c-10);
155  else outChar('0'+u8_c);
156  //LSDigit
157  u8_c= u8_x & 0xf;
158  if (u8_c > 9) outChar('A'+u8_c-10);
159  else outChar('0'+u8_c);
160 }
161 
162 /**
163 Output u8_x as formatted hex value with leading "0x".
164 \param u8_x value to output.
165 */
166 void outUint8(uint8_t u8_x) {
167  outString("0x");
168  outUint8NoLeader(u8_x);
169 }
170 
171 /**
172 Output u16_x as formatted hex value with leading "0x".
173 \param u16_x value to output.
174 */
175 void outUint16(uint16_t u16_x) {
176  uint8_t u8_c;
177 
178  outString("0x");
179  u8_c = (u16_x >> 8);
180  outUint8NoLeader(u8_c);
181  u8_c = (uint8_t) u16_x;
182  outUint8NoLeader(u8_c);
183 }
184 
185 /**
186 Output u32_x as formatted hex value with leading "0x".
187 \param u32_x value to output.
188 */
189 void outUint32(uint32_t u32_x) {
190  uint8_t u8_c;
191  outString("0x");
192  u8_c = (u32_x >> 24);
193  outUint8NoLeader(u8_c);
194  u8_c = (u32_x >> 16);
195  outUint8NoLeader(u8_c);
196  u8_c = (u32_x >> 8);
197  outUint8NoLeader(u8_c);
198  u8_c = u32_x;
199  outUint8NoLeader(u8_c);
200 }
201 
202 /**
203 Output u8_x as decimal value.
204 \param u8_x value to output.
205 */
207  static const uint8_t u8_d[]= {50, 30, 20, 10, 5, 3, 2, 1 };
208  static const uint8_t u8_f[]= {5, 3, 2, 1, 5, 3, 2, 1 };
209 
210  char psz_out[5];
211  uint8_t u8_i, u8_destroy;
212 
213  u8_i = 0;
214  u8_destroy = u8_x;
215  psz_out[0] = '0';
216  psz_out[1] = '0';
217  psz_out[2] = '0';
218  psz_out[3] = 0;
219  if (u8_destroy >= 200) {
220  psz_out[0] += 2;
221  u8_destroy -= 200;
222  } // end if()
223  if (u8_destroy >= 100) {
224  psz_out[0] += 1;
225  u8_destroy -= 100;
226  } // end if()
227  for (u8_i=0; u8_i<8; u8_i++) {
228  if (u8_destroy >= u8_d[u8_i]) {
229  psz_out[1+(u8_i/4)] += u8_f[u8_i];
230  u8_destroy -= u8_d[u8_i];
231  }
232  } //end for()
233  psz_out[3] = 0;
234  outString( psz_out );
235 }
236 
237 /**
238 Output u16_x as decimal value.
239 \param u16_x value to output.
240 */
241 void outUint16Decimal(uint16_t u16_x) {
242  static const uint16_t u16_d[]= {50000, 30000, 20000, 10000, 5000, 3000, 2000, 1000, \
243  500, 300, 200, 100, 50, 30, 20, 10, 5, 3, 2, 1
244  };
245  static const uint8_t u8_f[]= {5, 3, 2, 1 };
246 
247  uint8_t u8_i;
248  uint16_t u16_destroy;
249  char psz_out[5];
250 
251  u8_i = 0;
252  u16_destroy = u16_x;
253  psz_out[0] = '0';
254  psz_out[1] = '0';
255  psz_out[2] = '0';
256  psz_out[3] = '0';
257  psz_out[4] = '0';
258 
259  for (u8_i=0; u8_i<20; u8_i++) {
260  if (u16_destroy >= u16_d[u8_i]) {
261  psz_out[u8_i/4] += u8_f[u8_i % 4];
262  u16_destroy -= u16_d[u8_i];
263  }
264  } //end for()
265  psz_out[5] = 0;
266  outString( psz_out );
267 }
268 
269 /** Read a character from the serial port.
270  * This function blocks until a character is
271  * read.
272  * The serial port used is selected by the
273  * __C30_UART variable, which defaults to 1.
274  * \return Character read from the serial port.
275  */
277  switch (__C30_UART) {
278 #if (NUM_UART_MODS >= 1)
279  case 1 :
280  return inChar1();
281 #endif
282 #if (NUM_UART_MODS >= 2)
283  case 2 :
284  return inChar2();
285 #endif
286 #if (NUM_UART_MODS >= 3)
287  case 3 :
288  return inChar3();
289 #endif
290 #if (NUM_UART_MODS >= 4)
291  case 4 :
292  return inChar4();
293 #endif
294  default :
295  REPORT_ERROR("Invalid UART");
296  return 0;
297  }
298 }
299 
300 /**
301 Same as inChar(), except echo character that is back to console
302 */
303 
305  uint8_t u8_c;
306  u8_c = inChar(); //get character
307  outChar(u8_c); //echo
308  return u8_c;
309 }
310 
311 /** Determine if a character is ready to be read
312  * from the serial port.
313  * \return non-zero value if character is ready, zero otherwise..
314  */
316  switch (__C30_UART) {
317 #if (NUM_UART_MODS >= 1)
318  case 1 :
319  return isCharReady1();
320 #endif
321 #if (NUM_UART_MODS >= 2)
322  case 2 :
323  return isCharReady2();
324 #endif
325 #if (NUM_UART_MODS >= 3)
326  case 3 :
327  return isCharReady3();
328 #endif
329 #if (NUM_UART_MODS >= 4)
330  case 4 :
331  return isCharReady4();
332 #endif
333  default :
334  REPORT_ERROR("Invalid UART");
335  return 0;
336  }
337 }
338 
339 
340 
341 /** Configures a UART based compiler setting of DEFAULT_UART
342  * and sets __C30_UART to the default UART.
343  * If you want to configure a different UART, then call the configUARTx function explicitly.
344  * \param u32_baudRate The baud rate to use.
345  */
346 void configDefaultUART(uint32_t u32_baudRate) {
347  __C30_UART = DEFAULT_UART;
348 
349 #if DEFAULT_UART == 1
350  configUART1(u32_baudRate);
351 #elif DEFAULT_UART == 2
352  configUART2(u32_baudRate);
353 #elif DEFAULT_UART == 3
354  configUART3(u32_baudRate);
355 #elif DEFAULT_UART == 4
356  configUART4(u32_baudRate);
357 #else
358 # error "Invalid DEFAULT_UART."
359 #endif
360 }