Create interfaces for string-seeded blinking
[darcs-mirror-pidgin-blinklight.debian.git] / src / blink.c
1 /* © 2009 Joachim Breitner
2  *
3  * This program is free software; you can redistribute it and/or
4  * modify it under the terms of the GNU General Public License
5  * as published by the Free Software Foundation; either version 2
6  * of the License, or (at your option) any later version.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16  */
17 #ifdef HAVE_CONFIG_H
18 # include "../config.h"
19 #endif
20
21 #include <unistd.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include <blink.h>
27
28 #define OFF    0
29 #define ON     1
30 #define TOGGLE 2
31
32
33 struct interface {
34         char *sysfs;
35         char *commands[2];
36         char *scanline;
37 };
38
39 #define INTERFACES 3
40 static struct interface interfaces[] = {
41         {"/proc/acpi/ibm/light",                        {"off","on"},   "status: %9s" },
42         {"/proc/acpi/asus/mled",                        {"0","1"},          "%9s" },
43         {"/sys/class/leds/asus:phone/brightness",   {"0","1"},      "%9s" }
44 };
45
46 static struct interface *interface = NULL;
47
48 typedef struct {
49         int     state;
50         int     time;
51 } blinky;
52
53 typedef struct {
54         blinky *seq;
55         int pos;
56 } blinkstate;
57
58 /* TODO: We should really allow an option to continue blinking indefinitely
59          until user opens message */
60 blinky default_seq[] = {
61         {TOGGLE,        150},
62         {TOGGLE,        125},
63         {TOGGLE,        150},
64         {TOGGLE,        0}
65 };
66
67 static guint
68 blinklight_blink(blinkstate *bstate) {
69         FILE *file;
70         char *new_state = NULL;
71         char old_state[10] = "";
72         int ret;
73
74         blinky *seq = &bstate->seq[bstate->pos];
75
76         if (interface == NULL) return FALSE;
77
78         // purple_debug_info("pidgin-blinklight","blink called with parameter: %i\n", seq->state);
79         
80         if (seq->state == ON)  new_state=interface->commands[ON];
81         if (seq->state == OFF) new_state=interface->commands[OFF];
82         if (seq->state == TOGGLE) {
83                 // purple_debug_info("pidgin-blinklight","trying to toggle\n");
84                 file = fopen(interface->sysfs,"r");
85                       if (file == NULL) { perror ("Trying to open sysfs for reading"); return FALSE;};
86                 ret = fscanf(file,interface->scanline,old_state);
87                       if (ret == EOF)  { perror ("Trying to read from sysfs"); return FALSE;};
88                 ret = fclose(file);
89                       if (ret != 0) { perror ("Trying to close sysfs"); return FALSE;};
90                 // purple_debug_info("pidgin-blinklight","done reading old state %s\n", old_state);
91
92                 if (strcmp(old_state,interface->commands[ON])  == 0) new_state=interface->commands[OFF];
93                 if (strcmp(old_state,interface->commands[OFF]) == 0) new_state=interface->commands[ON];
94         }
95         
96         if (new_state == NULL) {
97                 // purple_debug_info("pidgin-blinklight","No new state defined\n");
98                 return FALSE;
99         }
100         // purple_debug_info("pidgin-blinklight","setting new state: %s\n", new_state);
101
102         file = fopen(interface->sysfs,"w");
103                 if (file == NULL) { perror ("Trying to open sysfs for writing"); return FALSE;};
104         ret = fprintf(file,"%s",new_state);
105                 if (ret < 0)   { perror ("Trying to write to sysfs"); return FALSE;};
106         ret = fclose(file);
107                 if (ret != 0) { perror ("Trying to close sysfs"); return FALSE;};
108
109         // purple_debug_info("pidgin-blinklight","done setting new state: %s\n", new_state);
110         
111         if (seq->time) { 
112                 bstate->pos++;
113                 blinklight_timeout_add(seq->time,(GSourceFunc)blinklight_blink,bstate);
114         } else {
115                 free(bstate->seq);
116                 free(bstate);
117         }
118         return FALSE;
119 }
120
121 void
122 blinklight_startblink(char *seed) {
123         int length = 4;
124         blinkstate *bstate = malloc(sizeof(blinkstate));
125         blinky *seq ;
126
127         if (seed == NULL) {
128                 seq = malloc(sizeof(default_seq));
129                 memcpy(seq, default_seq, sizeof(default_seq));
130
131         } else {
132                 seq = calloc(sizeof(blinky),length);
133                 
134                 // Initialize to four toggle commands
135                 for (int i=0; i<length; i++) {
136                         seq[i].state = TOGGLE;
137                 }
138                 // Set timeing based on string
139                 // 100 + [0,1]*100 ms
140                 for (int i=0; i<length-1; i++) {
141                         seq[i].time = 100 + ((int)seed[i]*103) % 100;
142                         printf("Time %d: %d\n", i, seq[i].time);
143                 }
144         }
145
146         bstate->seq = seq;
147         bstate->pos = 0;
148         blinklight_blink(bstate);
149 }
150
151 char *
152 blinklight_init() {
153         // figure out which interface to use
154         for (int i=0; i< INTERFACES; i++) {
155                 if (! access(interfaces[i].sysfs, R_OK)) {
156                         // File exists and is readable (not checking writable because of possible race condition)
157                         interface = &interfaces[i];
158                         return interfaces[i].sysfs;
159                 }
160                 
161         }
162         return NULL;
163 }