Add lss file for cpp_obj program
[avr_serial_lcd.git] / tester / serial_lcd_tester.c
1 /******************************************************************************\r
2  ** FILE IDENTIFICATION\r
3  **   Name:               serial_lcd_tester.c\r
4  **   Purpose:            Tests Serial_Lcd\r
5  **   Author:             Kevin M. Rosenberg\r
6  **   Last Modification:  March 2007\r
7  **\r
8  ** PLATFORM\r
9  **   Linux and Windows/Cygwin\r
10  **\r
11  ** Custom character bitmaps by Carl W. Livingston\r
12  ******************************************************************************/\r
13 \r
14 // Will likely need to change for your system and LCD display\r
15 \r
16 #define DEFAULT_PORT "/dev/com7"\r
17 static unsigned char lcdCols = 20;\r
18 static unsigned char lcdRows = 4;\r
19 \r
20 #include <stdio.h>   /* Standard input/output definitions */\r
21 #include <string.h>  /* String function definitions */\r
22 #include <unistd.h>  /* UNIX standard function definitions */\r
23 #include <fcntl.h>   /* File control definitions */\r
24 #include <errno.h>   /* Error number definitions */\r
25 #include <termios.h> /* POSIX terminal control definitions */\r
26 #include <sys/select.h>\r
27 #include <time.h>\r
28 #include <sys/time.h>\r
29 #include <stdlib.h>\r
30 \r
31 void MakeCustomChar (const char *Symbol, char Address);\r
32 void delay_ms(unsigned int t);\r
33 void clear_display(void);\r
34 void display_banner(void);\r
35 \r
36 int open_serial_port (char const* const);\r
37 void close_serial_port (void);\r
38 void serial_puts (const char* str);\r
39 void serial_putc (const unsigned char c);\r
40 void run_test(void);\r
41 \r
42 static inline double get_time(void) {\r
43   struct timeval tv;\r
44   gettimeofday (&tv, NULL);\r
45   return tv.tv_sec + tv.tv_usec/1e6;\r
46 }\r
47 \r
48 // Integer delay_ms routine\r
49 // 65.535 seconds maximum\r
50 void delay_ms(unsigned int t)\r
51 {\r
52   double start = get_time();\r
53   double end = start + t/1000;\r
54   while (get_time() < end) {}\r
55 }\r
56 \r
57 \r
58 void usage(char const* const prog) {\r
59   fprintf(stderr, "usage: %s <portname>\n", basename(prog));\r
60   fprintf(stderr, "Port name is in Cygwin format.\n");\r
61   fprintf(stderr, "Example: COM1 would be /dev/com1\n");\r
62 }\r
63 \r
64 \r
65 int main(int argc, char ** argv) {\r
66   char portName[30];\r
67   portName[sizeof(portName)] = 0;  // ensure string is zero-terminated by below strncpy\r
68   if (argc == 1) {\r
69     strncpy (portName, DEFAULT_PORT, sizeof(portName)-1);\r
70     fprintf (stderr, "Using default serial port of %s\n", portName);\r
71   } else if (argc == 2) {\r
72     strncpy (portName, argv[1], sizeof(portName));\r
73   } else {\r
74     usage(argv[0]);\r
75     exit(1);\r
76   }\r
77   if (! open_serial_port (portName)) {\r
78     fprintf(stderr, "Unable to open serial port %s\n", portName);\r
79     return 1;\r
80   }\r
81   run_test();\r
82   close_serial_port();\r
83   return 0;\r
84 }\r
85 \r
86 // Serial_Lcd command delimiter\r
87 #define SERIAL_LCD_CMD_MODE 0xFE\r
88 \r
89 // Display clear text command\r
90 #define LCD_CLR_CMD  0x01\r
91 // Display home cursor command\r
92 #define LCD_HOME_CMD 0x02\r
93 \r
94 // Display entry mode command & parameters\r
95 #define LCD_ENTRY_CMD 0x04\r
96 #define CURSOR_DIR    0x02\r
97 #define CURSOR_MOVE   0x01\r
98 \r
99 // Display control mode & parameters\r
100 #define LCD_CONTROL_CMD 0x08\r
101 #define LCD_ON          0x04\r
102 #define CURSOR_ON       0x02\r
103 #define CURSOR_BLINK    0x01\r
104 \r
105 // Display cursor control & parameters\r
106 #define LCD_CURSOR_CMD  0x10\r
107 #define LCD_SHIFT       0x08\r
108 #define DISPLAY_L_R     0x04\r
109 \r
110 // Display line position addressing\r
111 #define LINE1_ADDR      0x80\r
112 #define LINE2_ADDR      0xC0\r
113 #define LINE3_ADDR      0x94\r
114 #define LINE4_ADDR      0xD4\r
115 \r
116 // Display data & character generator selection bits\r
117 #define DD_RAM          0x80\r
118 #define CG_RAM          0x40\r
119 \r
120 // Custom Character DDRAM location addressing\r
121 #define DDRAM_START_ADD_0 0x00\r
122 #define DDRAM_START_ADD_1 0x01\r
123 #define DDRAM_START_ADD_2 0x02\r
124 #define DDRAM_START_ADD_3 0x03\r
125 #define DDRAM_START_ADD_4 0x04\r
126 #define DDRAM_START_ADD_5 0x05\r
127 #define DDRAM_START_ADD_6 0x06\r
128 #define DDRAM_START_ADD_7 0x07\r
129 \r
130 // Custom Character CGRAM Starting addresses\r
131 #define CGRAM_START_ADD_0 0x40\r
132 #define CGRAM_START_ADD_1 0x48\r
133 #define CGRAM_START_ADD_2 0x50\r
134 #define CGRAM_START_ADD_3 0x58\r
135 #define CGRAM_START_ADD_4 0x60\r
136 #define CGRAM_START_ADD_5 0x68\r
137 #define CGRAM_START_ADD_6 0x70\r
138 #define CGRAM_START_ADD_7 0x78\r
139 \r
140 // ASCII control code (0xFB) to set LED brightness.\r
141 // Next byte sets brightness (from 0 to 255)\r
142 #define CMD_SET_BRIGHTNESS 0xFB\r
143 #define NUM_BRIGHTNESS_LEVELS 8\r
144 #define BRIGHTNESS_SCALE(b)  ((unsigned char) ((b * 254.) / (double) (NUM_BRIGHTNESS_LEVELS-1)) + 1)\r
145 \r
146 // ASCII control code (0xFC) turns on LED\r
147 #define LED_ON 0xFC\r
148 // ASCII control code (0xFD) turns on LED\r
149 #define LED_OFF 0xFD\r
150 \r
151 // Smiley face\r
152 const char Smiley_face[] = {// Smiley face\r
153   0x0E,  // 0b00001110,\r
154   0x1F,  // 0b00011111,\r
155   0x00,  // 0b00000000,\r
156   0x0A,  // 0b00001010,\r
157   0x04,  // 0b00000100,\r
158   0x11,  // 0b00010001,\r
159   0x0E,  // 0b00001110,\r
160   0x00,  // 0b00000000\r
161 };\r
162 const char Thin_cross[] = {// Thin cross\r
163   0x11,  // 0b00010001,\r
164   0x00,  // 0b00000000,\r
165   0x1F,  // 0b00011111,\r
166   0x15,  // 0b00010101,\r
167   0x1B,  // 0b00011011,\r
168   0x0E,  // 0b00001110,\r
169   0x11,  // 0b00010001,\r
170   0x00,  // 0b00000000\r
171 };\r
172 const char Thick_cross[] = {// Thick cross\r
173   0x00,  // 0b00000000,\r
174   0x0E,  // 0b00001110,\r
175   0x1B,  // 0b00011011,\r
176   0x11,  // 0b00010001,\r
177   0x1B,  // 0b00011011,\r
178   0x0E,  // 0b00001110,\r
179   0x00,  // 0b00000000,\r
180   0x00,  // 0b00000000\r
181 };\r
182 const char Music_note[] = {// Music note\r
183   0x03,  // 0b00000011,\r
184   0x02,  // 0b00000010,\r
185   0x07,  // 0b00000111,\r
186   0x02,  // 0b00000010,\r
187   0x1E,  // 0b00011110,\r
188   0x12,  // 0b00010010,\r
189   0x1E,  // 0b00011110,\r
190   0x00,  // 0b00000000\r
191 };\r
192 const char Loop_Antenna[] = {// Loop Antenna\r
193   0x11,  // 0b00010001,\r
194   0x11,  // 0b00010001,\r
195   0x1F,  // 0b00011111,\r
196   0x15,  // 0b00010101,\r
197   0x15,  // 0b00010101,\r
198   0x04,  // 0b00000100,\r
199   0x0E,  // 0b00001110,\r
200   0x00,  // 0b00000000\r
201 };\r
202 const char Lh_Yagi_Antenna[] = {// Lh Yagi Antenna\r
203   0x10,  // 0b00010000,\r
204   0x14,  // 0b00010100,\r
205   0x15,  // 0b00010101,\r
206   0x1F,  // 0b00011111,\r
207   0x15,  // 0b00010101,\r
208   0x14,  // 0b00010100,\r
209   0x10,  // 0b00010000,\r
210   0x00,  // 0b00000000\r
211 };\r
212 const char Diamond[] = {// Diamond\r
213   0x00,  // 0b00000000,\r
214   0x1F,  // 0b00011111,\r
215   0x11,  // 0b00010001,\r
216   0x15,  // 0b00010101,\r
217   0x11,  // 0b00010001,\r
218   0x1F,  // 0b00011111,\r
219   0x00,  // 0b00000000,\r
220   0x00,  // 0b00000000\r
221 };\r
222 const char Rh_Yagi_Antenna[] = {// Rh Yagi Antenna\r
223   0x01,  // 0b00000001,\r
224   0x05,  // 0b00000101,\r
225   0x15,  // 0b00010101,\r
226   0x1F,  // 0b00011111,\r
227   0x15,  // 0b00010101,\r
228   0x05,  // 0b00000101,\r
229   0x01,  // 0b00000001,\r
230   0x00,  // 0b00000000\r
231 };\r
232 \r
233 const char BannerMessage1[] = "Serial Lcd";\r
234 const char BannerMessage2[] = "Tester By";\r
235 const char BannerMessage3[] = "Kevin M. Rosenberg";\r
236 const char BannerMessage4[] = "www.avrcode.com";\r
237 \r
238 char led_on;\r
239 unsigned char brightness = NUM_BRIGHTNESS_LEVELS - 1;\r
240 \r
241 void run_test (void) {\r
242   double start_time = get_time();\r
243 \r
244   delay_ms(40); // Ensure time for LCD to be ready\r
245   led_on = 0;\r
246   serial_putc (LED_OFF); // turn off the LED\r
247 \r
248   MakeCustomChar (Smiley_face, CGRAM_START_ADD_0);\r
249   MakeCustomChar (Lh_Yagi_Antenna, CGRAM_START_ADD_1);\r
250   MakeCustomChar (Diamond, CGRAM_START_ADD_2);\r
251   MakeCustomChar (Rh_Yagi_Antenna, CGRAM_START_ADD_3);\r
252   MakeCustomChar (Thin_cross, CGRAM_START_ADD_4);\r
253   MakeCustomChar (Thick_cross, CGRAM_START_ADD_5);\r
254   MakeCustomChar (Music_note, CGRAM_START_ADD_6);\r
255   MakeCustomChar (Loop_Antenna, CGRAM_START_ADD_7);\r
256 \r
257   // Put the banner message on the display\r
258   clear_display(); // Clear the display for the banner message\r
259   display_banner(); // Display the banner message\r
260   delay_ms(1000); // Display banner message for 1 seconds\r
261 \r
262   struct termios inopt;\r
263   funlockfile(stdin);\r
264 #ifdef __CYGWIN__\r
265   tcgetattr(stdin->_file, &inopt);\r
266 #else\r
267   tcgetattr(stdin->_fileno, &inopt);\r
268 #endif\r
269   inopt.c_lflag &= ~ICANON;  // non-canonical mode: no waiting on read\r
270   inopt.c_cc[VMIN] = 0; // minimum read characters\r
271   inopt.c_cc[VTIME] = 0; // timeout in deciseconds\r
272 #ifdef __CYGWIN__\r
273   if (tcsetattr (stdin->_file, TCSANOW, &inopt) < 0) {\r
274 #else\r
275   if (tcsetattr (stdin->_fileno, TCSANOW, &inopt) < 0) {\r
276 #endif\r
277     fprintf(stderr, "Error setting stdin parameters (%d: %s)\n",\r
278             errno, strerror(errno));\r
279     exit(1);\r
280   }\r
281 \r
282   clear_display(); // Clear the display for updating data\r
283 \r
284   while(1) {\r
285     char cntStr[20];\r
286     serial_putc (SERIAL_LCD_CMD_MODE); // Put the LCD in command mode\r
287     serial_putc (LINE2_ADDR);   // Set the LCD cursor position\r
288     double elapsed = get_time() - start_time;\r
289     snprintf(cntStr, sizeof(cntStr), "%.3lf", elapsed);\r
290     serial_puts (cntStr);\r
291 \r
292     // Write the custom characters to the display\r
293     serial_putc (SERIAL_LCD_CMD_MODE); // Put the LCD in command mode\r
294     serial_putc (LINE1_ADDR);   // Set the LCD cursor position\r
295     serial_putc (DDRAM_START_ADD_0); // Display custom character 0\r
296     serial_putc (DDRAM_START_ADD_1); // Display custom character 1\r
297     serial_putc (DDRAM_START_ADD_2); // Display custom character 2\r
298     serial_putc (DDRAM_START_ADD_3); // Display custom character 3\r
299     serial_putc (DDRAM_START_ADD_4); // Display custom character 4\r
300     serial_putc (DDRAM_START_ADD_5); // Display custom character 5\r
301     serial_putc (DDRAM_START_ADD_6); // Display custom character 6\r
302     serial_putc (DDRAM_START_ADD_7); // Display custom character 7\r
303 \r
304 \r
305     char ch = getc_unlocked(stdin);\r
306     if (ch == 'l') {\r
307       if (led_on) {\r
308         serial_putc (LED_OFF); // Else, turn off the LED\r
309         led_on = 0;\r
310       } else {\r
311         serial_putc (LED_ON); // Turn on the LED\r
312         led_on = 1;\r
313       }\r
314     } else if (ch == 'b') {\r
315       if (brightness >= NUM_BRIGHTNESS_LEVELS - 1)\r
316         brightness = 0;\r
317       else\r
318         brightness++;\r
319       serial_putc (CMD_SET_BRIGHTNESS);\r
320       printf("%u(%u)", brightness, (unsigned int) BRIGHTNESS_SCALE(brightness));\r
321       serial_putc (BRIGHTNESS_SCALE(brightness));\r
322     }\r
323   }\r
324 }\r
325 \r
326 void MakeCustomChar (const char *Symbol, char Address) {\r
327   // Set up the custom characters\r
328   serial_putc (SERIAL_LCD_CMD_MODE); // Put the LCD in command mode\r
329   serial_putc (Address);  // Set the display to CGRAM mode, address 0\r
330   // Output the 8 bytes of the custom character\r
331   for (unsigned char i = 0; i < 8; i++) {\r
332     serial_putc (Symbol[n]);\r
333   }\r
334 }\r
335 \r
336 // Clear the display\r
337 void clear_display(void)\r
338 {\r
339   serial_putc (SERIAL_LCD_CMD_MODE);    // Put the LCD in command mode\r
340   serial_putc (LCD_CLR_CMD); // Send the clear the LCD display\r
341   delay_ms (30);             // Wait for LCD controller to startup\r
342 }\r
343 \r
344 void tx_string_center (const char* str, unsigned char line_num) {\r
345   unsigned char pos;\r
346   switch (line_num) {\r
347   case 3:\r
348     pos = LINE4_ADDR;\r
349     break;\r
350   case 2:\r
351     pos = LINE3_ADDR;\r
352     break;\r
353   case 1:\r
354     pos = LINE2_ADDR;\r
355     break;\r
356   case 0:\r
357   default:\r
358     pos = LINE1_ADDR;\r
359     break;\r
360   }\r
361 \r
362   serial_putc (SERIAL_LCD_CMD_MODE); // Put the LCD in command mode\r
363   char offset = (lcdCols - strlen(str)) / 2; // offset to center line\r
364   if (offset < 0)\r
365     offset = 0;\r
366   serial_putc (pos + offset); // Set LCD cursor position\r
367   serial_puts (str); // Display string\r
368 }\r
369 \r
370 // Print the banner message\r
371 void display_banner(void) {\r
372   tx_string_center (BannerMessage1, 0);\r
373   tx_string_center (BannerMessage2, 1);\r
374   tx_string_center (BannerMessage3, 2);\r
375   tx_string_center (BannerMessage4, 3);\r
376 }\r
377 \r
378 \r
379 // Serial port section\r
380 \r
381 static int serialFd = -1; // serial port file descriptor\r
382 \r
383 int open_serial_port(char const* const port ) {\r
384   struct termios options;\r
385   int count,ret;\r
386 \r
387   serialFd = open (port, O_RDWR | O_NOCTTY | O_NONBLOCK);\r
388   if (serialFd == -1)\r
389     return 0;\r
390 \r
391   fcntl(serialFd, F_SETFL, 0);\r
392 \r
393   if (tcgetattr(serialFd, &options) < 0) {\r
394     fprintf(stderr, "Error reading serial port parameters (%d: %s)\n",\r
395             errno, strerror(errno));\r
396     exit(1);\r
397   }\r
398 \r
399   cfsetispeed (&options, B115200); // 115200 baud\r
400   cfsetospeed (&options, B115200); // 115200 baud\r
401 \r
402   options.c_cflag |= (CLOCAL | CREAD); /* enable */\r
403   options.c_cflag &= ~PARENB; // turn off parity\r
404   options.c_cflag &= ~CSTOPB; // one stop bit\r
405   options.c_cflag &= ~CSIZE;\r
406   options.c_cflag |= CS8; // 8-bit input\r
407   options.c_cflag &= ~CRTSCTS; // no flow control\r
408 \r
409   options.c_lflag &= ~ICANON;  // non-canonical mode: no waiting on read\r
410   options.c_lflag &= ~ECHO;  // Do not echo bytes written\r
411   options.c_lflag &= ~ECHOE;\r
412   options.c_lflag &= ~ECHONL;  // Do not echo newline\r
413   options.c_lflag &= ~IEXTEN;  // Disable implementation input processing\r
414   options.c_lflag &= ~ISIG;  // Disable signal processing\r
415 \r
416   options.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INPCK | IXOFF\r
417                        | INLCR | IGNCR | ICRNL | IXON | IXANY);\r
418 \r
419   options.c_oflag &= ~OPOST;   // Disable implementation output processing\r
420 \r
421   options.c_cc[VMIN] = 0; // minimum read characters\r
422   options.c_cc[VTIME] = 0; // timeout in deciseconds\r
423 \r
424   /* set all of the options */\r
425   tcflush(serialFd, TCIFLUSH);\r
426   if (tcsetattr (serialFd, TCSANOW, &options) < 0) {\r
427     fprintf(stderr, "Error setting serial port parameters (%d: %s)\n",\r
428             errno, strerror(errno));\r
429     exit(1);\r
430   }\r
431 \r
432   // Verify settings\r
433   if (tcgetattr(serialFd, &options) < 0) {\r
434     fprintf(stderr, "Error to re-read serial port parameters (%d: %s)\n",\r
435             errno, strerror(errno));\r
436     exit(1);\r
437   }\r
438   if (options.c_lflag & ICANON) {\r
439     fprintf(stderr, "Error: still in canonical serial mode\n");\r
440     exit(1);\r
441   }\r
442   if (options.c_cc[VTIME] != 0) {\r
443     fprintf(stderr, "Error: VTIME does not equal 0, but is %d\n", options.c_cc[VTIME]);\r
444     exit(1);\r
445   }\r
446   if (options.c_cc[VMIN] != 0) {\r
447     fprintf(stderr, "Error: VMIN does not equal 0, but is %d\n", options.c_cc[VMIN]);\r
448     exit(1);\r
449   }\r
450 \r
451 \r
452   return 1;\r
453 }\r
454 \r
455 void close_serial_port(void) {\r
456   if (serialFd >= 0) {\r
457     close(serialFd);\r
458     serialFd = -1;\r
459   }\r
460 }\r
461 \r
462 void serial_puts (const char* str) {\r
463   int len = strlen(str);\r
464   int written = write (serialFd, str, len);\r
465   if (written < 0) {\r
466       fprintf (stderr, "Unable to write '%s' to fd %d, errno = %d (%s)\n",\r
467                str, serialFd, errno, strerror(errno));\r
468       close (serialFd);\r
469       exit (1);\r
470   } else if (written != len) {\r
471     fprintf (stderr, "Unable to fully write '%s', %d bytes written\n",\r
472              str, written);\r
473     close (serialFd);\r
474     exit(1);\r
475   }\r
476 }\r
477 \r
478 \r
479 void serial_putc (const unsigned char c) {\r
480   int written = write (serialFd, &c, 1);\r
481   if (written < 0) {\r
482       fprintf (stderr, "Unable to write '%c' to fd %d, errno = %d (%s)\n",\r
483                c, serialFd, errno, strerror(errno));\r
484       close (serialFd);\r
485       exit (1);\r
486   }\r
487 }\r