pertd2.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675
  1. /* Daemon for the Pertelian LCD display.
  2. This program will horizontally scroll information across the display.
  3. Written by Ron Lauzon - 2007
  4. I release this code into the Public Domain.
  5. Use this at your own risk.
  6. */
  7. #include <stdio.h>
  8. #include <time.h>
  9. #include <string.h>
  10. #include <sys/types.h>
  11. #include <sys/stat.h>
  12. #include <fcntl.h>
  13. #include <ctype.h>
  14. #include <stdlib.h>
  15. #include "fifo.h"
  16. #include "pert_interf.h"
  17. # define BUF_SIZE 512
  18. #ifdef DEBUG
  19. #define CONFIG_FILE_NAME "./pertd2.conf"
  20. #else
  21. #define CONFIG_FILE_NAME "/etc/pertd2.conf"
  22. #endif
  23. /* Commands */
  24. char *command_text[] = {"backlight on",
  25. "backlight off",
  26. "stop",
  27. "line1",
  28. "line2",
  29. "line3",
  30. "line4",
  31. "delay time",
  32. "char delay",
  33. "backlight mgt on",
  34. "backlight mgt off",
  35. NULL};
  36. enum command_enum {
  37. backlight_on = 0,
  38. backlight_off,
  39. stop,
  40. line1,
  41. line2,
  42. line3,
  43. line4,
  44. delay_time_cmd,
  45. char_delay_cmd,
  46. backlight_mgt_on,
  47. backlight_mgt_off,
  48. error_cmd=999};
  49. /* Config information */
  50. char *fifo_name = NULL;
  51. char *device_name = NULL;
  52. unsigned int delay_time = 0;
  53. int backlight_mgt = 0;
  54. /* Information about the data to display */
  55. char *lines[4]; /* The line text */
  56. int pos[4]; /* The position we are in the line */
  57. time_t refresh_time[4]; /* Time data was last refreshed */
  58. int timeout[4]; /* Number of seconds before we expire the line */
  59. int backlight_status; /* 0 - backlight not on, 1 - backlight on */
  60. /* This routine puts the program into "daemon" mode.
  61. * i.e. it disconnects from the current session so that
  62. * it's not automatically killed when the user logs off.
  63. */
  64. int daemon_init() {
  65. pid_t pid;
  66. FILE *pidfile;
  67. #ifdef DEBUG
  68. return(0); /* Don't go daemon in debug mode */
  69. #endif
  70. /* Fork off 8-) */
  71. if ( (pid=fork()) < 0)
  72. return(-1); /* If error - leave */
  73. else if (pid != 0)
  74. exit(0); /* parent exits */
  75. /* Child continues */
  76. /* Become session leader */
  77. setsid();
  78. return(0);
  79. }
  80. int is_numeric(char *buffer) {
  81. int i;
  82. /* Look through all the chars in the buffer */
  83. for (i=0; i<strlen(buffer); i++) {
  84. /* If we find a character that isn't a digit */
  85. if (!isdigit(buffer[i])) {
  86. /* It was bad data */
  87. return(0); /* false - not numeric */
  88. }
  89. }
  90. /* By the time we get here, all the characters are digits */
  91. return(1); /* true - numeric */
  92. }
  93. int read_config(char *config_file_name) {
  94. FILE *config_file;
  95. char line[1024];
  96. char *parm;
  97. char *value;
  98. #ifdef DEBUG
  99. printf("Opening config file %s\n",config_file_name);
  100. #endif
  101. char_delay = 1; /* default correctly for old systems */
  102. /* Try to open the config file */
  103. if ((config_file = fopen(config_file_name,"r")) != NULL) {
  104. /* Read lines from the config file */
  105. while(fgets(line,1024,config_file) != NULL) {
  106. /* Trim the new line */
  107. line[strlen(line)-1] = '\0';
  108. /* If comment, ignore */
  109. if (line[0] == '#')
  110. continue;
  111. /* If no = in the string, ignore */
  112. if (strchr(line,'=') == NULL)
  113. continue;
  114. /* We found a parm/value pair. Point to the value. */
  115. value=strchr(line,'=');
  116. value[0] = '\0';
  117. value++;
  118. /* Now, process the parm */
  119. if (strcmp(line,"fifo_name") == 0) {
  120. fifo_name = (char *)malloc(strlen(value)+1);
  121. strcpy(fifo_name,value);
  122. }
  123. if (strcmp(line,"device") == 0) {
  124. device_name = (char *)malloc(strlen(value)+1);
  125. strcpy(device_name,value);
  126. }
  127. if (strcmp(line,"delay_time") == 0) {
  128. delay_time=atoi(value);
  129. }
  130. if (strcmp(line,"char_delay") == 0) {
  131. char_delay=atoi(value);
  132. }
  133. if (strcmp(line,"backlight_mgt") == 0) {
  134. backlight_mgt=atoi(value);
  135. }
  136. }
  137. fclose(config_file);
  138. }
  139. /* Set defaults for any values not in the config file */
  140. if (fifo_name == NULL) {
  141. fifo_name = (char *)malloc(1024);
  142. strcpy(fifo_name,"/tmp/pertd2.fifo");
  143. }
  144. if (device_name == NULL) {
  145. device_name = (char *)malloc(1024);
  146. strcpy(device_name,"/dev/ttyUSB0");
  147. }
  148. if (delay_time == 0)
  149. delay_time = 500000; /* 1/2 second (500,000 milliseconds) */
  150. }
  151. int get_command() {
  152. char *command;
  153. int i;
  154. command = read_line();
  155. if (command == NULL) {
  156. return(error_cmd); /* No data */
  157. }
  158. /* lower case the command */
  159. for(i=0;i<strlen(command);i++)
  160. command[i] = tolower(command[i]);
  161. #ifdef DEBUG
  162. printf("Command:%s\n",command);
  163. #endif
  164. /* Loop through the commands */
  165. i = 0;
  166. while(command_text[i] != NULL) {
  167. /* If we found the command text */
  168. if (strcmp(command,command_text[i]) == 0) {
  169. free(command); /* memory leaks are bad */
  170. #ifdef DEBUG
  171. printf("Command_num:%d\n",i);
  172. #endif
  173. /* Return that command number */
  174. return(i);
  175. }
  176. i++;
  177. }
  178. /* If we got here, we didn't find the command
  179. * so the data is invalid. Throw it out. */
  180. free(command); /* memory leaks are bad */
  181. return(error_cmd); /* bad data */
  182. }
  183. int get_timeout() {
  184. char *timeout;
  185. int i;
  186. int int_timeout;
  187. timeout = read_line();
  188. if (timeout == NULL) {
  189. return(-1); /* No data */
  190. }
  191. /* Validate that the timeout is a number */
  192. if (!is_numeric(timeout)) {
  193. /* If it wasn't a digit, it was bad data */
  194. free(timeout);
  195. return(-1); /* bad data */
  196. }
  197. #ifdef DEBUG
  198. printf("Timeout:%s\n",timeout);
  199. #endif
  200. /* Convert the buffer into a int and return it */
  201. int_timeout = atoi(timeout);
  202. free(timeout);
  203. return(int_timeout);
  204. }
  205. char *get_line() {
  206. char *EOD;
  207. char *current_line, *temp;
  208. char *line_buffer;
  209. int current_length;
  210. /* Get EOD string */
  211. EOD = read_line();
  212. if (EOD == NULL) {
  213. return(NULL); /* no data */
  214. }
  215. /* We have data */
  216. /* Allocate a buffer for the line */
  217. current_length = 1;
  218. line_buffer = (char *)malloc(current_length);
  219. line_buffer[0] = '\0';
  220. /* Read the next line from the fifo */
  221. current_line = read_line();
  222. /* While we didn't hit the end of data marker
  223. * and we didn't run out of fifo data */
  224. while ((current_line != NULL)
  225. && (strcmp(current_line,EOD) != 0)) {
  226. /* If our buffer is too small */
  227. if ((strlen(current_line) + strlen(line_buffer)+1) > current_length) {
  228. /* Allocate new buffer and copy the old data over */
  229. temp = line_buffer;
  230. line_buffer = (char *)malloc(current_length+BUF_SIZE);
  231. memcpy(line_buffer,temp,current_length);
  232. current_length += BUF_SIZE;
  233. free(temp);
  234. }
  235. /* Add the current line to the buffer */
  236. if (strlen(line_buffer) > 0)
  237. strcat(line_buffer," ");
  238. strcat(line_buffer,current_line);
  239. free(current_line); /* memory leaks are bad */
  240. current_line = read_line();
  241. }
  242. if (current_line != NULL)
  243. free(current_line); /* memory leaks are bad */
  244. free(EOD);
  245. return(line_buffer);
  246. }
  247. void process_delay_time() {
  248. char *cur_line;
  249. /* Get the delay time */
  250. cur_line = read_line();
  251. #ifdef DEBUG
  252. printf("Read delay_time:%s\n",cur_line);
  253. #endif
  254. /* No delay time - exit */
  255. if (cur_line == NULL)
  256. return;
  257. if (strlen(cur_line) == 0)
  258. return;
  259. /* The delay time must be a number */
  260. if (is_numeric(cur_line)) {
  261. delay_time = atoi(cur_line);
  262. free(cur_line);
  263. #ifdef DEBUG
  264. printf("Processed delay_time:%d\n",delay_time);
  265. #endif
  266. return;
  267. }
  268. /* If it's not a number, it's bad data - ignore the command */
  269. }
  270. void process_char_delay() {
  271. char *cur_line;
  272. /* Get the delay time */
  273. cur_line = read_line();
  274. /* No char delay - exit */
  275. if (cur_line == NULL)
  276. return;
  277. if (strlen(cur_line) == 0)
  278. return;
  279. /* The delay time must be a number */
  280. if (is_numeric(cur_line)) {
  281. char_delay = atoi(cur_line);
  282. free(cur_line);
  283. return;
  284. }
  285. /* If it's not a number, it's bad data - ignore the command */
  286. }
  287. void process_line(int line_num) {
  288. int cur_timeout;
  289. char *cur_line;
  290. time_t now;
  291. time(&now);
  292. cur_timeout = get_timeout();
  293. if (cur_timeout < 0) {
  294. cur_timeout = 0;
  295. }
  296. cur_line = get_line();
  297. if (lines[line_num] != NULL)
  298. free(lines[line_num]);
  299. lines[line_num] = cur_line;
  300. timeout[line_num] = cur_timeout;
  301. refresh_time[line_num] = now;
  302. }
  303. int data_to_display() {
  304. int temp;
  305. int i;
  306. temp = 0;
  307. /* Look through all the lines */
  308. for (i=0; i<4; i++) {
  309. /* If the line isn't empty */
  310. if (lines[i] != NULL) {
  311. if (strlen(lines[i]) > 0) {
  312. return 1; /* we have data */
  313. }
  314. }
  315. }
  316. /* We only get here when no lines have data */
  317. return 0;
  318. }
  319. void display_date_time() {
  320. time_t now_t;
  321. struct tm *now_tm;
  322. char line2[PERT_DISPLAY_WIDTH+1], line3[PERT_DISPLAY_WIDTH+1];
  323. /* First we need to get the current time */
  324. now_t = time(NULL);
  325. /* Now, we need to convert the time_t to something useful */
  326. now_tm = localtime(&now_t);
  327. /* Format the date/time into a date line and a time line */
  328. /* DDD MMM DD, YYYY - 16 chars pad 4 spaces */
  329. strftime(line2,PERT_DISPLAY_WIDTH+1," %a %b %d, %Y ",now_tm);
  330. /* HH:MM:SS - 8 chars - pad 12 spaces */
  331. strftime(line3,PERT_DISPLAY_WIDTH+1," %T ",now_tm);
  332. line2[PERT_DISPLAY_WIDTH] = '\0';
  333. line3[PERT_DISPLAY_WIDTH] = '\0';
  334. #ifdef DEBUG
  335. printf("line2= %s\n",line2);
  336. printf("line3= %s\n",line3);
  337. #endif
  338. /* Put the lines on the display */
  339. wrtln(1,line2);
  340. wrtln(2,line3);
  341. }
  342. /* Copy over PERT_DISPLAY_WIDTH chars of data into line - wrapping around
  343. * when at the end of the data */
  344. char *fill_line(int lineno,int offset) {
  345. static char temp_line[21];
  346. int i;
  347. int temp_pos;
  348. /* If the line contains no data */
  349. if (lines[lineno] == NULL) {
  350. /* If we are on the first line */
  351. if (lineno == 0) {
  352. /* No data to display - return blanks to clear line */
  353. memset(temp_line,' ',PERT_DISPLAY_WIDTH);
  354. temp_line[PERT_DISPLAY_WIDTH] = '\0';
  355. return(temp_line);
  356. } else {
  357. /* Try to fill with some of the previous line */
  358. return(fill_line(lineno-1,offset + PERT_DISPLAY_WIDTH));
  359. }
  360. }
  361. if (strlen(lines[lineno]) == 0) {
  362. /* If we are on the first line */
  363. if (lineno == 0) {
  364. /* No data to display - return blanks to clear line */
  365. memset(temp_line,' ',PERT_DISPLAY_WIDTH);
  366. temp_line[PERT_DISPLAY_WIDTH] = '\0';
  367. return(temp_line);
  368. } else {
  369. /* Try to fill with some of the previous line */
  370. return(fill_line(lineno-1,offset + PERT_DISPLAY_WIDTH));
  371. }
  372. }
  373. /* If there are PERT_DISPLAY_WIDTH or less chars to display */
  374. if (strlen(lines[lineno]) < 21) {
  375. /* If this is the first time called */
  376. if (offset == 0) {
  377. /* Return the line and pad with blanks */
  378. strcpy(temp_line,(lines[lineno]));
  379. for (i=strlen(lines[lineno]); i<PERT_DISPLAY_WIDTH; i++)
  380. temp_line[i] = ' ';
  381. temp_line[PERT_DISPLAY_WIDTH] = '\0';
  382. return(temp_line);
  383. } else { /* not the first time called - return blanks */
  384. /* No data to display - return blanks to clear line */
  385. memset(temp_line,' ',PERT_DISPLAY_WIDTH);
  386. temp_line[PERT_DISPLAY_WIDTH] = '\0';
  387. return(temp_line);
  388. }
  389. }
  390. /* If there's not enough data to display */
  391. if (strlen(lines[lineno]) <= offset) {
  392. /* No data to display - return blanks to clear line */
  393. memset(temp_line,' ',PERT_DISPLAY_WIDTH);
  394. temp_line[PERT_DISPLAY_WIDTH] = '\0';
  395. return(temp_line);
  396. }
  397. /* If there are more than PERT_DISPLAY_WIDTH chars to display,
  398. * display PERT_DISPLAY_WIDTH starting at the last position
  399. * displayed */
  400. temp_pos = pos[lineno] + offset;
  401. while (temp_pos > strlen(lines[lineno]))
  402. temp_pos = temp_pos - strlen(lines[lineno]);
  403. if (temp_pos < 0)
  404. temp_pos = 0;
  405. /* For each char in the temp line */
  406. for (i=0; i<PERT_DISPLAY_WIDTH; i++) {
  407. /* If we are pointing beyond the original line,
  408. * start over at the beginning */
  409. if (temp_pos >= strlen(lines[lineno]))
  410. temp_pos = 0;
  411. /* Copy over 1 char from the original line */
  412. temp_line[i] = lines[lineno][temp_pos];
  413. temp_pos++;
  414. }
  415. /* Increment where we start */
  416. pos[lineno]++;
  417. /* If we went past the end of the line,
  418. * start over */
  419. if (pos[lineno] >= strlen(lines[lineno]))
  420. pos[lineno] = 0;
  421. /* Force an end of line */
  422. temp_line[PERT_DISPLAY_WIDTH] = '\0';
  423. return(temp_line);
  424. }
  425. int main(int argc, char *argv[]) {
  426. int stop_indicated;
  427. int processing_command;
  428. int i;
  429. time_t now;
  430. /* Read config file */
  431. if (argc > 1) {
  432. /* We have an argument - try to read the config file
  433. * using that argument */
  434. if (!read_config(argv[1])) {
  435. /* If we failed - try to read the default config file */
  436. read_config(CONFIG_FILE_NAME);
  437. }
  438. } else {
  439. /* No parm - use default config file */
  440. read_config(CONFIG_FILE_NAME);
  441. }
  442. #ifdef DEBUG
  443. printf("Device = %s\n",device_name);
  444. printf("Fifo = %s\n",fifo_name);
  445. printf("Delay time = %d\n",delay_time);
  446. printf("Char Delay time = %d\n",char_delay);
  447. #endif
  448. /* Initialize arrays */
  449. time(&now);
  450. for(i=0;i<4;i++) {
  451. lines[i] = NULL;
  452. refresh_time[i] = now;
  453. timeout[i] = 0;
  454. pos[i] = 0;
  455. }
  456. /* Initialize the Pertelian */
  457. display_init(device_name);
  458. /* The backlight is on when the program starts */
  459. backlight_status = 1;
  460. backlight(1);
  461. /* Go daemon */
  462. if (daemon_init() != 0) {
  463. fprintf(stderr,"Failed to go daemon\n");
  464. return(1);
  465. }
  466. /* Try to open the fifo */
  467. if (!open_fifo(fifo_name)) {
  468. fprintf(stderr,"Error creating FIFO: %s\n",fifo_name);
  469. return(1);
  470. }
  471. /* Loop until we are told to stop */
  472. stop_indicated = 0;
  473. while (!stop_indicated) {
  474. time(&now);
  475. /* Get the command from the fifo */
  476. processing_command = 1;
  477. while (processing_command) {
  478. switch (get_command()) {
  479. case backlight_on:
  480. backlight(1);
  481. backlight_status = 1;
  482. break;
  483. case backlight_off:
  484. backlight(0);
  485. backlight_status = 0;
  486. break;
  487. case stop:
  488. stop_indicated = 1;
  489. break;
  490. case line1:
  491. process_line(0);
  492. break;
  493. case line2:
  494. process_line(1);
  495. break;
  496. case line3:
  497. process_line(2);
  498. break;
  499. case line4:
  500. process_line(3);
  501. break;
  502. case delay_time_cmd:
  503. process_delay_time();
  504. break;
  505. case char_delay_cmd:
  506. process_char_delay();
  507. break;
  508. case backlight_mgt_on:
  509. backlight_mgt = 1;
  510. break;
  511. case backlight_mgt_off:
  512. backlight_mgt = 0;
  513. break;
  514. default:
  515. processing_command = 0; /* no command to process */
  516. break;
  517. }
  518. }
  519. #ifdef DEBUG
  520. printf("main:processed command\n");
  521. #endif
  522. /* Refresh the display */
  523. for(i=0;i<4;i++) {
  524. /* If the line has data */
  525. if (lines[i] != NULL) {
  526. /* If we are supposed to time the line out */
  527. if (timeout[i] > 0) {
  528. /* If the line is old */
  529. if (difftime(now,refresh_time[i]) > timeout[i]) {
  530. /* Get rid of the line */
  531. free(lines[i]); /* Memory leaks are bad */
  532. lines[i] = NULL;
  533. }
  534. }
  535. }
  536. /* Write out the line to the display */
  537. wrtln(i,fill_line(i,0));
  538. }
  539. /* If there was no data to display */
  540. if (!data_to_display()) {
  541. /* Let's put the date/time on the display */
  542. display_date_time();
  543. /* If the backlight is on,
  544. * and backight mgt is on,
  545. * turn the backlight off */
  546. if ((backlight_status == 1)
  547. && (backlight_mgt == 1)) {
  548. backlight(0);
  549. backlight_status=0;
  550. }
  551. } else {
  552. /* There was data to display.
  553. * If the backlight is off,
  554. * and backlight mangement is on,
  555. * turn the backlight on */
  556. if ((backlight_status == 0)
  557. && (backlight_mgt ==1)) {
  558. backlight(1);
  559. backlight_status=1;
  560. }
  561. }
  562. /* Pause for a bit */
  563. sleep_us(delay_time);
  564. }
  565. /* Display a useful message on the Pertelian */
  566. wrtln(0," ");
  567. wrtln(1,"pertd daemon stopped");
  568. wrtln(2," ");
  569. wrtln(3," ");
  570. /* Clean up the connect to the Pertelian */
  571. display_close();
  572. /* Done - clean up */
  573. close_fifo(fifo_name);
  574. return(0);
  575. }