Make multi-threaded
[wakeup.git] / src / lightswitch.c
1 #include <sys/stat.h>
2 #include <sys/types.h>
3 #include <fcntl.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <sys/mman.h>
7 #include <unistd.h>
8 #include <errno.h>
9 #include <time.h>
10 #include <getopt.h>
11
12 #define PAGE_SIZE (4*1024)
13 #define BLOCK_SIZE (4*1024)
14  
15 /*  Direct access to GPIO hardware  */
16
17 // Access from ARM Running Linux
18 // For Raspberry Pi 2 and Pi 3, change BCM2708_PERI_BASE to 0x3F000000 for the code to work.
19  
20 //#define BCM2708_PERI_BASE        0x20000000
21 #define BCM2708_PERI_BASE        0x3F000000
22 #define GPIO_BASE                (BCM2708_PERI_BASE + 0x200000) /* GPIO controller */
23  
24  
25 // I/O access
26 volatile unsigned *gpio;
27  
28  
29 // GPIO setup macros. Always use INP_GPIO(x) before using OUT_GPIO(x) or SET_GPIO_ALT(x,y)
30 #define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3))
31 #define OUT_GPIO(g) *(gpio+((g)/10)) |=  (1<<(((g)%10)*3))
32 #define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3))
33  
34 #define GPIO_SET *(gpio+7)  // sets   bits which are 1 ignores bits which are 0
35 #define GPIO_CLR *(gpio+10) // clears bits which are 1 ignores bits which are 0
36  
37 #define GET_GPIO(g) (*(gpio+13)&(1<<g)) // 0 if LOW, (1<<g) if HIGH
38  
39 #define GPIO_PULL *(gpio+37) // Pull up/pull down
40 #define GPIO_PULLCLK0 *(gpio+38) // Pull up/pull down clock
41  
42 void setup_io();
43  
44
45
46 /*  GPIO pin assignments */
47
48 #define SWITCH_IN    2
49
50 #define FIRMASK 0x03
51
52 #define TEST_CYCLES  (60 * 5)  //  1 minute
53
54 unsigned fir_record[TEST_CYCLES];
55
56 int main(int argc, char *argv[])
57 {
58    unsigned int fir;  // A simple FIR filter
59
60    int    old_state, new_state;
61    struct timespec interval;
62
63    interval.tv_sec   = 0;
64    interval.tv_nsec  = 200000000;
65
66    // Set up gpi pointer for direct register access
67    setup_io();
68  
69    // Initialize the IO pins.
70    INP_GPIO(SWITCH_IN);
71
72    //   Initialize to switched off state
73    fir = 0xffff;
74    old_state = 1;  // Off
75
76    int cycle = 0;
77    //while (1)
78    while (cycle < TEST_CYCLES)
79    {
80       unsigned input = GET_GPIO(SWITCH_IN) == 0 ? 0 : 1;
81  
82       fir <<= 1;
83       fir |= input;
84
85       //fprintf(stderr, "FIR =  0x%x\r", fir);
86       if ( (fir & FIRMASK) == 0)
87       {
88          new_state = 0;   // On
89       }
90       if ( (fir & FIRMASK) == FIRMASK)
91       {
92          new_state = 1;   // Off
93       }
94
95       if (new_state != old_state)
96       {
97          //fprintf(stderr, "Changed state to %d\r", new_state);
98          if (new_state == 0)
99          {
100             system("lightcontrol -r 100 -g 100 -b 100 -w 100");
101          }
102          else
103          {
104             system("lightcontrol -r 0 -g 0 -b 0 -w 0");
105          }
106
107          old_state = new_state;
108       }
109       fir_record[cycle++] = fir;
110
111       nanosleep(&interval, NULL);
112    }
113
114    for (int i = 0; i < TEST_CYCLES; i++)
115    {
116       printf("FIR = 0x%08x\n", fir_record[i]);
117    }
118
119    return 0;
120 }
121
122 //
123 // Set up a memory regions to access GPIO
124 //
125 void setup_io()
126 {
127    void *gpio_map;
128    int  mem_fd;
129
130    /* open /dev/mem */
131    if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0)
132    {
133       printf("can't open /dev/mem \n");
134       exit(-1);
135    }
136  
137    /* mmap GPIO */
138    gpio_map = mmap(
139       NULL,             //Any adddress in our space will do
140       BLOCK_SIZE,       //Map length
141       PROT_READ|PROT_WRITE,// Enable reading & writting to mapped memory
142       MAP_SHARED,       //Shared with other processes
143       mem_fd,           //File to map
144       GPIO_BASE         //Offset to GPIO peripheral
145    );
146  
147    close(mem_fd); //No need to keep mem_fd open after mmap
148  
149    if (gpio_map == MAP_FAILED)
150    {
151       printf("mmap error %d, errno = %d\n", gpio_map, errno);//errno also set!
152       exit(-1);
153    }
154  
155    // Always use volatile pointer!
156    gpio = (volatile unsigned *)gpio_map;
157  
158  
159 } // setup_io