1. Sebastian Bub
  2. Raspberry Pi GPIO Web Control

Commits

Sebastian Bub  committed 49f77d1

bugfixing of real port handling

  • Participants
  • Parent commits 3787bb3
  • Branches default

Comments (0)

Files changed (4)

File README.md

View file
-# RASPBERRY PI GPIO CONTROL WEB INTERFACE
-
-## Watch out Revision d2454f058ab0 was broken
+# RASPBERRY PI GPIO WEB CONTROL INTERFACE
 
 ## A Java webapp to control your GPIO ports of the Raspberry Pi using http
 
 * You can define a blocking time for an output port (so it is not switched to
   fast in case the user makes a request twice).
 * You can define a toggle time for an output port (i.e. if you want to turn
-  a port on for a defined period of time, it can be done with a single request).
+  a port on for a defined period of time, it can be done with a single request). 
 * You can set a simulation mode for testing your client.
 * Setting multiple ports in one requests are set one after another, but the code
-  is optimized and nothing unnecessary is done in between (it takes about 2-5ms on an idle RaspBerry to set all 17 ports).
+  is optimized and nothing unnecessary is done in between (it takes about 2-5ms on an idle RaspBerry Pi to set all 17 ports, a simple 'find /' in the background will slow it down to 10-15ms).
 * Cronjobs (exact to the second) for output ports (http://quartz-scheduler.org/documentation/quartz-2.1.x/tutorials/crontrigger). Output ports can be set conditionally and you have a simple but powerful semaphore mechanism.
 
 ### Planned Features
 
-* sunset and sunrise aware cronjobs, e.g. for lights (see http://lexikon.astronomie.info/zeitgleichung/)
-* more status information via web
-
+* Sunset and sunrise aware cronjobs, e.g. for lights (see http://lexikon.astronomie.info/zeitgleichung/)
+* More status information via web about configuration and current gpio state.
 
 ### Possible Unplaned Features
 
-* bit sequences (especially with AUTO.TOGGLE.TIME) for serial output or to control a servo
-* some kind of PLC (Programmable Logic Controller)
+* Bit sequences (especially with AUTO.TOGGLE.TIME) for serial output or to control a servo
+* Some kind of PLC (Programmable Logic Controller)
+* Make your suggestions via email
 
 
 ## Project Status
 
 4. Install Mercurial `sudo apt-get install mercurial`
 
-5. Get the project `hg clone https://bitbucket.org/sbub/rpi-gpio-webapp` (or `hg update -r 7ac567df3513` to have a more stable release (newer versions have cronjobs and conditional output ports introduced. Testing and feedback is very welcome.))
+5. Get the project `hg clone https://bitbucket.org/sbub/rpi-gpio-webapp`
 
 6. **Get Winstone Servlet Engine**: http://winstone.sourceforge.net/ and put the jar in the same directory as the start.sh
 
-7. Build the project `mvn package` (It takes 3-7 minutes to build on RaspBerry)
+7. Build the project `mvn package` (It takes about 3-7 minutes to build on RaspBerry Pi)
 
 8. Check the location and name of WINSTONE_JAR in start.sh
 
 9. **Copy gpio.conf.MUST_BE_CHANGED** to gpio.conf and configure it
 
-10. Start the servlet container `sudo ./start.sh`. You may have to mark the script executable `chmod a+x start.sh` first. Furthermore a simple init.d script is also provided: src/main/resources/init.d/gpio-winstone
+10. Start the servlet container `sudo ./start.sh`. You may have to mark the script executable `chmod a+x start.sh stop.sh` first.
 
 11. Make a request, e.g. **http://raspberrypi:8080/handle?g0=1&g1=0**
 
     It will return {"g1":0,"g0":1} (and you may check the log).
+    
+12. Stop the servlet container `sudo ./stop.sh`. Make sure that there are no old Winstone processes with old configurations running! You can check that with `ps -ef| grep java`.
 
-12. To enable cronjobs, you need to copy cron.conf.MAY_BE_CHANGED to cron.conf and configure it
+13. To enable cronjobs, you need to copy cron.conf.MAY_BE_CHANGED to cron.conf and configure it
 
 
 ## Going Productive
 
-* Make sure you **disable simulate mode**
-* turn down logging after testing
+* Make sure you **disable simulate mode**.
+* Turn down logging after testing in log4j.properties.
+* A simple init.d script is also provided in src/main/resources/init.d/gpio-winstone which can be installed with the follwing commands:
+
+```
+chmod a+x /home/pi/rpi-gpio-webapp/src/main/resources/init.d/gpio-winstone
+sudo cp /home/pi/rpi-gpio-webapp/src/main/resources/init.d/gpio-winstone /etc/init.d/gpio-winstone
+sudo update-rc.d gpio-winstone defaults 3 3
+```
+
+    Do not forget that your GPIO ports may be operated by this process now!
 
 ## Configuration and Logging and Debugging
 

File cron.conf.MAY_BE_CHANGED

View file
 # 0 15 10 * * ? 2005    :: g0=1
 #
 #
-# Fire between 16:00 and 21:00: only set lamp1out if not already set and dark enough
+# Fire between 16:00 and 21:00 every minute, but only set lamp1out if not already set and dark enough
 # 0 * 16-21 ? * *         :: VIRTUALlamp1alreadyOn==0&darknessSensor1in==1&lamp1out=1&VIRTUALlamp1alreadyOn=1
 # Fire at 22:00 and turn off lamp1out
 # 0 0 22 ? * *            :: lamp1out=0&VIRTUALlamp1alreadyOn=0

File src/main/java/de/derbub/rpigpio/gpio/GpioOutAutoToggleThread.java

View file
 
     private static Logger log = Logger.getLogger(GpioOutAutoToggleThread.class);
     List<ConfiguredGpio> gpioList;
-    Long nowGPIOWritten;
+    Long sysfsProcessingTime;
 
-    public GpioOutAutoToggleThread(List<ConfiguredGpio> gpioList, Long nowGPIOWritten) {
+    public GpioOutAutoToggleThread(List<ConfiguredGpio> gpioList, Long sysfsProcessingTime) {
         this.gpioList = gpioList;
-        this.nowGPIOWritten = nowGPIOWritten;
+        this.sysfsProcessingTime = sysfsProcessingTime;
     }
 
     @Override
             currentDeltaSleepTime = tmpSleepTime - absSleepTime;
             absSleepTime = tmpSleepTime;
             try {
-                currentDeltaSleepTime -= (System.currentTimeMillis()-(nowGPIOWritten-25)); // add some time for processing
-                log.debug("run() sleep for " + currentDeltaSleepTime + " ms");
+                currentDeltaSleepTime -= sysfsProcessingTime; // remove some time for processing here
                 if(currentDeltaSleepTime > 0) {
+                    log.debug("run() sleep for " +currentDeltaSleepTime +" ms");
                     sleep(currentDeltaSleepTime);
+                } else {
+                    log.debug("run() not sleeping already late by " + currentDeltaSleepTime + " ms");
                 }
             } catch (InterruptedException e) {
                 log.error("run() interrupted (shutdown in progress?). Thread is stopped!");
                 break;
             }
-            nowGPIOWritten=System.currentTimeMillis();  // only a approximation
+            long before=System.currentTimeMillis();
             // after delta time, find notable
             Map<ConfiguredGpio, String> outGpioValueMap = new HashMap();
             for (ConfiguredGpio gpio : gpioList) {
             // remove notable from list and handle them
             gpioList.removeAll(outGpioValueMap.keySet());
             GpioSysFsInterface.getInitializedInstance().writeGpios(outGpioValueMap, true);
+            sysfsProcessingTime = System.currentTimeMillis()-before;
         }
         log.debug("run() finished");
     }

File src/main/java/de/derbub/rpigpio/gpio/GpioSysFsInterface.java

View file
         ConfiguredGpio[] perfileConfiguredGpioArray = new ConfiguredGpio[perfFileWriterArray.length];
         int perfIndex = 0;
         Long nowForBlocking = System.currentTimeMillis();
-        Long nowForGPIOWrite = nowForBlocking; // will be changed later
         
         // for each gpio prepare (if blocked and add to perfArrays)
         for (ConfiguredGpio gpio : outGpioValueMap.keySet()) {
                 }
             }
         }
-		perfIndex--;
 
-        FileWriter aGpioFileWriter;
+        int i = 0; // i may be needed in catch block
         try {
             long before = System.currentTimeMillis();
-            for (int i = 0; i < perfIndex; i++) {
-                aGpioFileWriter = perfFileWriterArray[perfIndex];
-                aGpioFileWriter.write(perfValueArray[perfIndex]);
-                aGpioFileWriter.flush();
+            for (i = 0; i < perfIndex; i++) {
+                FileWriter aGpioFileWriter = perfFileWriterArray[i];
+                if(null != aGpioFileWriter){
+                aGpioFileWriter.write(perfValueArray[i]);
+                aGpioFileWriter.flush();                    
+                } else {
+                    log.debug("File handle for file " + aGpioFile + " is null, ignoring.");
+                }
             }
-            nowForGPIOWrite = System.currentTimeMillis();
-            log.info("Writing of gpio ports took " + (nowForGPIOWrite-before) + "ms at " + nowForGPIOWrite);
+            long after = System.currentTimeMillis();
+            log.info("Writing of gpio ports took " + (after-before) + "ms at " + after  + (SIMULATE_GPIOS?" (in simulation)":""));
       } catch (Exception e) {
             // if we get here, forget about timing: log and overwrite
             log.error("Got " + e.getClass().getName() + " with message: " + e.getMessage() + " with file " + aGpioFile);
-            returnMap.put(perfileConfiguredGpioArray[perfIndex].getUserdefinedName(), Integer.toString(ConfiguredGpio.NO_STATE));
+            returnMap.put(perfileConfiguredGpioArray[i].getUserdefinedName(), Integer.toString(ConfiguredGpio.NO_STATE));
         } finally {
-            for (int i = 0; i < perfIndex; i++) {
-                aGpioFileWriter = perfFileWriterArray[perfIndex];
+            for (i = 0; i < perfIndex; i++) {
+                FileWriter aGpioFileWriter = perfFileWriterArray[i];
                 try {
                     if (null != aGpioFileWriter) {
                         aGpioFileWriter.close();
                     }
                 } catch (Exception e) {
-                    // catch away
+                    log.error("Got a " + e.getClass().getName() + " with message: " + e.getMessage() + " with file " + aGpioFile
+                            + " while closing. You may ignore this error, but the cause of upcoming errors may be here.");
                 } finally {
                     aGpioFileWriter = null;
                 }
         }
         // if we have something to toggle back to default state later, do it
         if (!isAutoTogglingThread && !autoToggleList.isEmpty()) {
-            GpioOutAutoToggleThread atThread = new GpioOutAutoToggleThread(autoToggleList, nowForGPIOWrite);
+            GpioOutAutoToggleThread atThread = new GpioOutAutoToggleThread(autoToggleList, (System.currentTimeMillis()-nowForBlocking));
             atThread.start();
         }
         return returnMap;