1 /***************************************************************************
2 * Copyright (C) 2008 by Peter Marquardt *
3 * p_marquardt@users.sourceforge.net *
4 * code base Copyright (C) 2007 by Carsten Presser *
6 * This program is free software; you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation; either version 2 of the License, or *
9 * (at your option) any later version. *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program; if not, write to the *
18 * Free Software Foundation, Inc., *
19 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
20 ***************************************************************************/
22 /*! \file pcctldisplaytest.cpp
23 \brief A utility to test the picctl lcd display and interface
24 \author Peter Marquardt p_marquardt@users.sourceforge.net
25 \author Carsten Presser
26 \todo sanitize command line argument parsing
36 #include "picctldisplaytest.h"
40 runtime_flags myflags;
46 uint8_t buf_cmd_start;
50 int main(int argc, char *argv[])
52 bool kill_flag = false;
53 struct termios options;
59 buf_flag_escape = false;
61 cout << "** picctldisplaytest - simple test utility for picctl lcd displays **" << endl
65 myconfig.debug = false;
66 myconfig.verbosity = 0;
67 myconfig.modem_device = "/dev/ttyACM0";
68 myflags.parse_return_clockram = false;
71 for (int i = 1; i < argc; i++) {
72 if (*argv[i] == 'd') {
74 myconfig.modem_device = argv[i];
76 else if (*argv[i] == 'v') {
78 myconfig.verbosity = atoi(argv[i]);
80 else if (*argv[i] == 'D') {
85 if (myconfig.verbosity > 0 || myconfig.debug) {
86 cout << "picctldisplaytest called with\n"
87 << "device: " << myconfig.modem_device << endl
88 << "verbosity: " << myconfig.verbosity << endl
89 << "debug mode:" << boolalpha << myconfig.debug << endl;
92 /* open the device to be non-blocking (read will return immediatly) */
93 fd = open(myconfig.modem_device, O_RDWR | O_NOCTTY | O_NONBLOCK);
94 if (fd <0) {perror(myconfig.modem_device); exit(-1); }
96 cfsetispeed(&options, BAUDRATE);
97 cfsetospeed(&options, BAUDRATE);
99 options.c_cflag &= ~PARENB;
100 options.c_cflag &= ~CSTOPB;
101 options.c_cflag &= ~CSIZE;
102 options.c_cflag |= CS8;
104 options.c_cflag &= ~CRTSCTS;
105 options.c_cflag |= (CLOCAL | CREAD);
106 options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
107 options.c_iflag &= ~(IXON | IXOFF | IXANY);
108 options.c_oflag &= ~OPOST;
109 tcsetattr(fd, TCSANOW, &options);
111 if (myconfig.debug || myconfig.verbosity > 0) print_help();
113 while ( cin.get(key)) {
116 cout << "Exiting." << endl;
120 cout << "Switching to unmanaged mode..." << endl;
121 send_data(CMD_SET_MODE_UNMANAGED,(sizeof(CMD_SET_MODE_UNMANAGED)/sizeof(char)));
124 cout << "Switching to managed mode..." << endl;
125 send_data(CMD_SET_MODE_MANAGED,(sizeof(CMD_SET_MODE_MANAGED)/sizeof(char)));
128 cout << "Sending Clear Display..." << endl;
129 send_data(CMD_DISP_CLEAR_SCREEN,(sizeof(CMD_DISP_CLEAR_SCREEN)/sizeof(char)));
132 cout << "Sending Bootload Start..." << endl;
133 send_data(CMD_BOOT,(sizeof(CMD_BOOT)/sizeof(char)));
142 cout << "Display CG ROM charset..." << endl;
143 send_data(TEST_STRING_1,(sizeof(TEST_STRING_1)/sizeof(char)));
144 send_data(TEST_STRING_2,(sizeof(TEST_STRING_2)/sizeof(char)));
145 send_data(TEST_STRING_3,(sizeof(TEST_STRING_3)/sizeof(char)));
148 cout << "Filling the Display with CG ROM charset..." << endl;
149 send_data(TEST_STRING_1,(sizeof(TEST_STRING_1)/sizeof(char)));
150 send_data(TEST_STRING_2,(sizeof(TEST_STRING_2)/sizeof(char)));
151 send_data(TEST_STRING_3,(sizeof(TEST_STRING_3)/sizeof(char)));
152 send_data(TEST_STRING_4,(sizeof(TEST_STRING_4)/sizeof(char)));
153 send_data(TEST_STRING_5,(sizeof(TEST_STRING_5)/sizeof(char)));
156 cout << "Sending Test String... one line per packet, 8 lines of 30 chars" << endl;
157 for (int j = 0; j < 8; j++) {
158 const unsigned char cmd[] = {0xAA,0x14,0x00,32,((j*30)),0x08,
159 16,17,18,19,20,21,22,23,24,25,
160 16,17,18,19,20,21,22,23,24,25,
161 16,17,18,19,20,21,22,23,24,25};
162 send_data(cmd,(sizeof(cmd)/sizeof(char)));
167 cout << "Sending Test String.. one char per packet,8 lines of 30 chars" << endl;
168 for (int j = 0; j < 8; j++) {
169 for (int k = 0; k < 30; k++) {
170 const unsigned char cmd[] = {0xAA,0x14,0x00,3,k+(j*30),0x08,
172 send_data(cmd,(sizeof(cmd)/sizeof(char)));
178 cout << "Set PWM1 0%..." << endl;
179 CMD_SET_PWM1[4] = 0x00;
180 send_data(CMD_SET_PWM1,(sizeof(CMD_SET_PWM1)/sizeof(char)));
183 cout << "SetPWM1 25%..." << endl;
184 CMD_SET_PWM1[4] = 0x40;
185 send_data(CMD_SET_PWM1,(sizeof(CMD_SET_PWM1)/sizeof(char)));
188 cout << "Set PWM1 50%..." << endl;
189 CMD_SET_PWM1[4] = 0x80;
190 send_data(CMD_SET_PWM1,(sizeof(CMD_SET_PWM1)/sizeof(char)));
193 cout << "Set PWM1 75%..." << endl;
194 CMD_SET_PWM1[4] = 0xC0;
195 send_data(CMD_SET_PWM1,(sizeof(CMD_SET_PWM1)/sizeof(char)));
198 cout << "Set PWM1 100%..." << endl;
199 CMD_SET_PWM1[4] = 0xFF;
200 send_data(CMD_SET_PWM1,(sizeof(CMD_SET_PWM1)/sizeof(char)));
203 cout << "Set PWM2 0%..." << endl;
204 CMD_SET_PWM2[4] = 0x00;
205 send_data(CMD_SET_PWM2,(sizeof(CMD_SET_PWM2)/sizeof(char)));
208 cout << "SetPWM2 25%..." << endl;
209 CMD_SET_PWM2[4] = 0x40;
210 send_data(CMD_SET_PWM2,(sizeof(CMD_SET_PWM2)/sizeof(char)));
213 cout << "Set PWM2 50%..." << endl;
214 CMD_SET_PWM2[4] = 0x80;
215 send_data(CMD_SET_PWM2,(sizeof(CMD_SET_PWM2)/sizeof(char)));
218 cout << "Set PWM2 75%..." << endl;
219 CMD_SET_PWM2[4] = 0xC0;
220 send_data(CMD_SET_PWM2,(sizeof(CMD_SET_PWM2)/sizeof(char)));
223 cout << "Set PWM2 100%..." << endl;
224 CMD_SET_PWM2[4] = 0xFF;
225 send_data(CMD_SET_PWM2,(sizeof(CMD_SET_PWM2)/sizeof(char)));
228 cout << "Setting pcf8583 clock memory..." << endl;
229 time_t mytime = time(NULL);
230 tm * myltime = localtime( &mytime);
231 if (myconfig.debug || myconfig.verbosity > 0) cout << "Local Time is: " << myltime->tm_hour << ":" << myltime->tm_min << ":" << myltime->tm_sec << " " << myltime->tm_mday << "." << myltime->tm_mon+1 << endl;
232 const unsigned char tcmd[] = {0xAA,0x41,0x00,0x10,
233 0x04,0x00,dec2bcd(myltime->tm_sec),dec2bcd(myltime->tm_min),dec2bcd(myltime->tm_hour),dec2bcd(myltime->tm_mday),
234 (dec2bcd(myltime->tm_mon+1)),0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
235 send_data(tcmd,(sizeof(tcmd)/sizeof(char)));
239 cout << "Dumping pcf8583 clock memory..." << endl;
240 int oldverbosity = myconfig.verbosity;
241 myflags.parse_return_clockram = true;
242 if (myconfig.verbosity < 2) {
243 myconfig.verbosity = 2;
245 send_data(CMD_GET_CLOCK_MEMORY,(sizeof(CMD_GET_CLOCK_MEMORY)/sizeof(char)));
246 myconfig.verbosity = oldverbosity;
247 myflags.parse_return_clockram = false;
251 cout << "Showing test picture 1..."<< endl;
252 write_gfx_ram( TEST_PICTURE_1,(sizeof(TEST_PICTURE_1)/sizeof(char)));
256 cout << "Showing test picture 2 - horizontal lines..."<< endl;
257 unsigned char mycmd[36] = {0xAA,0x14,0x00,0x20,0x00,0x00,
258 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
259 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
260 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
262 for (int i = 0; i <64;i+=2) {
263 mycmd[5] = (i*30) / 256;
264 mycmd[4] = (i*30) - (256 * mycmd[5]);
265 send_data(mycmd, (sizeof(mycmd)/sizeof(char)));
270 cout << "Showing test picture 3 - vertical lines..."<< endl;
271 unsigned char mycmd[36] = {0xAA,0x14,0x00,0x20,0x00,0x00,
272 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
273 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,
274 0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa,0xaa
276 for (int i = 0; i <64;i++) {
277 mycmd[5] = (i*30) / 256;
278 mycmd[4] = (i*30) - (256 * mycmd[5]);
279 send_data(mycmd, (sizeof(mycmd)/sizeof(char)));
284 cout << "Showing test picture 4...Boxes"<< endl;
285 write_gfx_ram(TEST_PICTURE_2,(sizeof(TEST_PICTURE_2)/sizeof(char)));
289 cout << "Showing test picture 5 - outline + center cross..."<< endl;
290 unsigned char mycmd_1[36] = {0xAA,0x14,0x00,0x20,0x00,0x00,
291 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
292 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
293 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff
295 unsigned char mycmd_2[36] = {0xAA,0x14,0x00,0x20,0x00,0x00,
296 0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
297 0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,
298 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01
301 for (int j = 0;j<2;j++) {
302 send_data(mycmd_1, (sizeof(mycmd_1)/sizeof(char)));
303 for ( i = 1; i <31;i++) {
304 mycmd_2[5] = ((i*30) + (j*960)) / 256;
305 mycmd_2[4] = ((i*30) + (j*960)) - (256 * mycmd_2[5]);
306 send_data(mycmd_2, (sizeof(mycmd_2)/sizeof(char)));
308 mycmd_1[5] = ((i*30) + (j*960)) / 256;
309 mycmd_1[4] = ((i*30) + (j*960)) - (256 * mycmd_1[5]);
311 send_data(mycmd_1, (sizeof(mycmd_1)/sizeof(char)));
319 if (key != 0x13 && key != '\n') cout << ">";
325 unsigned char bitendian (unsigned char in)
327 unsigned char ret = 0x00;
328 if (in & 0x01) ret+=0x80;
329 if (in & 0x02) ret+=0x40;
330 if (in & 0x04) ret+=0x20;
331 if (in & 0x08) ret+=0x10;
332 if (in & 0x10) ret+=0x08;
333 if (in & 0x20) ret+=0x04;
334 if (in & 0x40) ret+=0x02;
335 if (in & 0x80) ret+=0x01;
341 bool write_gfx_ram(const unsigned char * buffer, int numbytes) {
342 if (numbytes > 1920) {
343 cout << "Too much data for gfx RAM, ignoring..." << endl;
346 int i = 0, offset = 6, memaddr = 0;
347 bool all_sent = false;
348 unsigned char mycmd[63] = {0xAA,0x14,0x00,0x02,0x00,0x00};
349 while (i <numbytes) {
351 mycmd[offset] = bitendian(buffer[i]);
358 mycmd[5] = (memaddr / 256);
359 mycmd[4] = (memaddr - (mycmd[5]*256));
365 mycmd[3] = (offset-4);
366 send_data(mycmd,offset);
374 // read all available data (always get single bytes...)
375 while (read(fd,&buf[buf_pos],1) > 0)
377 // search for SYNC byte
378 if ((buf[buf_pos] == CMD_SYNC_RECV) && (!buf_flag_escape))
380 if (buf_cmd_start != 255)
384 printf("Damaged Packet: ");
385 for (i=buf_cmd_start; i<buf_pos; i++)
387 printf("0x%02x ",buf[i]);
389 printf("; buf_pos = %d, buf_cmd_start = %d\n",buf_pos,buf_cmd_start);
393 buf[buf_pos] = CMD_SYNC_RECV;
395 buf_cmd_start = buf_pos;
399 // escaping is not used so far...
400 /* if ((buf[buf_pos] == CMD_ESCAPE_BYTE) && (!buf_flag_escape))
402 // this byte was for masking only.. ignore it!
403 buf_flag_escape = true;
406 buf_flag_escape = false;*/
410 // we need to check for a valid packet...
411 if ((buf_pos - buf_cmd_start) >= CMD_DATA_START)
413 // if we recieved a valid packet: start decoding
414 if (buf[buf_cmd_start + CMD_HDR_LENGTH+1] == (buf_pos - buf_cmd_start - CMD_DATA_START))
426 /*! \brief prints some help
430 cout << "Usage:" << endl;
431 cout << "u\tset unmanaged mode" << endl;
432 cout << "m\tset managed mode" << endl;
434 cout << "T\tset pcf8583 clock to system time" << endl;
435 cout << "t\tdump pcf8583 clock memory" << endl;
437 cout << "Set PWM:" << endl;
438 cout << "PWM1\ta 0%\ts 25%\td 50%\tf 75%\tg 100%" << endl;
439 cout << "PWM2\tA 0%\tS 25%\tD 50%\tF 75%\tG 100%" << endl;
441 cout << "1\tshow ROM charset" << endl;
442 cout << "2\tfill Text area with ROM charset" << endl;
443 cout << "3\tfill Text area (8 lines / 30 chars, one line per packet)" << endl;
444 cout << "4\tfill Text area (8 lines / 30 chars, one char per packet)" << endl;
446 cout << "5\tshow test picture 1 (240x64px)" << endl;
447 cout << "6\tshow test picture 2 - horizontal lines (240x64px)" << endl;
448 cout << "7\tshow test picture 3 - vertical lines (240x64px)" << endl;
449 cout << "8\tshow test picture 4 - Boxes (240x64px)" << endl;
450 cout << "9\tshow test picture 5 - outline + center cross (240x64px)" << endl;
452 cout << "c\tclear display" << endl;
454 cout << "b\tenter bootload mode" << endl;
456 cout << "h\tprint this help" << endl;
457 cout << "j\tprint command line options" << endl;
458 cout << "q\tquit" << endl;
462 /*! \brief prints command line options
464 void print_cli_options() {
466 << " Command line options:\n"
469 << "\tSets the display device to DEVICE, default value is /dev/ttyACM0\n"
471 << "\tpicctldisplaytest d /dev/ttyACM0\n"
473 cout << "v VERBOSITY\n"
474 << "\tSets verbosity to level VERBOSITY ( Range: 0-2, default 0 )\n"
476 << "\tpicctldisplaytest v 1\n"
479 << "\tRun in debugging mode (aka. very verbose)\n"
481 << "\tpicctldisplaytest D\n"
483 cout << "Combining command line options\n"
484 << "\tAll command line options can be combined (though some combinations might not prove useful).\n"
486 << "\tpicctldisplaytest D d /dev/ttyACM0\n"
490 /*! \brief encodes an integer to a BCD value
492 int dec2bcd(int decimal) {
493 return (decimal > 99 ? false : ((decimal/10)<<4)+(decimal%10));
496 /*! \brief decodes a BCD value and returns it as integer
498 int bcd2dec(int bcd) {
499 return (((bcd>>4)*10)+bcd%16);
502 /*! \brief handles SIGIO
505 if (myconfig.debug || myconfig.verbosity > 0) {
506 //cout << "Received Data\n";
507 if (buf[buf_cmd_start] == CMD_SYNC_RECV) {
508 switch (buf[buf_cmd_start + 1]) {
510 cout << "Received an ACK packet, payload: " << (int) buf[3] << " bytes." << endl;
514 cout << "Received a NACK packet." << endl;
517 cout << "Received COMMAND NOT IMPLEMENTED." << endl;
520 cout << "Received IR/Key data." << endl;
523 cout <<"Unknown Response code 0x" << hex << buf[1] << endl;
529 if (myflags.parse_return_clockram || myconfig.debug || myconfig.verbosity > 1) {
530 for (int i=buf_cmd_start; i<buf_pos; i++) {
531 cout << "0x" << ((int) buf[i] < 10 ? "0" : "") << hex << (int) buf[i] << " ";
532 if (myflags.parse_return_clockram && i > 3) {
535 cout << "(ctrl: " << dec << bcd2dec((int) buf[i]) << ") ";
538 cout << "(1/100s: " << dec << bcd2dec((int) buf[i]) << ") ";
541 cout << "(sec: " << dec << bcd2dec((int) buf[i]) << ") ";
544 cout << "(min: " << dec << bcd2dec((int) buf[i]) << ") ";
547 cout << "(hours: " << dec << bcd2dec((int) buf[i]) << ") ";
550 cout << "(year/date: " << dec << bcd2dec((int) buf[i]) << ") ";
553 cout << "(wday/month: " << dec << bcd2dec((int) buf[i]) << ") ";
556 cout << "(timer day: " << dec << bcd2dec((int) buf[i]) << ") ";
559 cout << "(alarm ctrl: " << dec << bcd2dec((int) buf[i]) << ") ";
562 cout << "(bcd2int: " << dec << bcd2dec((int) buf[i]) << ") ";
566 if (i == 3 || (i+3)%8==0) cout << endl;
570 if (myconfig.debug || myconfig.verbosity > 0) cout << dec << (buf_pos - buf_cmd_start) << " bytes received.\n";
573 /*! \brief sends size bytes of buffer data to the display
575 \warning send_data doesn't check if buffer really is numbytes big. Expect all kind of weirdness if abused.
576 \param buffer pointer to a char buffer conatining the data
577 \param numbytes Number of bytes in buffer
579 bool send_data(const unsigned char * buffer, int numbytes) {
583 if (numbytes > 64 ) {
584 cout << "Buffer size exceeds 64 Bytes, send_data aborted." << endl;
587 write(fd,buffer,numbytes);
588 if (myconfig.debug || myconfig.verbosity > 0) cout << numbytes <<" bytes sent.";
589 if (myconfig.debug || myconfig.verbosity > 1) {
590 cout <<" Data: " << endl ;
591 for ( int i = 0; i <numbytes; i++) {
592 cout << " 0x" << ((int) buffer[i] < 10 ? "0" : "") << hex << (int) buffer[i] << dec;
593 if (i > 0 && ((i-3)%8 ==0 || i == 3)) cout << endl;
596 if (myconfig.debug || myconfig.verbosity > 0) cout << endl;
600 while (!ack_flag && tout < 1000) {