/***************************************************************************************/ /* */ /* file : ledBtn.c */ /* */ /* synopsis : */ /* the compiled code should be ran with root privileges to allow for access to */ /* the GPIO pins through direct GPIO register manipulation in C-code. */ /* After initialization, the code update the LEDs status according to the commands */ /* passed on std input (using a pipe). */ /* It also monitors the push-button and triggers a reboot sequence */ /* when it is depressed. */ /* */ /* */ /* This code is based on examples from */ /* http://elinux.org/RPi_Low-level_peripherals#C */ /* How to access GPIO registers from C-code on the Raspberry-Pi, Example program */ /* Dom and Gert, 15-January-2012, Revised: 15-Feb-2013 */ /* */ /* and from Raphael Vinot (CIRCL.lu) */ /* */ /* v 1.00 - 22/02/2015 - initial release (Marc Durvaux) */ /* v 1.10 - 27/02/2015 - added 'z' command for debugging, improved handling of */ /* concateneted command sequences */ /* */ /* */ /* */ /***************************************************************************************/ // Includes #include #include #include #include #include #include #include // Constant for low-level access to GPIO #define BCM2708_PERI_BASE 0x20000000 #define GPIO_BASE (BCM2708_PERI_BASE + 0x200000) /* GPIO controller */ #define BLOCK_SIZE (4*1024) // global variables related to GPIO int mem_fd ; void *gpio_map ; volatile unsigned *gpio ; // I/O access // GPIO setup macros. Always use INP_GPIO(x) before using OUT_GPIO(x) or SET_GPIO_ALT(x,y) #define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3)) #define OUT_GPIO(g) *(gpio+((g)/10)) |= (1<<(((g)%10)*3)) #define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3)) #define GPIO_SET *(gpio+7) // sets bits which are 1 ignores bits which are 0 #define GPIO_CLR *(gpio+10) // clears bits which are 1 ignores bits which are 0 #define GET_GPIO(g) (*(gpio+13)&(1<= 4) { // final state, immediate reboot close(fd) ; do_reboot() ; } } if (Btn_press_count == LONG_PUSH) { // trigger forced reboot state = 10 ; // LED animation before reboot repeat_count = 0 ; } } Btn_prev_state = Btn_state ; nbytes = read(fd, &code, 1) ; if (nbytes < 0) { perror("read") ; exit (2) ; } if (nbytes > 0) { switch (code) { // codes evaluated at every tic case 'z' : // clear without restart (for debugging) GPIO_CLR = 1<= MAX_COUNT) { count = 0 ; switch (state) { // states evaluated after MAX_COUNT tics case 3 : // green LED flash OFF GPIO_CLR = 1< 5) { state = 12 ; } else { state = 10 ; } break ; case 12 : // proceed with reboot close(fd) ; do_reboot() ; break ; } // end switch } // end if // loop delay nanosleep((struct timespec[]){{0, TIME_TIC}}, NULL) ; } return 0 ; // we should never come here! } // main /***************************************************************************************/ // // Set up a memory region to access GPIO // void setup_io() { /* open /dev/mem */ if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) { printf("can't open /dev/mem \n"); exit(-1); } /* mmap GPIO */ gpio_map = mmap( NULL, //Any adddress in our space will do BLOCK_SIZE, //Map length PROT_READ|PROT_WRITE,// Enable reading & writting to mapped memory MAP_SHARED, //Shared with other processes mem_fd, //File to map GPIO_BASE //Offset to GPIO peripheral ); close(mem_fd); //No need to keep mem_fd open after mmap if (gpio_map == MAP_FAILED) { printf("mmap error %d\n", (int)gpio_map);//errno also set! exit(-1); } // Always use volatile pointer! gpio = (volatile unsigned *)gpio_map ; // initializes the LED and push-button pins INP_GPIO( GREEN_LED) ; // must use INP_GPIO before we can use OUT_GPIO OUT_GPIO( GREEN_LED) ; INP_GPIO( YELLOW_LED) ; OUT_GPIO( YELLOW_LED) ; INP_GPIO( RED_LED) ; OUT_GPIO( RED_LED) ; INP_GPIO( PUSHBUTTON) ; // initializes LEDs to OFF state GPIO_CLR = 1<