Installation of pwm startup script
[wakeup.git] / src / pwm.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
9 #include <sys/ipc.h>
10 #include <sys/shm.h>
11
12 #include "pwm.h"
13
14 #define PAGE_SIZE (4*1024)
15 #define BLOCK_SIZE (4*1024)
16  
17 /*  Direct access to GPIO hardware  */
18
19 // Access from ARM Running Linux
20 // For Raspberry Pi 2 and Pi 3, change BCM2708_PERI_BASE to 0x3F000000 for the code to work.
21  
22 //#define BCM2708_PERI_BASE        0x20000000
23 #define BCM2708_PERI_BASE        0x3F000000
24 #define GPIO_BASE                (BCM2708_PERI_BASE + 0x200000) /* GPIO controller */
25  
26  
27 // I/O access
28 volatile unsigned *gpio;
29  
30  
31 // GPIO setup macros. Always use INP_GPIO(x) before using OUT_GPIO(x) or SET_GPIO_ALT(x,y)
32 #define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3))
33 #define OUT_GPIO(g) *(gpio+((g)/10)) |=  (1<<(((g)%10)*3))
34 #define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3))
35  
36 #define GPIO_SET *(gpio+7)  // sets   bits which are 1 ignores bits which are 0
37 #define GPIO_CLR *(gpio+10) // clears bits which are 1 ignores bits which are 0
38  
39 #define GET_GPIO(g) (*(gpio+13)&(1<<g)) // 0 if LOW, (1<<g) if HIGH
40  
41 #define GPIO_PULL *(gpio+37) // Pull up/pull down
42 #define GPIO_PULLCLK0 *(gpio+38) // Pull up/pull down clock
43  
44 void setup_io();
45  
46
47
48 /*  GPIO pin assignments */
49
50 #define OUTPUT_RED    3
51 #define OUTPUT_GREEN 14
52 #define OUTPUT_BLUE  15
53 #define OUTPUT_WHITE  4
54
55 const int N_COLORS    = 4;      // The number of LED colors
56
57 int main()
58 {
59    int shmid;
60    key_t key;
61    char *shm;
62    struct pwm *signals;
63
64    int i;
65
66     /*
67      * We need to get the segment named
68      * SHM_KEY, created by the server.
69      */
70    key = SHM_KEY;
71
72     /*
73      * Create the shared memory segment if it does not exist yet.
74      */
75    if ((shmid = shmget(key, sizeof(struct pwm) * (N_COLORS + 1), 0666)) < 0)
76    {
77
78       if ((shmid = shmget(key, sizeof(struct pwm) * (N_COLORS + 1), IPC_CREAT | 0666)) < 0)
79       {
80           perror("shmget");
81           exit(1);
82       }
83
84       //   Now we attach the new segment to our data space.
85       if ((shm = shmat(shmid, (const void *)NULL, 0)) == (void *) -1)
86       {
87           perror("shmat");
88           exit(1);
89       }
90       signals = (struct pwm *)shm;
91       signals[0].output = LED_RED;
92       signals[1].output = LED_GREEN;
93       signals[2].output = LED_BLUE;
94       signals[3].output = LED_WHITE;
95    }
96    else
97    {
98       //   Now we attach the existing segment to our data space.
99       if ((shm = shmat(shmid, (const void *)NULL, 0)) == (void *) -1)
100       {
101           perror("shmat");
102           exit(1);
103       }
104    }
105
106    signals = (struct pwm *)shm;
107
108    // Set up gpi pointer for direct register access
109    setup_io();
110  
111    INP_GPIO(OUTPUT_RED); // must use INP_GPIO before we can use OUT_GPIO
112    OUT_GPIO(OUTPUT_RED);
113    INP_GPIO(OUTPUT_GREEN); // must use INP_GPIO before we can use OUT_GPIO
114    OUT_GPIO(OUTPUT_GREEN);
115    INP_GPIO(OUTPUT_BLUE); // must use INP_GPIO before we can use OUT_GPIO
116    OUT_GPIO(OUTPUT_BLUE);
117    INP_GPIO(OUTPUT_WHITE); // must use INP_GPIO before we can use OUT_GPIO
118    OUT_GPIO(OUTPUT_WHITE);
119
120    int fd[4];
121  
122    fd[0] = OUTPUT_RED;
123    fd[1] = OUTPUT_GREEN;
124    fd[2] = OUTPUT_BLUE;
125    fd[3] = OUTPUT_WHITE;
126
127
128    int repeat = 80000;
129
130    while (1)
131    {
132       if (signals->interval != 0)
133       {
134          usleep(signals->interval);
135       }
136       if (signals->output == -1)
137       {
138          /*  End of the list: Turn all 4 outputs on  */
139          GPIO_SET = 1 << fd[0];
140          GPIO_SET = 1 << fd[1];
141          GPIO_SET = 1 << fd[2];
142          GPIO_SET = 1 << fd[3];
143
144          signals = (struct pwm *)shm;
145       }
146       else
147       {
148          //write(fd[signals->output], "0", 1);
149          GPIO_CLR = 1 << fd[signals->output];
150          signals++;
151       }
152    }
153
154    /*  Turn all outputs off */
155
156    GPIO_CLR = 1 << fd[0];
157    GPIO_CLR = 1 << fd[1];
158    GPIO_CLR = 1 << fd[2];
159    GPIO_CLR = 1 << fd[3];
160
161    return 0;
162 }
163
164 //
165 // Set up a memory regions to access GPIO
166 //
167 void setup_io()
168 {
169    void *gpio_map;
170    int  mem_fd;
171
172    /* open /dev/mem */
173    if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0)
174    {
175       printf("can't open /dev/mem \n");
176       exit(-1);
177    }
178  
179    /* mmap GPIO */
180    gpio_map = mmap(
181       NULL,             //Any adddress in our space will do
182       BLOCK_SIZE,       //Map length
183       PROT_READ|PROT_WRITE,// Enable reading & writting to mapped memory
184       MAP_SHARED,       //Shared with other processes
185       mem_fd,           //File to map
186       GPIO_BASE         //Offset to GPIO peripheral
187    );
188  
189    close(mem_fd); //No need to keep mem_fd open after mmap
190  
191    if (gpio_map == MAP_FAILED)
192    {
193       printf("mmap error %d\n", gpio_map);//errno also set!
194       exit(-1);
195    }
196  
197    // Always use volatile pointer!
198    gpio = (volatile unsigned *)gpio_map;
199  
200  
201 } // setup_io