├── osd ├── README.md ├── osd ├── Makefile ├── osd-backup.c └── osd.c ├── .DS_Store ├── LICENSE ├── rfkill ├── rfkill └── README.txt ├── resources ├── .DS_Store ├── AUD0.png ├── AUD25.png ├── AUD50.png ├── AUD75.png ├── main.png ├── plug.png ├── AUD100.png ├── audio_2.png ├── battery.png ├── joystick.png ├── joystick.psd ├── wifi_1.png ├── wifi_2.png ├── wifi_3.png ├── bluetooth.png ├── wifi_error.png ├── low-battery.png ├── wifi_warning.png ├── main_no_joystick.png └── main_no_joystick_pocketfe.png ├── .gitmodules ├── .idea ├── vcs.xml ├── modules.xml └── Retropie-open-OSD.iml ├── Makefile ├── general.cfg ├── SystemConfigs └── MintyPi-Lite │ ├── general.cfg │ └── mintypi-lite.cfg ├── keysGamepad.cfg ├── keysKeyboard.cfg ├── keysWill.cfg ├── .gitignore ├── README.md └── monitor.py /osd/README.md: -------------------------------------------------------------------------------- 1 | Build instructions: 2 | 3 | ./make 4 | -------------------------------------------------------------------------------- /osd/osd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/withgallantry/OneForAll/HEAD/osd/osd -------------------------------------------------------------------------------- /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/withgallantry/OneForAll/HEAD/.DS_Store -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Software and/or source code may not be used without express permission. -------------------------------------------------------------------------------- /rfkill/rfkill: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/withgallantry/OneForAll/HEAD/rfkill/rfkill -------------------------------------------------------------------------------- /resources/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/withgallantry/OneForAll/HEAD/resources/.DS_Store -------------------------------------------------------------------------------- /resources/AUD0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/withgallantry/OneForAll/HEAD/resources/AUD0.png -------------------------------------------------------------------------------- /resources/AUD25.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/withgallantry/OneForAll/HEAD/resources/AUD25.png -------------------------------------------------------------------------------- /resources/AUD50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/withgallantry/OneForAll/HEAD/resources/AUD50.png -------------------------------------------------------------------------------- /resources/AUD75.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/withgallantry/OneForAll/HEAD/resources/AUD75.png -------------------------------------------------------------------------------- /resources/main.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/withgallantry/OneForAll/HEAD/resources/main.png -------------------------------------------------------------------------------- /resources/plug.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/withgallantry/OneForAll/HEAD/resources/plug.png -------------------------------------------------------------------------------- /resources/AUD100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/withgallantry/OneForAll/HEAD/resources/AUD100.png -------------------------------------------------------------------------------- /resources/audio_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/withgallantry/OneForAll/HEAD/resources/audio_2.png -------------------------------------------------------------------------------- /resources/battery.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/withgallantry/OneForAll/HEAD/resources/battery.png -------------------------------------------------------------------------------- /resources/joystick.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/withgallantry/OneForAll/HEAD/resources/joystick.png -------------------------------------------------------------------------------- /resources/joystick.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/withgallantry/OneForAll/HEAD/resources/joystick.psd -------------------------------------------------------------------------------- /resources/wifi_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/withgallantry/OneForAll/HEAD/resources/wifi_1.png -------------------------------------------------------------------------------- /resources/wifi_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/withgallantry/OneForAll/HEAD/resources/wifi_2.png -------------------------------------------------------------------------------- /resources/wifi_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/withgallantry/OneForAll/HEAD/resources/wifi_3.png -------------------------------------------------------------------------------- /resources/bluetooth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/withgallantry/OneForAll/HEAD/resources/bluetooth.png -------------------------------------------------------------------------------- /resources/wifi_error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/withgallantry/OneForAll/HEAD/resources/wifi_error.png -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "osd/lib"] 2 | path = osd/lib 3 | url = https://github.com/vascofazza/raspidmx.git 4 | -------------------------------------------------------------------------------- /resources/low-battery.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/withgallantry/OneForAll/HEAD/resources/low-battery.png -------------------------------------------------------------------------------- /resources/wifi_warning.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/withgallantry/OneForAll/HEAD/resources/wifi_warning.png -------------------------------------------------------------------------------- /resources/main_no_joystick.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/withgallantry/OneForAll/HEAD/resources/main_no_joystick.png -------------------------------------------------------------------------------- /resources/main_no_joystick_pocketfe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/withgallantry/OneForAll/HEAD/resources/main_no_joystick_pocketfe.png -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | TARGETS=osd/lib/lib \ 2 | osd 3 | 4 | default :all 5 | 6 | all: 7 | for target in $(TARGETS); do ($(MAKE) -C $$target); done 8 | 9 | clean: 10 | for target in $(TARGETS); do ($(MAKE) -C $$target clean); done 11 | 12 | -------------------------------------------------------------------------------- /general.cfg: -------------------------------------------------------------------------------- 1 | [GENERAL] 2 | KEYS_CONFIG=keysKeyboard.cfg 3 | SHUTDOWN_DETECT=27 4 | SHOW_OVERLAY_HOTKEY_ONLY=false 5 | 6 | [BATTERY] 7 | ENABLED=True 8 | FULL_BATT_VOLTAGE=375 9 | BATT_LOW_VOLTAGE=340 10 | BATT_SHUTDOWN_VOLT=328 11 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SystemConfigs/MintyPi-Lite/general.cfg: -------------------------------------------------------------------------------- 1 | [GENERAL] 2 | KEYS_CONFIG=keysKeyboard.cfg 3 | SHUTDOWN_DETECT=27 4 | SHOW_OVERLAY_HOTKEY_ONLY=false 5 | BACKLIGHT_PWM=true 6 | SENSOR_DETECT=22 7 | SENSOR_COMMAND=shutdown 8 | 9 | [BATTERY] 10 | ENABLED=True 11 | FULL_BATT_VOLTAGE=373 12 | BATT_LOW_VOLTAGE=330 13 | BATT_SHUTDOWN_VOLT=322 14 | -------------------------------------------------------------------------------- /keysGamepad.cfg: -------------------------------------------------------------------------------- 1 | [KEYS] 2 | BTN_DPAD_LEFT=26 3 | BTN_DPAD_RIGHT=13 4 | BTN_DPAD_DOWN=6 5 | BTN_DPAD_UP=12 6 | BTN_A=5 7 | BTN_B=7 8 | BTN_X=4 9 | BTN_Y=17 10 | BTN_TL=16 11 | BTN_TR=20 12 | BTN_SELECT=22 13 | BTN_START=15 14 | 15 | [HOTKEYS] 16 | OSD_SHOW=22 17 | VOLUME_UP=12 18 | VOLUME_DOWN=6 19 | TOGGLE_WIFI=26 20 | TOGGLE_BLE=13 21 | TOGGLE_JOYSTICK=5 22 | SAFE_SHUTDOWN=-1 23 | 24 | [COMBOS] 25 | 26 | [JOYSTICK] 27 | ENABLED=True 28 | DEADZONE=300 29 | VCC=1600 30 | -------------------------------------------------------------------------------- /.idea/Retropie-open-OSD.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /keysKeyboard.cfg: -------------------------------------------------------------------------------- 1 | [KEYS] 2 | KEY_LEFT=26 #Left DPAD 3 | KEY_RIGHT=13 #Right DPAD 4 | KEY_DOWN=6 #Down DPAD 5 | KEY_UP=12 #Up DPAD 6 | KEY_LEFTCTRL=5 #A Button 7 | KEY_LEFTALT=7 #B Button 8 | KEY_Z=4 #X Button 9 | KEY_X=17 #Y Button 10 | KEY_G=16 #L1 Button 11 | KEY_H=20 #R1 Button 12 | KEY_SPACE=22 #Select Button 13 | KEY_ENTER=15 #Start Button 14 | 15 | [COMBOS] 16 | KEY_ESC=4,17 17 | 18 | [HOTKEYS] 19 | OSD_SHOW=22 20 | VOLUME_UP=12 21 | VOLUME_DOWN=6 22 | TOGGLE_WIFI=17 23 | TOGGLE_BLE=4 24 | TOGGLE_JOYSTICK=5 25 | SAFE_SHUTDOWN=-1 26 | 27 | [JOYSTICK] 28 | ENABLED=False 29 | DEADZONE=300 30 | VCC=1600 31 | -------------------------------------------------------------------------------- /SystemConfigs/MintyPi-Lite/mintypi-lite.cfg: -------------------------------------------------------------------------------- 1 | [KEYS] 2 | KEY_LEFT=4 #Left DPAD 3 | KEY_RIGHT=15 #Right DPAD 4 | KEY_DOWN=17 #Down DPAD 5 | KEY_UP=23 #Up DPAD 6 | KEY_LEFTCTRL=12 #A Button 7 | KEY_LEFTALT=26 #B Button 8 | KEY_Z=16 #X Button 9 | KEY_X=20 #Y Button 10 | KEY_G=27 #L1 Button 11 | KEY_H=6 #R1 Button 12 | KEY_SPACE=5 #Select Button 13 | KEY_ENTER=13 #Start Button 14 | 15 | [COMBOS] 16 | KEY_ESC=4,17 17 | 18 | [HOTKEYS] 19 | OSD_SHOW=7 20 | VOLUME_UP=23 21 | VOLUME_DOWN=17 22 | TOGGLE_WIFI=4 23 | TOGGLE_BLE=12 24 | TOGGLE_JOYSTICK=20 25 | 26 | [JOYSTICK] 27 | ENABLED=False 28 | DEADZONE=300 29 | VCC=1600 30 | -------------------------------------------------------------------------------- /osd/Makefile: -------------------------------------------------------------------------------- 1 | OBJS=osd.o 2 | BIN=osd 3 | 4 | CFLAGS+=-Wall -g -O3 -I./lib/common $(shell libpng-config --cflags) 5 | LDFLAGS+=-L/opt/vc/lib/ -lbcm_host -lm $(shell libpng-config --ldflags) -L./lib/lib -lraspidmx 6 | 7 | INCLUDES+=-I/opt/vc/include/ -I/opt/vc/include/interface/vcos/pthreads -I/opt/vc/include/interface/vmcs_host/linux 8 | 9 | all: $(BIN) 10 | 11 | %.o: %.c 12 | @rm -f $@ 13 | $(CC) $(CFLAGS) $(INCLUDES) -g -c $< -o $@ -Wno-deprecated-declarations 14 | 15 | $(BIN): $(OBJS) 16 | $(CC) -o $@ -Wl,--whole-archive $(OBJS) $(LDFLAGS) -pthread -Wl,--no-whole-archive -rdynamic 17 | chmod +x $@ 18 | clean: 19 | @rm -f $(OBJS) 20 | @rm -f $(BIN) 21 | -------------------------------------------------------------------------------- /keysWill.cfg: -------------------------------------------------------------------------------- 1 | # This config was created by Will (https://www.instagram.com/invader_meh/). The keys used are most suited for most emulators 2 | [KEYS] 3 | KEY_LEFT=26 #Left DPAD 4 | KEY_RIGHT=13 #Right DPAD 5 | KEY_DOWN=6 #Down DPAD 6 | KEY_UP=12 #Up DPAD 7 | KEY_X=5 #A Button 8 | KEY_Z=7 #B Button 9 | KEY_S=4 #X Button 10 | KEY_A=17 #Y Button 11 | KEY_U=16 #L1 Button 12 | KEY_Y=20 #R1 Button 13 | KEY_ESC=22 #Select Button 14 | KEY_ENTER=15 #Start Button 15 | 16 | [COMBOS] 17 | 18 | [HOTKEYS] 19 | OSD_SHOW=22 20 | VOLUME_UP=12 21 | VOLUME_DOWN=6 22 | TOGGLE_WIFI=26 23 | TOGGLE_BLE=4 24 | TOGGLE_JOYSTICK=5 25 | 26 | [JOYSTICK] 27 | ENABLED=False 28 | DEADZONE=300 29 | VCC=1600 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | q# Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | *.idea* 11 | 12 | # Linker output 13 | *.ilk 14 | *.map 15 | *.exp 16 | 17 | # Precompiled Headers 18 | *.gch 19 | *.pch 20 | 21 | # Libraries 22 | *.lib 23 | *.a 24 | *.la 25 | *.lo 26 | 27 | # Shared objects (inc. Windows DLLs) 28 | *.dll 29 | *.so 30 | *.so.* 31 | *.dylib 32 | 33 | # Executables 34 | *.exe 35 | *.out 36 | *.app 37 | *.i*86 38 | *.x86_64 39 | *.hex 40 | 41 | # Debug files 42 | *.dSYM/ 43 | *.su 44 | *.idb 45 | *.pdb 46 | 47 | # Kernel Module Compile Results 48 | *.mod* 49 | *.cmd 50 | .tmp_versions/ 51 | modules.order 52 | Module.symvers 53 | Mkfile.old 54 | dkms.conf 55 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # One For All 3 | 4 | One For All is software that was originally written and works best with with Helders [Retro PSU](https://heldergametech.com/shop/gameboy-zero/retropsu/). 5 | 6 | This software is designed to be used on Raspberry Pi handheld systems, such as the Gameboy Zero projects. This software handles battery monitoring, GPIO pins as control inputs, an analog joystick and safe shutdown. You will need specific hardware for some of these functions, which is listed below. The easiest way is to use Helders Retro PSU. 7 | 8 | ## Build instructions: 9 | 10 | * git clone --recursive https://github.com/withgallantry/OneForAll.git 11 | 12 | * make 13 | 14 | ## How to use it: 15 | 16 | * Configure (edit) the monitor script accordingly to your hardware configuration 17 | 18 | * sudo python monitor_evdev.py -------------------------------------------------------------------------------- /rfkill/README.txt: -------------------------------------------------------------------------------- 1 | RFKILL binary taken from: 2 | 3 | pi@retropie:~ $ sudo apt-get install rfkill 4 | Reading package lists... Done 5 | Building dependency tree 6 | Reading state information... Done 7 | The following packages will be upgraded: 8 | rfkill 9 | 1 upgraded, 0 newly installed, 0 to remove and 0 not upgraded. 10 | Need to get 8,022 B of archives. 11 | After this operation, 38.9 kB disk space will be freed. 12 | Get:1 http://mirrordirector.raspbian.org/raspbian/ jessie/main rfkill armhf 0.5-1 [8,022 B] 13 | Fetched 8,022 B in 0s (55.8 kB/s) 14 | Reading changelogs... Done 15 | (Reading database ... 86916 files and directories currently installed.) 16 | Preparing to unpack .../rfkill_0.5-1_armhf.deb ... 17 | Unpacking rfkill (0.5-1) over (0.5-1) ... 18 | Processing triggers for man-db (2.7.0.2-5) ... 19 | Setting up rfkill (0.5-1) ... 20 | -------------------------------------------------------------------------------- /osd/osd-backup.c: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------- 2 | // 3 | // 4 | // This file originates from Vascofazza's Retropie open OSD project. 5 | // Author: Federico Scozzafava 6 | // 7 | // THIS HEADER MUST REMAIN WITH THIS FILE AT ALL TIMES 8 | // 9 | // This firmware is free software: you can redistribute it and/or modify 10 | // it under the terms of the GNU General Public License as published by 11 | // the Free Software Foundation, either version 3 of the License, or 12 | // (at your option) any later version. 13 | // 14 | // This firmware is distributed in the hope that it will be useful, 15 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | // GNU General Public License for more details. 18 | // 19 | // You should have received a copy of the GNU General Public License 20 | // along with this repo. If not, see . 21 | // 22 | // 23 | //------------------------------------------------------------------------- 24 | 25 | #define _GNU_SOURCE 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include "font.h" 35 | #include "imageGraphics.h" 36 | #include "imageLayer.h" 37 | #include "loadpng.h" 38 | #include 39 | 40 | #include "bcm_host.h" 41 | 42 | //------------------------------------------------------------------------- 43 | 44 | #define NDEBUG 45 | 46 | #define BATTERY_IMAGE "/home/pi/Retropie-open-OSD/resources/battery.png" 47 | #define CHARGE_IMAGE "/home/pi/Retropie-open-OSD/resources/plug.png" 48 | #define INFO_IMAGE "/home/pi/Retropie-open-OSD/resources/main16.png" 49 | //#define INFO_IMAGE "/home/pi/Retropie-open-OSD/resources/battery.png" 50 | #define BATTERY_TH 20 51 | #define AUDIO_IMAGES (const char*[5]){"/home/pi/Retropie-open-OSD/resources/AUD0.png","/home/pi/Retropie-open-OSD/resources/AUD25.png","/home/pi/Retropie-open-OSD/resources/AUD50.png","/home/pi/Retropie-open-OSD/resources/AUD75.png","/home/pi/Retropie-open-OSD/resources/AUD100.png"} 52 | #define WIFI_IMAGES (const char*[5]){"/home/pi/Retropie-open-OSD/resources/wifi_warning.png", "/home/pi/Retropie-open-OSD/resources/wifi_error.png", "/home/pi/Retropie-open-OSD/resources/wifi_1.png", "/home/pi/Retropie-open-OSD/resources/wifi_2.png", "/home/pi/Retropie-open-OSD/resources/wifi_3.png"} 53 | #define BRIGHTNESS_MAX 7 54 | 55 | volatile bool run = true; 56 | 57 | //------------------------------------------------------------------------- 58 | 59 | static RGBA8_T clearColor = {0,0,0,0}; 60 | static RGBA8_T backgroundColour = { 0, 0, 0, 100 }; 61 | static RGBA8_T textColour = { 255, 255, 255, 255 }; 62 | static RGBA8_T greenColour = { 0, 255, 0, 200 }; 63 | static RGBA8_T redColour = { 255, 0, 0, 200 }; 64 | static int battery = 0, infos = 0, hud = 1, brightness = 0, charge = 0, audio = 0, wifi = 0, voltage = 0; 65 | static float temp = 0.f; 66 | 67 | void updateInfo(IMAGE_LAYER_T*); 68 | void getInput(); 69 | void clearLayer(IMAGE_LAYER_T*); 70 | void updateBattery(float, IMAGE_LAYER_T*); 71 | 72 | static void 73 | signalHandler(int signalNumber) 74 | { 75 | switch (signalNumber) 76 | { 77 | case SIGUSR1: 78 | getInput(); 79 | break; 80 | case SIGINT: 81 | case SIGTERM: 82 | 83 | run = false; 84 | break; 85 | }; 86 | } 87 | 88 | void updateBattery(float batval, IMAGE_LAYER_T* batteryLayer) 89 | { 90 | IMAGE_T *image = &(batteryLayer->image); 91 | clearImageRGB(image,&clearColor); 92 | //to config params 93 | RGBA8_T *col = battery < BATTERY_TH ? &redColour : &greenColour; 94 | imageBoxFilledRGB(image, 2,3,2+(int)round((batteryLayer->image.width-7)*batval),batteryLayer->image.height-3, col); 95 | changeSourceAndUpdateImageLayer(batteryLayer); 96 | } 97 | 98 | void getInput() 99 | { 100 | char buffer[100]; 101 | char *bp = buffer; 102 | int c; 103 | while(run && '\n' != (c=fgetc(stdin)) && (bp-buffer) < sizeof(buffer)) 104 | *bp++=c; 105 | *bp = 0;//terminator 106 | #ifndef NDEBUG 107 | printf("buffer: %s\n", buffer); 108 | #endif 109 | char *saveptr; 110 | char *word; 111 | char *str = buffer; 112 | while((word = strtok_r(str," ",&saveptr))) 113 | { 114 | #ifndef NDEBUG 115 | printf("word: %s\n", word); 116 | #endif 117 | str = NULL; 118 | if(word[0] == 'b') 119 | { 120 | //Battery 121 | battery = atoi(word+1); 122 | } 123 | else if(word[0] == 'w') 124 | { 125 | //wifi 126 | wifi= atoi(word+1); 127 | } 128 | else if(word[0] == 'a') 129 | { 130 | //audio 131 | audio= atoi(word+1); 132 | } 133 | else if(word[0] == 'l') 134 | { 135 | //Brightness 136 | brightness= atoi(word+1); 137 | } 138 | else if(word[0] == 't') 139 | { 140 | //temperature 141 | temp= atof(word+1); 142 | } 143 | else if(word[0] == 'v') 144 | { 145 | //voltage 146 | voltage= atoi(word+1); 147 | } 148 | else if(!strcmp(word, "on")) 149 | { 150 | infos = 1; 151 | } 152 | else if(!strcmp(word, "off")) 153 | { 154 | infos = 0; 155 | } 156 | else if(!strcmp(word, "allon")) 157 | { 158 | hud = 1; 159 | } 160 | else if(!strcmp(word, "alloff")) 161 | { 162 | hud = 0; 163 | } 164 | else if(!strcmp(word, "charge")) 165 | { 166 | charge = 1; 167 | } 168 | else if(!strcmp(word, "ncharge")) 169 | { 170 | charge = 0; 171 | } 172 | else if(!strcmp(word,"quit")) 173 | run = false; 174 | } 175 | #ifndef NDEBUG 176 | printf("out\n"); 177 | #endif 178 | } 179 | 180 | void clearLayer(IMAGE_LAYER_T *layer) 181 | { 182 | IMAGE_T *image = &(layer->image); 183 | clearImageRGB(image, &clearColor); 184 | changeSourceAndUpdateImageLayer(layer); 185 | } 186 | 187 | //------------------------------------------------------------------------- 188 | 189 | int main(int argc, char *argv[]) 190 | { 191 | uint32_t displayNumber = 0; 192 | 193 | //------------------------------------------------------------------- 194 | 195 | int opt; 196 | 197 | while ((opt = getopt(argc, argv, "d:")) != -1) 198 | { 199 | switch (opt) 200 | { 201 | case 'd': 202 | 203 | displayNumber = atoi(optarg); 204 | break; 205 | 206 | default: 207 | 208 | fprintf(stderr, "Usage: %s [-d ]\n", basename(argv[0])); 209 | fprintf(stderr, " -d - Raspberry Pi display number\n"); 210 | exit(EXIT_FAILURE); 211 | break; 212 | } 213 | } 214 | 215 | if (signal(SIGINT, signalHandler) == SIG_ERR) 216 | { 217 | perror("installing SIGINT signal handler"); 218 | exit(EXIT_FAILURE); 219 | } 220 | 221 | //--------------------------------------------------------------------- 222 | 223 | if (signal(SIGTERM, signalHandler) == SIG_ERR) 224 | { 225 | perror("installing SIGTERM signal handler"); 226 | exit(EXIT_FAILURE); 227 | } 228 | 229 | //--------------------------------------------------------------------- 230 | 231 | if (signal(SIGUSR1, signalHandler) == SIG_ERR) 232 | { 233 | perror("installing SIGTERM signal handler"); 234 | exit(EXIT_FAILURE); 235 | } 236 | 237 | //------------------------------------------------------------------- 238 | 239 | VC_IMAGE_TYPE_T type = VC_IMAGE_RGBA32; 240 | 241 | //--------------------------------------------------------------------- 242 | 243 | bcm_host_init(); 244 | 245 | //--------------------------------------------------------------------- 246 | 247 | DISPMANX_DISPLAY_HANDLE_T display 248 | = vc_dispmanx_display_open(displayNumber); 249 | assert(display != 0); 250 | 251 | //--------------------------------------------------------------------- 252 | 253 | DISPMANX_MODEINFO_T info; 254 | int result = vc_dispmanx_display_get_info(display, &info); 255 | assert(result == 0); 256 | 257 | //--------------------------------------------------------------------- 258 | 259 | static int layer = 30000; 260 | 261 | IMAGE_LAYER_T infoLayer; 262 | 263 | if (loadPng(&(infoLayer.image), INFO_IMAGE) == false) 264 | { 265 | fprintf(stderr, "unable to load %s\n", INFO_IMAGE); 266 | exit(EXIT_FAILURE); 267 | } 268 | 269 | 270 | createResourceImageLayer(&infoLayer, layer + 3); 271 | 272 | 273 | IMAGE_LAYER_T bimageLayer; 274 | if (loadPng(&(bimageLayer.image), BATTERY_IMAGE) == false) 275 | { 276 | fprintf(stderr, "unable to load %s\n", argv[optind]); 277 | } 278 | createResourceImageLayer(&bimageLayer, layer+2); 279 | 280 | IMAGE_LAYER_T batteryLayer; 281 | initImageLayer(&batteryLayer, 282 | bimageLayer.image.width, 283 | bimageLayer.image.height, 284 | VC_IMAGE_RGBA16); 285 | createResourceImageLayer(&batteryLayer, layer+1); 286 | 287 | IMAGE_LAYER_T cimageLayer; 288 | initImageLayer(&cimageLayer, 289 | bimageLayer.image.width, 290 | bimageLayer.image.height, 291 | type); 292 | createResourceImageLayer(&cimageLayer, layer+2); 293 | 294 | IMAGE_LAYER_T wimageLayer; 295 | initImageLayer(&wimageLayer, 296 | bimageLayer.image.height, 297 | bimageLayer.image.height, 298 | type); 299 | createResourceImageLayer(&wimageLayer, layer+2); 300 | 301 | IMAGE_LAYER_T aimageLayer; 302 | initImageLayer(&aimageLayer, 303 | 20, 304 | 11, 305 | type); 306 | createResourceImageLayer(&aimageLayer, layer+2); 307 | 308 | int xOffset = info.width-bimageLayer.image.width-1; 309 | int yOffset = 1; 310 | DISPMANX_UPDATE_HANDLE_T update = vc_dispmanx_update_start(0); 311 | assert(update != 0); 312 | 313 | addElementImageLayerOffset(&infoLayer, 314 | (info.width - infoLayer.image.width) / 2, 315 | (info.height - infoLayer.image.height) / 2, 316 | display, 317 | update); 318 | 319 | addElementImageLayerOffset(&wimageLayer, 320 | xOffset-wimageLayer.image.width-2, 321 | yOffset, 322 | display, 323 | update); 324 | 325 | addElementImageLayerOffset(&aimageLayer, 326 | (xOffset-wimageLayer.image.width)-aimageLayer.image.width-8, 327 | yOffset, 328 | display, 329 | update); 330 | 331 | addElementImageLayerOffset(&batteryLayer, 332 | xOffset, 333 | yOffset, 334 | display, 335 | update); 336 | addElementImageLayerOffset(&bimageLayer, 337 | xOffset, 338 | yOffset, 339 | display, 340 | update); 341 | addElementImageLayerOffset(&cimageLayer, 342 | xOffset, 343 | yOffset, 344 | display, 345 | update); 346 | 347 | 348 | result = vc_dispmanx_update_submit_sync(update); 349 | assert(result == 0); 350 | 351 | while (run) 352 | { 353 | float batval = battery/100.f; 354 | { 355 | updateBattery(batval, &batteryLayer); 356 | } 357 | if(charge > 0 && hud) 358 | { 359 | //TODO preload for efficiency 360 | if (loadPng(&(cimageLayer.image), CHARGE_IMAGE) == false) 361 | { 362 | fprintf(stderr, "unable to charge load %s\n", argv[optind]); 363 | } 364 | changeSourceAndUpdateImageLayer(&cimageLayer); 365 | charge = -1; 366 | } 367 | else if(!charge && hud) 368 | { 369 | clearLayer(&cimageLayer); 370 | charge = -1; 371 | } 372 | if(wifi > 0 && hud) 373 | { 374 | //TODO preload for efficienty 375 | if (loadPng(&(wimageLayer.image), WIFI_IMAGES[wifi-1]) == false) 376 | { 377 | fprintf(stderr, "unable to wifi load %s\n", argv[optind]); 378 | } 379 | changeSourceAndUpdateImageLayer(&wimageLayer); 380 | wifi = -1; 381 | } 382 | else if (!wifi) 383 | { 384 | clearLayer(&wimageLayer); 385 | } 386 | if(audio > 0) 387 | { 388 | //TODO preload for efficienty 389 | if (loadPng(&(aimageLayer.image), AUDIO_IMAGES[audio-1]) == false) 390 | { 391 | fprintf(stderr, "unable to audio load %s\n", argv[optind]); 392 | } 393 | changeSourceAndUpdateImageLayer(&aimageLayer); 394 | audio = -1; 395 | } 396 | else if (!audio) 397 | { 398 | clearLayer(&aimageLayer); 399 | } 400 | if (!hud) { 401 | clearLayer(&batteryLayer); 402 | clearLayer(&wimageLayer); 403 | clearLayer(&aimageLayer); 404 | clearLayer(&bimageLayer); 405 | clearLayer(&cimageLayer); 406 | } 407 | if(infos > 0) 408 | { 409 | updateInfo(&infoLayer); 410 | } 411 | else if(!infos) 412 | { 413 | infos = -1; 414 | clearLayer(&infoLayer); 415 | } 416 | else 417 | { 418 | pause(); //stop thread 419 | } 420 | usleep(1000000); //sleep 1sec 421 | } 422 | //--------------------------------------------------------------------- 423 | 424 | destroyImageLayer(&infoLayer); 425 | destroyImageLayer(&batteryLayer); 426 | destroyImageLayer(&wimageLayer); 427 | destroyImageLayer(&aimageLayer); 428 | destroyImageLayer(&bimageLayer); 429 | destroyImageLayer(&cimageLayer); 430 | result = vc_dispmanx_display_close(display); 431 | assert(result == 0); 432 | 433 | //--------------------------------------------------------------------- 434 | 435 | return 0; 436 | } 437 | 438 | void updateInfo(IMAGE_LAYER_T *infoLayer) 439 | { 440 | IMAGE_T *image = &(infoLayer->image); 441 | // clearImageRGB(image, &backgroundColour); 442 | loadPng(&(infoLayer->image), INFO_IMAGE); 443 | // int x = 1, y = 1; 444 | // drawStringRGB(x, y, buffer, &textColour, image); 445 | changeSourceAndUpdateImageLayer(infoLayer); 446 | } 447 | 448 | -------------------------------------------------------------------------------- /monitor.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # sudo apt-get install python-serial 3 | # 4 | # This file originates from Vascofazza's Retropie open OSD project. 5 | # Author: Federico Scozzafava 6 | # 7 | # THIS HEADER MUST REMAIN WITH THIS FILE AT ALL TIMES 8 | # 9 | # This firmware is free software: you can redistribute it and/or modify 10 | # it under the terms of the GNU General Public License as published by 11 | # the Free Software Foundation, either version 3 of the License, or 12 | # (at your option) any later version. 13 | # 14 | # This firmware is distributed in the hope that it will be useful, 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | # GNU General Public License for more details. 18 | # 19 | # You should have received a copy of the GNU General Public License 20 | # along with this repo. If not, see . 21 | # 22 | import Adafruit_ADS1x15 23 | import RPi.GPIO as gpio 24 | import configparser 25 | import logging 26 | import logging.handlers 27 | import os 28 | import re 29 | import signal 30 | import sys 31 | import thread as thread 32 | import time 33 | import uinput 34 | from subprocess import Popen, PIPE, check_output, check_call 35 | from threading import Event 36 | 37 | # Batt variables 38 | voltscale = 118.0 # ADJUST THIS 39 | currscale = 640.0 40 | resdivmul = 4.0 41 | resdivval = 1000.0 42 | dacres = 20.47 43 | dacmax = 4096.0 44 | 45 | backlightSetting = 1024 46 | 47 | batt_threshold = 4 48 | 49 | temperature_max = 70.0 50 | temperature_threshold = 5.0 51 | 52 | # BT Variables 53 | bt_state = 'UNKNOWN' 54 | 55 | # Wifi variables 56 | wifi_state = 'UNKNOWN' 57 | wif = 0 58 | wifi_off = 0 59 | wifi_warning = 1 60 | wifi_error = 2 61 | wifi_1bar = 3 62 | wifi_2bar = 4 63 | wifi_3bar = 5 64 | 65 | 66 | def str2bool(v): 67 | return v.lower() in ("yes", "true", "True", "1") 68 | 69 | 70 | bin_dir = os.path.dirname(os.path.abspath(sys.argv[0])) 71 | osd_path = bin_dir + '/osd/osd' 72 | rfkill_path = bin_dir + '/rfkill/rfkill' 73 | 74 | # General Configuration 75 | generalConfig = configparser.ConfigParser() 76 | generalConfig.read(bin_dir + '/general.cfg') 77 | 78 | general = generalConfig['GENERAL'] 79 | 80 | # Keys Configuration 81 | keysConfig = configparser.ConfigParser(inline_comment_prefixes="#") 82 | keysConfig.read(bin_dir + '/' + general['KEYS_CONFIG']) 83 | hotkeys = keysConfig['HOTKEYS'] 84 | 85 | if generalConfig.has_option("GENERAL", "DEBUG"): 86 | logging.basicConfig(filename=bin_dir + '/osd.log', level=logging.DEBUG) 87 | 88 | HOTKEYS = [] 89 | BUTTONS = [] 90 | KEYS = {} 91 | PREVIOUS_KEYSTATES = {} 92 | COMBO_CURRENT_KEYS = set() 93 | 94 | KEY_COMBOS = {} 95 | 96 | # GPIO Init 97 | gpio.setwarnings(False) 98 | gpio.setmode(gpio.BCM) 99 | 100 | for key, pin in keysConfig.items('KEYS'): 101 | BUTTONS.append(int(pin)) 102 | KEYS.update({int(pin): getattr(uinput, key.upper())}) 103 | PREVIOUS_KEYSTATES.update({int(pin): 0}) 104 | 105 | for key, pinSet in keysConfig.items('COMBOS'): 106 | pins = set(map(int, pinSet.split(','))) 107 | KEY_COMBOS.update({frozenset(pins): getattr(uinput, key.upper())}) 108 | 109 | VOLUME_UP = int(hotkeys['VOLUME_UP']) 110 | VOLUME_DOWN = int(hotkeys['VOLUME_DOWN']) 111 | TOGGLE_WIFI = int(hotkeys['TOGGLE_WIFI']) 112 | TOGGLE_BLE = int(hotkeys['TOGGLE_BLE']) 113 | TOGGLE_JOYSTICK = int(hotkeys['TOGGLE_JOYSTICK']) 114 | SHOW_OSD_KEY = int(hotkeys['OSD_SHOW']) 115 | SHUTDOWN = int(general['SHUTDOWN_DETECT']) 116 | SHOW_OVERLAY_HOTKEY_ONLY = str2bool(general['SHOW_OVERLAY_HOTKEY_ONLY']) 117 | 118 | if generalConfig.has_option("GENERAL", "BACKLIGHT_PWM"): 119 | if str2bool(general['BACKLIGHT_PWM']): 120 | import wiringpi 121 | 122 | wiringpi.wiringPiSetupGpio() 123 | 124 | wiringpi.pinMode(13, wiringpi.OUTPUT) 125 | wiringpi.pinMode(13, wiringpi.PWM_OUTPUT) 126 | wiringpi.pwmWrite(13, backlightSetting) 127 | 128 | BRIGHTNESS_UP = int(hotkeys['BRIGHTNESS_UP']) 129 | BRIGHTNESS_DOWN = int(hotkeys['BRIGHTNESS_DOWN']) 130 | 131 | if generalConfig.has_option("GENERAL", "SENSOR_DETECT"): 132 | SENSOR_DETECT = int(general['SENSOR_DETECT']) 133 | else: 134 | SENSOR_DETECT = -1 135 | 136 | if keysConfig.has_option("HOTKEYS", "SAFE_SHUTDOWN"): 137 | SAFE_SHUTDOWN = int(hotkeys['SAFE_SHUTDOWN']) 138 | else: 139 | SAFE_SHUTDOWN = -1 140 | 141 | if keysConfig.has_option("HOTKEYS", "QUICKSAVE"): 142 | QUICKSAVE = int(hotkeys['QUICKSAVE']) 143 | else: 144 | QUICKSAVE = -1 145 | 146 | if keysConfig.has_option("HOTKEYS", "QUICKSAVE"): 147 | KEYS.update({int(QUICKSAVE): uinput.KEY_F2}) 148 | KEYS.update({int(99): uinput.KEY_F4}) 149 | 150 | # Joystick Hardware settings 151 | joystickConfig = keysConfig['JOYSTICK'] # TODO: Make this go to keys 152 | DZONE = int(joystickConfig['DEADZONE']) # dead zone applied to joystick (mV) 153 | VREF = int(joystickConfig['VCC']) # joystick Vcc (mV) 154 | JOYSTICK_ENABLED = joystickConfig['ENABLED'] 155 | 156 | if JOYSTICK_ENABLED == 'True': 157 | KEYS.update({10001: uinput.ABS_X + (0, VREF, 0, 0), 158 | 10002: uinput.ABS_Y + (0, VREF, 0, 0), }) 159 | 160 | # Battery config 161 | battery = generalConfig['BATTERY'] 162 | monitoring_enabled = str2bool(battery['ENABLED']) 163 | batt_full = int(battery['FULL_BATT_VOLTAGE']) 164 | batt_low = int(battery['BATT_LOW_VOLTAGE']) 165 | batt_shdn = int(battery['BATT_SHUTDOWN_VOLT']) 166 | 167 | BOUNCE_TIME = 0.03 # Debounce time in seconds 168 | 169 | # GPIO Init 170 | gpio.setup(BUTTONS, gpio.IN, pull_up_down=gpio.PUD_UP) 171 | 172 | if not SHUTDOWN == -1: 173 | gpio.setup(SHUTDOWN, gpio.IN, pull_up_down=gpio.PUD_UP) 174 | 175 | if not SENSOR_DETECT == -1: 176 | gpio.setup(SENSOR_DETECT, gpio.IN, pull_up_down=gpio.PUD_UP) 177 | 178 | if keysConfig.has_option("HOTKEYS", "QUICKSAVE"): 179 | gpio.setup(int(QUICKSAVE), gpio.IN, pull_up_down=gpio.PUD_UP) 180 | 181 | # Global Variables 182 | global brightness 183 | global volt 184 | global info 185 | global wifi 186 | global volume 187 | global charge 188 | global bat 189 | global joystick 190 | global bluetooth 191 | global lowbattery 192 | global LAST_TRIGGERED_COMBO 193 | LAST_TRIGGERED_COMBO = None 194 | 195 | brightness = -1 196 | info = False 197 | volt = 410 198 | volume = 1 199 | wifi = 2 200 | charge = 0 201 | bat = 0 202 | last_bat_read = 450 203 | joystick = False 204 | showOverlay = False 205 | lowbattery = 0 206 | overrideCounter = Event() 207 | 208 | if JOYSTICK_ENABLED == 'True': 209 | joystick = True 210 | 211 | # TO DO REPLACE A LOT OF OLD CALLS WITH THE CHECK_OUTPUT 212 | if monitoring_enabled: 213 | adc = Adafruit_ADS1x15.ADS1015(address=0x48, busnum=1) 214 | else: 215 | adc = False 216 | 217 | device = uinput.Device(KEYS.values(), name="OneForAll", version=0x3) 218 | 219 | time.sleep(1) 220 | 221 | 222 | def hotkeyAction(key): 223 | if key == QUICKSAVE: 224 | return True 225 | 226 | if not gpio.input(SHOW_OSD_KEY) or (key == SHOW_OSD_KEY): 227 | if key in HOTKEYS: 228 | return True 229 | 230 | return False 231 | 232 | 233 | def handle_sensor(pin): 234 | command = "backlight" 235 | if generalConfig.has_option("GENERAL", "SENSOR_COMMAND"): 236 | command = general['SENSOR_COMMAND'] 237 | 238 | if command == "backlight": 239 | global backlightSetting 240 | state = 0 if gpio.input(pin) else 1 241 | if state == 1: 242 | wiringpi.pwmWrite(13, 0) 243 | if state == 0: 244 | wiringpi.pwmWrite(13, backlightSetting) 245 | 246 | if command == "shutdown": 247 | device.emit(uinput.KEY_SPACE, state) 248 | device.emit(uinput.KEY_F2, state) 249 | doShutdown() 250 | 251 | 252 | def handle_quicksave(pin): 253 | logging.debug("Handling QUICKSAVE press") 254 | state = 0 if gpio.input(pin) else 1 255 | if not gpio.input(SHOW_OSD_KEY): 256 | logging.debug("Loading Game") 257 | device.emit(uinput.KEY_SPACE, state) 258 | device.emit(uinput.KEY_F4, state) 259 | device.syn() 260 | if gpio.input(SHOW_OSD_KEY): 261 | logging.debug("Saving Game") 262 | device.emit(uinput.KEY_SPACE, state) 263 | device.emit(uinput.KEY_F2, state) 264 | device.syn() 265 | 266 | 267 | def handle_button(pin): 268 | global showOverlay 269 | global info 270 | global LAST_TRIGGERED_COMBO 271 | time.sleep(BOUNCE_TIME) 272 | state = 0 if gpio.input(pin) else 1 273 | 274 | if state == 1: 275 | COMBO_CURRENT_KEYS.add(pin) 276 | else: 277 | COMBO_CURRENT_KEYS.discard(pin) 278 | 279 | if frozenset(COMBO_CURRENT_KEYS) in KEY_COMBOS: 280 | # If the current set of keys are in the mapping, execute the function 281 | if KEY_COMBOS[frozenset(COMBO_CURRENT_KEYS)] == LAST_TRIGGERED_COMBO: 282 | device.emit(KEY_COMBOS[frozenset(COMBO_CURRENT_KEYS)], 2) 283 | else: 284 | device.emit(KEY_COMBOS[frozenset(COMBO_CURRENT_KEYS)], 1) 285 | LAST_TRIGGERED_COMBO = KEY_COMBOS[frozenset(COMBO_CURRENT_KEYS)] 286 | else: 287 | if LAST_TRIGGERED_COMBO is not None: 288 | device.emit(LAST_TRIGGERED_COMBO, 0) 289 | LAST_TRIGGERED_COMBO = None 290 | 291 | if pin == SHOW_OSD_KEY: 292 | if state == 1: 293 | showOverlay = True 294 | try: 295 | info = showOverlay 296 | overrideCounter.set() 297 | except Exception: 298 | pass 299 | else: 300 | showOverlay = False 301 | try: 302 | info = showOverlay 303 | overrideCounter.set() 304 | except Exception: 305 | pass 306 | 307 | if not hotkeyAction(pin): 308 | key = KEYS[pin] 309 | if PREVIOUS_KEYSTATES[pin] == 1 and state == 1: 310 | device.emit(key, 2) 311 | else: 312 | device.emit(key, state) 313 | PREVIOUS_KEYSTATES.update({pin: state}) 314 | time.sleep(BOUNCE_TIME) 315 | logging.debug("Pin: {}, KeyCode: {}, Event: {}".format(pin, key, 'press' if state else 'release')) 316 | else: 317 | checkKeyInputPowerSaving() 318 | 319 | device.syn() 320 | PREVIOUS_KEYSTATES.update({pin: state}) 321 | 322 | 323 | def handle_shutdown(pin): 324 | state = 0 if gpio.input(pin) else 1 325 | if (state): 326 | logging.info("SHUTDOWN") 327 | doShutdown() 328 | 329 | 330 | # Initialise Safe shutdown 331 | if not SHUTDOWN == -1: 332 | gpio.add_event_detect(SHUTDOWN, gpio.BOTH, callback=handle_shutdown, bouncetime=1) 333 | 334 | if not SENSOR_DETECT == -1: 335 | gpio.add_event_detect(SENSOR_DETECT, gpio.BOTH, callback=handle_sensor, bouncetime=1) 336 | 337 | if keysConfig.has_option("HOTKEYS", "QUICKSAVE"): 338 | gpio.add_event_detect(QUICKSAVE, gpio.BOTH, callback=handle_quicksave, bouncetime=1) 339 | 340 | # Initialise Buttons 341 | for button in BUTTONS: 342 | gpio.add_event_detect(button, gpio.BOTH, callback=handle_button, bouncetime=1) 343 | logging.debug("Button: {}".format(button)) 344 | 345 | for key, pin in keysConfig.items('HOTKEYS'): 346 | HOTKEYS.append(int(pin)) 347 | 348 | if not int(pin) in BUTTONS and int(pin) != QUICKSAVE: 349 | if pin != -1: 350 | gpio.setup(int(pin), gpio.IN, pull_up_down=gpio.PUD_UP) 351 | gpio.add_event_detect(int(pin), gpio.BOTH, callback=handle_button, bouncetime=1) 352 | 353 | # Send centering commands 354 | device.emit(uinput.ABS_X, VREF / 2, syn=False); 355 | device.emit(uinput.ABS_Y, VREF / 2); 356 | 357 | # Set up OSD service 358 | try: 359 | if JOYSTICK_ENABLED == 'False': 360 | osd_proc = Popen([osd_path, bin_dir, "nojoystick"], shell=False, stdin=PIPE, stdout=None, stderr=None) 361 | else: 362 | osd_proc = Popen([osd_path, bin_dir, "full"], shell=False, stdin=PIPE, stdout=None, stderr=None) 363 | osd_in = osd_proc.stdin 364 | time.sleep(1) 365 | osd_poll = osd_proc.poll() 366 | if (osd_poll): 367 | logging.error("ERROR: Failed to start OSD, got return code [" + str(osd_poll) + "]\n") 368 | sys.exit(1) 369 | except Exception as e: 370 | logging.exception("ERROR: Failed start OSD binary"); 371 | sys.exit(1); 372 | 373 | 374 | # Check for shutdown state 375 | def checkShdn(volt): 376 | global lowbattery 377 | global info 378 | if volt < batt_shdn: 379 | lowbattery = 1 380 | info = 1 381 | overrideCounter.set() 382 | doShutdown() 383 | 384 | 385 | # Read voltage 386 | def readVoltage(): 387 | global last_bat_read; 388 | voltVal = adc.read_adc(0, gain=1) 389 | print voltVal 390 | print 'read' 391 | volt = int((float(voltVal) * (4.09 / 2047.0)) * 100) 392 | 393 | if volt < 300 or (last_bat_read > 300 and last_bat_read - volt > 6 and not last_bat_read == 450): 394 | volt = last_bat_read; 395 | 396 | last_bat_read = volt; 397 | 398 | return volt 399 | 400 | 401 | # Get voltage percent 402 | def getVoltagepercent(volt): 403 | return clamp(int(float(volt - batt_shdn) / float(batt_full - batt_shdn) * 100), 0, 100) 404 | 405 | 406 | def readVolumeLevel(): 407 | process = os.popen("amixer get Master | grep 'Left:' | awk -F'[][]' '{ print $2 }'") 408 | res = process.readline() 409 | process.close() 410 | 411 | vol = 0; 412 | try: 413 | vol = int(res.replace("%", "").replace("'C\n", "")) 414 | except Exception as e: 415 | logging.info("Audio Err : " + str(e)) 416 | 417 | return vol; 418 | 419 | 420 | # Read wifi (Credits: kite's SAIO project) Modified to only read, not set wifi. 421 | def readModeWifi(toggle=False): 422 | ret = 0; 423 | wifiVal = not os.path.exists(osd_path + 'wifi') # int(ser.readline().rstrip('\r\n')) 424 | if toggle: 425 | wifiVal = not wifiVal 426 | global wifi_state 427 | if (wifiVal): 428 | if os.path.exists(osd_path + 'wifi'): 429 | os.remove(osd_path + 'wifi') 430 | if (wifi_state != 'ON'): 431 | wifi_state = 'ON' 432 | logging.info("Wifi [ENABLING]") 433 | try: 434 | out = check_output(['sudo', rfkill_path, 'unblock', 'wifi']) 435 | logging.info("Wifi [" + str(out) + "]") 436 | except Exception as e: 437 | logging.info("Wifi : " + str(e)) 438 | ret = wifi_warning # Get signal strength 439 | 440 | else: 441 | with open(osd_path + 'wifi', 'a'): 442 | n = 1 443 | if (wifi_state != 'OFF'): 444 | wifi_state = 'OFF' 445 | logging.info("Wifi [DISABLING]") 446 | try: 447 | out = check_output(['sudo', rfkill_path, 'block', 'wifi']) 448 | logging.info("Wifi [" + str(out) + "]") 449 | except Exception as e: 450 | logging.info("Wifi : " + str(e)) 451 | ret = wifi_error 452 | return ret 453 | # check signal 454 | raw = check_output(['cat', '/proc/net/wireless']) 455 | strengthObj = re.search(r'.wlan0: \d*\s*(\d*)\.\s*[-]?(\d*)\.', raw, re.I) 456 | if strengthObj: 457 | strength = 0 458 | if (int(strengthObj.group(1)) > 0): 459 | strength = int(strengthObj.group(1)) 460 | elif (int(strengthObj.group(2)) > 0): 461 | strength = int(strengthObj.group(2)) 462 | logging.info("Wifi [" + str(strength) + "]strength") 463 | if (strength > 55): 464 | ret = wifi_3bar 465 | elif (strength > 40): 466 | ret = wifi_2bar 467 | elif (strength > 5): 468 | ret = wifi_1bar 469 | else: 470 | ret = wifi_warning 471 | else: 472 | logging.info("Wifi [---]strength") 473 | ret = wifi_error 474 | return ret 475 | 476 | 477 | def readModeBluetooth(toggle=False): 478 | ret = 0; 479 | BtVal = not os.path.exists(osd_path + 'bluetooth') # int(ser.readline().rstrip('\r\n')) 480 | if toggle: 481 | BtVal = not BtVal 482 | global bt_state 483 | if (BtVal): 484 | if os.path.exists(osd_path + 'bluetooth'): 485 | os.remove(osd_path + 'bluetooth') 486 | if (bt_state != 'ON'): 487 | bt_state = 'ON' 488 | logging.info("BT [ENABLING]") 489 | try: 490 | out = check_output(['sudo', rfkill_path, 'unblock', 'bluetooth']) 491 | logging.info("BT [" + str(out) + "]") 492 | except Exception as e: 493 | logging.info("BT : " + str(e)) 494 | ret = wifi_warning # Get signal strength 495 | 496 | else: 497 | with open(osd_path + 'bluetooth', 'a'): 498 | n = 1 499 | if (bt_state != 'OFF'): 500 | bt_state = 'OFF' 501 | logging.info("BT [DISABLING]") 502 | try: 503 | out = check_output(['sudo', rfkill_path, 'block', 'bluetooth']) 504 | logging.info("BT [" + str(out) + "]") 505 | except Exception as e: 506 | logging.info("BT : " + str(e)) 507 | ret = wifi_error 508 | return ret 509 | # check if it's enabled 510 | raw = check_output(['hcitool', 'dev']) 511 | return True if raw.find("hci0") > -1 else False 512 | 513 | 514 | # Do a shutdown 515 | def doShutdown(channel=None): 516 | # check_call("sudo killall emulationstation", shell=True) 517 | # time.sleep(1) 518 | check_call("sudo shutdown -h now", shell=True) 519 | try: 520 | sys.stdout.close() 521 | except: 522 | pass 523 | try: 524 | sys.stderr.close() 525 | except: 526 | pass 527 | sys.exit(0) 528 | 529 | 530 | # Signals the OSD binary 531 | def updateOSD(volt=0, bat=0, temp=0, wifi=0, audio=0, lowbattery=0, info=False, charge=False, bluetooth=False): 532 | global showOverlay 533 | showState = showOverlay if SHOW_OVERLAY_HOTKEY_ONLY else True 534 | commands = "s" + str(int(showState)) + " p" + str(int((backlightSetting / 1024) * 100)) + " v" + str( 535 | volt) + " b" + str(bat) + " t" + str(temp) + " w" + str( 536 | wifi) + " a" + str( 537 | audio) + " j" + ("1 " if joystick else "0 ") + " u" + ("1 " if bluetooth else "0 ") + " l" + ( 538 | "1 " if lowbattery else "0 ") + " " + ("on " if info else "off ") + ( 539 | "charge" if charge else "ncharge") + "\n" 540 | # print commands 541 | osd_proc.send_signal(signal.SIGUSR1) 542 | osd_in.write(commands) 543 | osd_in.flush() 544 | 545 | 546 | # Misc functions 547 | def clamp(n, minn, maxn): 548 | return max(min(maxn, n), minn) 549 | 550 | 551 | def volumeUp(): 552 | global volume 553 | volume = min(100, volume + 5) 554 | os.system("amixer sset -q 'PCM' " + str(volume) + "%") 555 | 556 | 557 | def volumeDown(): 558 | global volume 559 | volume = max(0, volume - 5) 560 | os.system("amixer sset -q 'PCM' " + str(volume) + "%") 561 | 562 | 563 | def inputReading(): 564 | global volume 565 | global wifi 566 | global info 567 | global volt 568 | global bat 569 | global charge 570 | global joystick 571 | while (1): 572 | if joystick == True: 573 | checkJoystickInput() 574 | time.sleep(.05) 575 | 576 | 577 | def checkKeyInputPowerSaving(): 578 | global info 579 | global wifi 580 | global joystick 581 | global bluetooth 582 | global bat 583 | global volume 584 | global volt 585 | global showOverlay 586 | 587 | info = showOverlay 588 | overrideCounter.set() 589 | 590 | if not gpio.input(SHOW_OSD_KEY): 591 | if not gpio.input(VOLUME_UP): 592 | volumeUp() 593 | time.sleep(0.6) 594 | elif not gpio.input(VOLUME_DOWN): 595 | volumeDown() 596 | time.sleep(0.6) 597 | elif not gpio.input(TOGGLE_WIFI): 598 | wifi = readModeWifi(True) 599 | time.sleep(0.6) 600 | elif not gpio.input(TOGGLE_JOYSTICK): 601 | joystick = not joystick 602 | time.sleep(0.6) 603 | elif not gpio.input(TOGGLE_BLE): 604 | bluetooth = readModeBluetooth(True) 605 | time.sleep(0.6) 606 | elif not gpio.input(BRIGHTNESS_UP): 607 | brightnessUp() 608 | time.sleep(0.6) 609 | elif not gpio.input(BRIGHTNESS_DOWN): 610 | brightnessDown() 611 | time.sleep(0.6) 612 | elif SAFE_SHUTDOWN != -1: 613 | if not gpio.input(SAFE_SHUTDOWN): 614 | doShutdown() 615 | 616 | 617 | def checkJoystickInput(): 618 | an1 = adc.read_adc(2, gain=2 / 3); 619 | an0 = adc.read_adc(1, gain=2 / 3); 620 | 621 | logging.debug("X: {} | Y: {}".format(an0, an1)) 622 | logging.debug("Above: {} | Below: {}".format((VREF / 2 + DZONE), (VREF / 2 - DZONE))) 623 | 624 | # Check and apply joystick states 625 | if (an0 > ((VREF / 2 + DZONE)) or (an0 < (VREF / 2 - DZONE))) and an0 <= VREF: 626 | val = an0 - 100 - 200 * (an0 < VREF / 2 - DZONE) + 200 * (an0 > VREF / 2 + DZONE) 627 | device.emit(uinput.ABS_X, val, syn=False) 628 | else: 629 | # Center the sticks if within deadzone 630 | device.emit(uinput.ABS_X, VREF / 2, syn=False) 631 | if ((an1 > (VREF / 2 + DZONE)) or (an1 < (VREF / 2 - DZONE))) and an1 <= VREF: 632 | valy = an1 + 100 - 200 * (an1 < VREF / 2 - DZONE) + 200 * (an1 > VREF / 2 + DZONE) 633 | device.emit(uinput.ABS_Y, valy) 634 | else: 635 | # Center the sticks if within deadzone 636 | device.emit(uinput.ABS_Y, VREF / 2) 637 | 638 | 639 | def constrain(val, min_val, max_val): 640 | return min(max_val, max(min_val, val)) 641 | 642 | 643 | def brightnessUp(): 644 | global backlightSetting 645 | backlightSetting = constrain(backlightSetting + 128, 0, 1024) 646 | wiringpi.pwmWrite(13, backlightSetting); 647 | 648 | 649 | def brightnessDown(): 650 | global backlightSetting 651 | backlightSetting = constrain(backlightSetting - 128, 0, 1024) 652 | wiringpi.pwmWrite(13, backlightSetting); 653 | 654 | 655 | def exit_gracefully(signum=None, frame=None): 656 | gpio.cleanup 657 | osd_proc.terminate() 658 | sys.exit(0) 659 | 660 | 661 | signal.signal(signal.SIGINT, exit_gracefully) 662 | signal.signal(signal.SIGTERM, exit_gracefully) 663 | 664 | # Read Initial States 665 | volume = readVolumeLevel() 666 | 667 | wifi = readModeWifi() 668 | bluetooth = bluetooth = readModeBluetooth() 669 | 670 | if JOYSTICK_ENABLED == 'True': 671 | inputReadingThread = thread.start_new_thread(inputReading, ()) 672 | 673 | try: 674 | while 1: 675 | try: 676 | if not adc == False: 677 | volt = readVoltage() 678 | bat = getVoltagepercent(volt) 679 | checkShdn(volt) 680 | updateOSD(volt, bat, 20, wifi, volume, lowbattery, info, charge, bluetooth) 681 | print 'update OSD' 682 | overrideCounter.wait(10) 683 | if overrideCounter.is_set(): 684 | overrideCounter.clear() 685 | runCounter = 0; 686 | 687 | except Exception: 688 | logging.info("EXCEPTION") 689 | pass 690 | 691 | except KeyboardInterrupt: 692 | exit_gracefully() 693 | -------------------------------------------------------------------------------- /osd/osd.c: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------- 2 | // 3 | // 4 | // This file originates from Vascofazza's Retropie open OSD project. 5 | // Author: Federico Scozzafava 6 | // 7 | // THIS HEADER MUST REMAIN WITH THIS FILE AT ALL TIMES 8 | // 9 | // This firmware is free software: you can redistribute it and/or modify 10 | // it under the terms of the GNU General Public License as published by 11 | // the Free Software Foundation, either version 3 of the License, or 12 | // (at your option) any later version. 13 | // 14 | // This firmware is distributed in the hope that it will be useful, 15 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | // GNU General Public License for more details. 18 | // 19 | // You should have received a copy of the GNU General Public License 20 | // along with this repo. If not, see . 21 | // 22 | // 23 | //------------------------------------------------------------------------- 24 | 25 | #define _GNU_SOURCE 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include "font.h" 36 | #include "imageGraphics.h" 37 | #include "imageLayer.h" 38 | #include "loadpng.h" 39 | #include 40 | #include 41 | 42 | #include "bcm_host.h" 43 | 44 | //------------------------------------------------------------------------- 45 | 46 | #define NDEBUG 47 | #define BATTERY_IMAGE "./resources/battery.png" 48 | #define CHARGE_IMAGE "./resources/plug.png" 49 | #define LOW_BATTERY_IMAGE "./resources/low-battery.png" 50 | #define INFO_IMAGE "./resources/main.png" 51 | #define INFO_NO_JOYSTICK "./resources/main_no_joystick.png" 52 | #define JOYSTICK_IMAGE "./resources/joystick.png" 53 | #define BLUETOOTH_IMAGE "./resources/bluetooth.png" 54 | #define BATTERY_TH 20 55 | #define AUDIO_IMAGES (const char*[5]){"./resources/AUD0.png","./resources/AUD25.png","./resources/AUD50.png","./resources/AUD75.png","./resources/AUD100.png"} 56 | #define WIFI_IMAGES (const char*[5]){"./resources/wifi_warning.png", "./resources/wifi_error.png", "./resources/wifi_1.png", "./resources/wifi_2.png", "./resources/wifi_3.png"} 57 | 58 | volatile bool run = true; 59 | volatile bool show = false; 60 | 61 | //------------------------------------------------------------------------- 62 | 63 | static RGBA8_T clearColor = {0,0,0,0}; 64 | static RGBA8_T backgroundColour = { 0, 0, 0, 100 }; 65 | static RGBA8_T textColour = { 255, 255, 255, 255 }; 66 | static RGBA8_T greenColour = { 0, 255, 0, 200 }; 67 | static RGBA8_T redColour = { 255, 0, 0, 200 }; 68 | static int battery = 0, infos = 0, hud = 1, charge = 0, low_battery = 0, audio = 0, wifi = 0, wifi_loaded = 0, voltage = 0, backlight = 0, vol_image = 0, infos_loaded = 0, warning_loaded = 0, joystick = 0, bluetooth = 0; 69 | static float temp = 0.f; 70 | 71 | void updateInfo(IMAGE_LAYER_T*, char[]); 72 | void updateInfoText(IMAGE_LAYER_T*, bool); 73 | void getInput(); 74 | void clearLayer(IMAGE_LAYER_T*); 75 | void updateBattery(float, IMAGE_LAYER_T*); 76 | char *getcwd(char *buf, size_t size); 77 | 78 | static void 79 | signalHandler(int signalNumber) 80 | { 81 | switch (signalNumber) 82 | { 83 | case SIGUSR1: 84 | getInput(); 85 | break; 86 | case SIGINT: 87 | case SIGTERM: 88 | 89 | run = false; 90 | break; 91 | }; 92 | } 93 | 94 | void updateBattery(float batval, IMAGE_LAYER_T* batteryLayer) 95 | { 96 | IMAGE_T *image = &(batteryLayer->image); 97 | clearImageRGB(image,&clearColor); 98 | //to config params 99 | RGBA8_T *col = battery < BATTERY_TH ? &redColour : &greenColour; 100 | imageBoxFilledRGB(image, 2,3,2+(int)round((batteryLayer->image.width-7)*batval),batteryLayer->image.height-3, col); 101 | changeSourceAndUpdateImageLayer(batteryLayer); 102 | } 103 | 104 | int getImageIconFromVolume(int vol) { 105 | if (vol == 0) { 106 | return 1; 107 | } 108 | if (vol <= 25) { 109 | return 2; 110 | } 111 | if (vol <= 50) { 112 | return 3; 113 | } 114 | if (vol <= 75) { 115 | return 4; 116 | } 117 | if (vol <= 100) { 118 | return 5; 119 | } 120 | return 1; 121 | } 122 | 123 | void getInput() 124 | { 125 | char buffer[100]; 126 | char *bp = buffer; 127 | int c; 128 | while(run && '\n' != (c=fgetc(stdin)) && (bp-buffer) < sizeof(buffer)) 129 | *bp++=c; 130 | *bp = 0;//terminator 131 | #ifndef NDEBUG 132 | printf("buffer: %s\n", buffer); 133 | #endif 134 | char *saveptr; 135 | char *word; 136 | char *str = buffer; 137 | while((word = strtok_r(str," ",&saveptr))) 138 | { 139 | #ifndef NDEBUG 140 | printf("word: %s\n", word); 141 | #endif 142 | str = NULL; 143 | if(word[0] == 'b') 144 | { 145 | //Battery 146 | battery = atoi(word+1); 147 | } 148 | else if(word[0] == 's') 149 | { 150 | show = atoi(word+1) > 0; 151 | } 152 | else if(word[0] == 'w') 153 | { 154 | //wifi 155 | wifi= atoi(word+1); 156 | } 157 | else if(word[0] == 'p') 158 | { 159 | //backlight setting 160 | backlight= atoi(word+1); 161 | } 162 | else if(word[0] == 'a') 163 | { 164 | //audio 165 | audio= atoi(word+1); 166 | } 167 | else if(word[0] == 'j') 168 | { 169 | joystick= atoi(word+1); 170 | } 171 | else if(word[0] == 'u') 172 | { 173 | bluetooth= atoi(word+1); 174 | } 175 | else if(word[0] == 'l') 176 | { 177 | low_battery= atoi(word+1); 178 | } 179 | else if(word[0] == 't') 180 | { 181 | //temperature 182 | temp= atof(word+1); 183 | } 184 | else if(word[0] == 'v') 185 | { 186 | //voltage 187 | voltage= atoi(word+1); 188 | } 189 | else if(!strcmp(word, "on")) 190 | { 191 | infos = 1; 192 | } 193 | else if(!strcmp(word, "off")) 194 | { 195 | infos = 0; 196 | } 197 | else if(!strcmp(word, "allon")) 198 | { 199 | hud = 1; 200 | } 201 | else if(!strcmp(word, "alloff")) 202 | { 203 | hud = 1; 204 | } 205 | else if(!strcmp(word, "charge")) 206 | { 207 | charge = 1; 208 | } 209 | else if(!strcmp(word, "ncharge")) 210 | { 211 | charge = 0; 212 | } 213 | else if(!strcmp(word,"quit")) 214 | run = false; 215 | } 216 | #ifndef NDEBUG 217 | printf("out\n"); 218 | #endif 219 | } 220 | 221 | void clearLayer(IMAGE_LAYER_T *layer) 222 | { 223 | IMAGE_T *image = &(layer->image); 224 | clearImageRGB(image, &clearColor); 225 | changeSourceAndUpdateImageLayer(layer); 226 | } 227 | 228 | //------------------------------------------------------------------------- 229 | 230 | int main(int argc, char *argv[]) 231 | { 232 | uint32_t displayNumber = 0; 233 | 234 | //------------------------------------------------------------------- 235 | 236 | if(argc==1) { 237 | perror("No file path provided"); 238 | return 1; 239 | } 240 | 241 | chdir(argv[1]); 242 | 243 | bool no_joystick; 244 | 245 | if (strcmp( argv[2], "nojoystick") == 0) { 246 | no_joystick = true; 247 | } else 248 | { 249 | no_joystick = false; 250 | } 251 | 252 | int opt; 253 | 254 | while ((opt = getopt(argc, argv, "d:")) != -1) 255 | { 256 | switch (opt) 257 | { 258 | case 'd': 259 | 260 | displayNumber = atoi(optarg); 261 | break; 262 | 263 | default: 264 | 265 | fprintf(stderr, "Usage: %s [-d ]\n", basename(argv[0])); 266 | fprintf(stderr, " -d - Raspberry Pi display number\n"); 267 | exit(EXIT_FAILURE); 268 | break; 269 | } 270 | } 271 | 272 | if (signal(SIGINT, signalHandler) == SIG_ERR) 273 | { 274 | perror("installing SIGINT signal handler"); 275 | exit(EXIT_FAILURE); 276 | } 277 | 278 | //--------------------------------------------------------------------- 279 | 280 | if (signal(SIGTERM, signalHandler) == SIG_ERR) 281 | { 282 | perror("installing SIGTERM signal handler"); 283 | exit(EXIT_FAILURE); 284 | } 285 | 286 | //--------------------------------------------------------------------- 287 | 288 | if (signal(SIGUSR1, signalHandler) == SIG_ERR) 289 | { 290 | perror("installing SIGTERM signal handler"); 291 | exit(EXIT_FAILURE); 292 | } 293 | 294 | //------------------------------------------------------------------- 295 | 296 | VC_IMAGE_TYPE_T type = VC_IMAGE_RGBA32; 297 | 298 | //--------------------------------------------------------------------- 299 | 300 | bcm_host_init(); 301 | 302 | //--------------------------------------------------------------------- 303 | 304 | DISPMANX_DISPLAY_HANDLE_T display 305 | = vc_dispmanx_display_open(displayNumber); 306 | assert(display != 0); 307 | 308 | //--------------------------------------------------------------------- 309 | 310 | DISPMANX_MODEINFO_T info; 311 | int result = vc_dispmanx_display_get_info(display, &info); 312 | assert(result == 0); 313 | 314 | //--------------------------------------------------------------------- 315 | 316 | static int layer = 30000; 317 | 318 | IMAGE_LAYER_T infoTextLayer; 319 | initImageLayer(&infoTextLayer, 320 | 320, 321 | 240, 322 | type); 323 | createResourceImageLayer(&infoTextLayer, layer + 4); 324 | 325 | IMAGE_LAYER_T infoLayer; 326 | initImageLayer(&infoLayer, 327 | 320, 328 | 240, 329 | type); 330 | createResourceImageLayer(&infoLayer, layer); 331 | 332 | IMAGE_LAYER_T warningLayer; 333 | initImageLayer(&warningLayer, 334 | 320, 335 | 240, 336 | type); 337 | createResourceImageLayer(&warningLayer, layer); 338 | 339 | IMAGE_LAYER_T bimageLayer; 340 | if (loadPng(&(bimageLayer.image), BATTERY_IMAGE) == false) 341 | { 342 | fprintf(stderr, "unable to load %s\n", argv[optind]); 343 | } 344 | createResourceImageLayer(&bimageLayer, layer+2); 345 | 346 | IMAGE_LAYER_T batteryLayer; 347 | initImageLayer(&batteryLayer, 348 | bimageLayer.image.width, 349 | bimageLayer.image.height, 350 | VC_IMAGE_RGBA16); 351 | createResourceImageLayer(&batteryLayer, layer+1); 352 | 353 | IMAGE_LAYER_T cimageLayer; 354 | initImageLayer(&cimageLayer, 355 | bimageLayer.image.width, 356 | bimageLayer.image.height, 357 | type); 358 | createResourceImageLayer(&cimageLayer, layer+2); 359 | 360 | IMAGE_LAYER_T wimageLayer; 361 | initImageLayer(&wimageLayer, 362 | bimageLayer.image.height, 363 | bimageLayer.image.height, 364 | type); 365 | createResourceImageLayer(&wimageLayer, layer+2); 366 | 367 | IMAGE_LAYER_T aimageLayer; 368 | IMAGE_LAYER_T joystickImageLayer; 369 | IMAGE_LAYER_T bluetoothImageLayer; 370 | 371 | 372 | initImageLayer(&aimageLayer, 373 | 22, 374 | 13, 375 | type); 376 | createResourceImageLayer(&aimageLayer, layer+2); 377 | 378 | 379 | 380 | initImageLayer(&joystickImageLayer, 381 | 11, 382 | 11, 383 | type); 384 | createResourceImageLayer(&joystickImageLayer, layer+2); 385 | 386 | 387 | 388 | initImageLayer(&bluetoothImageLayer, 389 | 15, 390 | 13, 391 | type); 392 | createResourceImageLayer(&bluetoothImageLayer, layer+2); 393 | 394 | 395 | int xOffset = info.width-bimageLayer.image.width-1; 396 | int yOffset = 1; 397 | DISPMANX_UPDATE_HANDLE_T update = vc_dispmanx_update_start(0); 398 | assert(update != 0); 399 | 400 | addElementImageLayerOffset(&infoTextLayer, 401 | (info.width - infoTextLayer.image.width) / 2, 402 | (info.height - infoTextLayer.image.height) / 2, 403 | display, 404 | update); 405 | 406 | addElementImageLayerOffset(&infoLayer, 407 | (info.width - infoLayer.image.width) / 2, 408 | (info.height - infoLayer.image.height) / 2, 409 | display, 410 | update); 411 | 412 | addElementImageLayerOffset(&warningLayer, 413 | (info.width - warningLayer.image.width) / 2, 414 | (info.height - warningLayer.image.height) / 2, 415 | display, 416 | update); 417 | 418 | addElementImageLayerOffset(&wimageLayer, 419 | xOffset-wimageLayer.image.width-2, 420 | yOffset, 421 | display, 422 | update); 423 | 424 | addElementImageLayerOffset(&aimageLayer, 425 | (xOffset-wimageLayer.image.width)-aimageLayer.image.width-7, 426 | yOffset, 427 | display, 428 | update); 429 | 430 | 431 | 432 | addElementImageLayerOffset(&joystickImageLayer, 433 | (xOffset-wimageLayer.image.width)-aimageLayer.image.width - 22, 434 | yOffset + 1, 435 | display, 436 | update); 437 | 438 | addElementImageLayerOffset(&bluetoothImageLayer, 439 | (xOffset-wimageLayer.image.width)-aimageLayer.image.width - 38, 440 | yOffset , 441 | display, 442 | update); 443 | 444 | addElementImageLayerOffset(&batteryLayer, 445 | xOffset, 446 | yOffset, 447 | display, 448 | update); 449 | addElementImageLayerOffset(&bimageLayer, 450 | xOffset, 451 | yOffset, 452 | display, 453 | update); 454 | 455 | addElementImageLayerOffset(&cimageLayer, 456 | xOffset, 457 | yOffset, 458 | display, 459 | update); 460 | 461 | result = vc_dispmanx_update_submit_sync(update); 462 | assert(result == 0); 463 | 464 | while (run) 465 | { 466 | int sleepTime = 10000000; 467 | 468 | if(infos > 0) 469 | { 470 | sleepTime = 100000; 471 | 472 | if (no_joystick) { 473 | updateInfo(&infoLayer, INFO_NO_JOYSTICK); 474 | } else { 475 | updateInfo(&infoLayer, INFO_IMAGE); 476 | } 477 | updateInfoText(&infoTextLayer, no_joystick); 478 | 479 | } 480 | else if(infos <= 0) 481 | { 482 | clearLayer(&infoLayer); 483 | clearLayer(&infoTextLayer); 484 | infos_loaded = 0; 485 | } 486 | 487 | if (low_battery == 1) { 488 | updateWarning(&warningLayer, LOW_BATTERY_IMAGE); 489 | } else if (low_battery >= 2) { 490 | clearLayer(&warningLayer); 491 | warning_loaded = 0; 492 | } 493 | 494 | if (show) { 495 | 496 | float batval = battery/100.f; 497 | { 498 | if (loadPng(&(bimageLayer.image), BATTERY_IMAGE) == false) 499 | { 500 | fprintf(stderr, "unable to load %s\n", argv[optind]); 501 | } 502 | changeSourceAndUpdateImageLayer(&bimageLayer); 503 | updateBattery(batval, &batteryLayer); 504 | } 505 | if(charge > 0 && hud) 506 | { 507 | //TODO preload for efficiency 508 | if (loadPng(&(cimageLayer.image), CHARGE_IMAGE) == false) 509 | { 510 | fprintf(stderr, "unable to charge load %s\n", argv[optind]); 511 | } 512 | changeSourceAndUpdateImageLayer(&cimageLayer); 513 | charge = -1; 514 | } 515 | else if(!charge && hud) 516 | { 517 | clearLayer(&cimageLayer); 518 | charge = -1; 519 | } 520 | if(wifi > 0 && hud) 521 | { 522 | if (wifi_loaded == 0) { 523 | //TODO preload for efficienty 524 | if (loadPng(&(wimageLayer.image), WIFI_IMAGES[wifi-1]) == false) 525 | { 526 | fprintf(stderr, "unable to wifi load %s\n", argv[optind]); 527 | } 528 | changeSourceAndUpdateImageLayer(&wimageLayer); 529 | wifi_loaded = 1; 530 | } 531 | } 532 | else if (!wifi) 533 | { 534 | clearLayer(&wimageLayer); 535 | wifi_loaded = 0; 536 | } 537 | if(audio >= 0) 538 | { 539 | vol_image = getImageIconFromVolume(audio); 540 | //TODO preload for efficienty 541 | if (loadPng(&(aimageLayer.image), AUDIO_IMAGES[vol_image-1]) == false) 542 | { 543 | fprintf(stderr, "unable to audio load %s\n", argv[optind]); 544 | } 545 | changeSourceAndUpdateImageLayer(&aimageLayer); 546 | //audio = -1; 547 | } 548 | else if (!audio) 549 | { 550 | clearLayer(&aimageLayer); 551 | } 552 | if (!hud) { 553 | clearLayer(&batteryLayer); 554 | clearLayer(&wimageLayer); 555 | clearLayer(&aimageLayer); 556 | clearLayer(&bimageLayer); 557 | clearLayer(&cimageLayer); 558 | } 559 | if(joystick > 0) { 560 | if (loadPng(&(joystickImageLayer.image), JOYSTICK_IMAGE) == false) { 561 | fprintf(stderr, "unable to joystick load %s\n", argv[optind]); 562 | } 563 | changeSourceAndUpdateImageLayer(&joystickImageLayer); 564 | } 565 | else if(joystick <= 0) { 566 | clearLayer(&joystickImageLayer); 567 | } 568 | if(bluetooth > 0) { 569 | if (loadPng(&(bluetoothImageLayer.image), BLUETOOTH_IMAGE) == false) { 570 | fprintf(stderr, "unable to baluetooth load %s\n", argv[optind]); 571 | } 572 | changeSourceAndUpdateImageLayer(&bluetoothImageLayer); 573 | } 574 | else if(bluetooth <= 0) { 575 | clearLayer(&bluetoothImageLayer); 576 | } 577 | } else { 578 | clearLayer(&batteryLayer); 579 | clearLayer(&wimageLayer); 580 | clearLayer(&aimageLayer); 581 | clearLayer(&bimageLayer); 582 | clearLayer(&cimageLayer); 583 | clearLayer(&bluetoothImageLayer); 584 | } 585 | usleep(sleepTime); 586 | } 587 | //--------------------------------------------------------------------- 588 | 589 | destroyImageLayer(&infoLayer); 590 | destroyImageLayer(&batteryLayer); 591 | destroyImageLayer(&wimageLayer); 592 | 593 | destroyImageLayer(&infoTextLayer); 594 | destroyImageLayer(&aimageLayer); 595 | destroyImageLayer(&bimageLayer); 596 | destroyImageLayer(&cimageLayer); 597 | 598 | result = vc_dispmanx_display_close(display); 599 | assert(result == 0); 600 | 601 | //--------------------------------------------------------------------- 602 | 603 | return 0; 604 | } 605 | 606 | void updateInfo(IMAGE_LAYER_T *infoLayer, char imageType[]) 607 | { 608 | if (infos_loaded == 0) { 609 | //clearImageRGB(image, &backgroundColour); 610 | loadPng(&(infoLayer->image), imageType); 611 | changeSourceAndUpdateImageLayer(infoLayer); 612 | infos_loaded = 1; 613 | } 614 | } 615 | 616 | void updateWarning(IMAGE_LAYER_T *infoLayer, char imageType[]) 617 | { 618 | if (warning_loaded == 0) { 619 | //clearImageRGB(image, &backgroundColour); 620 | loadPng(&(infoLayer->image), imageType); 621 | changeSourceAndUpdateImageLayer(infoLayer); 622 | warning_loaded = 1; 623 | } 624 | } 625 | 626 | void updateInfoText(IMAGE_LAYER_T *infoLayer, bool no_joystick) 627 | { 628 | clearImageRGB(&(infoLayer->image), &clearColor); 629 | char volumeText[60]; 630 | char wifiText[20]; 631 | char joystickText[20]; 632 | char bluetoothText[20]; 633 | char backlightText[60]; 634 | snprintf(volumeText, sizeof(volumeText),"Volume: %d%%", audio); 635 | snprintf(backlightText, sizeof(backlightText),"Backlight: %d%%", backlight); 636 | 637 | if (wifi > 0) { 638 | snprintf(wifiText, sizeof(wifiText),"WiFi Enabled"); 639 | } else if (wifi <= 0) { 640 | snprintf(wifiText, sizeof(wifiText),"WiFi Disabled"); 641 | } 642 | 643 | 644 | if (joystick > 0) { 645 | snprintf(joystickText, sizeof(joystickText),"Joystick Enabled"); 646 | } else if (joystick <= 0) { 647 | snprintf(joystickText, sizeof(joystickText),"Joystick Disabled"); 648 | } 649 | 650 | if (bluetooth > 0) { 651 | snprintf(bluetoothText, sizeof(bluetoothText),"Bluetooth Enabled"); 652 | } else if (bluetooth <= 0) { 653 | snprintf(bluetoothText, sizeof(bluetoothText),"Bluetooth Disabled"); 654 | } 655 | 656 | if (no_joystick == false) { 657 | drawStringRGB(137, 29, volumeText, &textColour, &(infoLayer->image)); 658 | // drawStringRGB(137, 76, backlightText, &textColour, &(infoLayer->image)); 659 | drawStringRGB(137, 76, volumeText, &textColour, &(infoLayer->image)); 660 | 661 | drawStringRGB(137, 124, wifiText, &textColour, &(infoLayer->image)); 662 | drawStringRGB(137, 167, joystickText, &textColour, &(infoLayer->image)); 663 | drawStringRGB(137, 214, bluetoothText, &textColour, &(infoLayer->image)); 664 | } 665 | else if (no_joystick == true) { 666 | drawStringRGB(137, 74, volumeText, &textColour, &(infoLayer->image)); 667 | drawStringRGB(137, 122, volumeText, &textColour, &(infoLayer->image)); 668 | 669 | drawStringRGB(137, 170, wifiText, &textColour, &(infoLayer->image)); 670 | drawStringRGB(137, 214, bluetoothText, &textColour, &(infoLayer->image)); 671 | } 672 | 673 | changeSourceAndUpdateImageLayer(infoLayer); 674 | } 675 | --------------------------------------------------------------------------------