From 166248463d504decfc04ab1eed2788c8f0bf9825 Mon Sep 17 00:00:00 2001 From: HoldYourWaffle Date: Tue, 14 Aug 2018 23:12:20 +0200 Subject: [PATCH] Delete everything except the Blinkt! controller Also gradle and the license as a separate file --- .gitignore | 22 + Jimbo/Boards/com/fourtronix/ZeroPoint.java | 203 ------ Jimbo/Boards/com/pimoroni/Blinkt.java | 124 ---- Jimbo/Boards/com/pimoroni/MicroDotPHAT.java | 218 ------ Jimbo/Boards/com/pimoroni/Piglow.java | 343 --------- Jimbo/Boards/com/pimoroni/RainbowHAT.java | 560 --------------- Jimbo/Boards/com/pimoroni/ScrollPHATHD.java | 161 ----- Jimbo/Boards/com/pimoroni/ScrollPhat.java | 201 ------ Jimbo/Boards/com/pimoroni/UnicornHAT.java | 137 ---- Jimbo/Boards/com/pimoroni/UnicornHATHD.java | 145 ---- Jimbo/Boards/com/pimoroni/UnicornPhat.java | 134 ---- Jimbo/Boards/com/thepihut/ZeroSeg.java | 304 -------- Jimbo/Boards/me/kano/LightShow.java | 180 ----- .../uk/co/pocketmoneytronics/RGBTree.java | 108 --- Jimbo/Devices/APA102.java | 231 ------ Jimbo/Devices/BMP280.java | 511 ------------- Jimbo/Devices/HT16K33.java | 214 ------ Jimbo/Devices/IS31FL3730.java | 389 ---------- Jimbo/Devices/IS31FL3731.java | 273 ------- Jimbo/Devices/MAX7219.java | 481 ------------- Jimbo/Devices/Pi2C.java | 153 ---- Jimbo/Devices/SN3218.java | 133 ---- Jimbo/Devices/WS2811/Makefile | 19 - Jimbo/Devices/WS2811/WS2811.C | 158 ---- Jimbo/Devices/WS2811/WS2811.java | 241 ------- Jimbo/Devices/WS2811/WS2811Raw.java | 81 --- Jimbo/Graphics/BitMatrix.java | 53 -- Jimbo/Graphics/BitMatrixDemo.java | 54 -- Jimbo/Graphics/Colour.java | 124 ---- Jimbo/Graphics/ColourMatrix.java | 80 --- Jimbo/Graphics/ColourMatrixDemo.java | 122 ---- Jimbo/Graphics/FlipX.java | 93 --- Jimbo/Graphics/FlipY.java | 92 --- Jimbo/Graphics/Identity.java | 91 --- Jimbo/Graphics/Mapping.java | 148 ---- Jimbo/Graphics/Matrix.java | 61 -- Jimbo/Graphics/MonoMatrix.java | 82 --- Jimbo/Graphics/MonoMatrixDemo.java | 89 --- Jimbo/Graphics/Point.java | 94 --- Jimbo/Graphics/Snake.java | 96 --- Jimbo/Graphics/SwapXY.java | 100 --- Jimbo/Logging/Logging.java | 124 ---- LICENSE | 674 ++++++++++++++++++ README.md | 3 - build.gradle | 27 + gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 54413 bytes gradle/wrapper/gradle-wrapper.properties | 5 + gradlew | 172 +++++ gradlew.bat | 84 +++ .../jimbo/pijava/blinkt/BlinktController.java | 204 ++++++ 50 files changed, 1188 insertions(+), 7208 deletions(-) create mode 100644 .gitignore delete mode 100644 Jimbo/Boards/com/fourtronix/ZeroPoint.java delete mode 100644 Jimbo/Boards/com/pimoroni/Blinkt.java delete mode 100644 Jimbo/Boards/com/pimoroni/MicroDotPHAT.java delete mode 100644 Jimbo/Boards/com/pimoroni/Piglow.java delete mode 100644 Jimbo/Boards/com/pimoroni/RainbowHAT.java delete mode 100644 Jimbo/Boards/com/pimoroni/ScrollPHATHD.java delete mode 100644 Jimbo/Boards/com/pimoroni/ScrollPhat.java delete mode 100644 Jimbo/Boards/com/pimoroni/UnicornHAT.java delete mode 100644 Jimbo/Boards/com/pimoroni/UnicornHATHD.java delete mode 100644 Jimbo/Boards/com/pimoroni/UnicornPhat.java delete mode 100644 Jimbo/Boards/com/thepihut/ZeroSeg.java delete mode 100644 Jimbo/Boards/me/kano/LightShow.java delete mode 100644 Jimbo/Boards/uk/co/pocketmoneytronics/RGBTree.java delete mode 100644 Jimbo/Devices/APA102.java delete mode 100644 Jimbo/Devices/BMP280.java delete mode 100644 Jimbo/Devices/HT16K33.java delete mode 100644 Jimbo/Devices/IS31FL3730.java delete mode 100644 Jimbo/Devices/IS31FL3731.java delete mode 100644 Jimbo/Devices/MAX7219.java delete mode 100644 Jimbo/Devices/Pi2C.java delete mode 100644 Jimbo/Devices/SN3218.java delete mode 100644 Jimbo/Devices/WS2811/Makefile delete mode 100644 Jimbo/Devices/WS2811/WS2811.C delete mode 100644 Jimbo/Devices/WS2811/WS2811.java delete mode 100644 Jimbo/Devices/WS2811/WS2811Raw.java delete mode 100644 Jimbo/Graphics/BitMatrix.java delete mode 100644 Jimbo/Graphics/BitMatrixDemo.java delete mode 100644 Jimbo/Graphics/Colour.java delete mode 100644 Jimbo/Graphics/ColourMatrix.java delete mode 100644 Jimbo/Graphics/ColourMatrixDemo.java delete mode 100644 Jimbo/Graphics/FlipX.java delete mode 100644 Jimbo/Graphics/FlipY.java delete mode 100644 Jimbo/Graphics/Identity.java delete mode 100644 Jimbo/Graphics/Mapping.java delete mode 100644 Jimbo/Graphics/Matrix.java delete mode 100644 Jimbo/Graphics/MonoMatrix.java delete mode 100644 Jimbo/Graphics/MonoMatrixDemo.java delete mode 100644 Jimbo/Graphics/Point.java delete mode 100644 Jimbo/Graphics/Snake.java delete mode 100644 Jimbo/Graphics/SwapXY.java delete mode 100644 Jimbo/Logging/Logging.java create mode 100644 LICENSE delete mode 100644 README.md create mode 100644 build.gradle create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100644 gradlew create mode 100644 gradlew.bat create mode 100644 src/main/java/jimbo/pijava/blinkt/BlinktController.java diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2fbbeff --- /dev/null +++ b/.gitignore @@ -0,0 +1,22 @@ +# eclipse +bin +*.launch +.settings +.metadata +.classpath +.project + +# idea +out +*.ipr +*.iws +*.iml +.idea + +# gradle +.gradle +build/ + +# general +*.log +desktop.ini diff --git a/Jimbo/Boards/com/fourtronix/ZeroPoint.java b/Jimbo/Boards/com/fourtronix/ZeroPoint.java deleted file mode 100644 index 608abed..0000000 --- a/Jimbo/Boards/com/fourtronix/ZeroPoint.java +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Copyright (C) 2016 Jim Darby. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see - * . - */ - -package Jimbo.Boards.com.fourtronix; - -import com.pi4j.io.gpio.GpioController; -import com.pi4j.io.gpio.GpioFactory; -import com.pi4j.io.gpio.GpioPinDigitalOutput; -import com.pi4j.io.gpio.RaspiPin; - -import com.pi4j.component.servo.Servo; -import com.pi4j.component.servo.ServoDriver; -import com.pi4j.component.ComponentBase; - -/** - * This class controls the 4tronix ZeroPoint. - * - * @author Jim Darby. - */ - -public class ZeroPoint extends ComponentBase implements Servo -{ - /** - * Construct a ZeroPoint object. There can be only one (TM) and we have - * no way of checking one is actually wired up. - */ - public ZeroPoint () - { - moveto (0); - } - - /** - * Move to a specific step. This uses the original version of the values - * with the range 0 to 600. - * - * @param pos The position to move to. - */ - public void moveto (int pos) - { - // Already there? - if (pos == location) - return; - - final boolean up = pos > location; - final int steps = up ? (pos - location) : (location - pos); - - for (int i = 0; i < steps; ++i) - { - if (up) - { - phase += 1; - - if (phase >= SEQUENCE.length) - phase = 0; - } - else - { - phase -= 1; - - if (phase < 0) - phase = SEQUENCE.length - 1; - } - - for (int j = 0; j < pins.length; ++j) - pins[j].setState (SEQUENCE[phase][j]); - - try - { - // Lots of debate over the rate. 500 steps per second seems to - // work all the time. - - Thread.sleep (2); - } - - // That didn't got according to play.... But ignore it. - catch (InterruptedException ex) - { - } - } - - location = pos; - } - - /** - * Set the position using the Servo interface. It's not a servo but - * seems to wat to act like one. - * - * @param pos The position: -100 to +100. - */ - @Override - public void setPosition (float pos) - { - moveto ((int) ((pos + 100) / 200 * (MAX - MIN) + MIN)); - } - - /** - * Return the current position in the range -100 to +100. - * - * @return The position. - */ - @Override - public float getPosition () - { - return (float) (((double) (location - MIN) / (MAX - MIN) - 0.5) * 200); - } - - /** - * Return the servo driver used. As we don't use on this returns null. - * This may cause problems later. - * - * @return The servo driver (null). - */ - @Override - public ServoDriver getServoDriver () - { - return null; - } - - /** - * Implement the off option for the servo. This makes it all passive. - */ - @Override - public void off () - { - for (int i = 0; i < pins.length; ++i) - pins[i].setState (false); - } - - /** - * The SEQUENCE from Gareth. This doesn't appear to be the standard one. - * There may be some odd wiring going on here. Or I just don't understand! - */ - static private final boolean[][] SEQUENCE = - { - { true, false, false, true}, - { true, false, true, false}, - {false, true, true, false}, - {false, true, false, true} - }; - - /** The GPIO controller we're going to use. */ - private final GpioController gpio = GpioFactory.getInstance(); - - /** Our list of pins used. */ - private final GpioPinDigitalOutput pins[] = - { - gpio.provisionDigitalOutputPin (RaspiPin.GPIO_07, "A"), - gpio.provisionDigitalOutputPin (RaspiPin.GPIO_00, "B"), - gpio.provisionDigitalOutputPin (RaspiPin.GPIO_01, "C"), - gpio.provisionDigitalOutputPin (RaspiPin.GPIO_02, "D") - }; - - /** Our current location. Start at 650 then we move to zero. */ - private int location = 650; - /** Our current phase in the steps. */ - private int phase = 0; - - /** The minimum step value used. */ - public static final int MIN = 0; - /** The maximum step value used. */ - public static final int MAX = 600; - - public static void main (String args[]) throws InterruptedException - { - ZeroPoint zp = new ZeroPoint (); - - System.out.println ("At " + zp.location + " aka " + zp.getPosition ()); - zp.moveto (MAX); - System.out.println ("At " + zp.location + " aka " + zp.getPosition ()); - - zp.moveto (MAX / 2); - System.out.println ("At " + zp.location + " aka " + zp.getPosition ()); - Thread.sleep (500); - - zp.setPosition (-50); - System.out.println ("At " + zp.location + " aka " + zp.getPosition ()); - Thread.sleep (1000); - - zp.setPosition (50); - System.out.println ("At " + zp.location + " aka " + zp.getPosition ()); - Thread.sleep (1000); - - zp.setPosition (0); - System.out.println ("At " + zp.location + " aka " + zp.getPosition ()); - Thread.sleep (1000); - } - } - \ No newline at end of file diff --git a/Jimbo/Boards/com/pimoroni/Blinkt.java b/Jimbo/Boards/com/pimoroni/Blinkt.java deleted file mode 100644 index 5944f12..0000000 --- a/Jimbo/Boards/com/pimoroni/Blinkt.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (C) 2016-2017 Jim Darby. - * - * This software is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this software; if not, If not, see - * . - */ - -package Jimbo.Boards.com.pimoroni; - -import com.pi4j.io.gpio.GpioFactory; -import com.pi4j.io.gpio.RaspiPin; - -import Jimbo.Devices.APA102; - -import Jimbo.Graphics.Point; -import Jimbo.Graphics.Colour; -import Jimbo.Graphics.ColourMatrix; -import Jimbo.Graphics.ColourMatrixDemo; -import java.io.IOException; - -/** - * This class drives a Pimoroni Blinkt LED string. - * - * @author Jim Darby - */ -public class Blinkt implements ColourMatrix -{ - public Blinkt () - { - a = new APA102 (GpioFactory.getInstance(), RaspiPin.GPIO_04, RaspiPin.GPIO_05, 8); - } - - /** - * Set a pixel the generic way. - * - * @param p The pixel to set. - * @param value The colour to set it to. - */ - @Override - public void setPixel(Point p, Colour value) - { - if (p.getY () != 0) - throw new IllegalArgumentException ("Invalid Y coordinate"); - - set (p.getX (), value.getRed (), value.getGreen (), value.getBlue (), 31); - } - - /** - * Set a LED to a specific red, green and blue value. We also set the - * brightness. - * - * @param n The LED number, in the range 0 to the number of LEDs minus one. - * @param r The red value (0 to 255). - * @param g The green value (0 to 255). - * @param b The blue value (0 to 255). - * @param bright The brightness (0 to 31). - */ - public void set (int n, int r, int g, int b, int bright) - { - a.set (n, r, g, b, bright); - } - - /** - * Update the LED chain. - */ - @Override - public final void show () - { - a.show (); - } - - /** - * Return a point with the maximum values for X and Y in this - * matrix. - * - * @return The maximum size. - */ - @Override - public Point getMax () - { - return MAX; - } - - /** - * Run a simple test demo on the board. - * - * @param args The command line arguments. They're ignored. - * - * @throws InterruptedException If Thread.sleep gets interrupted. - * @throws java.io.IOException In case of trouble. - */ - public static void main (String args[]) throws InterruptedException, IOException - { - final Blinkt b = new Blinkt (); - - ColourMatrixDemo.run (b); - } - - /** The width of the board. */ - public static final int WIDTH = 8; - /** The height of the board. */ - public static final int HEIGHT = 1; - /** The maximum X value. */ - public static final int MAX_X = WIDTH - 1; - /** The maximum Y value. */ - public static final int MAX_Y = HEIGHT - 1; - - /** The maximum values as a Point. */ - private final static Point MAX = new Point (MAX_X, MAX_Y); - - /** Internal pointer to the hat. */ - private final APA102 a; -} diff --git a/Jimbo/Boards/com/pimoroni/MicroDotPHAT.java b/Jimbo/Boards/com/pimoroni/MicroDotPHAT.java deleted file mode 100644 index adee2b0..0000000 --- a/Jimbo/Boards/com/pimoroni/MicroDotPHAT.java +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright (C) 2016 Jim Darby. - * - * This software is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this software; if not, If not, see - * . - */ - -package Jimbo.Boards.com.pimoroni; - -import com.pi4j.io.i2c.I2CBus; - -import Jimbo.Devices.Pi2C; -import Jimbo.Devices.IS31FL3730; -import java.io.IOException; - -/** - * This class interfaces to the Pimoroni Micro Dot pHAT. It consists of three - * IS31FL3730 controller chips wired to six displays in a delightfully unusual - * manner. I blame the grog! - * - * @author Jim Darby - */ -public class MicroDotPHAT -{ - /** - * Constructor - builds an object to handle the device. Only one may be used - * at once. - * - * @throws IOException In case of error - * @throws InterruptedException In case of error - */ - public MicroDotPHAT () throws IOException, InterruptedException - { - final I2CBus bus = Pi2C.useBus (); - - for (int i = 0; i < driver.length; ++i) - { - driver[i] = new IS31FL3730 (bus, ADDRS[i]); - driver[i].setMode (IS31FL3730.MODE_M12 | IS31FL3730.MODE_8X8); - driver[i].setLightingEffect (IS31FL3730.LER_35MA); - driver[i].setPWM (128); - - for (int j = 0; j < 8; ++j) - { - m1[i][j] = 0; - m2[i][j] = 0; - } - - driver[i].fastUpdateM1 (m1[i]); - driver[i].fastUpdateM2 (m2[i]); - driver[i].update (); - } - } - - /** - * Set a single bit on the display. The origin is at the bottom left, as it - * should be. - * - * @param x The x coordinate, range 0 to 29. - * @param y The y coordinate, range 0 to 6. - * @param on Make the pixel light up? - * @throws IOException In case of issues. - */ - public void set (int x, int y, boolean on) throws IOException - { - // Validate parameters - if ( x< 0 || x >= WIDTH || y < 0 || y >= HEIGHT) - throw new IOException ("Invalid coordidinates"); - - // Now figure out the display and the coordinates on it. - final int index = x / 10; - final boolean left = (x % 10) < 5; - final int offset = x % 5; - final int y_flip = HEIGHT - 1 - y; - - // Now map it into the device - if (left) - { - if (on) - m2[index][offset] |= (byte) (1 << y_flip); - else - m2[index][offset] &= (byte) ~(1 << y_flip); - } - else - { - if (on) - m1[index][y_flip] |= (byte) (1 << offset); - else - m1[index][y_flip] &= (byte) ~(1 << offset); - } - } - - /** - * Set a decimal point on the display. - * - * @param n Which one. 0 is leftmost, 5 is rightmost. - * @param on Turn it on or off? True for on, false for off. - * @throws IOException In case of error. - */ - public void setPoint (int n, boolean on) throws IOException - { - if (n < 0 || n > 5) - throw new IOException ("Invalid decimal point"); - - // Now figure out the display and the coordinates on it. - final int index = n / 2; - final boolean left = (n % 2) == 0; - - // Now map it into the device - if (left) - { - if (on) - m2[index][7] |= (byte) (0x40); - else - m2[index][7] &= (byte) ~(0x40); - } - else - { - if (on) - m1[index][6] |= (byte) 0x80; - else - m1[index][6] &= (byte) ~(0x80); - } - } - - /** - * Update the physical device. - * @throws IOException In case of problems. - */ - public void update () throws IOException - { - for (int i = 0; i < driver.length; ++i) - { - driver[i].fastUpdateM1 (m1[i]); - driver[i].fastUpdateM2 (m2[i]); - driver[i].update (); - } - } - - /** - * Set the PWM of the board. - * @param pwm Bright nice in range 0 to 128 (yes, 129 levels). - * @throws IOException In case of trouble. - */ - public void setPWM (int pwm) throws IOException - { - // Rather naughtily we let the lower level routines do the range checking. - for (int i = 0; i < driver.length; ++i) - driver[i].setPWM (pwm); - } - - /** - * Basic test routine. - * @param args Command line arguments, ignored. - * @throws IOException In case of error. - * @throws InterruptedException In case of error. - */ - public static void main (String[] args) throws IOException, InterruptedException - { - final MicroDotPHAT m = new MicroDotPHAT (); - boolean setting = true; - int pwm = 128; - - while (true) - { - for (int i = 0; i < 6; ++i) - { - m.setPoint (i, setting); - m.update (); - Thread.sleep (200); - } - - for (int y = 0; y < HEIGHT; ++y) - for (int x = 0; x < WIDTH; ++x) - { - m.setPWM (pwm); - - pwm -= 1; - - if (pwm < 0) - pwm = 128; - - m.set (x, y, setting); - m.update (); - - Thread.sleep (5); - } - - setting = !setting; - } - } - - /** The width of the device. */ - public static final int WIDTH = 30; - /** The height of the device. */ - public static final int HEIGHT = 7; - - /** The addresses, left to right, of the chips */ - private static final int[] ADDRS = { 0x63, 0x62, 0x61 }; - /** Our drivers for each chip. */ - private final IS31FL3730 driver[] = new IS31FL3730[ADDRS.length]; - - /** Local cache of M1 data. */ - private final byte[][] m1 = new byte[driver.length][8]; - /** Local cache of M2 data. */ - private final byte[][] m2 = new byte[driver.length][8]; -} diff --git a/Jimbo/Boards/com/pimoroni/Piglow.java b/Jimbo/Boards/com/pimoroni/Piglow.java deleted file mode 100644 index 6755719..0000000 --- a/Jimbo/Boards/com/pimoroni/Piglow.java +++ /dev/null @@ -1,343 +0,0 @@ -/* - * Copyright (C) 2016 Jim Darby. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - */ - -package Jimbo.Boards.com.pimoroni; - -import java.io.IOException; - -import Jimbo.Devices.SN3218; -import Jimbo.Devices.Pi2C; - -/** - * This class allows control of the Piglow from Pimoroni. - * - * The device has three legs each of six LEDs. The LEDs are coloured (from - * inside to outside) white, blue, green, yellow, orange and red. - * - * @author Jim Darby. - */ -public class Piglow -{ - /** - * Construct a Piglow controller. - * - * @throws IOException In case of difficulty. - * @throws InterruptedException In case of difficulty. - */ - public Piglow () throws IOException, InterruptedException - { - pg = new SN3218 (Pi2C.useBus ()); - } - - /** - * Set a specific LED to a specific value. The mapping from LED number to - * which one it is is a little curious so it's often better to use the more - * nuanced routines. - * - * @param led The LED to set. - * @param value The value to set it to. - * @throws IOException In case of error. - */ - public void set (int led, int value) throws IOException - { - pg.set (led, value); - } - - /** - * Set all the red LEDs to a specific value. - * - * @param value The value to set. - * @throws IOException In case of error. - */ - public void setReds (int value) throws IOException - { - set (REDS, value); - } - - /** - * Set all the orange LEDs to a specific value. - * - * @param value The value to set. - * @throws IOException In case of error. - */ - public void setOranges (int value) throws IOException - { - set (ORANGES, value); - } - - /** - * Set all the yellow LEDs to a specific value. - * - * @param value The value to set. - * @throws IOException In case of error. - */ - public void setYellows (int value) throws IOException - { - set (YELLOWS, value); - } - - /** - * Set all the green LEDs to a specific value. - * - * @param value The value to set. - * @throws IOException In case of error. - */ - public void setGreens (int value) throws IOException - { - set (GREENS, value); - } - - /** - * Set all the blue LEDs to a specific value. - * - * @param value The value to set. - * @throws IOException In case of error. - */ - public void setBlues (int value) throws IOException - { - set (BLUES, value); - } - - /** - * Set all the white LEDs to a specific value. - * - * @param value The value to set. - * @throws IOException In case of error. - */ - public void setWhites (int value) throws IOException - { - set (WHITES, value); - } - - /** - * Set all the LEDs on leg 0 to a specific value. - * - * @param value The value to set. - * @throws IOException In case of error. - */ - public void setLeg0 (int value) throws IOException - { - set (LEG0, value); - } - - /** - * Set all the LEDs on leg 1 to a specific value. - * - * @param value The value to set. - * @throws IOException In case of error. - */ - public void setLeg1 (int value) throws IOException - { - set (LEG1, value); - } - - /** - * Set all the LEDs on leg 2 to a specific value. - * - * @param value The value to set. - * @throws IOException In case of error. - */ - public void setLeg2 (int value) throws IOException - { - set (LEG2, value); - } - - /** - * Set all the LEDs on a given leg to a specific value. - * - * @param leg The leg to set. - * @param value The value to set. - * @throws IOException In case of error. - */ - public void setLeg (int leg, int value) throws IOException - { - if (leg < 0 || leg >= LEGS.length) - throw new IOException ("Invalid leg given"); - - set (LEGS[leg], value); - } - - /** - * Set a leg to a series of values. - * - * @param leg The leg to use. - * @param values The values to use. - * @throws IOException In case of trouble. - */ - public void setLeg (int leg, int values[]) throws IOException - { - if (leg < 0 || leg >= LEGS.length) - throw new IOException ("Invalid leg given"); - - if (LEGS[leg].length != values.length) - throw new IOException ("Invalid leg data given"); - - for (int i = 0; i < values.length; ++i) - set (LEGS[leg][i], values[i]); - } - - /** - * Set all the legs. This should be an array of type int[3][6]. - * - * @param values The array of information. It should be of type int[3][6]. - * @throws IOException In case of trouble. - */ - public void setLegs (int values[][]) throws IOException - { - for (int i = 0; i < values.length; ++i) - setLeg (i, values[i]); - } - - /** - * Set a number of LEDs to a specific value. - * - * @param leds The LEDs to set. - * @param value The value to set. - * @throws IOException In case of error. - */ - public void set (byte[] leds, int value) throws IOException - { - for (int i = 0; i < leds.length; ++i) - set (leds[i], value); - } - - /** - * Update the Piglow from the set data. - * - * @throws IOException in case of error. - */ - public void update () throws IOException - { - pg.update (); - } - - /** The device we're working with. */ - private final SN3218 pg; - - /** All the red LEDs. */ - private static final byte[] REDS = { 6, 17, 0 }; - /** All the orange LEDs. */ - private static final byte[] ORANGES = { 7, 16, 1 }; - /** All the yellow LEDs. */ - private static final byte[] YELLOWS = { 8, 15, 2 }; - /** All the green LEDs. */ - private static final byte[] GREENS = { 5, 13, 3 }; - /** All the blue LEDs. */ - private static final byte[] BLUES = { 4, 11, 14 }; - /** All the white LEDs. */ - private static final byte[] WHITES = { 9, 10, 12 }; - - /** All the LEDs on leg 0. */ - private static final byte[] LEG0 = { 9, 4, 5, 8, 7, 6 }; - /** All the LEDs on leg 1. */ - private static final byte[] LEG1 = { 10, 11, 13, 15, 16, 17 }; - /** All the LEDs on leg 2. */ - private static final byte[] LEG2 = { 12, 14, 3, 2, 1, 0 }; - /** All the legs. */ - private static final byte[][] LEGS = { LEG0, LEG1, LEG2 }; - /**All the rings. */ - private static final byte[][] RINGS = { WHITES, BLUES, GREENS, YELLOWS, ORANGES, REDS }; - - - public static void main (String args[]) throws IOException, InterruptedException - { - Piglow pg = new Piglow (); - - for (int i = 0; i < 18; ++i) - { - System.out.println (i); - pg.set (i, 40); - pg.update (); - Thread.sleep (100); - pg.set (i, 0); - pg.update (); - Thread.sleep (100); - } - - pg.setReds (255); - pg.update (); - Thread.sleep (100); - pg.setReds (0); - - pg.setOranges (255); - pg.update (); - Thread.sleep (100); - pg.setOranges (0); - - pg.setYellows (255); - pg.update (); - Thread.sleep (100); - pg.setYellows (0); - - pg.setGreens (255); - pg.update (); - Thread.sleep (100); - pg.setGreens (0); - - pg.setBlues (255); - pg.update (); - Thread.sleep (100); - pg.setBlues (0); - - pg.setWhites (255); - pg.update (); - Thread.sleep (100); - pg.setWhites (0); - - pg.setLeg0 (255); - pg.update (); - Thread.sleep (100); - pg.setLeg0 (0); - - pg.setLeg1 (255); - pg.update (); - Thread.sleep (100); - pg.setLeg1 (0); - - pg.setLeg2 (255); - pg.update (); - Thread.sleep (100); - pg.setLeg2 (0); - pg.update (); - - while (true) - { - for (int step = 0; step < 256; ++step) - { - final double offset = (Math.PI * step) / 255; - - pg.setReds (toLed (Math.sin (Math.PI * 0 / 6 + offset))); - pg.setOranges (toLed (Math.sin (Math.PI * 1 / 6 + offset))); - pg.setYellows (toLed (Math.sin (Math.PI * 2 / 6 + offset))); - pg.setGreens (toLed (Math.sin (Math.PI * 3 / 6 + offset))); - pg.setBlues (toLed (Math.sin (Math.PI * 4 / 6 + offset))); - pg.setWhites (toLed (Math.sin (Math.PI * 5 / 6 + offset))); - pg.update (); - Thread.sleep (4); - } - } - } - - private static int toLed (double value) - { - if (value < 0) - value = -value; - - return (int) (255 * value); - } -} diff --git a/Jimbo/Boards/com/pimoroni/RainbowHAT.java b/Jimbo/Boards/com/pimoroni/RainbowHAT.java deleted file mode 100644 index a5226ea..0000000 --- a/Jimbo/Boards/com/pimoroni/RainbowHAT.java +++ /dev/null @@ -1,560 +0,0 @@ -/* - * Copyright (C) 2017 Jim Darby. - * - * This software is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this software; if not, If not, see - * . - */ - -package Jimbo.Boards.com.pimoroni; - -import com.pi4j.io.i2c.I2CBus; -import com.pi4j.io.gpio.RaspiPin; -import com.pi4j.io.gpio.GpioFactory; -import com.pi4j.io.gpio.GpioController; -import com.pi4j.io.gpio.Pin; -import com.pi4j.io.gpio.GpioPinDigitalInput; -import com.pi4j.io.gpio.GpioPinDigitalOutput; -import com.pi4j.io.gpio.PinPullResistance; - -import Jimbo.Devices.Pi2C; -import Jimbo.Devices.HT16K33; -import Jimbo.Devices.BMP280; -import Jimbo.Devices.APA102; -import Jimbo.Graphics.Colour; -import Jimbo.Graphics.ColourMatrix; -import Jimbo.Graphics.ColourMatrixDemo; -import Jimbo.Graphics.FlipX; -import Jimbo.Graphics.Mapping; -import Jimbo.Graphics.Point; - -import java.io.IOException; -import java.time.LocalTime; - -/** - * Driver class for the Rainbow HAT. - * - * @author Jim Darby - */ -public class RainbowHAT -{ - public static void main (String args[]) throws IOException, InterruptedException - { - boolean rainbow = true; - - for (int i = 0; i < args.length; ++i) - { - if (args[i].equals ("--norainbow")) - rainbow = false; - else - System.out.println ("Option " + args[i] + " ignored."); - } - - final RainbowHAT r = new RainbowHAT (); - - r.show ("Hola"); - r.setPoint (3, true); - r.update (); - - Thread.sleep (1000); - - final GpioPinDigitalOutput red = r.getRed (); - final GpioPinDigitalOutput green = r.getGreen (); - final GpioPinDigitalOutput blue = r.getBlue (); - final GpioPinDigitalInput a = r.getA (); - final GpioPinDigitalInput b = r.getB (); - final GpioPinDigitalInput c = r.getC (); - - boolean a_down = false; - boolean b_down = false; - boolean c_down = false; - - int state = 1; - - red. setState (true); - green.setState (false); - blue. setState (false); - - if (rainbow) - new Thread (new ColourMatrixDemo (r.getLEDs ())).start (); - - while (true) - { - final int old_state = state; - - if (a.isLow ()) - { - if (!a_down) - { - System.out.println ("A down"); - a_down = true; - state = 1; - } - } - else - { - if (a_down) - { - System.out.println ("A up"); - a_down = false; - } - } - - if (b.isLow ()) - { - if (!b_down) - { - System.out.println ("B down"); - b_down = true; - state = 2; - } - } - else - { - if (b_down) - { - System.out.println ("B up"); - b_down = false; - } - } - - if (c.isLow ()) - { - if (!c_down) - { - System.out.println ("C down"); - c_down = true; - state = 3; - } - } - else - { - if (c_down) - { - System.out.println ("C up"); - c_down = false; - } - } - - if (state != old_state) - { - System.out.println ("State is now " + state); - - red. setState (state == 1); - green.setState (state == 2); - blue. setState (state == 3); - } - - r.setPoint (0, false); - r.setPoint (1, false); - r.setPoint (2, false); - r.setPoint (3, false); - - switch (state) - { - case 1: - { - final LocalTime now = LocalTime.now (); - - r.setDigit (0, now.getHour () / 10); - r.setDigit (1, now.getHour () % 10); - r.setDigit (2, now.getMinute () / 10); - r.setDigit (3, now.getMinute () % 10); - - r.setPoint (1, now.getNano () > 500000000); - } - - break; - - case 2: - - { - final double temp = r.getBMP280 ().read ().getTemperature (); - - if (temp < -99 || temp >= 1000) - { - r.show ("Err"); - } - else - { - r.show (String.format ("%4d", (int) (temp * 10))); - r.setPoint (2, true); - } - } - - break; - - case 3: - - { - final double pressure = r.getBMP280 ().read ().getPressure () / 100; - - if (pressure < 0 || pressure >= 10000) - { - r.show ("Err"); - } - else - { - r.show (String.format ("%4d", (int) pressure)); - } - } - - break; - - default: - System.out.println ("In a strange state: " + state); - state = 1; - break; - } - - r.update (); - - Thread.sleep (20); - } - } - - /** - * Construct a RainbowHAT controller object. - * - * @throws IOException In case of error. - * @throws InterruptedException In case of error. - */ - public RainbowHAT () throws IOException, InterruptedException - { - final I2CBus bus = Pi2C.useBus (); - - display = new HT16K33 (bus, 0x70); - bmp280 = new BMP280 (bus, 0x77); - gpio = GpioFactory.getInstance (); - } - - /** - * Display a string on the 4-character display. - * - * @param s The string to display. - * @throws IOException In case of error. - */ - public void show (String s) throws IOException - { - for (int i = 0; i < Math.min(s.length (), 4); ++i) - { - final char ch = s.charAt (i); - - if (ch >= 0 && ch < CHARS.length) - display.setWord (i, CHARS[ch]); - else - display.setWord (i, (short) 0); - } - - for (int i = s.length (); i < 4; ++i) - display.setWord (i, (short) 0); - } - - /** - * Set the decimal point on the display. - * - * @param pos The decimal point: 0 to 3. - * @param on true for on, otherwise false. - * @throws IOException In case of error. - */ - public void setPoint (int pos, boolean on) throws IOException - { - if (pos < 0 || pos > 3) - throw new IllegalArgumentException ("RainbowHAT invalid point position"); - - // Some magic here.... - display.setBit (pos * 16 + 14, on); - } - - /** - * Set a specific character on the display to a specific numerical value. - * - * @param pos The position: 0 to 3. - * @param value The value: 0 to 9. - * @throws IOException In case of error. - */ - public void setDigit (int pos, int value) throws IOException - { - if (pos < 0 || pos > 3) - throw new IllegalArgumentException ("RainbowHAT invalid point position"); - - if (value < 0 || value > 9) - throw new IllegalArgumentException ("RainbowHAT invalid numeric value"); - - display.setWord (pos, CHARS['0' + value]); - } - - /** - * Return a digital output for the red LED (above the A button). - * - * @return The output. - */ - public GpioPinDigitalOutput getRed () - { - if (red == null) - red = provisionOut (RaspiPin.GPIO_22, "Red LED"); - - return red; - } - - /** - * Return a digital output for the green LED (above the B button). - * - * @return The output. - */ - public GpioPinDigitalOutput getGreen () - { - if (green == null) - green = provisionOut (RaspiPin.GPIO_24, "Green LED"); - - return green; - } - - /** - * Return a digital output for the blue LED (above the C button). - * - * @return The output. - */ - public GpioPinDigitalOutput getBlue () - { - if (blue == null) - blue = provisionOut (RaspiPin.GPIO_25, "Blue LED"); - - return blue; - } - - /** - * Return a GpioPinDigitalInput for the B button. - * - * @return The input. - */ - public GpioPinDigitalInput getA () - { - if (a == null) - a = provisionIn (RaspiPin.GPIO_29, "A"); - - return a; - } - - /** - * Return a GpioPinDigitalInput for the B button. - * - * @return The input. - */ - public GpioPinDigitalInput getB () - { - if (b == null) - b = provisionIn (RaspiPin.GPIO_28, "B"); - - return b; - } - - /** - * Return a GpioPinDigitalInput for the C button. - * - * @return The input. - */ - public GpioPinDigitalInput getC () - { - if (c == null) - c = provisionIn (RaspiPin.GPIO_27, "C"); - - return c; - } - - /** - * Return the BMP280 device. - * - * @return The BMP280 device. - */ - public BMP280 getBMP280 () - { - return bmp280; - } - - /** - * Return the APA102 LEDs. - * - * @return The LEDs - */ - public LEDs getLEDs () - { - if (leds == null) - leds = new LEDs (gpio); - - return leds; - } - - /** - * Update the 4-character display. - * - * @throws IOException In case of error. - */ - public void update () throws IOException - { - display.update (); - } - - public static class LEDs implements ColourMatrix - { - /** - * Construct the LEDs. We need a GPIO controller and the other - * parameters are defined by the board. - * - * @param gpio The GPIO Controller. - */ - private LEDs (GpioController gpio) - { - cs = gpio.provisionDigitalOutputPin (RaspiPin.GPIO_10, "LED Chip Select"); - cs.low (); - apa102 = new APA102 (gpio, RaspiPin.GPIO_12, RaspiPin.GPIO_14, 7); - cs.high (); - - map = new FlipX (WIDTH, HEIGHT); - } - - /** - * Return the maximum X and Y coordinates. - * - * @return The values. - */ - @Override - public Point getMax () - { - return MAX; - } - - /** - * Set a specific pixel to a specific value. The height is 1 and the - * width is 7 meaning the X coordinate goes from 0 to 6 and the Y has - * to be 0. - * - * @param p The point to change. - * @param value The value to change it to. - */ - @Override - public void setPixel (Point p, Colour value) - { - apa102.setPixel (map.map (p), value); - } - - /** - * Update the LEDs. - * - * @throws IOException In case of error. - */ - @Override - public void show () throws IOException - { - cs.low (); - apa102.show (); - cs.high (); - } - - /** - * Scale the brightness to avoid blindness. - * - * @param brightness The brightness scale factor: 0 to 31. - */ - public void brightness (int brightness) - { - apa102.brightness(brightness); - } - - /** The width of the board. */ - public final int WIDTH = 7; - /** The height of the board. */ - public static final int HEIGHT = 1; - /** The maximum X value. */ - public final int MAX_X = WIDTH - 1; - /** The maximum Y value. */ - public static final int MAX_Y = HEIGHT - 1; - /** The maximum values as a Point. */ - private final Point MAX = new Point (MAX_X, MAX_Y); - - /** Point to the underlying APA102 driver. */ - private final APA102 apa102; - /** Select pin. */ - private final GpioPinDigitalOutput cs; - /** Point mapping. */ - private final Mapping map; - } - - /** - * Provision an input pin. This will set the pin as an input and also set - * pull up on it. - * - * @param p The pin the create. - * @param name The name of the pin. - * @return The allocate pin object. - */ - private GpioPinDigitalInput provisionIn (Pin p, String name) - { - return gpio.provisionDigitalInputPin (p, name, PinPullResistance.PULL_UP); - } - - /** - * Provision an input pin. This will set the pin as an output. - * - * @param p The pin the create. - * @param name The name of the pin. - * @return The allocate pin object. - */ - private GpioPinDigitalOutput provisionOut (Pin p, String name) - { - return gpio.provisionDigitalOutputPin (p, name); - } - - /** The object that handles the 4-character display. */ - private final HT16K33 display; - /** The object that handles the temperature/pressure sensor. */ - private final BMP280 bmp280; - /** The GPIO Controller we're using. */ - private final GpioController gpio; - - /** The red LED. */ - private GpioPinDigitalOutput red = null; - /** The green LED. */ - private GpioPinDigitalOutput green = null; - /** The blue LED. */ - private GpioPinDigitalOutput blue = null; - /** The A button input. */ - private GpioPinDigitalInput a = null; - /** The B button input. */ - private GpioPinDigitalInput b = null; - /** The C button input. */ - private GpioPinDigitalInput c = null; - /** The LED handler object. */ - private LEDs leds = null; - - /** Characters we can put on the 4-character display. Keep it clean! */ - private static final short[] CHARS = - { - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0006, 0x0220, 0x12ce, 0x12ed, 0x0c24, 0x235d, 0x0400, - 0x2400, 0x0900, 0x3fc0, 0x12c0, 0x0800, 0x00c0, 0x0000, 0x0c00, - 0x0c3f, 0x0006, 0x00db, 0x008f, 0x00e6, 0x2069, 0x00fd, 0x0007, - 0x00ff, 0x00ef, 0x1200, 0x0a00, 0x2400, 0x00c8, 0x0900, 0x1083, - 0x02bb, 0x00f7, 0x128f, 0x0039, 0x120f, 0x00f9, 0x0071, 0x00bd, - 0x00f6, 0x1200, 0x001e, 0x2470, 0x0038, 0x0536, 0x2136, 0x003f, - 0x00f3, 0x203f, 0x20f3, 0x00ed, 0x1201, 0x003e, 0x0c30, 0x2836, - 0x2d00, 0x1500, 0x0c09, 0x0039, 0x2100, 0x000f, 0x0c03, 0x0008, - 0x0100, 0x1058, 0x2078, 0x00d8, 0x088e, 0x0858, 0x0071, 0x048e, - 0x1070, 0x1000, 0x000e, 0x3600, 0x0030, 0x10d4, 0x1050, 0x00dc, - 0x0170, 0x0486, 0x0050, 0x2088, 0x0078, 0x001c, 0x2004, 0x2814, - 0x28c0, 0x200c, 0x0848, 0x0949, 0x1200, 0x2489, 0x0520, 0x0000 - }; -} diff --git a/Jimbo/Boards/com/pimoroni/ScrollPHATHD.java b/Jimbo/Boards/com/pimoroni/ScrollPHATHD.java deleted file mode 100644 index 7551b77..0000000 --- a/Jimbo/Boards/com/pimoroni/ScrollPHATHD.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright (C) 2017 Jim Darby. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see - * . - */ - -package Jimbo.Boards.com.pimoroni; - -import java.io.IOException; - -import com.pi4j.io.i2c.I2CBus; -import com.pi4j.io.i2c.I2CFactory; - -import Jimbo.Devices.IS31FL3731; - -import Jimbo.Graphics.Point; -import Jimbo.Graphics.MonoMatrix; -import Jimbo.Graphics.MonoMatrixDemo; - -/** - * This class controls a Pimoroni ScrollpHAT HD. - * - * @author Jim Darby - */ -public class ScrollPHATHD implements MonoMatrix -{ - /** - * Create a ScrollPHATHD object. - * - * @throws IOException In case of issues. - * @throws I2CFactory.UnsupportedBusNumberException In case it can't find - * the correct I2C bus. - * @throws java.lang.InterruptedException In case of issues. - */ - public ScrollPHATHD () throws IOException, I2CFactory.UnsupportedBusNumberException, InterruptedException - { - phat = new IS31FL3731 (I2CFactory.getInstance (I2CBus.BUS_1), 0x74); - } - - /** - * Update the displayed data. Call this after setting up what you want - * displayed and it will transfer it to the device and hence actually - * display it. - * - * @throws IOException In case of problems. - */ - @Override - public void show () throws IOException - { - phat.update (); - } - - /** - * Set a specific pixel on or off. This works in the most efficient - * way. - * - * @param x The x coordinate. - * @param y The y coordinate. - * @param pwm The PWM value. - */ - @Override - public void setPixel (int x, int y, int pwm) - { - if (x < 0 || x > MAX_X || y < 0 || y > MAX_Y) - throw new IllegalArgumentException ("Invalid co-ordinates for set"); - - if (flip_x) - x = MAX_X - x; - - if (flip_y) - y = MAX_Y - y; - - // Piratical wiring madness! - - if (x >= 8) - { - x = (x - 8) * 2; - y = MAX_Y - y; - } - else - { - x = 15 - x * 2; - } - - phat.setLed (0, x * 8 + y, pwm); - } - - /** - * Set a pixel in the generic way. - * - * @param p The pixel. - * @param value The value. - */ - @Override - public void setPixel (Point p, Integer value) - { - setPixel (p.getX (), p.getY (), value); - } - - /** - * Optionally flip the x, y or both arguments. Useful for rotating - * and other general diddling of the display, - * - * @param x Flip the x coordinates? - * @param y Flip the y coordinates? - */ - public void flip (boolean x, boolean y) - { - flip_x = x; - flip_y = y; - } - - /** - * Get the maximum values for X and Y. - * - * @return A Point containing the maximum values. - */ - @Override - public Point getMax () - { - return MAX; - } - - public static void main (String args[]) throws IOException, I2CFactory.UnsupportedBusNumberException, InterruptedException - { - ScrollPHATHD p = new ScrollPHATHD (); - - MonoMatrixDemo.run (p); - } - - /** Device width. */ - public final static int WIDTH = 17; - /** Device height. */ - public final static int HEIGHT = 7; - /** The maximum X value. */ - public final static int MAX_X = WIDTH - 1; - /** The maximum Y value. */ - public final static int MAX_Y = HEIGHT - 1; - - /** The maximum values as a Point. */ - private final static Point MAX = new Point (MAX_X, MAX_Y); - - /** The device itself. */ - private final IS31FL3731 phat; - /** Flag to flip the x coordinate. */ - private boolean flip_x = false; - /** Flag to flip the y coordinate. */ - private boolean flip_y = false; -} diff --git a/Jimbo/Boards/com/pimoroni/ScrollPhat.java b/Jimbo/Boards/com/pimoroni/ScrollPhat.java deleted file mode 100644 index 1d3dbd2..0000000 --- a/Jimbo/Boards/com/pimoroni/ScrollPhat.java +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright (C) 2016-2017 Jim Darby. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see - * . - */ - -package Jimbo.Boards.com.pimoroni; - -import java.io.IOException; - -import com.pi4j.io.i2c.I2CBus; -import com.pi4j.io.i2c.I2CFactory; - -import Jimbo.Graphics.Point; -import Jimbo.Graphics.BitMatrix; -import Jimbo.Graphics.BitMatrixDemo; - -import Jimbo.Devices.IS31FL3730; - -/** - * This class controls a Pimoroni ScrollpHAT. - * - * @author Jim Darby - */ -public class ScrollPhat implements BitMatrix -{ - /** - * Create a ScroolPhat object. - * - * @throws IOException In case of issues. - * @throws I2CFactory.UnsupportedBusNumberException In case it can't find - * bus. - */ - public ScrollPhat () throws IOException, I2CFactory.UnsupportedBusNumberException - { - phat = new IS31FL3730 (I2CFactory.getInstance (I2CBus.BUS_1)); - - // Set five by 11. - phat.setMode (IS31FL3730.MODE_5X11 | IS31FL3730.MODE_M1); - - // Use 40mA drive - phat.setLightingEffect (IS31FL3730.LER_40MA); - - // It's a Pimoroni device, default LEDs to quarter power to avoid - // user blindness. - phat.setPWM (IS31FL3730.MAX_PWM / 4); - - // Clear it - for (int i = 0; i < data.length; ++i) - data[i] = 0; - - show (); - } - - /** - * Update the displayed data. Call this after setting up what you want - * displayed and it will transfer it to the device and hence actually - * display it. - * - * @throws IOException In case of problems. - */ - @Override - public final void show () throws IOException - { - phat.fastUpdateM1 (data); - } - - /** - * Set a specific pixel on or off. - * - * @param x The x coordinate. - * @param y The y coordinate. - * @param on True for on, otherwise false. - */ - @Override - public void setPixel (int x, int y, boolean on) - { - if (x < 0 || x > MAX_X || y < 0 || y > MAX_Y) - throw new IllegalArgumentException ("Invalid co-ordinates for set"); - - if (flip_x) - x = MAX_X - x; - - // We flip around Y because the board is wired "upside down". - if (!flip_y) - y = MAX_Y - y; - - if (on) - data[x] |= (1 << y); - else - data[x] &= ~(1 << y); - } - - - /** - * Set a pixel in the generic way. - * - * @param p The pixel. - * @param value The value. - */ - @Override - public void setPixel(Point p, Boolean value) - { - setPixel (p, value.booleanValue ()); - } - - /** - * Optionally flip the x, y or both arguments. Useful for rotating - * and other general diddling of the display, - * - * @param x Flip the x coordinates? - * @param y Flip the y coordinates? - */ - public void flip (boolean x, boolean y) - { - flip_x = x; - flip_y = y; - } - - /** - * Set the number of tries before logging a warning. Note this will - * never log if there isn't a retry. - * - * @param n The number of tries, must be non-negative. - * - * @throws IOException On a bad paramters. - */ - public void setTriesWarning (int n) throws IOException - { - phat.setTriesWarning (n); - } - - /** - * Return a point with the maximum values for X and Y in this - * matrix. - * - * @return The maximum size. - */ - @Override - public Point getMax () - { - return MAX; - } - - /** The device width. */ - public static final int WIDTH = 11; - /** The device height. */ - public static final int HEIGHT = 5; - - /** - * The maximum x value. X coordinates must be in the range 0 to this - * INCLUSIVE. - */ - private static final int MAX_X = WIDTH - 1; - /** - * The maximum y value. Y coordinates must be in the range 0 to this - * INCLUSIVE. - */ - private static final int MAX_Y = HEIGHT - 1; - - /** The maximum values as a Point. */ - private final static Point MAX = new Point (MAX_X, MAX_Y); - - /** Internal pointer to the low-level device. */ - private final IS31FL3730 phat; - /** Data we hold for the display. */ - private final byte data[] = new byte[12]; - /** Do we flip the x coordinate? */ - private boolean flip_x = false; - /** Do we flip the y coordinate? */ - private boolean flip_y = false; - - /** - * Test routine. - * - * @param args the command line arguments - * @throws java.io.IOException In case of problem. - * @throws java.lang.InterruptedException In case of problem. - * @throws com.pi4j.io.i2c.I2CFactory.UnsupportedBusNumberException In case of problem. - */ - public static void main(String[] args) throws IOException, InterruptedException, I2CFactory.UnsupportedBusNumberException - { - ScrollPhat s = new ScrollPhat (); - - s.setTriesWarning (0); - - BitMatrixDemo.run (s); - } -} diff --git a/Jimbo/Boards/com/pimoroni/UnicornHAT.java b/Jimbo/Boards/com/pimoroni/UnicornHAT.java deleted file mode 100644 index 70ac389..0000000 --- a/Jimbo/Boards/com/pimoroni/UnicornHAT.java +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (C) 2017 Jim Darby. - * - * This software is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this software; if not, If not, see - * . - */ - -package Jimbo.Boards.com.pimoroni; - -import Jimbo.Devices.WS2811.WS2811; -import Jimbo.Devices.WS2811.WS2811Raw; - -import Jimbo.Graphics.Snake; -import Jimbo.Graphics.FlipY; -import Jimbo.Graphics.SwapXY; -import Jimbo.Graphics.Point; -import Jimbo.Graphics.Colour; -import Jimbo.Graphics.ColourMatrix; -import Jimbo.Graphics.ColourMatrixDemo; -import java.io.IOException; - -/** - * This class controls the Pimoroni Unicorn HAT. - * - * @author Jim Darby - */ - -public class UnicornHAT implements ColourMatrix -{ - /** - * Construct a new UnicornHAT object. We can have only one though this - * isn't checked. The brightness is defaulted to 25% (because Pimoroni). - */ - public UnicornHAT () - { - h = new WS2811 (WIDTH, HEIGHT, new Snake (new SwapXY (new FlipY (WIDTH, HEIGHT))), WS2811Raw.WS2811_STRIP_GRB, 0.25); - } - - /** - * Construct a new UnicornHAT object. We can have only one though this - * isn't checked. - * - * @param brightness The value of brightness to use: 0.0 to 1.0. - */ - public UnicornHAT (double brightness) - { - h = new WS2811 (WIDTH, HEIGHT, new Snake (WIDTH, HEIGHT), WS2811Raw.WS2811_STRIP_GRB, brightness); - } - - /** - * Sets a pixel to a specific colour. - * - * @param p The address of the Pixel. - * @param r The red value: 0 to 255. - * @param g The green value: 0 to 255. - * @param b The blue value: 0 to 255. - */ - @Override - public void setPixel (Point p, int r, int g, int b) - { - h.setPixel (p, r, g, b); - } - - /** - * Set a specific pixel to a specific Colour value. - * - * @param p The point to set. - * @param c The colour to set it to. - */ - @Override - public void setPixel (Point p, Colour c) - { - h.setPixel (p, c); - } - - /** - * Update the display. - */ - @Override - public void show () - { - h.show (); - } - - /** - * Return a point with the maximum values for X and Y in this - * matrix. - * - * @return The maximum size. - */ - @Override - public Point getMax () - { - return MAX; - } - - /** - * Run a simple test demo on the board. - * - * @param args The command line arguments. They're ignored. - * - * @throws InterruptedException If Thread.sleep gets interrupted. - * @throws java.io.IOException In case of trouble. - */ - public static void main (String args[]) throws InterruptedException, IOException - { - final UnicornHAT u = new UnicornHAT (); - - ColourMatrixDemo.run (u); - } - - /** The width of the board. */ - public static final int WIDTH = 8; - /** The height of the board. */ - public static final int HEIGHT = 8; - /** The maximum X value. */ - public static final int MAX_X = WIDTH - 1; - /** The maximum Y value. */ - public static final int MAX_Y = HEIGHT - 1; - - /** The maximum values as a Point. */ - private final static Point MAX = new Point (MAX_X, MAX_Y); - - /** Internal pointer to the hat. */ - private final WS2811 h; -} diff --git a/Jimbo/Boards/com/pimoroni/UnicornHATHD.java b/Jimbo/Boards/com/pimoroni/UnicornHATHD.java deleted file mode 100644 index 6dfcfbe..0000000 --- a/Jimbo/Boards/com/pimoroni/UnicornHATHD.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright (C) 2017 Jim Darby. - * - * This software is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this software; if not, If not, see - * . - */ - -package Jimbo.Boards.com.pimoroni; - -import java.util.Arrays; -import java.io.IOException; - -import Jimbo.Graphics.Point; -import Jimbo.Graphics.Colour; -import Jimbo.Graphics.ColourMatrix; -import Jimbo.Graphics.ColourMatrixDemo; - -import com.pi4j.io.spi.SpiChannel; -import com.pi4j.io.spi.SpiDevice; -import com.pi4j.io.spi.SpiFactory; - -/** - * This class controls the Pimoroni Unicorn HAT HD. - * - * @author Jim Darby - */ -public class UnicornHATHD implements ColourMatrix -{ - /** - * Construct a UnicornHATHD object. - * - * @throws IOException In case of error. - */ - public UnicornHATHD () throws IOException - { - dev = SpiFactory.getInstance (SpiChannel.CS0, 9000000, SpiDevice.DEFAULT_SPI_MODE); - Arrays.fill (data, (byte) 0); - data[0] = 0x72; - show (); - } - - /** - * Sets a pixel to a specific colour. This is implemented in the fastest - * possible way. - * - * @param x The X coordinate (0 to 15). - * @param y The Y coordinate (0 to 15). - * @param r The red value: 0 to 255. - * @param g The green value: 0 to 255. - * @param b The blue value: 0 to 255. - */ - @Override - public void setPixel (int x, int y, int r, int g, int b) - { - if (x < 0 || x > MAX_X || y < 0 || y > MAX_Y) - throw new IllegalArgumentException ("Invalid coordinates for setPixel"); - - if (r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255) - throw new IllegalArgumentException ("Invalid colour for setPixel"); - - final int base = (x + WIDTH * (MAX_Y - y)) * 3 + 1; - - data[base ] = (byte) r; - data[base + 1] = (byte) g; - data[base + 2] = (byte) b; - } - - /** - * Set a specific pixel to a specific Colour value. This is the generic - * interface. - * - * @param p The point to set. - * @param value The colour to set it to. - */ - @Override - public void setPixel(Point p, Colour value) - { - setPixel (p.getX (), p.getY (), - value.getRed (), value.getGreen (), value.getBlue ()); - } - - /** - * Update the display. - */ - @Override - public final void show () throws IOException - { - dev.write (data, 0, data.length); - } - - /** - * Return a point with the maximum values for X and Y in this - * matrix. - * - * @return The maximum size. - */ - @Override - public Point getMax () - { - return MAX; - } - - /** - * Run a simple test demo on the board. - * - * @param args The command line arguments. They're ignored. - * - * @throws InterruptedException If Thread.sleep gets interrupted. - * @throws java.io.IOException In case of trouble. - */ - public static void main (String args[]) throws InterruptedException, IOException - { - final UnicornHATHD u = new UnicornHATHD (); - - ColourMatrixDemo.run (u); - } - - /** The width of the board. */ - public static final int WIDTH = 16; - /** The height of the board. */ - public static final int HEIGHT = 16; - /** The maximum X value. */ - public static final int MAX_X = WIDTH - 1; - /** The maximum Y value. */ - public static final int MAX_Y = HEIGHT - 1; - - /** The maximum values as a Point. */ - private final static Point MAX = new Point (MAX_X, MAX_Y); - - /** Data for the hat. */ - private final byte data[] = new byte [WIDTH * HEIGHT * 3 + 1]; - /** The SPI device we're going to use. */ - private final SpiDevice dev; -} diff --git a/Jimbo/Boards/com/pimoroni/UnicornPhat.java b/Jimbo/Boards/com/pimoroni/UnicornPhat.java deleted file mode 100644 index 1419118..0000000 --- a/Jimbo/Boards/com/pimoroni/UnicornPhat.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Copyright (C) 2017 Jim Darby. - * - * This software is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this software; if not, If not, see - * . - */ - -package Jimbo.Boards.com.pimoroni; - -import Jimbo.Devices.WS2811.WS2811; -import Jimbo.Devices.WS2811.WS2811Raw; - -import Jimbo.Graphics.FlipY; -import Jimbo.Graphics.Point; -import Jimbo.Graphics.Colour; -import Jimbo.Graphics.ColourMatrix; -import Jimbo.Graphics.ColourMatrixDemo; -import java.io.IOException; - -/** - * This class controls the Pimoroni Unicorn pHAT. - * - * @author Jim Darby - */ -public class UnicornPhat implements ColourMatrix -{ - /** - * Construct a new UnicornPhat object. We can have only one though this - * isn't checked. The brightness is defaulted to 25% (because Pimoroni). - */ - public UnicornPhat () - { - h = new WS2811 (WIDTH, HEIGHT, new FlipY (WIDTH, HEIGHT), WS2811Raw.WS2811_STRIP_GRB, 0.25); - } - - /** - * Construct a new UnicornPhat object. We can have only one though this - * isn't checked. - * - * @param brightness The value of brightness to use: 0.0 to 1.0. - */ - public UnicornPhat (double brightness) - { - h = new WS2811 (WIDTH, HEIGHT, new FlipY (WIDTH, HEIGHT), WS2811Raw.WS2811_STRIP_GRB, brightness); - } - - /** - * Sets a pixel to a specific colour. - * - * @param p The address of the Pixel. - * @param r The red value: 0 to 255. - * @param g The green value: 0 to 255. - * @param b The blue value: 0 to 255. - */ - @Override - public void setPixel (Point p, int r, int g, int b) - { - h.setPixel (p, r, g, b); - } - - /** - * Set a specific pixel to a specific Colour value. - * - * @param p The point to set. - * @param c The colour to set it to. - */ - @Override - public void setPixel (Point p, Colour c) - { - h.setPixel (p, c); - } - - /** - * Update the display. - */ - @Override - public void show () - { - h.show (); - } - - /** - * Return a point with the maximum values for X and Y in this - * matrix. - * - * @return The maximum size. - */ - @Override - public Point getMax () - { - return MAX; - } - - /** - * Run a simple test demo on the board. - * - * @param args The command line arguments. They're ignored. - * - * @throws InterruptedException If Thread.sleep gets interrupted. - * @throws java.io.IOException In case of trouble. - */ - public static void main (String args[]) throws InterruptedException, IOException - { - final UnicornPhat u = new UnicornPhat (); - - ColourMatrixDemo.run (u); - } - - /** The width of the board. */ - public static final int WIDTH = 8; - /** The height of the board. */ - public static final int HEIGHT = 4; - /** The maximum X value. */ - public static final int MAX_X = WIDTH - 1; - /** The maximum Y value. */ - public static final int MAX_Y = HEIGHT - 1; - - /** The maximum values as a Point. */ - private final static Point MAX = new Point (MAX_X, MAX_Y); - - /** Internal pointer to the hat. */ - private final WS2811 h; -} diff --git a/Jimbo/Boards/com/thepihut/ZeroSeg.java b/Jimbo/Boards/com/thepihut/ZeroSeg.java deleted file mode 100644 index 626de14..0000000 --- a/Jimbo/Boards/com/thepihut/ZeroSeg.java +++ /dev/null @@ -1,304 +0,0 @@ -/* - * Copyright (C) 2016 Jim Darby. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see - * . - */ -package Jimbo.Boards.com.thepihut; - -import com.pi4j.io.spi.SpiChannel; -import com.pi4j.io.gpio.RaspiPin; -import com.pi4j.io.gpio.GpioFactory; -import com.pi4j.io.gpio.GpioController; -import com.pi4j.io.gpio.GpioPinDigitalInput; - -import Jimbo.Devices.MAX7219; -import java.io.IOException; - -import java.time.LocalTime; -import java.time.LocalDate; - - -/** - * Driver class for The Pi Hut's ZeroSeg (designed by Average Man vs - * Pi). - * - * @author Jim Darby - */ -public class ZeroSeg -{ - public ZeroSeg () throws IllegalArgumentException, IOException - { - dev = new MAX7219 (SpiChannel.CS0, 1); - - // Set up and blank display - - shutdown (false); - displayTest (false); - setDecodeMode (MAX7219.DECODE_NONE); - setIntensity (8); - setScanLimit (7); - update (); - - final GpioController gpio = GpioFactory.getInstance (); - - left = gpio.provisionDigitalInputPin (RaspiPin.GPIO_00, "Left"); - right = gpio.provisionDigitalInputPin (RaspiPin.GPIO_25, "Right"); - } - - /** - * Put a single value into the byte for a specific digit. In this - * case we renumber them 0 on the left to 7 on the right. - * - * @param digit The digit to update. 0 to 7. - * @param value The byte value put in. - * - * @throws IOException In case of error. - */ - public void writeDigit (int digit, int value) throws IOException - { - final byte[] map = {7, 6, 5, 4, 3, 2, 1, 0}; - - if (digit < 0 || digit >= map.length) - throw new IllegalArgumentException ("Invalid digit"); - - if (value < 0 || value > 0xff) - throw new IllegalArgumentException ("Invalid value"); - - dev.writeDigit (map[digit], (byte) value); - } - - /** - * Sets the decode mode. - * - * @param mode The mode. One of DECODE_NONE, DECODE_B_FOR_0, - * DECODE_B_FOR_0_3 or DECODE_B_FOR_0_7. This either puts no decoding in - * (for DECODE_NONE) or maps the bottom four bits for digit 0 - * (DECODE_B_FOR_0), digits 1 to 3 (DECODE_B_FOR_0_3) or all the digits - * (DECODE_B_FOR_0_7). The decode turns the bottom 4 bits into 0 to 9, - * minus, E, H, L, P and blank (in that order). - * - * Does anyone else think someone was trapped in the factory and put the - * HELP in there as a “message in a bottle”? - * - * @throws IOException In case of error. - */ - public void setDecodeMode (byte mode) throws IOException - { - dev.setDecodeMode (mode); - } - - /** - * Set the intensity of the device. - * - * @param intensity The intensity level. It must be in the range 0 to 15. - * - * @throws IOException In case of error. - */ - public void setIntensity (int intensity) throws IOException - { - dev.setIntensity (intensity); - } - - /** - * Set the scan limit. The scan limit is the number of displays actually - * used. The value is between 0 and 7 for 1 to 8 displays. - * - * @param limit The limit on the number of displays. - * - * @throws IOException In case of error. - */ - public void setScanLimit (int limit) throws IOException - { - dev.setScanLimit (limit); - } - - /** - * Set the shutdown status of all devices. - * - * @param active If true the device is shut down. - * - * @throws IOException In case of problems. - */ - public void shutdown (boolean active) throws IOException - { - dev.shutdown (active); - } - - /** - * Set test mode. This sets all segments of all the displays on. - * - * @param active True to engage, false to turn off. - * - * @throws IOException In case of problems. - */ - public void displayTest (boolean active) throws IOException - { - dev.displayTest (active); - } - - /** - * Send all the display information to the device. This is done in one - * go to avoid excessive use of the bus on update of each digit. - * - * @throws IOException In case of problems. - */ - public void update () throws IOException - { - dev.update (); - } - - /** - * Get the left hand button. - * - * @return The Pin handler. - */ - public GpioPinDigitalInput getLeftPin () - { - return left; - } - - /** - * Get the right hand button. - * - * @return The Pin handler. - */ - public GpioPinDigitalInput getRightPin () - { - return right; - } - - public static void main (String args[]) throws IOException, InterruptedException - { - final ZeroSeg z = new ZeroSeg (); - final GpioPinDigitalInput left = z.getLeftPin (); - final GpioPinDigitalInput right = z.getRightPin (); - boolean time = true; - boolean old_left = true; - int intensity = 8; - boolean old_right = true; - boolean intensity_up = true; - - while (true) - { - boolean changed = false; - - // If left goes from high to low switch mode - if (left.isHigh ()) - { - old_left = true; - } - else - { - // High to low - if (old_left) - { - time = !time; - old_left = false; - changed = true; - } - } - - if (time) - { - final LocalTime now = LocalTime.now (); - - if (changed) - z.setDecodeMode (MAX7219.DECODE_NONE); - - z.writeDigit (0, DIGIT_MAP[now.getHour () / 10]); - z.writeDigit (1, DIGIT_MAP[now.getHour () % 10]); - z.writeDigit (2, 0); - z.writeDigit (3, DIGIT_MAP[now.getMinute () / 10]); - z.writeDigit (4, DIGIT_MAP[now.getMinute () % 10]); - z.writeDigit (5, 0); - z.writeDigit (6, DIGIT_MAP[now.getSecond () / 10]); - z.writeDigit (7, DIGIT_MAP[now.getSecond () % 10]); - - z.update (); - } - else - { - final LocalDate now = LocalDate.now (); - - if (changed) - z.setDecodeMode (MAX7219.DECODE_B_FOR_0_7); - - z.writeDigit (0, now.getYear () / 1000); - z.writeDigit (1, (now.getYear () / 100) % 10); - z.writeDigit (2, (now.getYear () / 10) % 10); - z.writeDigit (3, now.getYear () % 10); - z.writeDigit (4, now.getMonthValue () / 10); - z.writeDigit (5, now.getMonthValue () % 10); - z.writeDigit (6, now.getDayOfMonth () / 10); - z.writeDigit (7, now.getDayOfMonth () % 10); - - z.update (); - } - - // If right goes from high to low update intensity - if (right.isHigh ()) - { - old_right = true; - } - else - { - // High to low - if (old_right) - { - old_right = false; - - if (intensity_up) - { - if (intensity == 15) - { - intensity = 14; - intensity_up = false; - } - else - { - intensity += 1; - } - } - else - { - if (intensity == 0) - { - intensity = 1; - intensity_up = true; - } - else - { - intensity -= 1; - } - } - - z.setIntensity (intensity); - } - } - - Thread.sleep (10); - } - } - - public static final byte DIGIT_MAP[] = - { - 0x7e, 0x30, 0x6d, 0x79, 0x33, - 0x5b, 0x5f, 0x70, 0x7f, 0x7b - }; - - private final MAX7219 dev; - private final GpioPinDigitalInput left; - private final GpioPinDigitalInput right; -} diff --git a/Jimbo/Boards/me/kano/LightShow.java b/Jimbo/Boards/me/kano/LightShow.java deleted file mode 100644 index 88f3d72..0000000 --- a/Jimbo/Boards/me/kano/LightShow.java +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright (C) 2017 Jim Darby. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see - * . - */ - -package Jimbo.Boards.me.kano; - -import Jimbo.Graphics.MonoMatrix; -import Jimbo.Graphics.MonoMatrixDemo; -import Jimbo.Graphics.Point; -import com.pi4j.io.serial.Baud; -import com.pi4j.io.serial.DataBits; -import com.pi4j.io.serial.FlowControl; -import com.pi4j.io.serial.Parity; - -import com.pi4j.io.serial.Serial; -import com.pi4j.io.serial.SerialDataEvent; -import com.pi4j.io.serial.SerialFactory; -import com.pi4j.io.serial.SerialDataEventListener; -import com.pi4j.io.serial.SerialConfig; -import com.pi4j.io.serial.SerialPort; -import com.pi4j.io.serial.StopBits; -import java.io.IOException; - -/** - * This class controls the Kano LightShow board that's part of the powerup kit. - * - * @author Jim Darby - */ -public class LightShow implements MonoMatrix -{ - /** - * Constructor for the Kano LightShow that comes with the powerup - * kit. - * - * @throws IOException In case of error. - * @throws InterruptedException In case of error. - */ - public LightShow () throws IOException, InterruptedException - { - port = SerialFactory.createInstance (); - - // Add a daya sink for any input - port.addListener (new DataSink ()); - - // Now configure it. This is hardcoded for the LightShow. - final SerialConfig config = new SerialConfig (); - - config.device (SerialPort.getDefaultPort()). - baud (Baud._38400). - dataBits( DataBits._8). - parity (Parity.NONE). - stopBits (StopBits._1). - flowControl (FlowControl.NONE); - - port.open (config); - - data = new byte[WIDTH * HEIGHT]; - - for (int i = 0; i < data.length; ++i) - data[i] = 0; - - show (); - } - - /** - * Set a specific pixel on or off. This works in the most efficient - * way. - * - * @param x The x coordinate. - * @param y The y coordinate. - * @param pwm The PWM value. - */ - @Override - public void setPixel (int x, int y, int pwm) - { - if (x < 0 || x > MAX_X || y < 0 || y > MAX_Y || pwm < 0 || pwm > MAX_PWM) - throw new IllegalArgumentException ("Invalid parameters for setPixel"); - - data[x + WIDTH * (MAX_Y - y)] = (byte) (pwm >> 5); - } - - /** - * Set a pixel in the generic way. - * - * @param p The pixel. - * @param value The value. - */ - @Override - public void setPixel (Point p, Integer value) - { - setPixel (p.getX (), p.getY (), value); - } - - /** - * Update the displayed data. Call this after setting up what you want - * displayed and it will transfer it to the device and hence actually - * display it. - * - * @throws IOException In case of error - */ - @Override - public final void show() throws IOException - { - port.write (START); - port.write (data); - } - - /** - * Return the maximum X and Y values as a Point. - * - * @return The maximum X and Y values as a Point - */ - @Override - public Point getMax() - { - return MAX; - } - - /** - * A class that implements the SerialDataEventListener interface - * and just ignores everything that happens. We need this otherwise - * the data just piles up. - */ - private static class DataSink implements SerialDataEventListener - { - /** - * Read and ignore any data. - * - * @param e The data to ignore - */ - @Override - public void dataReceived(SerialDataEvent e) - { - // And ignore it! - } - } - - public static void main (String args[]) throws IOException, InterruptedException - { - LightShow l = new LightShow (); - - MonoMatrixDemo.run (l); - } - - /** The display's width. */ - private static final int WIDTH = 9; - /** The display's height. */ - private static final int HEIGHT = 14; - /** The maximum X value. */ - public final static int MAX_X = WIDTH - 1; - /** The maximum Y value. */ - public final static int MAX_Y = HEIGHT - 1; - /** The maximum values as a Point. */ - private final static Point MAX = new Point (MAX_X, MAX_Y); - - /** Start marker. */ - private static final byte START = 0x55; - /** Maximum PWM value. */ - private static final int MAX_PWM = 255; - - - /** The serial port to use. */ - private final Serial port; - /** The data for the display. */ - private final byte[] data; -} diff --git a/Jimbo/Boards/uk/co/pocketmoneytronics/RGBTree.java b/Jimbo/Boards/uk/co/pocketmoneytronics/RGBTree.java deleted file mode 100644 index 8f8a03e..0000000 --- a/Jimbo/Boards/uk/co/pocketmoneytronics/RGBTree.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (C) 2017 Jim Darby. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see - * . - */ - -package Jimbo.Boards.uk.co.pocketmoneytronics; - -import Jimbo.Devices.WS2811.WS2811; -import Jimbo.Devices.WS2811.WS2811Raw; - -import Jimbo.Graphics.Point; -import Jimbo.Graphics.Identity; -import Jimbo.Graphics.Colour; - -/** - * The class controls the WS2811-based RGB Christmas tree from - * PocketMoneyTronics. - * - * @author Jim Darby - */ -public class RGBTree -{ - /** - * Construct the tree. - */ - public RGBTree () - { - tree = new WS2811 (PIXELS, 1, new Identity (PIXELS, 1), WS2811Raw.WS2811_STRIP_RGB, 0.25); - } - - /** - * Set a specific pixel to a specific Colour value. - * - * @param n The pixel number. - * @param r The red value. - * @param g The green value. - * @param b The blue value. - */ - public void setPixel (int n, int r, int g, int b) - { - tree.setPixel (new Point (n, 0), r, g, b); - } - - /** - * Set a specific pixel to a specific Colour value. - * - * @param n The pixel number. - * @param c The colour to set it to. - */ - public void setPixel (int n, Colour c) - { - tree.setPixel (new Point (n, 0), c); - } - - /** - * Update the display. - */ - public void show () - { - tree.show (); - } - - /** - * Demo program. - * - * @param args Command line parameters. - * - * @throws java.lang.InterruptedException In case of interruption. - */ - public static void main (String args[]) throws InterruptedException - { - RGBTree t = new RGBTree (); - - final Colour[] colours = new Colour[3]; - - colours[0] = new Colour (255, 0, 0); - colours[1] = new Colour (0, 255, 0); - colours[2] = new Colour (0, 0, 255); - - for (int i = 0; i < colours.length; ++i) - { - for (int j = 0; j < PIXELS; ++j) - t.setPixel (j, colours[i]); - - t.show (); - - Thread.sleep (500); - } - } - - /** Number of pixels. */ - public final static int PIXELS = 6; - /** The tree. */ - private final WS2811 tree; -} diff --git a/Jimbo/Devices/APA102.java b/Jimbo/Devices/APA102.java deleted file mode 100644 index 8f0a686..0000000 --- a/Jimbo/Devices/APA102.java +++ /dev/null @@ -1,231 +0,0 @@ -/* - * Copyright (C) 2016-2017 Jim Darby. - * - * This software is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this software; if not, If not, see - * . - */ - -package Jimbo.Devices; - -import com.pi4j.io.gpio.GpioController; -import com.pi4j.io.gpio.GpioFactory; -import com.pi4j.io.gpio.GpioPinDigitalOutput; -import com.pi4j.io.gpio.Pin; -import com.pi4j.io.gpio.RaspiPin; - -import Jimbo.Graphics.Colour; -import Jimbo.Graphics.ColourMatrix; -import Jimbo.Graphics.ColourMatrixDemo; -import Jimbo.Graphics.Point; - -import java.io.IOException; - -/** - * This class drives a chain of APA102 "intelligent" LEDs. - * - * @author Jim Darby - */ -public class APA102 implements ColourMatrix -{ - /** - * Construct an APA102 controller. - * - * @param gpio The GpioController to use. - * @param data_pin The data pin to use - * @param clock_pin The clock pin to use. - * @param n The number of LEDs in the chain. - */ - public APA102 (GpioController gpio, Pin data_pin, Pin clock_pin, int n) - { - WIDTH = n; - MAX_X = WIDTH - 1; - MAX = new Point (MAX_X, MAX_Y); - dat = gpio.provisionDigitalOutputPin (data_pin); - clk = gpio.provisionDigitalOutputPin (clock_pin); - data = new int[n]; - - // Set all off to start with. - for (int i = 0; i < WIDTH; ++i) - data[i] = 0; - - // And push that out to the devices. - show (); - } - - /** - * Set a LED to a specific red, green and blue value. We also set the - * brightness. - * - * @param n The LED number, in the range 0 to the number of LEDs minus one. - * @param r The red value (0 to 255). - * @param g The green value (0 to 255). - * @param b The blue value (0 to 255). - * @param bright The brightness (0 to 31). - */ - public void set (int n, int r, int g, int b, int bright) - { - if (n < 0 || n >= WIDTH || - r < 0 || r > 255 || - g < 0 || g > 255 || - b < 0 || b > 255 || - bright < 0 || bright > 31) - throw new IllegalArgumentException ("Invalid parameter"); - - data[n] = (bright << 24) | (r << 16) | (g << 8) | b; - } - - /** - * Return a point with the maximum values for X and Y in this - * matrix. - * - * @return A Point object with the maximum values for X and Y. - */ - @Override - public Point getMax() - { - return MAX; - } - - /** - * Set a pixel the generic way. - * - * @param p The pixel to set. - * @param value The colour to set it to. - */ - @Override - public void setPixel(Point p, Colour value) - { - if (p.getY () != 0) - throw new IllegalArgumentException ("Invalid Y coordinate"); - - set (p.getX (), value.getRed (), value.getGreen (), value.getBlue (), brightness); - } - - /** - * Update the LED chain. - */ - @Override - public final void show () - { - // Transmit preamble - for (int i = 0; i < 4; ++i) - write_byte ((byte) 0); - - // Send data - for (int i = 0; i < WIDTH; ++i) - write_led (data[i]); - - // And latch it - latch (); - } - - /** - * Scale the brightness to avoid blindness. - * - * @param brightness The brightness scale factor: 0 to 31. - */ - - public final void brightness (int brightness) - { - if (brightness < 0 || brightness > 31) - throw new IllegalArgumentException ("Invalid brightness"); - - this.brightness = brightness; - } - - /** - * Write out a single byte. It goes out MSB first. - * - * @param out The byte to write. - */ - private void write_byte (byte out) - { - for (int i = 7; i >= 0; --i) - { - dat.setState ((out & (1 << i)) != 0); - clk.setState (true); - clk.setState (false); - } - } - - /** - * Write out a single LEDs information. - * - * @param data The data for that LED. - */ - private void write_led (int data) - { - write_byte ((byte) (0xe0 | ((data >> 24) & 0x1f))); - - write_byte ((byte) (data)); - write_byte ((byte) (data >> 8)); - write_byte ((byte) (data >> 16)); - } - - /** - * Latch the data into the devices. This has prompted much discussion as - * data sheet seems to be a work of fiction. These values seem to work. - * - * In case of any difficulties, blame Gadgetoid: it's all his fault! - */ - private void latch () - { - // Transmit zeros not ones! - dat.setState (false); - - // And 36 of them! - for (int i = 0; i < 36; ++i) - { - clk.setState (true); - clk.setState (false); - } - } - - public static void main (String args[]) throws InterruptedException, IOException - { - APA102 blinkt = new APA102 (GpioFactory.getInstance(), RaspiPin.GPIO_04, RaspiPin.GPIO_05, 8); - - for (int x = 0; x < 8; ++x) - { - blinkt.set (x, 255, 0, 0, 31); - blinkt.show (); - Thread.sleep (500); - blinkt.set (x, 0, 0, 0, 31); - blinkt.show (); - } - - ColourMatrixDemo.run (blinkt); - } - - /** The pin we use for data. */ - private final GpioPinDigitalOutput dat; - /** The pin we use for the clock. */ - private final GpioPinDigitalOutput clk; - /** The data for each LED in the chain. */ - private final int[] data; - /** Scale factor for brightness. Defaults to 8 (of 31) because Pimoroni. */ - private int brightness = 8; - - /** The width of the board. */ - public final int WIDTH; - /** The height of the board. */ - public static final int HEIGHT = 1; - /** The maximum X value. */ - public final int MAX_X; - /** The maximum Y value. */ - public static final int MAX_Y = HEIGHT - 1; - - /** The maximum values as a Point. */ - private final Point MAX; -} diff --git a/Jimbo/Devices/BMP280.java b/Jimbo/Devices/BMP280.java deleted file mode 100644 index 314006d..0000000 --- a/Jimbo/Devices/BMP280.java +++ /dev/null @@ -1,511 +0,0 @@ -/* - * Copyright (C) 2017 Jim Darby. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see - * . - */ - -package Jimbo.Devices; - -import java.io.IOException; - -import com.pi4j.io.i2c.I2CBus; -import com.pi4j.io.i2c.I2CDevice; -import com.pi4j.io.i2c.I2CFactory; - - -/** - * A class to talk to the BMP280 digital pressure and temperature - * sensor. - * - * @author Jim Darby - */ -public class BMP280 -{ - /** - * This class is used to return the result from a reading of a - * BMP280 device. It is (typically) constructed by the {@code BMP280} - * class as a result of asking for a reading and returns the values read in - * a convenient form. - */ - public class Result - { - /** - * This constructs the result value. - * - * @param pressure The pressure (in Pa). - * @param temperature The temperature (in degrees Celsius). - */ - public Result (double pressure, double temperature) - { - this.pressure = pressure; - this.temperature = temperature; - } - - /** - * This method returns the pressure reading in Pa. The value is - * set in the constructor and cannot be modified. - * - * @return The pressure in Pa. - */ - public double getPressure () - { - return pressure; - } - - /** - * This methods returns the temperature in degrees Celsius times 10. - * The value is set in the constructor and cannot be modified. - * - * @return The temperature in degrees Celsius. - */ - public double getTemperature () - { - return temperature; - } - - /** Where we hold the pressure (in Pa). */ - private final double pressure; - /** Where we hold the temperature (in Celsius). */ - private final double temperature; - } - - public static void main (String args[]) throws I2CFactory.UnsupportedBusNumberException, IOException, InterruptedException - { - BMP280 b = new BMP280 (I2CFactory.getInstance (I2CBus.BUS_1), 0x77); - - while (true) - { - Result r = b.read (); - System.out.println ("Temperature " + r.getTemperature () + " pressure " +r.getPressure ()); - Thread.sleep (1000); - } - } - - /** - * This is the constructor for the BMP280 class. It takes the bus the - * device is on and the address on that bus (which can be varied by setting - * various pins on the device. - * - * @param bus The {@code I2CBus} the device is on. - * @param dev The device address on that bus (it can be changed). - * - * @throws IOException If something goes amiss talking to the device. - */ - public BMP280 (I2CBus bus, int dev) throws IOException - { - // Get a device object to use for communication. - device = bus.getDevice (dev); - - // Verify it really is a BMP280 - final int signature = device.read (SIGNATURE_REG); - - if (signature != SIGNATURE) - throw new IOException ("BMP280: Invalid signature (" + signature + ')'); - - // Load the device calibration data (all in one go!). - final int got = device.read (CALIBRATION_REG, buffer, 0, BUFFER_SIZE); - - // Did we get it all? - if (got != BUFFER_SIZE) - throw new IOException ("BMP280: Failed to read calibration coefficients"); - - // The values are all 16-bit but T1 and P1 are unsigned. As Java - // doesn't have unsigned variables but bytes are signed we take great - // care with the following shifts and masks and place the results in - // 32-bit ints where they fit properly. - T1 = ((buffer[ 1] & 0xff) << 8) | (buffer[ 0] & 0xff); - T2 = ((buffer[ 3] ) << 8) | (buffer[ 2] & 0xff); - T3 = ((buffer[ 5] ) << 8) | (buffer[ 4] & 0xff); - P1 = ((buffer[ 7] & 0xff) << 8) | (buffer[ 6] & 0xff); - P2 = ((buffer[ 9] ) << 8) | (buffer[ 8] & 0xff); - P3 = ((buffer[11] ) << 8) | (buffer[10] & 0xff); - P4 = ((buffer[13] ) << 8) | (buffer[12] & 0xff); - P5 = ((buffer[15] ) << 8) | (buffer[14] & 0xff); - P6 = ((buffer[17] ) << 8) | (buffer[16] & 0xff); - P7 = ((buffer[19] ) << 8) | (buffer[18] & 0xff); - P8 = ((buffer[21] ) << 8) | (buffer[20] & 0xff); - P9 = ((buffer[23] ) << 8) | (buffer[22] & 0xff); - - if (DEBUGGING) - { - System.out.println ("T: " + T1 + ' ' + T2 + ' ' + T3); - System.out.println ("P: " + P1 + ' ' + P2 + ' ' + P3 + ' ' + P4 + ' ' + - P5 + ' ' + P6 + ' ' + P7 + ' ' + P8 + ' ' + P9); - } - - config (4, 4, false); - control (5, 5, 3); - } - - /** - * Test constructor for the BMP180. It runs through the standard test - * sequence for the temperature compensation to verify it. - */ - private BMP280 () - { - device = null; - - T1 = 27504; - T2 = 26435; - T3 = -1000; - - if (compensateTemperatureInt (519888) != 2508) - System.out.println ("Failed integer temperature validation!"); - - if (!within (compensateTemperatureFloat (519888), 25.08, 0.01)) - System.out.println ("Failed floating point temperature validation"); - - P1 = 36477; - P2 = -10685; - P3 = 3024; - P4 = 2855; - P5 = 140; - P6 = -7; - P7 = 15500; - P8 = -14600; - P9 = 6000; - - if (compensatePressureInt (415148) != 100653) - System.out.println ("Failed integer pressure validation!"); - - if (!within (compensatePressureFloat (415148), 100653.27, 0.01)) - System.out.println ("Failed floating point pressure validation!"); - } - - /** - * Set up the control register. For full details you'll need to read the - * data sheet. - * - * @param temperature_oversampling 0 means skip reading temperature. 1 to - * 5 means oversample 2^(n-1) times. 6 and above mean oversample 16 times. - * Only values in the range 0 to 7 are acceptable. - * @param pressure_oversampling 0 means skip reading temperature. 1 to - * 5 means oversample 2^(n-1) times. 6 and above mean oversample 16 times. - * Only values in the range 0 to 7 are acceptable. - * @param power_mode 0 is sleep mode, 1 and 2 are forced mode and 3 is - * normal mode. - * - * @throws IOException In case of error. - */ - public final void control (int temperature_oversampling, - int pressure_oversampling, - int power_mode) throws IOException - { - if (temperature_oversampling < 0 || temperature_oversampling > 7 || - pressure_oversampling < 0 || pressure_oversampling > 7 || - power_mode < 0 || power_mode > 3) - throw new IOException ("BMP280: Invalid control"); - - final byte value = (byte) ((temperature_oversampling << 5) | - (pressure_oversampling << 2) | power_mode); - - device.write (CONTROL_REG, value); - } - - /** - * Set the configuration register. For full details you'll need to read - * the data sheet. - * - * @param inactive Set the inactive duration. - * @param filter Set the IIR filter parameter. - * @param spi Switch to SPI mode. - * - * @throws IOException In case of error. - */ - public final void config (int inactive, int filter, boolean spi) throws IOException - { - if (inactive < 0 || inactive > 7 || - filter < 0 || filter > 7) - throw new IOException ("BMP280: Invalid config"); - - final byte value = (byte) ((inactive << 5) | (filter << 2) | (spi ? 1 : 0)); - - device.write (CONFIG_REG, value); - } - - public Result read () throws IOException - { - if (device.read (RESULTS_REG, buffer, 0, DATA_SIZE) != DATA_SIZE) - throw new IOException ("BMP280: Short data read"); - - final int pressure_adc = ((buffer[0] & 0xff) << 12) + - ((buffer[1] & 0xff) << 4) + ((buffer[2] & 0xff) >> 4); - final int temperature_adc = ((buffer[3] & 0xff) << 12) + - ((buffer[4] & 0xff) << 4) + ((buffer[5] & 0xff) >> 4); - - // They need to be calculated in the order as the temperature - // calculation sets a varaible to asist with pressure calculation. - // Thanks Bosch! - - final double temperature = compensateTemperatureFloat (temperature_adc); - final double pressure = compensatePressureFloat (pressure_adc); - - if (DEBUGGING) - { - System.out.println ("Raw: pressure " + pressure_adc + " temperature " + temperature_adc); - System.out.println ("Cooked: temperature " + temperature + " pressure " + pressure); - } - - return new Result (pressure, temperature); - } - - /** - * Calculate the compensated temperature using the integer version - * of the algorithm. - * - * @param adc The ADC value - * - * @return The temperature in hundreths of a degree Celsius. - */ - private int compensateTemperatureInt (int adc) - { - // This horror is from the data sheet. Don't blame me! - - final int var1 = ((((adc >> 3) - (T1 << 1))) * (T2)) >> 11; - final int var2 = (((((adc >> 4) - (T1)) * ((adc >> 4) - (T1))) >> 12) * (T3)) >> 14; - t_fine_int = var1 + var2; - final int T = (t_fine_int * 5 + 128) >> 8; - - if (DEBUGGING) - System.out.println ("var1 " + var1 + " var2 " + var2 + " t_fine " + t_fine_int + " T " + T); - - return T; - } - - /** - * Calculate the compensated temperature using the floating point - * version of the algorithm. - * - * @param adc The ADC value - * - * @return The temperature in degrees Celsius. - */ - private double compensateTemperatureFloat (int adc) - { - // This horror is from the data sheet. Don't blame me! - - final double val1 = (adc / 16384.0 - T1 / 1024.0) * T2; - final double val2 = ((adc / 131072.0) - T1 / 8192.0) * (adc / 131072.0 - T1 / 8192.0) * T3; - - t_fine_double = val1 + val2; - - final double T = t_fine_double / 5120; - - if (DEBUGGING) - System.out.println ("val1 " + val1 + " val2 " + val2 + " t_fine " + t_fine_double + " T " + T); - - return T; - } - - /** - * Calculate the compensated pressure using integer arithmetic. - * - * @param adc The ADC result. - * - * @return The pressure in Pascals. - */ - private int compensatePressureInt (int adc) - { - // This horror is from the data sheet. Don't blame me! - - long var1, var2, p; - var1 = ((long) t_fine_int) - 128000; - - if (DEBUGGING) - System.out.println ("var1 " + var1); - - var2 = var1 * var1 * (long) P6; - - if (DEBUGGING) - System.out.println ("var2 " + var2); - - var2 = var2 + ((var1*(long) P5)<<17); - - if (DEBUGGING) - System.out.println ("var2 " + var2); - - var2 = var2 + (((long) P4)<<35); - - if (DEBUGGING) - System.out.println ("var2 " + var2); - - var1 = ((var1 * var1 * (long) P3)>>8) + ((var1 * (long) P2)<<12); - - if (DEBUGGING) - System.out.println ("var1 " + var1); - - var1 = (((((long) 1)<<47)+var1))*((long) P1)>>33; - - if (DEBUGGING) - System.out.println ("var1 " + var1); - - if (var1 == 0) - { - return 0; // avoid exception caused by division by zero - } - - p = 1048576-adc; - - if (DEBUGGING) - System.out.println ("p " + p); - - p = (((p<<31)-var2)*3125)/var1; - - if (DEBUGGING) - System.out.println ("p " + p); - - var1 = (((long) P9) * (p>>13) * (p>>13)) >> 25; - - if (DEBUGGING) - System.out.println ("var1 " + var1); - - var2 = (((long) P8) * p) >> 19; - - if (DEBUGGING) - System.out.println ("var2 " + var2); - - p = ((p + var1 + var2) >> 8) + (((long) P7)<<4); - - if (DEBUGGING) - System.out.println ("p " + p); - - return (int) ((p + 128) / 256); - } - - /** - * Calculate the compensated pressure using floating point - * arithmetic. - * - * @param adc The ADC result. - * - * @return The pressure in Pascals. - */ - private double compensatePressureFloat (int adc) - { - // This horror is from the data sheet. Don't blame me! - - double var1, var2, p; - - var1 = t_fine_double / 2.0 - 64000; - - if (DEBUGGING) - System.out.println ("var1 " + var1); - - var2 = var1 * var1 * P6 / 32768; - - if (DEBUGGING) - System.out.println ("var2 " + var2); - - var2 = var2 + var1 * P5 * 2; - - if (DEBUGGING) - System.out.println ("var2 " + var2); - - var2 = var2 / 4 + P4 * 65536.0; - - if (DEBUGGING) - System.out.println ("var2 " + var2); - - var1 = ((var1 * var1 * P3) / 524288.0 + (var1 * P2 )) / 524288.0; - - if (DEBUGGING) - System.out.println ("var1 " + var1); - - var1 = (1 + var1 / 32768) * P1; - - if (DEBUGGING) - System.out.println ("var1 " + var1); - - if (var1 == 0) - { - return 0; // avoid exception caused by division by zero - } - - p = 1048576 - adc; - - if (DEBUGGING) - System.out.println ("p " + p); - - p = (p - var2 / 4096) * 6250 / var1; - - if (DEBUGGING) - System.out.println ("p " + p); - - var1 = P9 * p * p / 2147483648.0; - - if (DEBUGGING) - System.out.println ("var1 " + var1); - - var2 = P8 * p / 32768; - - if (DEBUGGING) - System.out.println ("var2 " + var2); - - p = p + (var1 + var2 + P7) / 16.0; - - if (DEBUGGING) - System.out.println ("p " + p); - - return p; - } - - private static boolean within (double a, double b, double limit) - { - return Math.abs (a - b) < limit; - } - - /** Locate of signature register. */ - private static final int SIGNATURE_REG = 0xd0; - /** Signature value. */ - private static final int SIGNATURE = 0x58; - /** Location of calibration data. */ - private static final int CALIBRATION_REG = 0x88; - /** Location of status register. */ - private static final int STATUS_REG = 0xf3; - /** Location of control register. */ - private static final int CONTROL_REG = 0xf4; - /** Location of configuration register. */ - private static final int CONFIG_REG = 0xf5; - /** Largest read data sized used (in fact calibration data). */ - private static final int BUFFER_SIZE = 24; - /** Base of data. */ - private static final int RESULTS_REG = 0xf7; - /** Size of data. */ - private static final int DATA_SIZE = 6; - /** Run in debugging mode. */ - private static final boolean DEBUGGING = false; - - /** The I2C device. */ - private final I2CDevice device; - /** Buffer used for reading results. */ - private final byte[] buffer = new byte[BUFFER_SIZE]; - - // Compensation parameters. - private final int T1; - private final int T2; - private final int T3; - private final int P1; - private final int P2; - private final int P3; - private final int P4; - private final int P5; - private final int P6; - private final int P7; - private final int P8; - private final int P9; - - int t_fine_int; - double t_fine_double; -} diff --git a/Jimbo/Devices/HT16K33.java b/Jimbo/Devices/HT16K33.java deleted file mode 100644 index 52628e7..0000000 --- a/Jimbo/Devices/HT16K33.java +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright (C) 2018 Jim Darby. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see - * . - */ - -package Jimbo.Devices; - -import java.io.IOException; - -import com.pi4j.io.i2c.I2CBus; -import com.pi4j.io.i2c.I2CDevice; -import com.pi4j.io.i2c.I2CFactory; - -/** - * This class controls a HT16K33 display controller. - * - * @author Jim Darby - */ -public class HT16K33 -{ - public HT16K33 (I2CBus bus, int dev) throws IOException - { - // Get a device object to use for communication. - device = bus.getDevice (dev); - - setOscillator (true); - setDisplay (true, DISPLAY_STEADY); - setBrightness (15); - - for (int i = 0; i < buffer.length; ++i) - buffer[i] = 0x00; - - update (); - } - - /** - * Turn the main oscillator on or off. Having the oscillator off is - * standby mode and on is the normal run mode. - * - * @param on Turn the oscillator on or not. - * - * @throws IOException In case of trouble. - */ - public void setOscillator (boolean on) throws IOException - { - device.write ((byte) (SETUP_REG | (on ? SETUP_ON : 0))); - } - - /** - * Set the display parameters. There is an on/off boolean and the blink - * rate which can be one of DISPLAY_STEADY (where it's on permanently), - * DISPLAY_TWOHZ (flashing at 2Hz), DISPLAY_ONEHZ (flashing at 1Hz) or - * DISPLAY_HALFHZ (flashing at 0.5Hz). - * - * @param on Display on/off. - * @param blink DISPLAY_STEADY, DISPLAY_TWOHZ, DISPLAY_ONEHZ or - * DISPLAY_HALFHZ. - * - * @throws IOException In case of trouble. - */ - public void setDisplay (boolean on, int blink) throws IOException - { - if (blink < 0 || blink > 3) - throw new IllegalArgumentException ("HT16K33 invalid blink value"); - - device.write ((byte) (DISPLAY_REG | (blink << 1) | (on ? DISPLAY_ON : 0))); - } - - /** - * Set the display's brightness level. - * - * @param level The brightness level: 0 to 15 mapping to 1/16 to 16/16 max. - * - * @throws IOException In case of trouble. - */ - public void setBrightness (int level) throws IOException - { - if (level < 0 || level > 15) - throw new IllegalArgumentException ("HT16K33 invalid brightness value"); - - device.write ((byte) (BRIGHTNESS_REG | level)); - } - - /** - * Set a single bit in the display on or off. Bits are number from byte - * zero upwards and inside a byte from LSB to MSB. - * - * @param bit The bit to set (in the range 0 to 127). - * @param on Set the bit on or off. - */ - public void setBit (int bit, boolean on) - { - if (bit < 0 || bit > buffer.length * 8 - 1) - throw new IllegalArgumentException ("HT16K33 invalid bit number"); - - final int index = bit / 8; - final byte value = (byte) (1 << (bit % 8)); - - if (on) - buffer[index] |= value; - else - buffer[index] &= ~value; - } - - /** - * Set a specific byte in the buffer. - * - * @param which Which byte to set (0 to 15). - * @param value The value to set it to. - */ - public void setByte (int which, byte value) - { - if (which < 0 || which >= buffer.length) - throw new IllegalArgumentException ("HT16K33 invalid byte number"); - - buffer[which] = value; - } - /** - * Set a specific word in the buffer. The words are stored in little - * endian format. - * - * @param which Which byte to set (0 to 15). - * @param value The value to set it to. - */ - - public void setWord (int which, short value) - { - if (which < 0 || which >= buffer.length / 2) - throw new IllegalArgumentException ("HT16K33 invalid byte number"); - - buffer[which*2 + 1] = (byte) (value >> 8); - buffer[which*2] = (byte) value; - } - - /** - * Update the display. - * - * @throws IOException In case of trouble. - */ - public void update () throws IOException - { - device.write (0, buffer); - } - -/** - * Test program. - * - * @param args (ignored) - * - * @throws IOException In case of trouble. - * @throws com.pi4j.io.i2c.I2CFactory.UnsupportedBusNumberException In case of trouble. - * @throws InterruptedException In case of trouble. - */ - public static void main (String args[]) throws IOException, I2CFactory.UnsupportedBusNumberException, InterruptedException - { - HT16K33 h = new HT16K33 (I2CFactory.getInstance (I2CBus.BUS_1), 0x70); - - boolean reset = false; - - while (true) - { - for (int i = 0; i < 128; ++i) - { - if (i > 0 && reset) - h.setBit (i - 1, false); - - System.out.println ("Setting bit " + i); - h.setBit (i, true); - h.update (); - - Thread.sleep (1000); - } - - reset = !reset; - } - } - - /** The I2C device. */ - private final I2CDevice device; - /** The data buffer */ - private final byte[] buffer = new byte[16]; - - /** Address of the setup register. */ - static private final int SETUP_REG = 0x20; - /** Command to turn the device on. */ - static private final byte SETUP_ON = 0x01; - /** Address of the display setup register. */ - static private final int DISPLAY_REG = 0x80; - /** Value to turn the display on. */ - static private final byte DISPLAY_ON = 0x01; - /** Value for no blinking. */ - static private final byte DISPLAY_STEADY = 0x00; - /** Value for blinking at 2 Hz. */ - static private final byte DISPLAY_TWOHZ = 0x01; - /** Value for blinking at 1Hz. */ - static private final byte DISPLAY_ONEHZ = 0x02; - /** Value for blinking at 0.5 Hz. */ - static private final byte DISPLAY_HALFHZ = 0x03; - /** Address of brightness register. */ - static private final int BRIGHTNESS_REG = 0xe0; -} diff --git a/Jimbo/Devices/IS31FL3730.java b/Jimbo/Devices/IS31FL3730.java deleted file mode 100644 index 2eaf1b4..0000000 --- a/Jimbo/Devices/IS31FL3730.java +++ /dev/null @@ -1,389 +0,0 @@ -/* - * Copyright (C) 2016 Jim Darby. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see - * . - */ - -package Jimbo.Devices; - -import java.io.IOException; - -import com.pi4j.io.i2c.I2CBus; -import com.pi4j.io.i2c.I2CDevice; - -import java.util.logging.Logger; -import java.util.logging.Level; - -/** - * This class drive the IS31FL3730 display controller. It's primary goal is to - * be generic so that its users can provide the appropriate parameters to make - * it work with the highly board specific implementation. - * - * @author Jim Darby - */ -public class IS31FL3730 -{ - private static final Logger LOG = Logger.getLogger ("Jimbo.Devices.IS31FL3730"); - - /** - * Constructor. This uses the default device address on the given bus. - * - * @param bus The bus the controller is on. - * @throws IOException When it can't create the bus device. - */ - public IS31FL3730 (I2CBus bus) throws IOException - { - this (bus, I2C_ADDR); - } - - /** - * Constructor. The uses a specified address on the given bus, - * - * @param bus The bus the controller is on. - * @param addr The address on the bus - * @throws IOException When it can't create the bus device. - */ - public IS31FL3730 (I2CBus bus, int addr) throws IOException - { - device = bus.getDevice (addr); - - // Clear retry timers - for (int i = 0; i < MAX_TRIES; ++i) - tries [i] = 0; - } - - /** - * Set the mode of the device. You really want to read the manual for this. - * - * @param mode You can have (or not) MODE_SSD, MODE_AE and one of: - * MODE_8X8, MODE_7X9, MODE_6X10 or MODE_9X11 and one of: - * MODE_M1, MODE_M2 or MODE_M12. - * @throws IOException If anything goes wrong. - */ - public void setMode (int mode) throws IOException - { - // Did they set any naughty bits? - if ((mode & ~(0x9f)) != 0) - throw new IllegalArgumentException ("Bad mode value " + mode); - - retryWrite (REG_CONFIG, (byte) mode); - } - - /** - * Set a single byte in M1. - * - * @param offset The offset (0 to 10). - * @param value The value - * @throws java.io.IOException On invalid parameters or error. - */ - public void setM1 (byte offset, byte value) throws IOException - { - if (offset < 0 || offset > 10) - throw new IllegalArgumentException ("Invalid offset " + offset); - - retryWrite (REG_M1_BASE + offset, value); - } - - /** - * Set a single byte in M2. - * - * @param offset The offset (0 to 10). - * @param value The value - * @throws java.io.IOException On invalid parameters or error. - */ - public void setM2 (byte offset, byte value) throws IOException - { - if (offset < 0 || offset > 10) - throw new IllegalArgumentException ("Invalid offset " + offset); - - retryWrite (REG_M2_BASE + offset, value); - } - - /** - * Write the M1 matrix data and then (maybe) hit the update register. - * This needs between 1 to 12 bytes of data but the 12th (if there) - * isn't used for anything useful except triggering the device to update. - * - * @param data A 1- to 12-item byte array. - * @throws IOException In case of problems. - */ - public void fastUpdateM1 (byte data[]) throws IOException - { - if (data.length < 1 || data.length > 12) - throw new IllegalArgumentException ("Invalid fastUpdate data"); - - retryWrite (REG_M1_BASE, data, 0, data.length); - } - - /** - * Write the entire M2 matrix data. - * - * @param data A 1- to 11-item byte array. - * @throws IOException In case of problems. - */ - public void fastUpdateM2 (byte data[]) throws IOException - { - if (data.length < 1 || data.length > 11) - throw new IllegalArgumentException ("Invalid fastUpdate data"); - - retryWrite (REG_M2_BASE, data, 0, data.length); - } - - /** - * Set the lighting effect register. See the datasheet for the full details. - * In summary, if you're using the audio input you set the gain here using - * one of the LER_*DB values for the appropriate decibel gain. You should - * always use one of the LER_*MA values to set the driver current for the - * LEDs in the matrix. - * - * @param effect The value to use. Must be between 0 and 127 inclusive. - * @throws IOException In case of error. - */ - public void setLightingEffect (int effect) throws IOException - { - if (effect < 0 || effect > 127) - throw new IllegalArgumentException ("Invalid effect " + effect); - - retryWrite (REG_LER, (byte) effect); - } - - /** - * Set the PWM parameter. - * - * @param pwm The PWM value. Must be between 0 and 128 inclusive. - * @throws IOException In case of error. - */ - public void setPWM (int pwm) throws IOException - { - if (pwm < 0 || pwm > MAX_PWM) - throw new IllegalArgumentException ("Bad PWM " + pwm); - - retryWrite (REG_PWM, (byte) pwm); - } - - /** - * Tell the device to update its display. - * - * @throws IOException In case things go wrong. - */ - public void update () throws IOException - { - retryWrite (REG_UCR, (byte) 0x00); - } - - /** - * Try a bus write until it works. - * - * @param reg The register to write. - * @param value The value to write - * @throws IOException If it really can't be made to work! - */ - private void retryWrite (int reg, byte value) throws IOException - { - buffer1[0] = value; - - retryWrite (reg, buffer1, 0, 1); - } - - /** - * Try a bus write until it works. - * - * @param reg The register to write. - * @param value The values to write - * @throws IOException If it really can't be made to work! - */ - private void retryWrite (int reg, byte[] value, int base, int length) throws IOException - { - IOException error = null; - - for (int i = 0; i < MAX_TRIES; ++i) - { - try - { - device.write (reg, value, base, length); - ++tries[i]; - - if (i > 0) - printTries (); - - error = null; - break; - } - - catch (IOException e) - { - error = e; - } - - try - { - Thread.sleep (1); - } - - catch (InterruptedException e) - { - LOG.log (Level.WARNING, "Sleep interrupted: {0}", e.getLocalizedMessage ()); - } - } - - if (error != null) - throw error; - } - - /** - * Set the number of tries before logging a warning. Note this will - * never log if there isn't a retry. - * - * @param n The number of tries, which must be non-negative. - */ - public void setTriesWarning (int n) - { - if (n < 0) - throw new IllegalArgumentException ("Bad number of tries " + n); - - warn_tries = n; - } - - /** - * Print out diagnostic information in case of failure. - */ - private void printTries () - { - int total = 0; - int failed = 0; - boolean summarise = false; - - for (int i = 0; i < MAX_TRIES; ++i) - { - total += tries[i]; - - if (i > 0 && tries[i] != 0) - { - failed += tries[i] * i; - - if (i > warn_tries) - { - LOG.log (Level.INFO, "Retries {0} = {1}", new Object[]{i, tries[i]}); - summarise = true; - } - } - } - - if (summarise) - LOG.log (Level.INFO, "As as percentage: {0}", (((double) failed / total)) * 100); - } - - // Dealing with communication and communication problems - - /** Buffer for single byte writes. */ - private final byte[] buffer1 = new byte[1]; - /** Warn if this or more tried needed to communicate with device. */ - private int warn_tries = 4; - /** The maximum number of tries to send something over the bus. */ - private static final int MAX_TRIES = 20; - /** Create a histogram of the number of tries;. */ - private final int tries[] = new int[MAX_TRIES]; - - /** The default I2C address of the device. */ - private static final byte I2C_ADDR = 0x60; - - /** Configuration register. */ - private static final byte REG_CONFIG = 0x00; - /** Base of Matrix 1 data. */ - private static final byte REG_M1_BASE = 0x01; - /** Base of Matrix 2 data. */ - private static final byte REG_M2_BASE = 0x0e; - /** Update control register. */ - private static final byte REG_UCR = 0x0c; - /** Lighting effects register. */ - private static final byte REG_LER = 0x0d; - /** PWM register. */ - private static final byte REG_PWM = 0x19; - /** Reset register */ - private static final byte REG_RESET = (byte) 0xff; - - /** Software shutdown mode */ - public static final byte MODE_SSD = (byte) 0x80; - /** Set matrix 1 only */ - public static final byte MODE_M1 = 0x00; - /** Set matrix 2 only */ - public static final byte MODE_M2 = 0x08; - /** Set matrix 1 and 2 */ - public static final byte MODE_M12 = 0x18; - /** Audio enable */ - public static final byte MODE_AE = 0x04; - /** Set 8x8 */ - public static final byte MODE_8X8 = 0x00; - /** Set 7*9 */ - public static final byte MODE_7X9 = 0x01; - /** Set 6*10 */ - public static final byte MODE_6X10 = 0x02; - /** Set 5*11 */ - public static final byte MODE_5X11 = 0x03; - - /** Set drive to 5mA. */ - public static final byte LER_05MA = 0x08; - /** Set drive to 10mA. */ - public static final byte LER_10MA = 0x09; - /** Set drive to 15mA. */ - public static final byte LER_15MA = 0x0a; - /** Set drive to 20mA. */ - public static final byte LER_20MA = 0x0b; - /** Set drive to 25mA. */ - public static final byte LER_25MA = 0x0c; - /** Set drive to 30mA. */ - public static final byte LER_30MA = 0x0d; - /** Set drive to 35mA. */ - public static final byte LER_35MA = 0x0e; - /** Set drive to 40mA. */ - public static final byte LER_40MA = 0x00; - /** Set drive to 45mA. */ - public static final byte LER_45MA = 0x01; - /** Set drive to 50mA. */ - public static final byte LER_50MA = 0x02; - /** Set drive to 55mA. */ - public static final byte LER_55MA = 0x03; - /** Set drive to 60mA. */ - public static final byte LER_60MA = 0x04; - /** Set drive to 65mA. */ - public static final byte LER_65MA = 0x05; - /** Set drive to 70mA. */ - public static final byte LER_70MA = 0x06; - /** Set drive to 75mA. */ - public static final byte LER_75MA = 0x07; - - /** Set audio gain to 0db. */ - public static final byte LER_0DB = 0x00; - /** Set audio gain to +3db. */ - public static final byte LER_3DB = 0x10; - /** Set audio gain to +6db. */ - public static final byte LER_6DB = 0x20; - /** Set audio gain to +9db. */ - public static final byte LER_9DB = 0x30; - /** Set audio gain to +12db. */ - public static final byte LER_12DB = 0x40; - /** Set audio gain to +15db. */ - public static final byte LER_15DB = 0x50; - /** Set audio gain to +18db. */ - public static final byte LER_18DB = 0x60; - /** Set audio gain to -6db. */ - public static final byte LER_M6DB = 0x70; - - /** The maximum value the PWM can be. */ - public static final int MAX_PWM = 128; - - /** Point to the device we're using. */ - private final I2CDevice device; -} diff --git a/Jimbo/Devices/IS31FL3731.java b/Jimbo/Devices/IS31FL3731.java deleted file mode 100644 index d3e3219..0000000 --- a/Jimbo/Devices/IS31FL3731.java +++ /dev/null @@ -1,273 +0,0 @@ -/* - * Copyright (C) 2017 Jim Darby. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see - * . - */ - -package Jimbo.Devices; - -import java.io.IOException; - -import com.pi4j.io.i2c.I2CBus; -import com.pi4j.io.i2c.I2CDevice; - -/** - * This class controls the IS31FL3731 display controller. It's currently - * very limited in what it offers but it isn't bad.... - * - * @author Jim Darby - */ -public class IS31FL3731 -{ - /** - * This uses the given device address on the given bus. - * - * @param bus The I2C bus to use. - * @param addr The address on the bus. - * - * @throws IOException In case of trouble. - * @throws InterruptedException In case of trouble. - */ - public IS31FL3731 (I2CBus bus, int addr) throws IOException, InterruptedException - { - device = bus.getDevice (addr); - - for (int i = 0; i < NUM_FRAMES; ++i) - { - // Turn blinking off - for (int j = BLINK_BASE; j < BLINK_END; ++j) - FRAME[i][j] = 0; - - // Turn LEDs on - for (int j = ENABLE_BASE; j < ENABLE_END; ++j) - FRAME[i][j] = (byte) 0xff; - - // Set the brightness to zero - for (int j = PWM_BASE; j < PWM_END; ++j) - FRAME[i][j] = 0; - - // Upload it to the device - sendFrame (i, FRAME[i]); - - // Set dirty markers - DIRTY_LOW[i] = FRAME_LEN; - DIRTY_HIGH[i] = -1; - } - - // Set "sensible" defaults - FUNCTION_BUFFER[REG_CONFIG] = 0x00; - FUNCTION_BUFFER[REG_DISPLAY] = 0x00; - FUNCTION_BUFFER[REG_AP1] = 0x00; - FUNCTION_BUFFER[REG_AP2] = 0x00; - FUNCTION_BUFFER[REG_RESERVED] = 0x00; // Not used - FUNCTION_BUFFER[REG_OPTION] = 0x00; - FUNCTION_BUFFER[REG_AUDIO] = 0x00; - FUNCTION_BUFFER[REG_FRAME] = 0x00; // Read only - FUNCTION_BUFFER[REG_BREATH1] = 0x00; - FUNCTION_BUFFER[REG_BREATH2] = 0x00; - FUNCTION_BUFFER[REG_SHUTDOWN] = 0x01; // Activate (only non-default!) - FUNCTION_BUFFER[REG_AGC_CTL] = 0x00; - FUNCTION_BUFFER[REG_AGC_RATE] = 0x00; - - sendFunction (); - } - - /** - * Set the PWM value of a specific LED in a specific frame. - * - * @param frame The frame the LED is in. - * @param led The LED number in that frame. - * @param pwm The PWM value. - */ - public void setLed (int frame, int led, int pwm) - { - if (frame < 0 || frame >= NUM_FRAMES) - throw new IllegalArgumentException ("Invalid frame " + frame); - - if (led < 0 || led >= NUM_LEDS) - throw new IllegalArgumentException ("Invalid LED " + led); - - if (pwm < 0 || pwm > MAX_PWM) - throw new IllegalArgumentException ("Invalid PWM " + pwm); - - final int index = PWM_BASE + led; - - FRAME[frame][index] = (byte) pwm; - - // Update the dirty values - - if (index > DIRTY_HIGH[frame]) - DIRTY_HIGH[frame] = index; - - if (index < DIRTY_LOW[frame]) - DIRTY_LOW[frame] = index; - } - - /** - * Update the display. - * - * @throws IOException In case of trouble. - */ - public void update () throws IOException - { - for (int i = 0; i < NUM_FRAMES; ++i) - { - if (DIRTY_HIGH[i] >= DIRTY_LOW[i]) - { - setPage (i); - - device.write(DIRTY_LOW[i], FRAME[i], DIRTY_LOW[i], DIRTY_HIGH[i] - DIRTY_LOW[i] + 1); - - DIRTY_LOW[i] = FRAME_LEN; - DIRTY_HIGH[i] = -1; - } - } - } - - /** - * Send a specific frame to the device. - * - * @param frame The frame to send. - * @param data The data to send. - * - * @throws IOException In case of trouble. - */ - private void sendFrame (int frame, byte[] data) throws IOException - { - if (frame < 0 || frame >= NUM_FRAMES) - throw new IllegalArgumentException ("Bad frame number " + frame); - - setPage (frame); - device.write (0, data); - } - - /** - * Send the function data to the device. - * - * @throws IOException In case of trouble. - */ - private void sendFunction () throws IOException - { - setPage (FUNCTION_PAGE); - device.write (0, FUNCTION_BUFFER); - } - - /** - * Set the page we're currently writing to. - * - * @param to The page we want to use. - * - * @throws IOException In case of trouble. - */ - private void setPage (int to) throws IOException - { - if ((to < 0 || to > 7) && to != FUNCTION_PAGE) - throw new IllegalArgumentException ("Bad page number " + to); - - if (to != current_page) - { - device.write (REG_CMD, (byte) to); - current_page = to; - } - } - - public static void main (String args[]) throws IOException, InterruptedException - { - IS31FL3731 d = new IS31FL3731 (Pi2C.useBus (), 0x74); - - for (int i = 0; i < 144; ++i) - { - d.setLed (0, i, 0xff); - d.update (); - Thread.sleep (100); - d.setLed (0, i, 0x00); - d.update (); - Thread.sleep (100); - } - } - - /** Number of LEDs per frame. */ - public final static int NUM_LEDS = 144; - /** Number of frames. */ - public final static int NUM_FRAMES = 8; - /** Maximum PWM value. */ - public final static int MAX_PWM = 0xff; - - /** Point to the device we're using. */ - private final I2CDevice device; - /** Current page we're on. */ - private int current_page = -1; - /** Two byte buffer. */ - //private final byte BUFFER2[] = new byte[2]; - - /** Frame output buffer. */ - //private final byte FRAME_BUFFER[] = new byte[1 + FRAME_LEN]; - /** Function buffer. */ - private final byte FUNCTION_BUFFER[] = new byte[FUNCTION_LEN]; - /** Frame storage. */ - private final byte FRAME[][] = new byte[NUM_FRAMES][FRAME_LEN]; - /** Dirty low marker. */ - private final int DIRTY_LOW[] = new int[NUM_FRAMES]; - /** Dirty high marker. */ - private final int DIRTY_HIGH[] = new int[NUM_FRAMES]; - - /** The command register. */ - private final static byte REG_CMD = (byte) 0xfd; - /** The function register page. */ - private final static int FUNCTION_PAGE = 0x0b; - - /** The configuration register. */ - private final static int REG_CONFIG = 0x00; - /** The display register. */ - private final static int REG_DISPLAY = 0x01; - private final static int REG_AP1 = 0x02; - private final static int REG_AP2 = 0x03; - /** The reserved register. */ - private final static int REG_RESERVED = 0x04; - /** The option register. */ - private final static int REG_OPTION = 0x05; - /** The audio register. */ - private final static int REG_AUDIO = 0x06; - /** The Frame register. */ - private final static int REG_FRAME = 0x07; - /** The breath register (part 1). */ - private final static int REG_BREATH1 = 0x08; - /** The breath register (part 2). */ - private final static int REG_BREATH2 = 0x09; - /** The shutdown register. */ - private final static int REG_SHUTDOWN = 0x0a; - /** The AGC control register. */ - private final static int REG_AGC_CTL = 0x0b; - /** The AGC rate register. */ - private final static int REG_AGC_RATE = 0x0c; - - /** Base of enable bits. */ - private final static int ENABLE_BASE = 0x00; - /** End of enable bits (+ 1!). */ - private final static int ENABLE_END = ENABLE_BASE + NUM_LEDS / 8; - /** Base of blink bits. */ - private final static int BLINK_BASE = ENABLE_END; - /** End of blink bits (+ 1!). */ - private final static int BLINK_END = BLINK_BASE + NUM_LEDS / 8; - /** Base of PWM data. */ - private final static int PWM_BASE = BLINK_END; - /** End of PWM data (+ 1!). */ - private final static int PWM_END = PWM_BASE + NUM_LEDS; - - /** Length of frame data. */ - private final static int FRAME_LEN = PWM_END; - /** Length of function data. */ - private final static int FUNCTION_LEN = 0x0d; -} diff --git a/Jimbo/Devices/MAX7219.java b/Jimbo/Devices/MAX7219.java deleted file mode 100644 index c208b11..0000000 --- a/Jimbo/Devices/MAX7219.java +++ /dev/null @@ -1,481 +0,0 @@ -/* - * Copyright (C) 2016 Jim Darby. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see - * . - */ - -package Jimbo.Devices; - -import java.io.IOException; - -import com.pi4j.io.spi.SpiChannel; -import com.pi4j.io.spi.SpiDevice; -import com.pi4j.io.spi.SpiFactory; - -/** - * A class to talk to the MAX7219 display multiplexor. - * - * @author Jim Darby - */ -public class MAX7219 -{ - /** - * Constructor for a MAX7219 object. - * - * @param channel The SPI channel it's on. - * @param chained How many of them are chained. - * - * @throws IllegalArgumentException For an invalid argument. - * @throws IOException In case of error. - */ - public MAX7219 (SpiChannel channel, int chained) throws IllegalArgumentException, IOException - { - if (chained < 1) - throw new IllegalArgumentException ("MAX7219 needs at least one device"); - - this.chained = chained; - - // We set 10 MHz (device limit) but in practice it'll be a power of 2 so 8MHz. - dev = SpiFactory.getInstance (channel, 10000000, SpiDevice.DEFAULT_SPI_MODE); - - // Allocate the buffer - buffer = new byte[chained * BYTES_PER_DEV]; - - for (int i = 0; i < buffer.length; ++i) - buffer[i] = 0; - - tx_buffer = new byte[2 * chained]; - } - - /** - * Put a single value into the byte for a specific digit. This version sends - * it to all the displays. - * - * @param digit The digit to update. 0 to 7. - * @param value The byte value put in. - * - * @throws IOException In case of error. - */ - public void writeDigit (byte digit, byte value) throws IOException - { - validateDigit (digit); - - for (int i = 0; i < chained; ++i) - buffer[i * BYTES_PER_DEV + digit] = value; - } - - /** - * Put a single value into the byte for a specific digit on a specific - * device. The devices are numbered from 0 (the first in the chain) to - * the chained parameter passed to the constructor minus 1. - * - * @param device The device number. - * @param digit The digit to update. 0 to 7. - * @param value The byte value put in. - * - * @throws IOException In case of error. - */ - public void writeDigit (int device, byte digit, byte value) throws IOException - { - validateDevice (device); - validateDigit (digit); - - buffer[device * BYTES_PER_DEV + digit] = value; - } - - /** - * Sets the decode mode for all devices. - * - * @param mode The mode. One of DECODE_NONE, DECODE_B_FOR_0, - * DECODE_B_FOR_0_3 or DECODE_B_FOR_0_7. This either puts no decoding in - * (for DECODE_NONE) or maps the bottom four bits for digit 0 - * (DECODE_B_FOR_0), digits 1 to 3 (DECODE_B_FOR_0_3) or all the digits - * (DECODE_B_FOR_0_7). The decode turns the bottom 4 bits into 0 to 9, - * minus, E, H, L, P and blank (in that order). - * - * Does anyone else think someone was trapped in the factory and put the - * HELP in there as a “message in a bottle”? - * - * @throws IOException In case of error. - */ - public void setDecodeMode (byte mode) throws IOException - { - validateMode (mode); - - tx_update (REG_DECODE_MODE, mode); - } - - /** - * Sets the decode mode for a specific device.. - * - * @param device The device to be addressed. This starts at 0 and must be - * less than the total number of devices. - * @param mode The mode. One of DECODE_NONE, DECODE_B_FOR_0, - * DECODE_B_FOR_0_3 or DECODE_B_FOR_0_7. This either puts no decoding in - * (for DECODE_NONE) or maps the bottom four bits for digit 0 - * (DECODE_B_FOR_0), digits 1 to 3 (DECODE_B_FOR_0_3) or all the digits - * (DECODE_B_FOR_0_7). The decode turns the bottom 4 bits into 0 to 9, - * minus, E, H, L, P and blank (in that order). - * - * Does anyone else think someone was trapped in the factory and put the - * HELP in there as a “message in a bottle”? - * - * @throws IOException In case of error. - */ - public void setDecodeMode (int device, byte mode) throws IOException - { - validateDevice (device); - validateMode (mode); - - tx_update (REG_NO_OP, mode, device, REG_DECODE_MODE); - } - - /** - * Set the intensity of the device. - * - * @param intensity The intensity level. It must be in the range 0 to 15. - * - * @throws IOException In case of error. - */ - public void setIntensity (int intensity) throws IOException - { - validateIntensity (intensity); - - tx_update (REG_INTENSITY, (byte) intensity); - } - - /** - * Set the intensity of the device. - * - * @param device The device to be addressed. This starts at 0 and must be - * less than the total number of devices. - * @param intensity The intensity level. It must be in the range 0 to 15. - * - * @throws IOException In case of error. - */ - public void setIntensity (int device, int intensity) throws IOException - { - validateDevice (device); - validateIntensity (intensity); - - tx_update (REG_NO_OP, (byte) intensity, device, REG_INTENSITY); - } - - /** - * Set the scan limit on all devices. The scan limit is the number of - * displays actually used. The value is between 0 and 7 for 1 to 8 displays. - * - * @param limit The limit on the number of displays. - * - * @throws IOException In case of error. - */ - public void setScanLimit (int limit) throws IOException - { - validateDigit (limit); - - tx_update (REG_SCAN_LIMIT, (byte) limit); - } - - /** - * Set the scan limit on a specific device. The scan limit is the number of - * displays actually used. The value is between 0 and 7 for 1 to 8 displays. - * - * @param device The device this applies to. - * @param limit The limit on the number of displays. - * - * @throws IOException In case of error. - */ - public void setScanLimit (int device, int limit) throws IOException - { - validateDevice (device); - validateDigit (limit); - - tx_update (REG_NO_OP, (byte) limit, device, REG_SCAN_LIMIT); - } - - /** - * Set the shutdown status of all devices. - * - * @param active If true the device is shut down. - * - * @throws IOException In case of problems. - */ - public void shutdown (boolean active) throws IOException - { - tx_update (REG_SHUTDOWN, active ? (byte) 0 : (byte) 1); - } - - /** - * Set the shutdown status of a specific device. - * - * @param device The device this applies to. - * @param active If true the device is shut down. - * - * @throws IOException In case of problems. - */ - public void shutdown (int device, boolean active) throws IOException - { - validateDevice (device); - - tx_update (REG_NO_OP, active ? (byte) 0 : (byte) 1, device, REG_SHUTDOWN); - } - - /** - * Set test mode for all displays. This sets all segments of all the - * displays on. - * - * @param active True to engage, false to turn off. - * - * @throws IOException In case of problems. - */ - public void displayTest (boolean active) throws IOException - { - tx_update (REG_DISPLAY_TEST, active ? (byte) 1 : (byte) 0); - } - - /** - * Set test mode for all displays. This sets all segments of the display on. - * - * @param device The device this applies to. - * @param active True to engage, false to turn off. - * - * @throws IOException In case of problems. - */ - public void displayTest (int device, boolean active) throws IOException - { - validateDevice (device); - - tx_update (REG_NO_OP, active ? (byte) 1 : (byte) 0, device, REG_DISPLAY_TEST); - } - - /** - * Send all the display information to the device. This is done in one go to - * avoid excessive use of the bus on update of each digit. - * - * @throws IOException In case of problems. - */ - public void update () throws IOException - { - for (int digit = 0; digit < BYTES_PER_DEV; ++digit) - { - for (int device = 0; device < chained; ++device) - { - final int base = (chained - device - 1) * 2; - tx_buffer[base] = (byte) (REG_DIGIT0 + digit); - tx_buffer[base + 1] = buffer[device * BYTES_PER_DEV + digit]; - } - - dev.write (tx_buffer, 0, tx_buffer.length); - - /*System.out.print ("Buffer"); - - for (int i = 0; i < tx_buffer.length; ++i) - System.out.print (" " + tx_buffer[i]); - - System.out.println ();*/ - } - } - - /** - * Check if the device is valid. - * - * @param device The device ID. Must be in the range 0 ≤ device < chained. - */ - private void validateDevice (int device) - { - if (device < 0 || device >= chained) - throw new IllegalArgumentException ("Invalid device"); - } - - /** - * Check if the digit is valid. - * - * @param digit The digit on the device. Must be in the range 0 ≤ digit < 8. - */ - private void validateDigit (int digit) - { - if (digit < 0 || digit >= BYTES_PER_DEV) - throw new IllegalArgumentException ("Invalid digit"); - } - - /** - * Validate the device mode. It must be one of DECODE_NONE, DECODE_B_FOR_0, - * DECODE_B_FOR_0_3 or DECODE_B_FOR_0_7. - * - * @param mode The device mode. - */ - private void validateMode (int mode) - { - switch (mode) - { - case DECODE_NONE: - case DECODE_B_FOR_0: - case DECODE_B_FOR_0_3: - case DECODE_B_FOR_0_7: - break; - - default: - throw new IllegalArgumentException ("Invalid decode mode"); - } - } - - /** - * Validate the device intensity. It should be in the range 0 ≤ intensity - * < 16. - * - * @param intensity The intensity. - */ - private void validateIntensity (int intensity) - { - if (intensity < 0 || intensity > 0x0f) - throw new IllegalArgumentException ("Invalid intensity"); - } - - /** - * Transmit an update to all controllers. The command and parameter pair is - * sent to each device in the chain. - * - * @param command The command to send. - * @param param The command's parameter. - * - * @throws IOException In case of error. - */ - private void tx_update (byte command, byte param) throws IOException - { - tx_update (command, param, -1, REG_NO_OP); - } - - /** - * Transmit an update to all controllers. The command and parameter pair is - * sent to each device in the chain *except* for except which gets the - * command exception. - * - * @param command The command to send. - * @param param The command's parameter. - * @param except The device that gets a *different* command. - * @param exception What the command to the exception device is. - * - * @throws IOException In case of error. - */ - private void tx_update (byte command, byte param, int except, byte exception) throws IOException - { - for (int i = 0; i < chained; ++i) - { - final int base = (chained - i - 1) * 2; - tx_buffer[base] = (i == except) ? exception : command; - tx_buffer[base + 1] = param; - } - - /*System.out.print ("Buffer"); - - for (int i = 0; i < tx_buffer.length; ++i) - System.out.print (" " + tx_buffer[i]); - - System.out.println ();*/ - - dev.write (tx_buffer, 0, tx_buffer.length); - } - - - public static void main (String args[]) throws IOException, InterruptedException - { - MAX7219 m = new MAX7219 (SpiChannel.CS0, 2); - - m.shutdown (false); - - m.displayTest (true); - Thread.sleep (1000); - m.displayTest (0, false); - - m.setIntensity ((byte) 8); - m.setScanLimit ((byte) 7); - - for (byte digit = 0; digit < 8; ++digit) - m.writeDigit (0, digit, (byte) 0); - - m.setDecodeMode (DECODE_B_FOR_0_7); - - for (byte digit = 0; digit < 8; ++digit) - for (byte value = 0; value < 0x10; ++value) - { - m.writeDigit (0, digit, value); - m.update (); - Thread.sleep (500); - m.writeDigit (0, digit, (byte) 0); - } - - m.setDecodeMode (DECODE_NONE); - - for (byte digit = 0; digit < 8; ++digit) - for (byte bit = 0; bit < 8; ++bit) - { - m.writeDigit (0, digit, (byte) (1 << bit)); - m.update (); - Thread.sleep (500); - m.writeDigit (0, digit, (byte) 0); - } - - m.update (); - } - - /** Number of chained devices. */ - private final int chained; - /** The SPI device we're going to use. */ - private final SpiDevice dev; - /** The buffer that holds all the display information. */ - private final byte[] buffer; - /** The buffer we use to transmit commands. */ - private final byte[] tx_buffer; - - /** No decode mode. The bit maps goes to the segments. */ - public static final byte DECODE_NONE = 0x00; - /** Just decode the first display. */ - public static final byte DECODE_B_FOR_0 = 0x01; - /** Decode displays 0 to 3 and not 4 to 7. */ - public static final byte DECODE_B_FOR_0_3 = 0x0f; - /** Decode all the displays. */ - public static final byte DECODE_B_FOR_0_7 = (byte) 0xff; - - /** The number of bytes per device. Also the number of digits per device. */ - private static final int BYTES_PER_DEV = 8; - /** The NO-OP register. */ - private static final byte REG_NO_OP = 0x0; - /** The register for digit 0. */ - private static final byte REG_DIGIT0 = 0x1; - /** The register for digit 1. */ - private static final byte REG_DIGIT1 = 0x2; - /** The register for digit 2. */ - private static final byte REG_DIGIT2 = 0x3; - /** The register for digit 3. */ - private static final byte REG_DIGIT3 = 0x4; - /** The register for digit 4. */ - private static final byte REG_DIGIT4 = 0x5; - /** The register for digit 5. */ - private static final byte REG_DIGIT5 = 0x6; - /** The register for digit 6. */ - private static final byte REG_DIGIT6 = 0x7; - /** The register for digit 7. */ - private static final byte REG_DIGIT7 = 0x8; - /** The register that controls the decode mode. */ - private static final byte REG_DECODE_MODE = 0x9; - /** The register that controls the intensity. */ - private static final byte REG_INTENSITY = 0xa; - /** The register that controls the scan limit. */ - private static final byte REG_SCAN_LIMIT = 0xb; - /** The register that controls shutdown. */ - private static final byte REG_SHUTDOWN = 0xc; - /** The register that controls the display test. */ - private static final byte REG_DISPLAY_TEST = 0xf; -} diff --git a/Jimbo/Devices/Pi2C.java b/Jimbo/Devices/Pi2C.java deleted file mode 100644 index 6cabe90..0000000 --- a/Jimbo/Devices/Pi2C.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright (C) 2016 Jim Darby. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see - * . - */ - -package Jimbo.Devices; - -import com.pi4j.io.i2c.I2CBus; -import com.pi4j.io.i2c.I2CFactory; -import com.pi4j.system.SystemInfo; - -import java.io.IOException; - -/** - * This class let's us find the right I2C bus to use. It does so by looking at - * the hardware version. Now it can also return the board type, whether it's a - * plus (40 pin) board and if it's the original rev1. - * - * @author Jim Darby - */ -public class Pi2C -{ - /** - * Determine the correct I2C bus to use. - * @return The bus. - * @throws IOException In case of error. - * @throws InterruptedException In case of error. - */ - public static I2CBus useBus () throws IOException, InterruptedException - { - check_board (); - - return bus; - } - - /** - * Determine the board type. - * @return The board type. - * @throws IOException In case of error. - * @throws InterruptedException In case of error. - */ - public static SystemInfo.BoardType boardType () throws IOException, InterruptedException - { - check_board (); - - return type; - } - - /** - * Are we a plus (40-pin) model? - * @return if we are. - * @throws IOException In case of error. - * @throws InterruptedException In case of error. - */ - public static boolean isPlus () throws IOException, InterruptedException - { - check_board (); - - return plus; - } - - /** - * Check the board we're running on and see what we can find. - * @throws IOException In case of problems. - * @throws InterruptedException In case of problems. - */ - private static synchronized void check_board () throws IOException, InterruptedException - { - int use_i2cbus; - type = SystemInfo.getBoardType (); - - switch (type) - { - // What do we know that it's bus 0? This is the most useful as - // we know about all the old boards. - case RaspberryPi_A: - case RaspberryPi_B_Rev1: - // Use the original I2C bus, rev1 and not plus - use_i2cbus = I2CBus.BUS_0; - rev1 = true; - plus = false; - break; - - // What do we *know* that's bus 1? - case RaspberryPi_B_Rev2: - use_i2cbus = I2CBus.BUS_1; - rev1 = false; - plus = false; - break; - - // Now bus 1 and plus (40-pin connector - case RaspberryPi_A_Plus: - case RaspberryPi_B_Plus: - - case RaspberryPi_2B: - case RaspberryPi_3B: - case RaspberryPi_Zero: - case RaspberryPi_ZeroW: - use_i2cbus = I2CBus.BUS_1; - rev1 = false; - plus = true; - break; - - // End up here for uknown Pies - case RaspberryPi_Unknown: - throw new IOException ("Unknown Raspberry Pi model"); - - case UNKNOWN: - // End up here for totally unknown boards - throw new IOException ("Unknown board type"); - - // End up here if we're totally confused - default: - throw new IOException ("Unknown board type with unexpected return value"); - } - - try - { - bus = I2CFactory.getInstance (use_i2cbus); - } - - catch (I2CFactory.UnsupportedBusNumberException e) - { - throw new IOException ("Unable to find correct I2C bus."); - } - - board_looked = true; - } - - /** Holds the bus once we find it */ - private static I2CBus bus = null; - /** Have we looked for the board type? */ - private static boolean board_looked = false; - /** What board type have we found? */ - private static SystemInfo.BoardType type; - /** Are we running on a Plus? */ - private static boolean plus; - /** Are we running on a 1 rev 1? */ - private static boolean rev1; -} diff --git a/Jimbo/Devices/SN3218.java b/Jimbo/Devices/SN3218.java deleted file mode 100644 index 88c0488..0000000 --- a/Jimbo/Devices/SN3218.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (C) 2016 Jim Darby. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - */ -package Jimbo.Devices; - -import java.io.IOException; - -import com.pi4j.io.i2c.I2CBus; -import com.pi4j.io.i2c.I2CDevice; - -/** - * The class interfaces to the Si-EN Technology SN3214 LED driver chip. This - * device is used in many cool devices, not least in things from Pimoroni for - * the Raspberry Pi. - * - * @author Jim Darby - */ -public class SN3218 { - - /** - * Construct a SN3218 driver. - * - * @param bus The bus the device is on. - * @throws IOException In case of problems. - */ - public SN3218 (I2CBus bus) throws IOException - { - // Set the data up. All enabled, all off - - for (int i = 0; i < LEDS; ++i) - data[i] = 0; - - for (int i = 0; i < ENABLES; ++i) - data[LEDS + i] = 0x3f; - - // Tell the device to go. Any value will do but this is in memory of - // Douglas Adams. - data[LEDS + ENABLES] = 42; - - // Allocate device - device = bus.getDevice (0x54); - - // And set everything up - device.write (0, wakeup, 0, wakeup.length); - } - - /** - * Set a single output to a value. - * - * @param led The LED (in the range 0 to 17). - * @param value The value (in the range 0 to 255). - * @throws IOException On an invalid parameter. - */ - public void set (int led, int value) throws IOException - { - if (led < 0 || led >= LEDS) - throw new IOException ("Invalid LED " + led); - - if (value < 0 || value > 255) - throw new IOException ("Invalid level " + value); - - data[led] = (byte) value; - } - - /** - * Set an RGB LED group with three values. The way the device is wired up - * determines the specific groupings. - * - * @param led The LED in the range 0 - 5. - * @param v1 The first value. - * @param v2 The second value. - * @param v3 The third value. - * @throws IOException On an invalid parameter. - */ - public void set (int led, int v1, int v2, int v3) throws IOException - { - if (led < 0 || led >= LEDS / 3) - throw new IOException ("Invalid RGB LED " + led); - - if (v1 < 0 || v1 > 255 || v2 < 0 || v2 > 255 || v3 < 0 || v3 > 255) - throw new IOException ("Invalid colour value"); - - data[led * 3 ] = (byte) v1; - data[led * 3 + 1] = (byte) v2; - data[led * 3 + 2] = (byte) v3; - } - - /** - * Update the display. This sends all the updated value to the LEDs. - * - * @throws IOException In case of an I2C error. - */ - public void update () throws IOException - { - device.write(1, data, 0, data.length); - } - - /** The I2C device. */ - private final I2CDevice device; - /** The number of LEDs. */ - private final static int LEDS = 18; - /** The number of enable bytes. */ - private final static int ENABLES = 3; - /** The number of go bytes. */ - private final static int GOS = 1; - /** The size of the data we hold: 18 values, 3 enables 1 go. */ - private final static int DATA_SIZE = LEDS + ENABLES + GOS; - /** The data we hold for the device. Starts at offset ONE in the device! */ - private final byte[] data = new byte[DATA_SIZE]; - /** Wakeup data. */ - private final byte[] wakeup = { - 0x01, // Wake up the device - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Data part one - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Data part two - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Data part three - 0x3f, 0x3f, 0x3f, // Enable all outputs - 0x42 // And go! - }; -} diff --git a/Jimbo/Devices/WS2811/Makefile b/Jimbo/Devices/WS2811/Makefile deleted file mode 100644 index 6b15db4..0000000 --- a/Jimbo/Devices/WS2811/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -CLASSPATH=/home/pi/NetBeansProjects/PiJava/build/classes -JAVAINC=-I /usr/lib/jvm/jdk-8-oracle-arm32-vfp-hflt/include -I /usr/lib/jvm/jdk-8-oracle-arm32-vfp-hflt/include/linux -RPI_WS281xDIR=/home/pi/rpi_ws281x - -libjavaws2811.so: WS2811.o ${RPI_WS281xDIR}/libws2811.a - gcc -o $@ -shared $^ -lstdc++ - -WS2811.o: WS2811.C Jimbo_Devices_WS2811_WS2811Raw.h ${RPI_WS281xDIR}/ws2811.h - gcc -O -c -g -fpic ${JAVAINC} -I ${RPI_WS281xDIR} WS2811.C - -Jimbo_Devices_WS2811_WS2811Raw.h: - javah -classpath ${CLASSPATH} Jimbo.Devices.WS2811.WS2811Raw - -clean: - rm libjavaws2811.so WS2811.o Jimbo_Devices_WS2811_WS2811Raw.h - -fred: - javah ~/NetBeansProjects/PiJava/build/classes/Jimbo/Devices/WS2812/WS2811Raw - gcc -o libws2811.so -shared WS2811Raw.o Build/rpi_ws281x/libws2811.a -lstdc++ diff --git a/Jimbo/Devices/WS2811/WS2811.C b/Jimbo/Devices/WS2811/WS2811.C deleted file mode 100644 index 69ac3c2..0000000 --- a/Jimbo/Devices/WS2811/WS2811.C +++ /dev/null @@ -1,158 +0,0 @@ -#include -#include - -extern "C" { -#include -} - -#include "Jimbo_Devices_WS2811_WS2811Raw.h" - -namespace -{ - bool in_use (false); - - const int TARGET_FREQ (WS2811_TARGET_FREQ); - const int GPIO_PIN (18); - const int DMA (10); - - ws2811_t leds; -} - -#ifdef __cplusplus -extern "C" { -#endif -/* - * Class: WS2811_WS2811 - * Method: ws2811_init - * Signature: (I)Z - */ -JNIEXPORT jboolean JNICALL Java_Jimbo_Devices_WS2811_WS2811Raw_ws2811_1init - (JNIEnv *env, jclass c, jint type, jint length) -{ - if (in_use) - return JNI_FALSE; - - // std::cout << "In C++ land, type = " << type - // << " length = " << length - // << std::endl; - - leds.freq = TARGET_FREQ; - leds.dmanum = DMA; - leds.channel[0].gpionum = GPIO_PIN; - leds.channel[0].count = length; - leds.channel[0].invert = 0; - leds.channel[0].brightness = 255; - leds.channel[0].strip_type = type; - leds.channel[1].gpionum = 0; - leds.channel[1].count = 0; - leds.channel[1].invert = 0; - leds.channel[1].brightness = 0; - - if (ws2811_init (&leds) != WS2811_SUCCESS) - return JNI_FALSE; - - in_use = true; - - return JNI_TRUE; -} - -/* - * Class: Jimbo_Devices_WS2811_WS2811Raw - * Method: ws2811_brightness - * Signature: (I)Z - */ - -JNIEXPORT jboolean JNICALL Java_Jimbo_Devices_WS2811_WS2811Raw_ws2811_1brightness - (JNIEnv *env, jclass c, jint value) -{ - if (value < 0 || value > 255) - { - std::cerr << "WS2811 brightness set to " << value << std::endl; - return JNI_FALSE; - } - - leds.channel[0].brightness = value; - return JNI_TRUE; -} - -/* - * Class: WS2811_WS2811 - * Method: ws2811_update - * Signature: ([I)Z - */ -JNIEXPORT jboolean JNICALL Java_Jimbo_Devices_WS2811_WS2811Raw_ws2811_1update - (JNIEnv *env, jclass c, jintArray jdata) -{ - if (!in_use) - return JNI_FALSE; - - jboolean copy; - - const jint len = env->GetArrayLength (jdata); - - // std::cout << "Update with " << len << " items" << std::endl; - - if (len != leds.channel[0].count) - return JNI_FALSE; - - jint *raw = env->GetIntArrayElements (jdata, ©); - - // std::cout << "Got the data, copy is " << (int) copy << std::endl; - // std::cout << "Data at " << leds.channel[0].leds << std::endl; - - for (int i = 0; i < len; ++i) - leds.channel[0].leds[i] = raw[i]; - - // std::cout << "Releasing elements" << std::endl; - - env->ReleaseIntArrayElements (jdata, raw, 0); - - // std::cout << "Rendering" << std::endl; - - ws2811_render (&leds); - - // std::cout << "And we're done" << std::endl; - - return JNI_TRUE; -} - -/* - * Class: WS2811_WS2811 - * Method: ws2811_wait - * Signature: ()Z - */ -JNIEXPORT jboolean JNICALL Java_Jimbo_Devices_WS2811_WS2811Raw_ws2811_1wait - (JNIEnv *env, jclass c) -{ - if (!in_use) - return JNI_FALSE; - - // std::cout << "Wait" << std::endl; - - ws2811_wait (&leds); - - return JNI_TRUE; -} - -/* - * Class: WS2811_WS2811 - * Method: ws2811_close - * Signature: ()Z - */ -JNIEXPORT jboolean JNICALL Java_Jimbo_Devices_WS2811_WS2811Raw_ws2811_1close - (JNIEnv *env, jclass c) -{ - const bool result = in_use; - - // std::cout << "That's all folks!" << std::endl; - - in_use = false; - - ws2811_fini (&leds); - - return result; -} - -#ifdef __cplusplus -} -#endif diff --git a/Jimbo/Devices/WS2811/WS2811.java b/Jimbo/Devices/WS2811/WS2811.java deleted file mode 100644 index e185d42..0000000 --- a/Jimbo/Devices/WS2811/WS2811.java +++ /dev/null @@ -1,241 +0,0 @@ -/* - * Copyright (C) 2016-2017 Jim Darby. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - */ - -package Jimbo.Devices.WS2811; - -import Jimbo.Graphics.Mapping; -import Jimbo.Graphics.Point; -import Jimbo.Graphics.Colour; -import Jimbo.Graphics.ColourMatrix; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.InputStream; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.StandardCopyOption; - -/** - * Provide a sensible interface to the WS2811 library. IT tries to - * provide access to the essentials of the underlying C library. - * - * @author Jim Darby - */ -public class WS2811 implements ColourMatrix -{ - /** - * Create an interface to the WS2811 hardware. - * - * @param width The width of the display. - * @param height The height of the display. - * @param map A mapping that takes (0,0) as the lower left and converts it - * into whatever the display actually uses. - * @param type The type of the display. One of WS2811Raw.WS2811_STRIP_RGB, - * SWS2811Raw.W2811_STRIP_RBG, WS2811Raw.WS2811_STRIP_GRB, - * WS2811Raw.WS2811_STRIP_GBR, WS2811Raw.WS2811_STRIP_BRG, - * WS2811Raw.WS2811_STRIP_BGR. - * @param brightness A scaling factor for the brightness: [0.0,1.0]. - */ - public WS2811 (int width, int height, - Mapping map, - int type, - double brightness) - { - if (width <= 0 || height <= 0 || - (type != WS2811Raw.WS2811_STRIP_RGB) && - (type != WS2811Raw.WS2811_STRIP_RBG) && - (type != WS2811Raw.WS2811_STRIP_GRB) && - (type != WS2811Raw.WS2811_STRIP_GBR) && - (type != WS2811Raw.WS2811_STRIP_BRG) && - (type != WS2811Raw.WS2811_STRIP_BGR) || - brightness < 0 || brightness > 1) - throw new IllegalArgumentException ("Invalid parameter to WS2811"); - - i_width = width; - i_height = height; - max = new Point (i_width - 1, i_height - 1); - - final Point out = map.getOutMax (); - - final int o_width = out.getX () + 1; - final int o_height = out.getY () + 1; - - leds = o_width * o_height; - this.map = new int[leds]; - data = new int[leds]; - - for (int y = 0; y < i_height; ++y) - for (int x = 0; x < i_width; ++x) - { - final Point p = map.map (new Point (x, y)); - final int value = p.getX () + o_width * p.getY (); - - this.map[x + i_width * y] = value; - } - - for (int i = 0; i < leds; ++i) - data[i] = 0; - - loadNative (); - - if (!WS2811Raw.ws2811_init (type, leds)) - throw new IllegalArgumentException ("Unable to start WS2811"); - - WS2811Raw.ws2811_brightness ((int) (brightness * 255)); - WS2811Raw.ws2811_update (data); - } - - /** - * Set a specific pixel to a specific RGB value. This works in the - * most efficient way. - * - * @param p The point to set. - * @param r Red value: [0,255]. - * @param g Green value: [0,255]. - * @param b Blue value: [0,255]. - */ - @Override - public void setPixel (Point p, int r, int g, int b) - { - if (!p.inside (max) || - r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255) - throw new IllegalArgumentException ("Invalid parameter to WS2811.setPixel"); - - final int x = p.getX (); - final int y = p.getY (); - - // System.out.println ("pos " + x + ',' + y + " -> " + map[x + i_width * y]); - - data[map[x + i_width * y]] = (r << 16) | (g << 8) | b; - } - - /** - * Set a specific pixel to a specific colour. This is the generic - * interface. - * - * @param p The pixel to set. - * @param c The colour to set. - */ - @Override - public void setPixel (Point p, Colour c) - { - setPixel (p, c.getRed (), c.getGreen (), c.getBlue ()); - } - - /** - * Send the data to the string. - */ - @Override - public void show () - { - WS2811Raw.ws2811_update (data); - } - - /** - * Return a point with the maximum values for X and Y in this - * matrix. - * - * @return The maximum size. - */ - @Override - public Point getMax () - { - return max; - } - - /** - * Shut everything down. - */ - void close () - { - WS2811Raw.ws2811_close (); - } - - /** - * Support routine to load the native library. Very strongly inspired - * by code from the pi4j library itself. - */ - private static void loadNative () - { - if (nativeLoaded) - return; - - try - { - final String path = "/Jimbo/Devices/WS2811/libjavaws2811.so"; - - Path inputPath = Paths.get (path); - - if (!inputPath.isAbsolute ()) - throw new IllegalArgumentException ("The path has to be absolute, but found: " + inputPath); - - final String fileNameFull = inputPath.getFileName ().toString (); - final int dotIndex = fileNameFull.indexOf ('.'); - - if (dotIndex < 0 || dotIndex >= fileNameFull.length () - 1) - throw new IllegalArgumentException ("The path has to end with a file name and extension, but found: " + fileNameFull); - - final String fileName = fileNameFull.substring (0, dotIndex); - final String extension = fileNameFull.substring (dotIndex); - - final Path target = Files.createTempFile (fileName, extension); - final File targetFile = target.toFile (); - - targetFile.deleteOnExit (); - - // System.out.println ("Tempfile at " + target); - - try (InputStream source = WS2811.class.getResourceAsStream (inputPath.toString ())) - { - if (source == null) - throw new FileNotFoundException ("File " + inputPath + " was not found in classpath."); - - Files.copy (source, target, StandardCopyOption.REPLACE_EXISTING); - } - - // Finally, load the library - System.load (target.toAbsolutePath ().toString ()); - } - - catch (Exception | UnsatisfiedLinkError e) - { - System.out.println ("Failed to load native library: " + e); - } - - nativeLoaded = true; - } - - /** The total input width. */ - final private int i_width; - /** The total input height. */ - final private int i_height; - /** A point containing the maximum values for X and Y. */ - final private Point max; - - /** The total number of LEDs (WS2811s to be precise) we have. */ - final private int leds; - - /** The map from input (X,Y) to data (X,Y). */ - final private int[] map; - /** The data of what is on the string (or will be when show is called. */ - final private int[] data; - - /** Have we loaded the native library. */ - private static boolean nativeLoaded = false; -} diff --git a/Jimbo/Devices/WS2811/WS2811Raw.java b/Jimbo/Devices/WS2811/WS2811Raw.java deleted file mode 100644 index 969f082..0000000 --- a/Jimbo/Devices/WS2811/WS2811Raw.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (C) 2017 Jim Darby. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - */ - -package Jimbo.Devices.WS2811; - -/** - * The most basic interface to the native libraries. We try and do as much as - * possible in Java land. - * - * @author Jim Darby - */ - -public class WS2811Raw -{ - /** - * Initialise the system. Only one user may use it at once. - * @param type The type of the string. One of WS2811_STRIP_RGB, - * WS2811_STRIP_RBG, WS2811_STRIP_GRB, WS2811_STRIP_GBR, WS2811_STRIP_BRG - * or WS2811_STRIP_BGR. - * - * @param length the number of units in the string - * - * @return If it worked. - */ - public static native boolean ws2811_init (int type, int length); - - /** - * Set the brightness level. The value is a double in the range 0.0 to 1.0. - * - * @param level The scaling in the range 0 to 255. - * - * @return true if it worked. - */ - public static native boolean ws2811_brightness (int level); - - /** - * Send the data to the string. - * - * @param data An array of ints, one per unit in the string. This must me - * the same length as used for the ws2811_init method. - * - * @return If it worked. - */ - public static native boolean ws2811_update (int[] data); - - /** - * Wait for the DMA to complete. - * - * @return If it worked. - */ - public static native boolean ws2811_wait (); - - /** - * Shut the system down. - * - * @return If it worked. - */ - public static native boolean ws2811_close (); - - public static final int WS2811_STRIP_RGB = 0x100800; - public static final int WS2811_STRIP_RBG = 0x100008; - public static final int WS2811_STRIP_GRB = 0x081000; - public static final int WS2811_STRIP_GBR = 0x080010; - public static final int WS2811_STRIP_BRG = 0x001008; - public static final int WS2811_STRIP_BGR = 0x000810; -} diff --git a/Jimbo/Graphics/BitMatrix.java b/Jimbo/Graphics/BitMatrix.java deleted file mode 100644 index f19e538..0000000 --- a/Jimbo/Graphics/BitMatrix.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2018 Jim Darby. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - */ - -package Jimbo.Graphics; - -/** - * This interface describes a matrix of bit values. - * - * @author Jim Darby - */ -public interface BitMatrix extends Matrix -{ - /** - * Sets a pixel to a specific colour. - * - * @param x The X coordinate of the pixel. - * @param y The Y coordinate of the pixel. - * @param on If the pixel is on. - */ - default public void setPixel (int x, int y, boolean on) - { - setPixel (new Point (x, y), on); - } - - /** - * Clear (blank) a pixel at a specific point. - * - * @param p The pixel to clear. - */ - @Override - default void clearPixel (Point p) - { - setPixel (p, BLACK); - } - - /** The value used to clear a pixel. */ - static final boolean BLACK = false; -} diff --git a/Jimbo/Graphics/BitMatrixDemo.java b/Jimbo/Graphics/BitMatrixDemo.java deleted file mode 100644 index 3f07945..0000000 --- a/Jimbo/Graphics/BitMatrixDemo.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2017 Jim Darby. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library. If not, see - * . - */ - -package Jimbo.Graphics; - -import java.io.IOException; - -/** - * Do a demo on an arbitrary BitMatrix. - * - * @author Jim Darby - */ -public class BitMatrixDemo -{ - /** - * Run the demo given a ColourMatrix. - * - * @param m The ColourMatrix to use. - * - * @throws InterruptedException In case of thread badness. - * @throws java.io.IOException In case of trouble. - */ - public static void run (BitMatrix m) throws InterruptedException, IOException - { - final Point limits = m.getMax (); - final int max_x = limits.getX (); - final int max_y = limits.getY (); - - while (true) - for (int on = 0; on < 2; ++on) - for (int x = 0; x <= max_x; ++x) - for (int y = 0; y <= max_y; ++y) - { - m.setPixel (x, y, on == 0); - m.show (); - Thread.sleep (50); - } - } -} diff --git a/Jimbo/Graphics/Colour.java b/Jimbo/Graphics/Colour.java deleted file mode 100644 index aed1134..0000000 --- a/Jimbo/Graphics/Colour.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (C) 2017 Jim Darby. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - */ - -package Jimbo.Graphics; - -/** - * This class describes a colour. - * - * @author Jim Darby - */ -public class Colour -{ - /** - * Create from red, green and blue values. All in the range 0 to 255. - * If this condition isn't met it will throw an IllegalArgumentException. - * - * @param red The red component. - * @param green The green component. - * @param blue The blue component. - */ - public Colour (int red, int green, int blue) - { - if (red < 0 || red > 255 || - green < 0 || green > 255 || - blue < 0 || blue > 255) - throw new IllegalArgumentException ("Invalid parameter to Colour"); - - this.red = red; - this.green = green; - this.blue = blue; - } - - /** - * Create the colour from an angle (in degrees) in a colour wheel. 0 - * is full red, 120 is full green and 240 is full blue. It must be in the - * range 0 to 360 inclusive. If this condition isn't met it will throw an - * IllegalArgumentException. - * - * @param angle The angle in the range 0 to 360 inclusive. - */ - public Colour (double angle) - { - if (angle >= 0 && angle < 120) - { - red = (int) (255 * (120.0 - angle) / 120.0); - green = 255 - red; - blue = 0; - - return; - } - - if (angle >= 120 && angle < 240) - { - red = 0; - green = (int) (255 * (240.0 - angle) / 120.0); - blue = 255 - green; - - return; - } - - if (angle >= 240 && angle <= 360) - { - green = 0; - blue = (int) (255 * (360.0 - angle) / 120.0); - red = 255 - blue; - - return; - } - - throw new IllegalArgumentException ("Invalid parameter to Colour"); - } - - /** - * Return the red component. - * - * @return The value. - */ - public int getRed () - { - return red; - } - - /** - * Return the green component. - * - * @return The value. - */ - public int getGreen () - { - return green; - } - - /** - * Return the blue component. - * - * @return The value. - */ - public int getBlue () - { - return blue; - } - - /** Where we store the red value. */ - final private int red; - /** Where we store the green value. */ - final private int green; - /** Where we store the blue value. */ - final private int blue; -} diff --git a/Jimbo/Graphics/ColourMatrix.java b/Jimbo/Graphics/ColourMatrix.java deleted file mode 100644 index a17606f..0000000 --- a/Jimbo/Graphics/ColourMatrix.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2018 Jim Darby. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - */ - -package Jimbo.Graphics; - -/** - * This interface describes a matrix of RGB Pixels. - * - * @author Jim Darby - */ -public interface ColourMatrix extends Matrix -{ - /** - * Sets a pixel to a specific colour. - * - * @param p The address of the Pixel. - * @param r The red value: 0 to 255. - * @param g The green value: 0 to 255. - * @param b The blue value: 0 to 255. - */ - default public void setPixel (Point p, int r, int g, int b) - { - setPixel (p, new Colour (r, g, b)); - } - - /** - * Sets a pixel to a specific colour. - * - * @param x The X coordinate of the pixel. - * @param y The Y coordinate of the pixel. - * @param r The red value: 0 to 255. - * @param g The green value: 0 to 255. - * @param b The blue value: 0 to 255. - */ - default public void setPixel (int x, int y, int r, int g, int b) - { - setPixel (new Point (x, y), new Colour (r, g, b)); - } - - /** - * Sets a pixel to a specific colour. - * - * @param x The X coordinate of the pixel. - * @param y The Y coordinate of the pixel. - * @param c The colour to set it to. - */ - default public void setPixel (int x, int y, Colour c) - { - setPixel (new Point (x, y), c); - } - - /** - * Clear (blank) a pixel at a specific point. - * - * @param p The pixel to clear. - */ - @Override - default void clearPixel (Point p) - { - setPixel (p, BLACK); - } - - /** The colour used for clearing a pixel. */ - static final Colour BLACK = new Colour (0, 0, 0); -} diff --git a/Jimbo/Graphics/ColourMatrixDemo.java b/Jimbo/Graphics/ColourMatrixDemo.java deleted file mode 100644 index 13acec9..0000000 --- a/Jimbo/Graphics/ColourMatrixDemo.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (C) 2017 Jim Darby. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - */ - -package Jimbo.Graphics; - -import java.io.IOException; - -/** - * Do a demo on an arbitrary ColourMatrix. - * - * @author Jim Darby - */ -public class ColourMatrixDemo implements Runnable -{ - public ColourMatrixDemo (ColourMatrix m) - { - this.m = m; - } - - @Override - public void run () - { - try - { - run (m); - } - - catch (InterruptedException | IOException e) - { - System.out.println ("ColourMatrixDemo thread got an exception: " + e); - } - } - - /** - * Run the demo given a ColourMatrix. This is a static, non-threaded - * version but is used by the threaded non-static version. - * - * @param m The ColourMatrix to use. - * - * @throws InterruptedException In case of thread badness. - * @throws java.io.IOException In case of trouble. - */ - public static void run (ColourMatrix m) throws InterruptedException, IOException - { - final Point limits = m.getMax (); - final int max_x = limits.getX (); - final int max_y = limits.getY (); - - // Basic scan - - int phase = 0; - - for (int y = 0; y <= max_y; ++y) - for (int x = 0; x <= max_x; ++x) - { - final Point p = new Point (x, y); - m.setPixel (p, - (phase == 0) ? 0x80 : 0x00, - (phase == 1) ? 0x80 : 0x00, - (phase == 2) ? 0x80 : 0x00); - m.show (); - Thread.sleep (250); - m.setPixel (p, 0x00, 0x00, 0x00); - m.show (); - Thread.sleep (50); - - phase = (phase + 1) % 3; - } - - // "I made it rainbow!" TM - - phase = 0; - - final double max_distance = Math.sqrt (max_x * max_x + max_y * max_y); - - while (true) - { - for (int y = 0; y <= limits.getY (); ++y) - for (int x = 0; x <= limits.getX (); ++x) - { - final double distance = Math.sqrt (x*x + y*y); - final double fraction = distance / max_distance; - - double value = 360 * (1 - fraction) + phase; - - if (value > 360) - value -= 360; - - final Colour c = new Colour (value); - - m.setPixel (new Point (x, y), c); - } - - m.show (); - - phase += 1; - - if (phase == 360) - phase = 0; - - Thread.sleep (10); - } - } - - /** The matrix we'll be working on. */ - private final ColourMatrix m; -} diff --git a/Jimbo/Graphics/FlipX.java b/Jimbo/Graphics/FlipX.java deleted file mode 100644 index 5e9db5f..0000000 --- a/Jimbo/Graphics/FlipX.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (C) 2017 Jim Darby. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - */ - -package Jimbo.Graphics; - -/** - * This class flips the X coordinates of a point around. So if the input x - * range is 0 to n the mapped X point will be n - x. The y coordinate remains - * the same. - * - * @author Jim Darby - */ -public class FlipX extends Mapping -{ - /** - * Create a mapping given the width and height of the input. Note that the - * valid X coordinates are from 0 to width - 1 and the valid Y coordinates - * are from 0 to height - 1. - * - * @param width The input width. - * @param height The input height. - */ - public FlipX (int width, int height) - { - super (new Point (width - 1, height - 1)); - } - - /** - * Create a mapping given a previous mapping. The width and height are - * inherited from the previous item. - * - * @param before The previous mapping. - */ - public FlipX (Mapping before) - { - super (before, before.getOutMax ()); - } - - /** - * Perform a mapping. Given a point p at (X,Y) it returns a point with the - * X coordinate reversed (i.e. with X in the range [0,n] it returns n - x. - * Y remains unchanged. - * - * @param p The input point. - * @return The mapped result. - */ - @Override - public Point map (Point p) - { - if (before != null) - p = before.map (p); - - validateIn (p); - - final Point result = new Point (getInMax ().getX () - p.getX (), p.getY ()); - - validateOut (result); - - return result; - } - - /** - * Return a printable form of the mapping. - * - * @return The String representation. - */ - @Override - public String toString () - { - String result = "FlipX from " + getInMax () + " to " + getOutMax (); - - if (before != null) - result = before.toString () + ' ' + result; - - return result; - } -} - diff --git a/Jimbo/Graphics/FlipY.java b/Jimbo/Graphics/FlipY.java deleted file mode 100644 index bc8fad1..0000000 --- a/Jimbo/Graphics/FlipY.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) 2017 Jim Darby. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - */ - -package Jimbo.Graphics; - -/** - * This class flips the Y coordinates of a point around. So if the input y - * range is 0 to n the mapped Y point will be n - y. The X coordinate remains - * the same. - * - * @author Jim Darby - */ -public class FlipY extends Mapping -{ - /** - * Create a mapping given the width and height of the input. Note that the - * valid X coordinates are from 0 to width - 1 and the valid Y coordinates - * are from 0 to height - 1. - * - * @param width The input width. - * @param height The input height. - */ - public FlipY (int width, int height) - { - super (new Point (width - 1, height - 1)); - } - - /** - * Create a mapping given a previous mapping. The width and height are - * inherited from the previous item. - * - * @param before The previous mapping. - */ - public FlipY (Mapping before) - { - super (before, before.getOutMax ()); - } - - /** - * Perform a mapping. Given a point p at (X,Y) it returns a point with the - * Y coordinate reversed (i.e. with Y in the range [0,n] it returns n - y. - * X remains unchanged. - * - * @param p The input point. - * @return The mapped result. - */ - @Override - public Point map (Point p) - { - if (before != null) - p = before.map (p); - - validateIn (p); - - final Point result = new Point (p.getX (), getInMax ().getY () - p.getY ()); - - validateOut (result); - - return result; - } - - /** - * Return a printable form of the mapping. - * - * @return The String representation. - */ - @Override - public String toString () - { - String result = "FlipY from " + getInMax () + " to " + getOutMax (); - - if (before != null) - result = before.toString () + ' ' + result; - - return result; - } -} diff --git a/Jimbo/Graphics/Identity.java b/Jimbo/Graphics/Identity.java deleted file mode 100644 index f1e450c..0000000 --- a/Jimbo/Graphics/Identity.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright (C) 2017 Jim Darby. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - */ - -package Jimbo.Graphics; - -/** - * This class flips the X coordinates of a point around. So if the input x - * range is 0 to n the mapped X point will be n - x. The y coordinate remains - * the same. - * - * @author Jim Darby - */ -public class Identity extends Mapping -{ - /** - * Create a mapping given the width and height of the input. Note that the - * valid X coordinates are from 0 to width - 1 and the valid Y coordinates - * are from 0 to height - 1. - * - * @param width The input width. - * @param height The input height. - */ - public Identity (int width, int height) - { - super (new Point (width - 1, height - 1)); - } - - /** - * Create a mapping given a previous mapping. The width and height are - * inherited from the previous item. - * - * @param before The previous mapping. - */ - public Identity (Mapping before) - { - super (before, before.getOutMax ()); - } - - /** - * Perform a mapping. This performs no actual action on the Point! - * - * @param p The input point. - * @return The mapped result. - */ - @Override - public Point map (Point p) - { - if (before != null) - p = before.map (p); - - validateIn (p); - - final Point result = p; - - validateOut (result); - - return result; - } - - /** - * Return a printable form of the mapping. - * - * @return The String representation. - */ - @Override - public String toString () - { - String result = "Identity from " + getInMax () + " to " + getOutMax (); - - if (before != null) - result = before.toString () + ' ' + result; - - return result; - } -} - diff --git a/Jimbo/Graphics/Mapping.java b/Jimbo/Graphics/Mapping.java deleted file mode 100644 index cb47432..0000000 --- a/Jimbo/Graphics/Mapping.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright (C) 2017 Jim Darby. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - */ -package Jimbo.Graphics; - -/** - * This defines the generic mapping class hierarchy. It takes an input Point - * and produces an output point. - * - * @author Jim Darby - */ -public abstract class Mapping -{ - /** - * Define a mapping where both input and output sizes are the same. - * - * @param inOutMax A point giving the maximum values for X and Y in both - * input and output - */ - public Mapping (Point inOutMax) - { - inMax = inOutMax; - outMax = inOutMax; - before = null; - } - - /** - * Define a mapping where input and output sizes are different. - * - * @param inMax The maximum input size. - * @param outMax The maximum output size. - */ - public Mapping (Point inMax, Point outMax) - { - this.inMax = inMax; - this.outMax = outMax; - before = null; - } - - /** - * Define a mapping where the input size is determined by a previous - * transformation and the output size is given. The previous transformation - * is remembered and performed whenever a mapping is done. - * - * @param before The previous transformation. - * @param outMax The output size. - */ - public Mapping (Mapping before, Point outMax) - { - this.inMax = before.getOutMax (); - this.outMax = outMax; - this.before = before; - } - - /** - * Validate that the input parameter is within the size expected, - * - * @param p The input point. - */ - public void validateIn (Point p) - { - if (p.inside (inMax)) - return; - - throw new IllegalArgumentException ("Input co-ordinate " + p + " outside " + inMax); - } - - /** - * Validate that the output parameter is within the size expected, - * - * @param p The output point. - */ - public void validateOut (Point p) - { - if (p.inside (outMax)) - return; - - throw new IllegalArgumentException ("Output co-ordinate " + p + " outside " + outMax); - } - - /** - * Return the input limit. - * - * @return The input limit. - */ - public Point getInMax () - { - return inMax; - } - - /** - * Return the original input limit. If we have a previous mapping then ask - * that otherwise return ours. - * - * @return The original input limit. - */ - public Point getOriginalMax () - { - return (before == null) ? inMax : before.getOriginalMax (); - } - - /** - * Return the output limit. - * - * @return The output limit. - */ - public Point getOutMax () - { - return outMax; - } - - /** - * Abstract method to perform a mapping. - * - * @param p The point to map. - * @return The mapped value. - */ - abstract public Point map (Point p); - - /** - * Return a printable version of the mapping. - * - * @return A printable String. - */ - @Override - abstract public String toString (); - - /** The input maximum. */ - protected final Point inMax; - /** The output maximum. */ - protected final Point outMax; - /** The previous mapping. */ - protected Mapping before; -} diff --git a/Jimbo/Graphics/Matrix.java b/Jimbo/Graphics/Matrix.java deleted file mode 100644 index 962bd82..0000000 --- a/Jimbo/Graphics/Matrix.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2018 Jim Darby. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - */ - -package Jimbo.Graphics; - -import java.io.IOException; - -/** - * This interface is the top level of the Matrix hierarchy. It just has - * a size on it. - * - * @author Jim Darby - * @param The type of pixel it is - */ -public interface Matrix -{ - /** - * Return a point with the maximum values for X and Y in this - * matrix. - * - * @return The maximum size. - */ - public Point getMax (); - - /** - * Set a pixel to a specific value. - * - * @param p The pixel to set. - * @param value The value to set it to. - */ - void setPixel (Point p, T value); - - /** - * Clear (blank) a pixel at a specific point. - * - * @param p The pixel to clear. - */ - void clearPixel (Point p); - - /** - * Update the display. - * - * @throws java.io.IOException In case of trouble. - */ - public void show () throws IOException; -} diff --git a/Jimbo/Graphics/MonoMatrix.java b/Jimbo/Graphics/MonoMatrix.java deleted file mode 100644 index cc9a44b..0000000 --- a/Jimbo/Graphics/MonoMatrix.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) 2018 Jim Darby. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - */ - -package Jimbo.Graphics; - -/** - * This interface describes a matrix of monochrome Pixels. - * - * @author Jim Darby - */ -public interface MonoMatrix extends Matrix -{ - /** - * Sets a pixel to a specific value. - * - * @param x The X coordinate of the pixel. - * @param y The Y coordinate of the pixel. - * @param value The value to set in the range 0 to 255. - */ - default public void setPixel (int x, int y, int value) - { - setPixel (new Point (x, y), new Integer (value)); - } - - /** - * Sets a pixel to a specific value. - * - * @param p The pixel to set. - * @param value The value to set in the range 0.0 to 1.0. - */ - default public void setPixel (Point p, double value) - { - if (value < 0 || value > 1) - throw new IllegalArgumentException ("Invalid pixel value " + value); - - setPixel (p, new Integer ((int) (value * 255 + 0.5))); - } - - /** - * Sets a pixel to a specific value. - * - * @param x The X coordinate of the pixel. - * @param y The Y coordinate of the pixel. - * @param value The value to set in the range 0.0 to 1.0. - */ - default public void setPixel (int x, int y, double value) - { - if (value < 0 || value > 1) - throw new IllegalArgumentException ("Invalid pixel value " + value); - - setPixel (new Point (x, y), new Integer ((int) (value * 255 + 0.5))); - } - - /** - * Clear (blank) a pixel at a specific point. - * - * @param p The pixel to clear. - */ - @Override - default void clearPixel (Point p) - { - setPixel (p, BLACK); - } - - /** The value used to clear a pixel. */ - static final Integer BLACK = 0; -} diff --git a/Jimbo/Graphics/MonoMatrixDemo.java b/Jimbo/Graphics/MonoMatrixDemo.java deleted file mode 100644 index 81c716f..0000000 --- a/Jimbo/Graphics/MonoMatrixDemo.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (C) 2018 Jim Darby. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - */ - -package Jimbo.Graphics; - -import java.io.IOException; - -/** - * Do a demo on an arbitrary MonoMatrix. - * - * @author Jim Darby - */ -public class MonoMatrixDemo -{ - /** - * Run the demo given a ColourMatrix. - * - * @param m The ColourMatrix to use. - * - * @throws InterruptedException In case of thread badness. - * @throws java.io.IOException In case of trouble. - */ - public static void run (MonoMatrix m) throws InterruptedException, IOException - { - final Point limits = m.getMax (); - final int max_x = limits.getX (); - final int max_y = limits.getY (); - final Double on = new Double (1); - final Double off = new Double (0); - final Clock clock = Clock.isClockable(m) ? new Clock <> (m) : null; - - for (int y = 0; y <= max_y; ++y) - for (int x = 0; x <= max_x; ++x) - { - final Point p = new Point (x, y); - m.setPixel (p, on); - m.show (); - Thread.sleep (50); - m.setPixel (p, off); - m.show (); - } - - final double max_distance = Math.sqrt (max_x * max_x + max_y * max_y); - - int phase = 0; - - while (true) - { - for (int y = 0; y <= max_y; ++y) - for (int x = 0; x <= max_x; ++x) - { - final double distance = Math.sqrt (x*x + y*y); - final double fraction = 1 - distance / max_distance; - final double value = Math.sin ((fraction + phase / 100.0) * 2 * Math.PI); - final Double pixel = 0.5 + 0.5 * value; - final Point p = new Point (x, y); - - m.setPixel (p, pixel); - } - - if (clock != null) - clock.filter(); - - m.show (); - - phase += 1; - - if (phase == 100) - phase = 0; - - Thread.sleep (10); - } - } -} diff --git a/Jimbo/Graphics/Point.java b/Jimbo/Graphics/Point.java deleted file mode 100644 index 1e5b38a..0000000 --- a/Jimbo/Graphics/Point.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (C) 2017 Jim Darby. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - */ - -package Jimbo.Graphics; - -/** - * This class represents a point on the x,y plane. It's held as a purely - * integer point where both x and y are greater then or equal to zero. - * - * @author Jim Darby - */ -public class Point -{ - /** - * Create a point with the given x and y coordinates. Both of these - * must be greater than or equal to zero as they represent a point on a - * display. - * - * @param x The x coordinate. - * @param y The y coordinate. - */ - public Point (int x, int y) - { - if (x < 0 || y < 0) - throw new IllegalArgumentException ("Negative co-ordinate in (" + x + ',' + y + ')'); - - this.x = x; - this.y = y; - } - - /** - * Get the x coordinate. - * - * @return The x coordinate. - */ - public int getX () - { - return x; - } - - /** - * Get the y coordinate. - * - * @return The y coordinate. - */ - public int getY () - { - return y; - } - - /** - * Return the item as a string contain both the x and y coordinates. - * - * @return A string representation. - */ - @Override - public String toString () - { - return "(" + x + ',' + y + ')'; - } - - /** - * Is a given point "inside" this point. This is better defined as the - * points coordinates both being less than or equal to our coordinates. - * - * @param p The point's coordinates. - * @return If the parameter's x and y coordinates are both less than or - * equal to ours. - */ - public boolean inside (Point p) - { - return x <= p.x && y <= p.y; - } - - /** Our x coordinate. */ - private final int x; - /** Our y coordinate. */ - private final int y; -} diff --git a/Jimbo/Graphics/Snake.java b/Jimbo/Graphics/Snake.java deleted file mode 100644 index a549511..0000000 --- a/Jimbo/Graphics/Snake.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (C) 2017 Jim Darby. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - */ - -package Jimbo.Graphics; - -/** - * The class performs a "snake" mapping of a point. This is very useful when - * the wiring of pixels is a little "unusual". It flips the X value but only on - * alternate lines. This allows a layout such as: - * - * 15 14 13 12 - * 08 09 10 11 - * 07 06 05 04 - * 00 01 02 03 - * - * @author Jim Darby. - */ -public class Snake extends Mapping -{ - /** - * Create a mapping given the width and height of the input. Note that the - * valid X coordinates are from 0 to width - 1 and the valid Y coordinates - * are from 0 to height - 1. - * - * @param width The input width. - * @param height The input height. - */ - public Snake (int width, int height) - { - super (new Point (width - 1, height - 1)); - } - - /** - * Create a mapping given a previous mapping. The width and height are - * inherited from the previous item. - * - * @param before The previous mapping. - */ - public Snake (Mapping before) - { - super (before, before.getOutMax ()); - } - - /** - * Perform a mapping. The flips odd numbered X lines. - * - * @param p The input point. - * @return The mapped result. - */ - @Override - public Point map (Point p) - { - if (before != null) - p = before.map (p); - - validateIn (p); - - final Point result = ((p.getY () & 1) != 0) ? new Point (getInMax ().getX () - p.getX (), p.getY ()) : p; - - validateOut (result); - - return result; - } - - /** - * Return a printable form of the mapping. - * - * @return The String representation. - */ - @Override - public String toString () - { - String result = "Snake from " + getInMax () + " to " + getOutMax (); - - if (before != null) - result = before.toString () + ' ' + result; - - return result; - } -} - diff --git a/Jimbo/Graphics/SwapXY.java b/Jimbo/Graphics/SwapXY.java deleted file mode 100644 index 25e6c6a..0000000 --- a/Jimbo/Graphics/SwapXY.java +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (C) 2017 Jim Darby. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, see - * . - */ - -package Jimbo.Graphics; - -/** - * This class swaps the X and Y coordinates over. - * - * So: - * - * 04 05 06 07 - * 00 01 02 03 - * - * becomes: - * - * 03 07 - * 02 06 - * 01 05 - * 00 04 - * - * @author Jim Darby. - */ -public class SwapXY extends Mapping -{ - /** - * Create a mapping given the width and height of the input. Note that the - * valid X coordinates are from 0 to width - 1 and the valid Y coordinates - * are from 0 to height - 1. - * - * @param width The input width. - * @param height The input height. - */ - public SwapXY (int width, int height) - { - super (new Point (width - 1, height - 1), new Point (height - 1, width - 1)); - } - - /** - * Create a mapping given a previous mapping. The width and height are - * inherited from the previous item. - * - * @param before The previous mapping. - */ - public SwapXY (Mapping before) - { - super (before, new Point (before.getOutMax ().getY (), before.getOutMax ().getX ())); - } - - /** - * Perform a mapping. This swaps the X and Y values over. - * - * @param p The input point. - * @return The mapped result. - */ - @Override - public Point map (Point p) - { - if (before != null) - p = before.map (p); - - validateIn (p); - - final Point result = new Point (p.getY (), p.getX ()); - - validateOut (result); - - return result; - } - - /** - * Return a printable form of the mapping. - * - * @return The String representation. - */ - @Override - public String toString () - { - String result = "SwapXY in " + getInMax () + " out " + getOutMax (); - - if (before != null) - result = before.toString () + ' ' + result; - - return result; - } -} diff --git a/Jimbo/Logging/Logging.java b/Jimbo/Logging/Logging.java deleted file mode 100644 index f0858dd..0000000 --- a/Jimbo/Logging/Logging.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (C) 2016 Jim Darby. - * - * This software is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this software; if not, If not, see - * . - */ - -package Jimbo.Logging; - -import java.util.logging.Logger; -import java.util.logging.Handler; -import java.util.logging.LogRecord; - -import java.text.MessageFormat; - -import java.time.Instant; -import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; -import java.time.ZoneOffset; -import java.time.ZoneId; -import java.time.temporal.ChronoUnit; -import java.util.logging.Level; - -/** - * Some useful stuff to customise logging for us. - * - * @author Jim Darby - */ -public class Logging -{ - public static void useStdout () - { - // Find the root logger - final Logger root_logger = Logger.getLogger (""); - - // Now kill off all the other handlers. - - Handler[] handlers = root_logger.getHandlers(); - - for (Handler handler : handlers) - root_logger.removeHandler (handler); - - // And insert ours. - root_logger.addHandler (new Reporter ()); - } - - /** - * Our own logging record handler class. Essentially just timestamps - * the record and then sends it to stdout. - */ - private static class Reporter extends Handler - { - /** - * Actually process a log record. - * - * @param r The log record to process. - */ - @Override - public void publish(LogRecord r) - { - // Extract raw message from the record - String text = r.getMessage (); - - // The message can be null, if so ignore it. - if (text == null) - return; - - final Object[] parameters = r.getParameters(); - - // Do we need to format the message? Thanks to Brenton for finding this - // algorithm. For full details see: - // https://docs.oracle.com/javase/8/docs/api/java/util/logging/Formatter.html#formatMessage-java.util.logging.LogRecord- - if (parameters != null && parameters.length != 0 && text.contains ("{0")) - text = new MessageFormat (text).format (parameters); - - final Instant instant = Instant.ofEpochMilli (r.getMillis()).truncatedTo (ChronoUnit.SECONDS); - final ZoneId zone = ZoneOffset.systemDefault (); - final LocalDateTime stamp = LocalDateTime.ofInstant (instant, zone); - final String when = stamp.format (DateTimeFormatter.ISO_LOCAL_DATE_TIME); - - System.out.println ("[" + when + "] " + text); - - /*System.out.println ("Logging record:"); - System.out.println (" Time: " + when); - System.out.println (" Level: " + r.getLevel()); - System.out.println (" Name: " + r.getLoggerName ()); - System.out.println (" Formatted: " + text); - System.out.println ();*/ - } - - @Override - public void flush() - { - } - - @Override - public void close() throws SecurityException - { - } - } - - public static void main (String args[]) - { - useStdout (); - - final Logger LOG = Logger.getLogger ("Test logger"); - - LOG.info ("Testing"); - - for (String s : args) - LOG.log (Level.INFO, "{0}", s); - } -} diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/README.md b/README.md deleted file mode 100644 index feea6ac..0000000 --- a/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# PiJava - -This is where I hold my Pi-specific Java work. diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..e61918c --- /dev/null +++ b/build.gradle @@ -0,0 +1,27 @@ +apply plugin: 'java-library' +version = 1.0 + +sourceCompatibility = targetCompatibility = 1.8 //same as pi4j + +repositories { + maven { url 'https://oss.sonatype.org/content/groups/public' } +} + +dependencies { + api 'com.pi4j:pi4j-core:1.2-SNAPSHOT' +} + +jar { + manifest { + attributes "Automatic-Module-Name": "com.github.jimbo.pijava.blinkt" + } +} + +task sourcesJar(type: Jar, dependsOn: classes) { + classifier = 'sources' + from sourceSets.main.allSource +} + +artifacts { + archives sourcesJar +} diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..91ca28c8b802289c3a438766657a5e98f20eff03 GIT binary patch literal 54413 zcmafaV|Zr4wq`oEZQHiZj%|LijZQlLf{tz5M#r{o+fI6V=G-$g=gzrzeyqLskF}nv zRZs0&c;EUi2L_G~0s;*U0szbK}f6%Pvi zRZ#mYf6f1oqJoH`jHHCB8l!^by~4z}yc`4LEP@;Z?bO6{g9`Hk+s@(L1jC5Tq{1Yf z4E;CQvrx0-gF+peRxFC*gF=&$zNYk(w0q}U=WqXMz`tYs@0o%B{dRD+{C_6(f9t^g zhmNJQv6-#;f2)f2uc{u-#*U8W&i{|ewYN^n_1~cv|1J!}zc&$eaBy{T{cEpa46s*q zHFkD2cV;xTHFj}{*3kBt*FgS4A5SI|$F%$gB@It9FlC}D3y`sbZG{2P6gGwC$U`6O zb_cId9AhQl#A<&=x>-xDD%=Ppt$;y71@Lwsl{x943#T@8*?cbR<~d`@@}4V${+r$jICUIOzgZJy_9I zu*eA(F)$~J07zX%tmQN}1^wj+RM|9bbwhQA=xrPE*{vB_P!pPYT5{Or^m*;Qz#@Bl zRywCG_RDyM6bf~=xn}FtiFAw|rrUxa1+z^H`j6e|GwKDuq}P)z&@J>MEhsVBvnF|O zOEm)dADU1wi8~mX(j_8`DwMT_OUAnjbWYer;P*^Uku_qMu3}qJU zTAkza-K9aj&wcsGuhQ>RQoD?gz~L8RwCHOZDzhBD$az*$TQ3!uygnx_rsXG`#_x5t zn*lb(%JI3%G^MpYp-Y(KI4@_!&kBRa3q z|Fzn&3R%ZsoMNEn4pN3-BSw2S_{IB8RzRv(eQ1X zyBQZHJ<(~PfUZ~EoI!Aj`9k<+Cy z2DtI<+9sXQu!6&-Sk4SW3oz}?Q~mFvy(urUy<)x!KQ>#7yIPC)(ORhKl7k)4eSy~} z7#H3KG<|lt68$tk^`=yjev%^usOfpQ#+Tqyx|b#dVA(>fPlGuS@9ydo z!Cs#hse9nUETfGX-7lg;F>9)+ml@M8OO^q|W~NiysX2N|2dH>qj%NM`=*d3GvES_# zyLEHw&1Fx<-dYxCQbk_wk^CI?W44%Q9!!9aJKZW-bGVhK?N;q`+Cgc*WqyXcxZ%U5QXKu!Xn)u_dxeQ z;uw9Vysk!3OFzUmVoe)qt3ifPin0h25TU zrG*03L~0|aaBg7^YPEW^Yq3>mSNQgk-o^CEH?wXZ^QiPiuH}jGk;75PUMNquJjm$3 zLcXN*uDRf$Jukqg3;046b;3s8zkxa_6yAlG{+7{81O3w96i_A$KcJhD&+oz1<>?lun#C3+X0q zO4JxN{qZ!e#FCl@e_3G?0I^$CX6e$cy7$BL#4<`AA)Lw+k`^15pmb-447~5lkSMZ` z>Ce|adKhb-F%yy!vx>yQbXFgHyl(an=x^zi(!-~|k;G1=E(e@JgqbAF{;nv`3i)oi zDeT*Q+Mp{+NkURoabYb9@#Bi5FMQnBFEU?H{~9c;g3K%m{+^hNe}(MdpPb?j9`?2l z#%AO!|2QxGq7-2Jn2|%atvGb(+?j&lmP509i5y87`9*BSY++<%%DXb)kaqG0(4Eft zj|2!Od~2TfVTi^0dazAIeVe&b#{J4DjN6;4W;M{yWj7#+oLhJyqeRaO;>?%mX>Ec{Mp~;`bo}p;`)@5dA8fNQ38FyMf;wUPOdZS{U*8SN6xa z-kq3>*Zos!2`FMA7qjhw-`^3ci%c91Lh`;h{qX1r;x1}eW2hYaE*3lTk4GwenoxQ1kHt1Lw!*N8Z%DdZSGg5~Bw}+L!1#d$u+S=Bzo7gi zqGsBV29i)Jw(vix>De)H&PC; z-t2OX_ak#~eSJ?Xq=q9A#0oaP*dO7*MqV;dJv|aUG00UX=cIhdaet|YEIhv6AUuyM zH1h7fK9-AV)k8sr#POIhl+?Z^r?wI^GE)ZI=H!WR<|UI(3_YUaD#TYV$Fxd015^mT zpy&#-IK>ahfBlJm-J(n(A%cKV;)8&Y{P!E|AHPtRHk=XqvYUX?+9po4B$0-6t74UUef${01V{QLEE8gzw* z5nFnvJ|T4dlRiW9;Ed_yB{R@)fC=zo4hCtD?TPW*WJmMXYxN_&@YQYg zBQ$XRHa&EE;YJrS{bn7q?}Y&DH*h;){5MmE(9A6aSU|W?{3Ox%5fHLFScv7O-txuRbPG1KQtI`Oay=IcEG=+hPhlnYC;`wSHeo|XGio0aTS6&W($E$ z?N&?TK*l8;Y^-xPl-WVZwrfdiQv10KdsAb9u-*1co*0-Z(h#H)k{Vc5CT!708cs%sExvPC+7-^UY~jTfFq=cj z!Dmy<+NtKp&}}$}rD{l?%MwHdpE(cPCd;-QFPk1`E5EVNY2i6E`;^aBlx4}h*l42z zpY#2cYzC1l6EDrOY*ccb%kP;k8LHE3tP>l3iK?XZ%FI<3666yPw1rM%>eCgnv^JS_ zK7c~;g7yXt9fz@(49}Dj7VO%+P!eEm& z;z8UXs%NsQ%@2S5nve)@;yT^61BpVlc}=+i6{ZZ9r7<({yUYqe==9*Z+HguP3`sA& z{`inI4G)eLieUQ*pH9M@)u7yVnWTQva;|xq&-B<>MoP(|xP(HqeCk1&h>DHNLT>Zi zQ$uH%s6GoPAi0~)sC;`;ngsk+StYL9NFzhFEoT&Hzfma1f|tEnL0 zMWdX4(@Y*?*tM2@H<#^_l}BC&;PYJl%~E#veQ61{wG6!~nyop<^e)scV5#VkGjYc2 z$u)AW-NmMm%T7WschOnQ!Hbbw&?`oMZrJ&%dVlN3VNra1d0TKfbOz{dHfrCmJ2Jj= zS#Gr}JQcVD?S9X!u|oQ7LZ+qcq{$40 ziG5=X^+WqeqxU00YuftU7o;db=K+Tq!y^daCZgQ)O=M} zK>j*<3oxs=Rcr&W2h%w?0Cn3);~vqG>JO_tTOzuom^g&^vzlEjkx>Sv!@NNX%_C!v zaMpB>%yVb}&ND9b*O>?HxQ$5-%@xMGe4XKjWh7X>CYoRI2^JIwi&3Q5UM)?G^k8;8 zmY$u;(KjZx>vb3fe2zgD7V;T2_|1KZQW$Yq%y5Ioxmna9#xktcgVitv7Sb3SlLd6D zfmBM9Vs4rt1s0M}c_&%iP5O{Dnyp|g1(cLYz^qLqTfN6`+o}59Zlu%~oR3Q3?{Bnr zkx+wTpeag^G12fb_%SghFcl|p2~<)Av?Agumf@v7y-)ecVs`US=q~=QG%(_RTsqQi z%B&JdbOBOmoywgDW|DKR5>l$1^FPhxsBrja<&}*pfvE|5dQ7j-wV|ur%QUCRCzBR3q*X`05O3U@?#$<>@e+Zh&Z&`KfuM!0XL& zI$gc@ZpM4o>d&5)mg7+-Mmp98K^b*28(|Ew8kW}XEV7k^vnX-$onm9OtaO@NU9a|as7iA%5Wrw9*%UtJYacltplA5}gx^YQM` zVkn`TIw~avq)mIQO0F0xg)w$c)=8~6Jl|gdqnO6<5XD)&e7z7ypd3HOIR+ss0ikSVrWar?548HFQ*+hC)NPCq*;cG#B$7 z!n?{e9`&Nh-y}v=nK&PR>PFdut*q&i81Id`Z<0vXUPEbbJ|<~_D!)DJMqSF~ly$tN zygoa)um~xdYT<7%%m!K8+V(&%83{758b0}`b&=`))Tuv_)OL6pf=XOdFk&Mfx9y{! z6nL>V?t=#eFfM$GgGT8DgbGRCF@0ZcWaNs_#yl+6&sK~(JFwJmN-aHX{#Xkpmg;!} zgNyYYrtZdLzW1tN#QZAh!z5>h|At3m+ryJ-DFl%V>w?cmVTxt^DsCi1ZwPaCe*D{) z?#AZV6Debz{*D#C2>44Czy^yT3y92AYDcIXtZrK{L-XacVl$4i=X2|K=Fy5vAzhk{ zu3qG=qSb_YYh^HirWf~n!_Hn;TwV8FU9H8+=BO)XVFV`nt)b>5yACVr!b98QlLOBDY=^KS<*m9@_h3;64VhBQzb_QI)gbM zSDto2i*iFrvxSmAIrePB3i`Ib>LdM8wXq8(R{-)P6DjUi{2;?}9S7l7bND4w%L2!; zUh~sJ(?Yp}o!q6)2CwG*mgUUWlZ;xJZo`U`tiqa)H4j>QVC_dE7ha0)nP5mWGB268 zn~MVG<#fP#R%F=Ic@(&Va4dMk$ysM$^Avr1&hS!p=-7F>UMzd(M^N9Ijb|364}qcj zcIIh7suk$fQE3?Z^W4XKIPh~|+3(@{8*dSo&+Kr(J4^VtC{z*_{2}ld<`+mDE2)S| zQ}G#Q0@ffZCw!%ZGc@kNoMIdQ?1db%N1O0{IPPesUHI;(h8I}ETudk5ESK#boZgln z(0kvE`&6z1xH!s&={%wQe;{^&5e@N0s7IqR?L*x%iXM_czI5R1aU?!bA7)#c4UN2u zc_LZU+@elD5iZ=4*X&8%7~mA;SA$SJ-8q^tL6y)d150iM)!-ry@TI<=cnS#$kJAS# zq%eK**T*Wi2OlJ#w+d_}4=VN^A%1O+{?`BK00wkm)g8;u?vM;RR+F1G?}({ENT3i= zQsjJkp-dmJ&3-jMNo)wrz0!g*1z!V7D(StmL(A}gr^H-CZ~G9u?*Uhcx|x7rb`v^X z9~QGx;wdF4VcxCmEBp$F#sms@MR?CF67)rlpMxvwhEZLgp2?wQq|ci#rLtrYRV~iR zN?UrkDDTu114&d~Utjcyh#tXE_1x%!dY?G>qb81pWWH)Ku@Kxbnq0=zL#x@sCB(gs zm}COI(!{6-XO5li0>1n}Wz?w7AT-Sp+=NQ1aV@fM$`PGZjs*L+H^EW&s!XafStI!S zzgdntht=*p#R*o8-ZiSb5zf6z?TZr$^BtmIfGAGK;cdg=EyEG)fc*E<*T=#a?l=R5 zv#J;6C(umoSfc)W*EODW4z6czg3tXIm?x8{+8i^b;$|w~k)KLhJQnNW7kWXcR^sol z1GYOp?)a+}9Dg*nJ4fy*_riThdkbHO37^csfZRGN;CvQOtRacu6uoh^gg%_oEZKDd z?X_k67s$`|Q&huidfEonytrq!wOg07H&z@`&BU6D114p!rtT2|iukF}>k?71-3Hk< zs6yvmsMRO%KBQ44X4_FEYW~$yx@Y9tKrQ|rC1%W$6w}-9!2%4Zk%NycTzCB=nb)r6*92_Dg+c0;a%l1 zsJ$X)iyYR2iSh|%pIzYV1OUWER&np{w1+RXb~ zMUMRymjAw*{M)UtbT)T!kq5ZAn%n=gq3ssk3mYViE^$paZ;c^7{vXDJ`)q<}QKd2?{r9`X3mpZ{AW^UaRe2^wWxIZ$tuyKzp#!X-hXkHwfD zj@2tA--vFi3o_6B?|I%uwD~emwn0a z+?2Lc1xs(`H{Xu>IHXpz=@-84uw%dNV;{|c&ub|nFz(=W-t4|MME(dE4tZQi?0CE|4_?O_dyZj1)r zBcqB8I^Lt*#)ABdw#yq{OtNgf240Jvjm8^zdSf40 z;H)cp*rj>WhGSy|RC5A@mwnmQ`y4{O*SJ&S@UFbvLWyPdh)QnM=(+m3p;0&$^ysbZ zJt!ZkNQ%3hOY*sF2_~-*`aP|3Jq7_<18PX*MEUH*)t{eIx%#ibC|d&^L5FwoBN}Oe z?!)9RS@Zz%X1mqpHgym75{_BM4g)k1!L{$r4(2kL<#Oh$Ei7koqoccI3(MN1+6cDJ zp=xQhmilz1?+ZjkX%kfn4{_6K_D{wb~rdbkh!!k!Z@cE z^&jz55*QtsuNSlGPrU=R?}{*_8?4L7(+?>?(^3Ss)f!ou&{6<9QgH>#2$?-HfmDPN z6oIJ$lRbDZb)h-fFEm^1-v?Slb8udG{7GhbaGD_JJ8a9f{6{TqQN;m@$&)t81k77A z?{{)61za|e2GEq2)-OqcEjP`fhIlUs_Es-dfgX-3{S08g`w=wGj2{?`k^GD8d$}6Z zBT0T1lNw~fuwjO5BurKM593NGYGWAK%UCYiq{$p^GoYz^Uq0$YQ$j5CBXyog8(p_E znTC+$D`*^PFNc3Ih3b!2Lu|OOH6@46D)bbvaZHy%-9=$cz}V^|VPBpmPB6Ivzlu&c zPq6s7(2c4=1M;xlr}bkSmo9P`DAF>?Y*K%VPsY`cVZ{mN&0I=jagJ?GA!I;R)i&@{ z0Gl^%TLf_N`)`WKs?zlWolWvEM_?{vVyo(!taG$`FH2bqB`(o50pA=W34kl-qI62lt z1~4LG_j%sR2tBFteI{&mOTRVU7AH>>-4ZCD_p6;-J<=qrod`YFBwJz(Siu(`S}&}1 z6&OVJS@(O!=HKr-Xyzuhi;swJYK*ums~y1ePdX#~*04=b9)UqHHg;*XJOxnS6XK#j zG|O$>^2eW2ZVczP8#$C`EpcWwPFX4^}$omn{;P(fL z>J~%-r5}*D3$Kii z34r@JmMW2XEa~UV{bYP=F;Y5=9miJ+Jw6tjkR+cUD5+5TuKI`mSnEaYE2=usXNBs9 zac}V13%|q&Yg6**?H9D620qj62dM+&&1&a{NjF}JqmIP1I1RGppZ|oIfR}l1>itC% zl>ed${{_}8^}m2^br*AIX$L!Vc?Sm@H^=|LnpJg`a7EC+B;)j#9#tx-o0_e4!F5-4 zF4gA;#>*qrpow9W%tBzQ89U6hZ9g=-$gQpCh6Nv_I0X7t=th2ajJ8dBbh{i)Ok4{I z`Gacpl?N$LjC$tp&}7Sm(?A;;Nb0>rAWPN~@3sZ~0_j5bR+dz;Qs|R|k%LdreS3Nn zp*36^t#&ASm=jT)PIjNqaSe4mTjAzlAFr*@nQ~F+Xdh$VjHWZMKaI+s#FF#zjx)BJ zufxkW_JQcPcHa9PviuAu$lhwPR{R{7CzMUi49=MaOA%ElpK;A)6Sgsl7lw)D$8FwE zi(O6g;m*86kcJQ{KIT-Rv&cbv_SY4 zpm1|lSL*o_1LGOlBK0KuU2?vWcEcQ6f4;&K=&?|f`~X+s8H)se?|~2HcJo{M?Ity) zE9U!EKGz2^NgB6Ud;?GcV*1xC^1RYIp&0fr;DrqWLi_Kts()-#&3|wz{wFQsKfnnsC||T?oIgUp z{O(?Df7&vW!i#_~*@naguLLjDAz+)~*_xV2iz2?(N|0y8DMneikrT*dG`mu6vdK`% z=&nX5{F-V!Reau}+w_V3)4?}h@A@O)6GCY7eXC{p-5~p8x{cH=hNR;Sb{*XloSZ_%0ZKYG=w<|!vy?spR4!6mF!sXMUB5S9o_lh^g0!=2m55hGR; z-&*BZ*&;YSo474=SAM!WzrvjmNtq17L`kxbrZ8RN419e=5CiQ-bP1j-C#@@-&5*(8 zRQdU~+e(teUf}I3tu%PB1@Tr{r=?@0KOi3+Dy8}+y#bvgeY(FdN!!`Kb>-nM;7u=6 z;0yBwOJ6OdWn0gnuM{0`*fd=C(f8ASnH5aNYJjpbY1apTAY$-%)uDi$%2)lpH=#)=HH z<9JaYwPKil@QbfGOWvJ?cN6RPBr`f+jBC|-dO|W@x_Vv~)bmY(U(!cs6cnhe0z31O z>yTtL4@KJ*ac85u9|=LFST22~!lb>n7IeHs)_(P_gU}|8G>{D_fJX)8BJ;Se? z67QTTlTzZykb^4!{xF!=C}VeFd@n!9E)JAK4|vWVwWop5vSWcD<;2!88v-lS&ve7C zuYRH^85#hGKX(Mrk};f$j_V&`Nb}MZy1mmfz(e`nnI4Vpq(R}26pZx?fq%^|(n~>* z5a5OFtFJJfrZmgjyHbj1`9||Yp?~`p2?4NCwu_!!*4w8K`&G7U_|np&g7oY*-i;sI zu)~kYH;FddS{7Ri#Z5)U&X3h1$Mj{{yk1Q6bh4!7!)r&rqO6K~{afz@bis?*a56i& zxi#(Ss6tkU5hDQJ0{4sKfM*ah0f$>WvuRL zunQ-eOqa3&(rv4kiQ(N4`FO6w+nko_HggKFWx@5aYr}<~8wuEbD(Icvyl~9QL^MBt zSvD)*C#{2}!Z55k1ukV$kcJLtW2d~%z$t0qMe(%2qG`iF9K_Gsae7OO%Tf8E>ooch ztAw01`WVv6?*14e1w%Wovtj7jz_)4bGAqqo zvTD|B4)Ls8x7-yr6%tYp)A7|A)x{WcI&|&DTQR&2ir(KGR7~_RhNOft)wS<+vQ*|sf;d>s zEfl&B^*ZJp$|N`w**cXOza8(ARhJT{O3np#OlfxP9Nnle4Sto)Fv{w6ifKIN^f1qO*m8+MOgA1^Du!=(@MAh8)@wU8t=Ymh!iuT_lzfm za~xEazL-0xwy9$48!+?^lBwMV{!Gx)N>}CDi?Jwax^YX@_bxl*+4itP;DrTswv~n{ zZ0P>@EB({J9ZJ(^|ptn4ks^Z2UI&87d~J_^z0&vD2yb%*H^AE!w= zm&FiH*c%vvm{v&i3S>_hacFH${|(2+q!`X~zn4$aJDAry>=n|{C7le(0a)nyV{kAD zlud4-6X>1@-XZd`3SKKHm*XNn_zCyKHmf*`C_O509$iy$Wj`Sm3y?nWLCDy>MUx1x zl-sz7^{m(&NUk*%_0(G^>wLDnXW90FzNi$Tu6* z<+{ePBD`%IByu977rI^x;gO5M)Tfa-l*A2mU-#IL2?+NXK-?np<&2rlF;5kaGGrx2 zy8Xrz`kHtTVlSSlC=nlV4_oCsbwyVHG4@Adb6RWzd|Otr!LU=% zEjM5sZ#Ib4#jF(l!)8Na%$5VK#tzS>=05GpV?&o* z3goH1co0YR=)98rPJ~PuHvkA59KUi#i(Mq_$rApn1o&n1mUuZfFLjx@3;h`0^|S##QiTP8rD`r8P+#D@gvDJh>amMIl065I)PxT6Hg(lJ?X7*|XF2Le zv36p8dWHCo)f#C&(|@i1RAag->5ch8TY!LJ3(+KBmLxyMA%8*X%_ARR*!$AL66nF= z=D}uH)D)dKGZ5AG)8N-;Il*-QJ&d8u30&$_Q0n1B58S0ykyDAyGa+BZ>FkiOHm1*& zNOVH;#>Hg5p?3f(7#q*dL74;$4!t?a#6cfy#}9H3IFGiCmevir5@zXQj6~)@zYrWZ zRl*e66rjwksx-)Flr|Kzd#Bg>We+a&E{h7bKSae9P~ z(g|zuXmZ zD?R*MlmoZ##+0c|cJ(O{*h(JtRdA#lChYhfsx25(Z`@AK?Q-S8_PQqk z>|Z@Ki1=wL1_c6giS%E4YVYD|Y-{^ZzFwB*yN8-4#+TxeQ`jhks7|SBu7X|g=!_XL z`mY=0^chZfXm%2DYHJ4z#soO7=NONxn^K3WX={dV>$CTWSZe@<81-8DVtJEw#Uhd3 zxZx+($6%4a&y_rD8a&E`4$pD6-_zZJ%LEE*1|!9uOm!kYXW< zOBXZAowsX-&$5C`xgWkC43GcnY)UQt2Qkib4!!8Mh-Q!_M%5{EC=Gim@_;0+lP%O^ zG~Q$QmatQk{Mu&l{q~#kOD;T-{b1P5u7)o-QPPnqi?7~5?7%IIFKdj{;3~Hu#iS|j z)Zoo2wjf%+rRj?vzWz(6JU`=7H}WxLF*|?WE)ci7aK?SCmd}pMW<{#1Z!_7BmVP{w zSrG>?t}yNyCR%ZFP?;}e8_ zRy67~&u11TN4UlopWGj6IokS{vB!v!n~TJYD6k?~XQkpiPMUGLG2j;lh>Eb5bLTkX zx>CZlXdoJsiPx=E48a4Fkla>8dZYB%^;Xkd(BZK$z3J&@({A`aspC6$qnK`BWL;*O z-nRF{XRS`3Y&b+}G&|pE1K-Ll_NpT!%4@7~l=-TtYRW0JJ!s2C-_UsRBQ=v@VQ+4> z*6jF0;R@5XLHO^&PFyaMDvyo?-lAD(@H61l-No#t@at@Le9xOgTFqkc%07KL^&iss z!S2Ghm)u#26D(e1Q7E;L`rxOy-N{kJ zTgfw}az9=9Su?NEMMtpRlYwDxUAUr8F+P=+9pkX4%iA4&&D<|=B|~s*-U+q6cq`y* zIE+;2rD7&D5X;VAv=5rC5&nP$E9Z3HKTqIFCEV%V;b)Y|dY?8ySn|FD?s3IO>VZ&&f)idp_7AGnwVd1Z znBUOBA}~wogNpEWTt^1Rm-(YLftB=SU|#o&pT7vTr`bQo;=ZqJHIj2MP{JuXQPV7% z0k$5Ha6##aGly<}u>d&d{Hkpu?ZQeL_*M%A8IaXq2SQl35yW9zs4^CZheVgHF`%r= zs(Z|N!gU5gj-B^5{*sF>;~fauKVTq-Ml2>t>E0xl9wywD&nVYZfs1F9Lq}(clpNLz z4O(gm_i}!k`wUoKr|H#j#@XOXQ<#eDGJ=eRJjhOUtiKOG;hym-1Hu)1JYj+Kl*To<8( za1Kf4_Y@Cy>eoC59HZ4o&xY@!G(2p^=wTCV>?rQE`Upo^pbhWdM$WP4HFdDy$HiZ~ zRUJFWTII{J$GLVWR?miDjowFk<1#foE3}C2AKTNFku+BhLUuT>?PATB?WVLzEYyu+ zM*x((pGdotzLJ{}R=OD*jUexKi`mb1MaN0Hr(Wk8-Uj0zA;^1w2rmxLI$qq68D>^$ zj@)~T1l@K|~@YJ6+@1vlWl zHg5g%F{@fW5K!u>4LX8W;ua(t6YCCO_oNu}IIvI6>Fo@MilYuwUR?9p)rKNzDmTAN zzN2d>=Za&?Z!rJFV*;mJ&-sBV80%<-HN1;ciLb*Jk^p?u<~T25%7jjFnorfr={+wm zzl5Q6O>tsN8q*?>uSU6#xG}FpAVEQ_++@}G$?;S7owlK~@trhc#C)TeIYj^N(R&a} zypm~c=fIs;M!YQrL}5{xl=tUU-Tfc0ZfhQuA-u5(*w5RXg!2kChQRd$Fa8xQ0CQIU zC`cZ*!!|O!*y1k1J^m8IIi|Sl3R}gm@CC&;4840^9_bb9%&IZTRk#=^H0w%`5pMDCUef5 zYt-KpWp2ijh+FM`!zZ35>+7eLN;s3*P!bp%-oSx34fdTZ14Tsf2v7ZrP+mitUx$rS zW(sOi^CFxe$g3$x45snQwPV5wpf}>5OB?}&Gh<~i(mU&ss#7;utaLZ!|KaTHniGO9 zVC9OTzuMKz)afey_{93x5S*Hfp$+r*W>O^$2ng|ik!<`U1pkxm3*)PH*d#>7md1y} zs7u^a8zW8bvl92iN;*hfOc-=P7{lJeJ|3=NfX{(XRXr;*W3j845SKG&%N zuBqCtDWj*>KooINK1 zFPCsCWr!-8G}G)X*QM~34R*k zmRmDGF*QE?jCeNfc?k{w<}@29e}W|qKJ1K|AX!htt2|B`nL=HkC4?1bEaHtGBg}V( zl(A`6z*tck_F$4;kz-TNF%7?=20iqQo&ohf@S{_!TTXnVh}FaW2jxAh(DI0f*SDG- z7tqf5X@p#l?7pUNI(BGi>n_phw=lDm>2OgHx-{`T>KP2YH9Gm5ma zb{>7>`tZ>0d5K$j|s2!{^sFWQo3+xDb~#=9-jp(1ydI3_&RXGB~rxWSMgDCGQG)oNoc#>)td zqE|X->35U?_M6{^lB4l(HSN|`TC2U*-`1jSQeiXPtvVXdN-?i1?d#;pw%RfQuKJ|e zjg75M+Q4F0p@8I3ECpBhGs^kK;^0;7O@MV=sX^EJLVJf>L;GmO z3}EbTcoom7QbI(N8ad!z(!6$!MzKaajSRb0c+ZDQ($kFT&&?GvXmu7+V3^_(VJx1z zP-1kW_AB&_A;cxm*g`$ z#Pl@Cg{siF0ST2-w)zJkzi@X)5i@)Z;7M5ewX+xcY36IaE0#flASPY2WmF8St0am{ zV|P|j9wqcMi%r-TaU>(l*=HxnrN?&qAyzimA@wtf;#^%{$G7i4nXu=Pp2#r@O~wi)zB>@25A*|axl zEclXBlXx1LP3x0yrSx@s-kVW4qlF+idF+{M7RG54CgA&soDU-3SfHW@-6_ z+*;{n_SixmGCeZjHmEE!IF}!#aswth_{zm5Qhj0z-@I}pR?cu=P)HJUBClC;U+9;$#@xia30o$% zDw%BgOl>%vRenxL#|M$s^9X}diJ9q7wI1-0n2#6>@q}rK@ng(4M68(t52H_Jc{f&M9NPxRr->vj-88hoI?pvpn}llcv_r0`;uN>wuE{ z&TOx_i4==o;)>V4vCqG)A!mW>dI^Ql8BmhOy$6^>OaUAnI3>mN!Zr#qo4A>BegYj` zNG_)2Nvy2Cqxs1SF9A5HHhL7sai#Umw%K@+riaF+q)7&MUJvA&;$`(w)+B@c6!kX@ zzuY;LGu6|Q2eu^06PzSLspV2v4E?IPf`?Su_g8CX!75l)PCvyWKi4YRoRThB!-BhG zubQ#<7oCvj@z`^y&mPhSlbMf0<;0D z?5&!I?nV-jh-j1g~&R(YL@c=KB_gNup$8abPzXZN`N|WLqxlN)ZJ+#k4UWq#WqvVD z^|j+8f5uxTJtgcUscKTqKcr?5g-Ih3nmbvWvvEk})u-O}h$=-p4WE^qq7Z|rLas0$ zh0j&lhm@Rk(6ZF0_6^>Rd?Ni-#u1y`;$9tS;~!ph8T7fLlYE{P=XtWfV0Ql z#z{_;A%p|8+LhbZT0D_1!b}}MBx9`R9uM|+*`4l3^O(>Mk%@ha>VDY=nZMMb2TnJ= zGlQ+#+pmE98zuFxwAQcVkH1M887y;Bz&EJ7chIQQe!pgWX>(2ruI(emhz@_6t@k8Z zqFEyJFX2PO`$gJ6p$=ku{7!vR#u+$qo|1r;orjtp9FP^o2`2_vV;W&OT)acRXLN^m zY8a;geAxg!nbVu|uS8>@Gvf@JoL&GP`2v4s$Y^5vE32&l;2)`S%e#AnFI-YY7_>d#IKJI!oL6e z_7W3e=-0iz{bmuB*HP+D{Nb;rn+RyimTFqNV9Bzpa0?l`pWmR0yQOu&9c0S*1EPr1 zdoHMYlr>BycjTm%WeVuFd|QF8I{NPT&`fm=dITj&3(M^q ze2J{_2zB;wDME%}SzVWSW6)>1QtiX)Iiy^p2eT}Ii$E9w$5m)kv(3wSCNWq=#DaKZ zs%P`#^b7F-J0DgQ1?~2M`5ClYtYN{AlU|v4pEg4z03=g6nqH`JjQuM{k`!6jaIL_F zC;sn?1x?~uMo_DFg#ypNeie{3udcm~M&bYJ1LI zE%y}P9oCX3I1Y9yhF(y9Ix_=8L(p)EYr&|XZWCOb$7f2qX|A4aJ9bl7pt40Xr zXUT#NMBB8I@xoIGSHAZkYdCj>eEd#>a;W-?v4k%CwBaR5N>e3IFLRbDQTH#m_H+4b zk2UHVymC`%IqwtHUmpS1!1p-uQB`CW1Y!+VD!N4TT}D8(V0IOL|&R&)Rwj@n8g@=`h&z9YTPDT+R9agnwPuM!JW~=_ya~% zIJ*>$Fl;y7_`B7G4*P!kcy=MnNmR`(WS5_sRsvHF42NJ;EaDram5HwQ4Aw*qbYn0j;#)bh1lyKLg#dYjN*BMlh+fxmCL~?zB;HBWho;20WA==ci0mAqMfyG>1!HW zO7rOga-I9bvut1Ke_1eFo9tbzsoPTXDW1Si4}w3fq^Z|5LGf&egnw%DV=b11$F=P~ z(aV+j8S}m=CkI*8=RcrT>GmuYifP%hCoKY22Z4 zmu}o08h3YhcXx-v-QC??8mDn<+}+*X{+gZH-I;G^|7=1fBveS?J$27H&wV5^V^P$! z84?{UeYSmZ3M!@>UFoIN?GJT@IroYr;X@H~ax*CQ>b5|Xi9FXt5j`AwUPBq`0sWEJ z3O|k+g^JKMl}L(wfCqyMdRj9yS8ncE7nI14Tv#&(?}Q7oZpti{Q{Hw&5rN-&i|=fWH`XTQSu~1jx(hqm$Ibv zRzFW9$xf@oZAxL~wpj<0ZJ3rdPAE=0B>G+495QJ7D>=A&v^zXC9)2$$EnxQJ<^WlV zYKCHb1ZzzB!mBEW2WE|QG@&k?VXarY?umPPQ|kziS4{EqlIxqYHP!HN!ncw6BKQzKjqk!M&IiOJ9M^wc~ZQ1xoaI z;4je%ern~?qi&J?eD!vTl__*kd*nFF0n6mGEwI7%dI9rzCe~8vU1=nE&n4d&8}pdL zaz`QAY?6K@{s2x%Sx%#(y+t6qLw==>2(gb>AksEebXv=@ht>NBpqw=mkJR(c?l7vo z&cV)hxNoYPGqUh9KAKT)kc(NqekzE6(wjjotP(ac?`DJF=Sb7^Xet-A3PRl%n&zKk zruT9cS~vV1{%p>OVm1-miuKr<@rotj*5gd$?K`oteNibI&K?D63RoBjw)SommJ5<4 zus$!C8aCP{JHiFn2>XpX&l&jI7E7DcTjzuLYvON2{rz<)#$HNu(;ie-5$G<%eLKnTK7QXfn(UR(n+vX%aeS6!q6kv z!3nzY76-pdJp339zsl_%EI|;ic_m56({wdc(0C5LvLULW=&tWc5PW-4;&n+hm1m`f zzQV0T>OPSTjw=Ox&UF^y< zarsYKY8}YZF+~k70=olu$b$zdLaozBE|QE@H{_R21QlD5BilYBTOyv$D5DQZ8b1r- zIpSKX!SbA0Pb5#cT)L5!KpxX+x+8DRy&`o-nj+nmgV6-Gm%Fe91R1ca3`nt*hRS|^ z<&we;TJcUuPDqkM7k0S~cR%t7a`YP#80{BI$e=E!pY}am)2v3-Iqk2qvuAa1YM>xj#bh+H2V z{b#St2<;Gg>$orQ)c2a4AwD5iPcgZ7o_}7xhO86(JSJ(q(EWKTJDl|iBjGEMbX8|P z4PQHi+n(wZ_5QrX0?X_J)e_yGcTM#E#R^u_n8pK@l5416`c9S=q-e!%0RjoPyTliO zkp{OC@Ep^#Ig-n!C)K0Cy%8~**Vci8F1U(viN{==KU0nAg2(+K+GD_Gu#Bx!{tmUm zCwTrT(tCr6X8j43_n96H9%>>?4akSGMvgd+krS4wRexwZ1JxrJy!Uhz#yt$-=aq?A z@?*)bRZxjG9OF~7d$J0cwE_^CLceRK=LvjfH-~{S><^D;6B2&p-02?cl?|$@>`Qt$ zP*iaOxg<+(rbk>34VQDQpNQ|a9*)wScu!}<{oXC87hRPqyrNWpo?#=;1%^D2n2+C* zKKQH;?rWn-@%Y9g%NHG&lHwK9pBfV1a`!TqeU_Fv8s6_(@=RHua7`VYO|!W&WL*x= zIWE9eQaPq3zMaXuf)D0$V`RIZ74f)0P73xpeyk4)-?8j;|K%pD$eq4j2%tL=;&+E91O(2p91K|85b)GQcbRe&u6Ilu@SnE={^{Ix1Eqgv8D z4=w65+&36|;5WhBm$!n*!)ACCwT9Sip#1_z&g~E1kB=AlEhO0lu`Ls@6gw*a)lzc# zKx!fFP%eSBBs)U>xIcQKF(r_$SWD3TD@^^2Ylm=kC*tR+I@X>&SoPZdJ2fT!ysjH% z-U%|SznY8Fhsq7Vau%{Ad^Pvbf3IqVk{M2oD+w>MWimJA@VSZC$QooAO3 zC=DplXdkyl>mSp^$zk7&2+eoGQ6VVh_^E#Z3>tX7Dmi<2aqlM&YBmK&U}m>a%8)LQ z8v+c}a0QtXmyd%Kc2QNGf8TK?_EK4wtRUQ*VDnf5jHa?VvH2K(FDZOjAqYufW8oIZ z31|o~MR~T;ZS!Lz%8M0*iVARJ>_G2BXEF8(}6Dmn_rFV~5NI`lJjp`Mi~g7~P%H zO`S&-)Fngo3VXDMo7ImlaZxY^s!>2|csKca6!|m7)l^M0SQT1_L~K29%x4KV8*xiu zwP=GlyIE9YPSTC0BV`6|#)30=hJ~^aYeq7d6TNfoYUkk-^k0!(3qp(7Mo-$|48d8Z2d zrsfsRM)y$5)0G`fNq!V?qQ+nh0xwFbcp{nhW%vZ?h);=LxvM(pWd9FG$Bg1;@Bv)mKDW>AP{ol zD(R~mLzdDrBv$OSi{E%OD`Ano=F^vwc)rNb*Bg3-o)bbAgYE=M7Gj2OHY{8#pM${_^ zwkU|tnTKawxUF7vqM9UfcQ`V49zg78V%W)$#5ssR}Rj7E&p(4_ib^?9luZPJ%iJTvW&-U$nFYky>KJwHpEHHx zVEC;!ETdkCnO|${Vj#CY>LLut_+c|(hpWk8HRgMGRY%E--%oKh@{KnbQ~0GZd}{b@ z`J2qHBcqqjfHk^q=uQL!>6HSSF3LXL*cCd%opM|k#=xTShX~qcxpHTW*BI!c3`)hQq{@!7^mdUaG7sFsFYnl1%blslM;?B8Q zuifKqUAmR=>33g~#>EMNfdye#rz@IHgpM$~Z7c5@bO@S>MyFE3_F}HVNLnG0TjtXU zJeRWH^j5w_qXb$IGs+E>daTa}XPtrUnnpTRO9NEx4g6uaFEfHP9gW;xZnJi{oqAH~ z5dHS(ch3^hbvkv@u3QPLuWa}ImaElDrmIc%5HN<^bwej}3+?g) z-ai7D&6Iq_P(}k`i^4l?hRLbCb>X9iq2UYMl=`9U9Rf=3Y!gnJbr?eJqy>Zpp)m>Ae zcQ4Qfs&AaE?UDTODcEj#$_n4KeERZHx-I+E5I~E#L_T3WI3cj$5EYR75H7hy%80a8Ej?Y6hv+fR6wHN%_0$-xL!eI}fdjOK7(GdFD%`f%-qY@-i@fTAS&ETI99jUVg8 zslPSl#d4zbOcrgvopvB2c2A6r^pEr&Sa5I5%@1~BpGq`Wo|x=&)WnnQjE+)$^U-wW zr2Kv?XJby(8fcn z8JgPn)2_#-OhZ+;72R6PspMfCVvtLxFHeb7d}fo(GRjm_+R(*?9QRBr+yPF(iPO~ zA4Tp1<0}#fa{v0CU6jz}q9;!3Pew>ikG1qh$5WPRTQZ~ExQH}b1hDuzRS1}65uydS z~Te*3@?o8fih=mZ`iI!hL5iv3?VUBLQv0X zLtu58MIE7Jbm?)NFUZuMN2_~eh_Sqq*56yIo!+d_zr@^c@UwR&*j!fati$W<=rGGN zD$X`$lI%8Qe+KzBU*y3O+;f-Csr4$?3_l+uJ=K@dxOfZ?3APc5_x2R=a^kLFoxt*_ z4)nvvP+(zwlT5WYi!4l7+HKqzmXKYyM9kL5wX$dTSFSN&)*-&8Q{Q$K-})rWMin8S zy*5G*tRYNqk7&+v;@+>~EIQgf_SB;VxRTQFcm5VtqtKZ)x=?-f+%OY(VLrXb^6*aP zP&0Nu@~l2L!aF8i2!N~fJiHyxRl?I1QNjB)`uP_DuaU?2W;{?0#RGKTr2qH5QqdhK zP__ojm4WV^PUgmrV)`~f>(769t3|13DrzdDeXxqN6XA|_GK*;zHU()a(20>X{y-x| z2P6Ahq;o=)Nge`l+!+xEwY`7Q(8V=93A9C+WS^W%p&yR)eiSX+lp)?*7&WSYSh4i> zJa6i5T9o;Cd5z%%?FhB?J{l+t_)c&_f86gZMU{HpOA=-KoU5lIL#*&CZ_66O5$3?# ztgjGLo`Y7bj&eYnK#5x1trB_6tpu4$EomotZLb*9l6P(JmqG`{z$?lNKgq?GAVhkA zvw!oFhLyX=$K=jTAMwDQ)E-8ZW5$X%P2$YB5aq!VAnhwGv$VR&;Ix#fu%xlG{|j_K zbEYL&bx%*YpXcaGZj<{Y{k@rsrFKh7(|saspt?OxQ~oj_6En(&!rTZPa7fLCEU~mA zB7tbVs=-;cnzv*#INgF_9f3OZhp8c5yk!Dy1+`uA7@eJfvd~g34~wKI1PW%h(y&nA zRwMni12AHEw36)C4Tr-pt6s82EJa^8N#bjy??F*rg4fS@?6^MbiY3;7x=gd~G|Hi& zwmG+pAn!aV>>nNfP7-Zn8BLbJm&7}&ZX+$|z5*5{{F}BRSxN=JKZTa#{ut$v0Z0Fs za@UjXo#3!wACv+p9k*^9^n+(0(YKIUFo`@ib@bjz?Mh8*+V$`c%`Q>mrc5bs4aEf4 zh0qtL1qNE|xQ9JrM}qE>X>Y@dQ?%` zBx(*|1FMzVY&~|dE^}gHJ37O9bjnk$d8vKipgcf+As(kt2cbxAR3^4d0?`}}hYO*O z{+L&>G>AYaauAxE8=#F&u#1YGv%`d*v+EyDcU2TnqvRE33l1r}p#Vmcl%n>NrYOqV z2Car_^^NsZ&K=a~bj%SZlfxzHAxX$>=Q|Zi;E0oyfhgGgqe1Sd5-E$8KV9=`!3jWZCb2crb;rvQ##iw}xm7Da za!H${ls5Ihwxkh^D)M<4Yy3bp<-0a+&KfV@CVd9X6Q?v)$R3*rfT@jsedSEhoV(vqv?R1E8oWV;_{l_+_6= zLjV^-bZU$D_ocfSpRxDGk*J>n4G6s-e>D8JK6-gA>aM^Hv8@)txvKMi7Pi#DS5Y?r zK0%+L;QJdrIPXS2 ztjWAxkSwt2xG$L)Zb7F??cjs!KCTF+D{mZ5e0^8bdu_NLgFHTnO*wx!_8#}NO^mu{FaYeCXGjnUgt_+B-Ru!2_Ue-0UPg2Y)K3phLmR<4 zqUCWYX!KDU!jYF6c?k;;vF@Qh^q(PWwp1ez#I+0>d7V(u_h|L+kX+MN1f5WqMLn!L z!c(pozt7tRQi&duH8n=t-|d)c^;%K~6Kpyz(o53IQ_J+aCapAif$Ek#i0F9U>i+94 zFb=OH5(fk-o`L(o|DyQ(hlozl*2cu#)Y(D*zgNMi1Z!DTex#w#)x(8A-T=S+eByJW z%-k&|XhdZOWjJ&(FTrZNWRm^pHEot_MRQ_?>tKQ&MB~g(&D_e>-)u|`Ot(4j=UT6? zQ&YMi2UnCKlBpwltP!}8a2NJ`LlfL=k8SQf69U)~=G;bq9<2GU&Q#cHwL|o4?ah1` z;fG)%t0wMC;DR?^!jCoKib_iiIjsxCSxRUgJDCE%0P;4JZhJCy)vR1%zRl>K?V6#) z2lDi*W3q9rA zo;yvMujs+)a&00~W<-MNj=dJ@4%tccwT<@+c$#CPR%#aE#Dra+-5eSDl^E>is2v^~ z8lgRwkpeU$|1LW4yFwA{PQ^A{5JY!N5PCZ=hog~|FyPPK0-i;fCl4a%1 z?&@&E-)b4cK)wjXGq|?Kqv0s7y~xqvSj-NpOImt{Riam*Z!wz-coZIMuQU>M%6ben z>P@#o^W;fizVd#?`eeEPs#Gz^ySqJn+~`Pq%-Ee6*X+E>!PJGU#rs6qu0z5{+?`-N zxf1#+JNk7e6AoJTdQwxs&GMTq?Djch_8^xL^A;9XggtGL>!@0|BRuIdE&j$tzvt7I zr@I@0<0io%lpF697s1|qNS|BsA>!>-9DVlgGgw2;;k;=7)3+&t!);W3ulPgR>#JiV zUerO;WxuJqr$ghj-veVGfKF?O7si#mzX@GVt+F&atsB@NmBoV4dK|!owGP005$7LN7AqCG(S+={YA- zn#I{UoP_$~Epc=j78{(!2NLN)3qSm-1&{F&1z4Dz&7Mj_+SdlR^Q5{J=r822d4A@?Rj~xATaWewHUOus{*C|KoH`G zHB8SUT06GpSt)}cFJ18!$Kp@r+V3tE_L^^J%9$&fcyd_AHB)WBghwqBEWW!oh@StV zDrC?ttu4#?Aun!PhC4_KF1s2#kvIh~zds!y9#PIrnk9BWkJpq}{Hlqi+xPOR&A1oP zB0~1tV$Zt1pQuHpJw1TAOS=3$Jl&n{n!a+&SgYVe%igUtvE>eHqKY0`e5lwAf}2x( zP>9Wz+9uirp7<7kK0m2&Y*mzArUx%$CkV661=AIAS=V=|xY{;$B7cS5q0)=oq0uXU z_roo90&gHSfM6@6kmB_FJZ)3y_tt0}7#PA&pWo@_qzdIMRa-;U*Dy>Oo#S_n61Fn! z%mrH%tRmvQvg%UqN_2(C#LSxgQ>m}FKLGG=uqJQuSkk=S@c~QLi4N+>lr}QcOuP&% zQCP^cRk&rk-@lpa0^Lcvdu`F*qE)-0$TnxJlwZf|dP~s8cjhL%>^+L~{umxl5Xr6@ z^7zVKiN1Xg;-h+kr4Yt2BzjZs-Mo54`pDbLc}fWq{34=6>U9@sBP~iWZE`+FhtU|x zTV}ajn*Hc}Y?3agQ+bV@oIRm=qAu%|zE;hBw7kCcDx{pm!_qCxfPX3sh5^B$k_2d` z6#rAeUZC;e-LuMZ-f?gHeZogOa*mE>ffs+waQ+fQl4YKoAyZii_!O0;h55EMzD{;) z8lSJvv((#UqgJ?SCQFqJ-UU?2(0V{;7zT3TW`u6GH6h4m3}SuAAj_K(raGBu>|S&Q zZGL?r9@caTbmRm7p=&Tv?Y1)60*9At38w)$(1c?4cpFY2RLyw9c<{OwQE{b@WI}FQ zTT<2HOF4222d%k70yL~x_d#6SNz`*%@4++8gYQ8?yq0T@w~bF@aOHL2)T4xj`AVps9k z?m;<2ClJh$B6~fOYTWIV*T9y1BpB1*C?dgE{%lVtIjw>4MK{wP6OKTb znbPWrkZjYCbr`GGa%Xo0h;iFPNJBI3fK5`wtJV?wq_G<_PZ<`eiKtvN$IKfyju*^t zXc}HNg>^PPZ16m6bfTpmaW5=qoSsj>3)HS}teRa~qj+Y}mGRE?cH!qMDBJ8 zJB!&-=MG8Tb;V4cZjI_#{>ca0VhG_P=j0kcXVX5)^Sdpk+LKNv#yhpwC$k@v^Am&! z_cz2^4Cc{_BC!K#zN!KEkPzviUFPJ^N_L-kHG6}(X#$>Q=9?!{$A(=B3)P?PkxG9gs#l! zo6TOHo$F|IvjTC3MW%XrDoc7;m-6wb9mL(^2(>PQXY53hE?%4FW$rTHtN`!VgH72U zRY)#?Y*pMA<)x3B-&fgWQ(TQ6S6nUeSY{9)XOo_k=j$<*mA=f+ghSALYwBw~!Egn!jtjubOh?6Cb-Zi3IYn*fYl()^3u zRiX0I{5QaNPJ9w{yh4(o#$geO7b5lSh<5ZaRg9_=aFdZjxjXv(_SCv^v-{ZKQFtAA}kw=GPC7l81GY zeP@0Da{aR#{6`lbI0ON0y#K=t|L*}MG_HSl$e{U;v=BSs{SU3(e*qa(l%rD;(zM^3 zrRgN3M#Sf(Cr9>v{FtB`8JBK?_zO+~{H_0$lLA!l{YOs9KQd4Zt<3*Ns7dVbT{1Ut z?N9{XkN(96?r(4BH~3qeiJ_CAt+h1}O_4IUF$S(5EyTyo=`{^16P z=VhDY!NxkDukQz>T`0*H=(D3G7Np*2P`s(6M*(*ZJa;?@JYj&_z`d5bap=KK37p3I zr5#`%aC)7fUo#;*X5k7g&gQjxlC9CF{0dz*m2&+mf$Sc1LnyXn9lpZ!!Bl!@hnsE5px};b-b-`qne0Kh;hziNC zXV|zH%+PE!2@-IrIq!HM2+ld;VyNUZiDc@Tjt|-1&kq}>muY;TA3#Oy zWdYGP3NOZWSWtx6?S6ES@>)_Yz%%nLG3P>Z7`SrhkZ?shTfrHkYI;2zAn8h65wV3r z^{4izW-c9!MTge3eN=~r5aTnz6*6l#sD68kJ7Nv2wMbL~Ojj0H;M`mAvk*`Q!`KI? z7nCYBqbu$@MSNd+O&_oWdX()8Eh|Z&v&dJPg*o-sOBb2hriny)< zd(o&&kZM^NDtV=hufp8L zCkKu7)k`+czHaAU567$?GPRGdkb4$37zlIuS&<&1pgArURzoWCbyTEl9OiXZBn4p<$48-Gekh7>e)v*?{9xBt z=|Rx!@Y3N@ffW5*5!bio$jhJ7&{!B&SkAaN`w+&3x|D^o@s{ZAuqNss8K;211tUWIi1B!%-ViYX+Ys6w)Q z^o1{V=hK#+tt&aC(g+^bt-J9zNRdv>ZYm9KV^L0y-yoY7QVZJ_ivBS02I|mGD2;9c zR%+KD&jdXjPiUv#t1VmFOM&=OUE2`SNm4jm&a<;ZH`cYqBZoAglCyixC?+I+}*ScG#;?SEAFob{v0ZKw{`zw*tX}<2k zoH(fNh!>b5w8SWSV}rQ*E24cO=_eQHWy8J!5;Y>Bh|p;|nWH|nK9+ol$k`A*u*Y^Uz^%|h4Owu}Cb$zhIxlVJ8XJ0xtrErT zcK;34CB;ohd|^NfmVIF=XlmB5raI}nXjFz;ObQ4Mpl_`$dUe7sj!P3_WIC~I`_Xy@ z>P5*QE{RSPpuV=3z4p3}dh>Dp0=We@fdaF{sJ|+_E*#jyaTrj-6Y!GfD@#y@DUa;& zu4Iqw5(5AamgF!2SI&WT$rvChhIB$RFFF|W6A>(L9XT{0%DM{L`knIQPC$4F`8FWb zGlem_>>JK-Fib;g*xd<-9^&_ue95grYH>5OvTiM;#uT^LVmNXM-n8chJBD2KeDV7t zbnv3CaiyN>w(HfGv86K5MEM{?f#BTR7**smpNZ}ftm+gafRSt=6fN$(&?#6m3hF!>e$X)hFyCF++Qvx(<~q3esTI zH#8Sv!WIl2<&~=B)#sz1x2=+KTHj=0v&}iAi8eD=M->H|a@Qm|CSSzH#eVIR3_Tvu zG8S**NFbz%*X?DbDuP(oNv2;Lo@#_y4k$W+r^#TtJ8NyL&&Rk;@Q}~24`BB)bgwcp z=a^r(K_NEukZ*|*7c2JKrm&h&NP)9<($f)eTN}3|Rt`$5uB0|!$Xr4Vn#i;muSljn zxG?zbRD(M6+8MzGhbOn%C`M#OcRK!&ZHihwl{F+OAnR>cyg~No44>vliu$8^T!>>*vYQJCJg=EF^lJ*3M^=nGCw`Yg@hCmP(Gq^=eCEE1!t-2>%Al{w@*c% zUK{maww*>K$tu;~I@ERb9*uU@LsIJ|&@qcb!&b zsWIvDo4#9Qbvc#IS%sV1_4>^`newSxEcE08c9?rHY2%TRJfK2}-I=Fq-C)jc`gzV( zCn?^noD(9pAf2MP$>ur0;da`>Hr>o>N@8M;X@&mkf;%2A*2CmQBXirsJLY zlX21ma}mKH_LgYUM-->;tt;6F?E5=fUWDwQhp*drQ%hH0<5t2m)rFP%=6aPIC0j$R znGI0hcV~}vk?^&G`v~YCKc7#DrdMM3TcPBmxx#XUC_JVEt@k=%3-+7<3*fTcQ>f~?TdLjv96nb66xj=wVQfpuCD(?kzs~dUV<}P+Fpd)BOTO^<*E#H zeE80(b~h<*Qgez(iFFOkl!G!6#9NZAnsxghe$L=Twi^(Q&48 zD0ohTj)kGLD){xu%pm|}f#ZaFPYpHtg!HB30>F1c=cP)RqzK2co`01O5qwAP zUJm0jS0#mci>|Nu4#MF@u-%-4t>oUTnn_#3K09Hrwnw13HO@9L;wFJ*Z@=gCgpA@p zMswqk;)PTXWuMC-^MQxyNu8_G-i3W9!MLd2>;cM+;Hf&w| zLv{p*hArp9+h2wsMqT5WVqkkc0>1uokMox{AgAvDG^YJebD-czexMB!lJKWllLoBI zetW2;;FKI1xNtA(ZWys!_un~+834+6y|uV&Lo%dKwhcoDzRADYM*peh{o`-tHvwWIBIXW`PKwS3|M>CW37Z2dr!uJWNFS5UwY4;I zNIy1^sr+@8Fob%DHRNa&G{lm?KWU7sV2x9(Ft5?QKsLXi!v6@n&Iyaz5&U*|hCz+d z9vu60IG<v6+^ZmBs_aN!}p|{f(ikVl&LcB+UY;PPz* zj84Tm>g5~-X=GF_4JrVmtEtm=3mMEL1#z+pc~t^Iify^ft~cE=R0TymXu*iQL+XLX zdSK$~5pglr3f@Lrcp`>==b5Z6r7c=p=@A5nXNacsPfr(5m;~ks@*Wu7A z%WyY$Pt*RAKHz_7cghHuQqdU>hq$vD?plol_1EU(Fkgyo&Q2&2e?FT3;H%!|bhU~D z>VX4-6}JLQz8g3%Bq}n^NhfJur~v5H0dbB^$~+7lY{f3ES}E?|JnoLsAG%l^%eu_PM zEl0W(sbMRB3rFeYG&tR~(i2J0)RjngE`N_Jvxx!UAA1mc7J>9)`c=`}4bVbm8&{A` z3sMPU-!r-8de=P(C@7-{GgB<5I%)x{WfzJwEvG#hn3ict8@mexdoTz*(XX!C&~}L* z^%3eYQ8{Smsmq(GIM4d5ilDUk{t@2@*-aevxhy7yk(wH?8yFz%gOAXRbCYzm)=AsM z?~+vo2;{-jkA%Pqwq&co;|m{=y}y2lN$QPK>G_+jP`&?U&Ubq~T`BzAj1TlC`%8+$ zzdwNf<3suPnbh&`AI7RAYuQ<#!sD|A=ky2?hca{uHsB|0VqShI1G3lG5g}9~WSvy4 zX3p~Us^f5AfXlBZ0hA;mR6aj~Q8yb^QDaS*LFQwg!!<|W!%WX9Yu}HThc7>oC9##H zEW`}UQ%JQ38UdsxEUBrA@=6R-v1P6IoIw8$8fw6F{OSC7`cOr*u?p_0*Jvj|S)1cd z-9T);F8F-Y_*+h-Yt9cQQq{E|y^b@r&6=Cd9j0EZL}Pj*RdyxgJentY49AyC@PM<< zl&*aq_ubX%*pqUkQ^Zsi@DqhIeR&Ad)slJ2g zmeo&+(g!tg$z1ao1a#Qq1J022mH4}y?AvWboI4H028;trScqDQrB36t!gs|uZS9}KG0}DD$ zf2xF}M*@VJSzEJ5>ucf+L_AtN-Ht=34g&C?oPP>W^bwoigIncKUyf61!ce!2zpcNT zj&;rPGI~q2!Sy>Q7_lRX*DoIs-1Cei=Cd=+Xv4=%bn#Yqo@C=V`|QwlF0Y- zONtrwpHQ##4}VCL-1ol(e<~KU9-ja^kryz!g!})y-2S5z2^gE$Isj8l{%tF=Rzy`r z^RcP7vu`jHgHLKUE957n3j+BeE(bf;f)Zw($XaU6rZ26Upl#Yv28=8Y`hew{MbH>* z-sGI6dnb5D&dUCUBS`NLAIBP!Vi!2+~=AU+)^X^IpOEAn#+ab=`7c z%7B|mZ>wU+L;^&abXKan&N)O;=XI#dTV|9OMYxYqLbtT#GY8PP$45Rm2~of+J>>HIKIVn(uQf-rp09_MwOVIp@6!8bKV(C#(KxcW z;Pesq(wSafCc>iJNV8sg&`!g&G55<06{_1pIoL`2<7hPvAzR1+>H6Rx0Ra%4j7H-<-fnivydlm{TBr06;J-Bq8GdE^Amo)ptV>kS!Kyp*`wUx=K@{3cGZnz53`+C zLco1jxLkLNgbEdU)pRKB#Pq(#(Jt>)Yh8M?j^w&RPUueC)X(6`@@2R~PV@G(8xPwO z^B8^+`qZnQr$8AJ7<06J**+T8xIs)XCV6E_3W+al18!ycMqCfV>=rW0KBRjC* zuJkvrv;t&xBpl?OB3+Li(vQsS(-TPZ)Pw2>s8(3eF3=n*i0uqv@RM^T#Ql7(Em{(~%f2Fw|Reg@eSCey~P zBQlW)_DioA*yxxDcER@_=C1MC{UswPMLr5BQ~T6AcRyt0W44ffJG#T~Fk}wU^aYoF zYTayu-s?)<`2H(w+1(6X&I4?m3&8sok^jpXBB<|ZENso#?v@R1^DdVvKoD?}3%@{}}_E7;wt9USgrfR3(wabPRhJ{#1es81yP!o4)n~CGsh2_Yj2F^z|t zk((i&%nDLA%4KFdG96pQR26W>R2^?C1X4+a*hIzL$L=n4M7r$NOTQEo+k|2~SUI{XL{ynLSCPe%gWMMPFLO{&VN2pom zBUCQ(30qj=YtD_6H0-ZrJ46~YY*A;?tmaGvHvS^H&FXUG4)%-a1K~ly6LYaIn+4lG zt=wuGLw!%h=Pyz?TP=?6O-K-sT4W%_|Nl~;k~YA^_`gqfe{Xw=PWn#9f1mNz)sFuL zJbrevo(DPgpirvGMb6ByuEPd=Rgn}fYXqeUKyM+!n(cKeo|IY%p!#va6`D8?A*{u3 zEeWw0*oylJ1X!L#OCKktX2|>-z3#>`9xr~azOH+2dXHRwdfnpri9|xmK^Q~AuY!Fg z`9Xx?hxkJge~)NVkPQ(VaW(Ce2pXEtgY*cL8i4E)mM(iz_vdm|f@%cSb*Lw{WbShh41VGuplex9E^VvW}irx|;_{VK=N_WF39^ zH4<*peWzgc)0UQi4fBk2{FEzldDh5+KlRd!$_*@eYRMMRb1gU~9lSO_>Vh-~q|NTD zL}X*~hgMj$*Gp5AEs~>Bbjjq7G>}>ki1VxA>@kIhLe+(EQS0mjNEP&eXs5)I;7m1a zmK0Ly*!d~Dk4uxRIO%iZ!1-ztZxOG#W!Q_$M7_DKND0OwI+uC;PQCbQ#k#Y=^zQve zTZVepdX>5{JSJb;DX3%3g42Wz2D@%rhIhLBaFmx#ZV8mhya}jo1u{t^tzoiQy=jJp zjY2b7D2f$ZzJx)8fknqdD6fd5-iF8e(V}(@xe)N=fvS%{X$BRvW!N3TS8jn=P%;5j zShSbzsLs3uqycFi3=iSvqH~}bQn1WQGOL4?trj(kl?+q2R23I42!ipQ&`I*&?G#i9 zWvNh8xoGKDt>%@i0+}j?Ykw&_2C4!aYEW0^7)h2Hi7$;qgF3;Go?bs=v)kHmvd|`R z%(n94LdfxxZ)zh$ET8dH1F&J#O5&IcPH3=8o;%>OIT6w$P1Yz4S!}kJHNhMQ1(prc zM-jSA-7Iq=PiqxKSWb+YbLB-)lSkD6=!`4VL~`ExISOh2ud=TI&SKfR4J08Bad&rj zcXxMpcNgOB?w$~L7l^wPcXxw$0=$oV?)`I44)}b#ChS`_lBQhvb6ks?HDr3tFgkg&td19?b8=!sETXtp=&+3T$cCwZe z0nAET-7561gsbBws$TVjP7QxY(NuBYXVn9~9%vyN-B#&tJhWgtL1B<%BTS*-2$xB` zO)cMDHoWsm%JACZF--Pa7oP;f!n%p`*trlpvZ!HKoB={l+-(8O;;eYv2A=ra z3U7rSMCkP_6wAy`l|Se(&5|AefXvV1E#XA(LT!% zjj4|~xlZ-kPLNeQLFyXb%$K}YEfCBvHA-Znw#dZSI6V%3YD{Wj2@utT5Hieyofp6Qi+lz!u)htnI1GWzvQsA)baEuw9|+&(E@p8M+#&fsX@Kf`_YQ>VM+40YLv`3-(!Z7HKYg@+l00WGr779i-%t`kid%e zDtbh8UfBVT3|=8FrNian@aR3*DTUy&u&05x%(Lm3yNoBZXMHWS7OjdqHp>cD>g!wK z#~R{1`%v$IP;rBoP0B0P><;dxN9Xr+fp*s_EK3{EZ94{AV0#Mtv?;$1YaAdEiq5)g zYME;XN9cZs$;*2p63Q9^x&>PaA1p^5m7|W?hrXp2^m;B@xg0bD?J;wIbm6O~Nq^^K z2AYQs@7k)L#tgUkTOUHsh&*6b*EjYmwngU}qesKYPWxU-z_D> zDWr|K)XLf_3#k_9Rd;(@=P^S^?Wqlwert#9(A$*Y$s-Hy)BA0U0+Y58zs~h=YtDKxY0~BO^0&9{?6Nny;3=l59(6ec9j(79M?P1cE zex!T%$Ta-KhjFZLHjmPl_D=NhJULC}i$}9Qt?nm6K6-i8&X_P+i(c*LI3mtl3 z*B+F+7pnAZ5}UU_eImDj(et;Khf-z^4uHwrA7dwAm-e4 zwP1$Ov3NP5ts+e(SvM)u!3aZMuFQq@KE-W;K6 zag=H~vzsua&4Sb$4ja>&cSJ)jjVebuj+?ivYqrwp3!5>ul`B*4hJGrF;!`FaE+wKo z#};5)euvxC1zX0-G;AV@R(ZMl=q_~u8mQ5OYl;@BAkt)~#PynFX#c1K zUQ1^_N8g+IZwUl*n0Bb-vvliVtM=zuMGU-4a8|_8f|2GEd(2zSV?aSHUN9X^GDA8M zgTZW06m*iAy@7l>F3!7+_Y3mj^vjBsAux3$%U#d$BT^fTf-7{Y z_W0l=7$ro5IDt7jp;^cWh^Zl3Ga1qFNrprdu#g=n9=KH!CjLF#ucU5gy6*uASO~|b z7gcqm90K@rqe({P>;ww_q%4}@bq`ST8!0{V08YXY)5&V!>Td)?j7#K}HVaN4FU4DZ z%|7OppQq-h`HJ;rw-BAfH* z1H$ufM~W{%+b@9NK?RAp-$(P0N=b<(;wFbBN0{u5vc+>aoZ|3&^a866X@el7E8!E7 z=9V(Ma**m_{DKZit2k;ZOINI~E$|wO99by=HO{GNc1t?nl8soP@gxk8)WfxhIoxTP zoO`RA0VCaq)&iRDN9yh_@|zqF+f07Esbhe!e-j$^PS57%mq2p=+C%0KiwV#t^%_hH zoO?{^_yk5x~S)haR6akK6d|#2TN& zfWcN zc7QAWl)E9`!KlY>7^DNw$=yYmmRto>w0L(~fe?|n6k2TBsyG@sI)goigj=mn)E)I* z4_AGyEL7?(_+2z=1N@D}9$7FYdTu;%MFGP_mEJXc2OuXEcY1-$fpt8m_r2B|<~Xfs zX@3RQi`E-1}^9N{$(|YS@#{ZWuCxo)91{k>ESD54g_LYhm~vlOK_CAJHeYFfuIVB^%cqCfvpy#sU8Do8u}# z>>%PLKOZ^+$H54o@brtL-hHorSKcsjk_ZibBKBgyHt~L z=T6?e0oLX|h!Z3lbkPMO27MM?xn|uZAJwvmX?Yvp#lE3sQFY)xqet>`S2Y@1t)Z*& z;*I3;Ha8DFhk=YBt~{zp=%%*fEC}_8?9=(-k7HfFeN^GrhNw4e?vx*#oMztnO*&zY zmRT9dGI@O)t^=Wj&Og1R3b%(m*kb&yc;i`^-tqY9(0t!eyOkH<$@~1lXmm!SJllE_ zr~{a&w|8*LI>Z^h!m%YLgKv06Js7j7RaoX}ZJGYirR<#4Mghd{#;38j3|V+&=ZUq#1$ zgZb-7kV)WJUko?{R`hpSrC;w2{qa`(Z4gM5*ZL`|#8szO=PV^vpSI-^K_*OQji^J2 zZ_1142N}zG$1E0fI%uqHOhV+7%Tp{9$bAR=kRRs4{0a`r%o%$;vu!_Xgv;go)3!B#;hC5qD-bcUrKR&Sc%Zb1Y($r78T z=eG`X#IpBzmXm(o6NVmZdCQf6wzqawqI63v@e%3TKuF!cQ#NQbZ^?6K-3`_b=?ztW zA>^?F#dvVH=H-r3;;5%6hTN_KVZ=ps4^YtRk>P1i>uLZ)Ii2G7V5vy;OJ0}0!g>j^ z&TY&E2!|BDIf1}U(+4G5L~X6sQ_e7In0qJmWYpn!5j|2V{1zhjZt9cdKm!we6|Pp$ z07E+C8=tOwF<<}11VgVMzV8tCg+cD_z?u+$sBjwPXl^(Ge7y8-=c=fgNg@FxI1i5Y-HYQMEH z_($je;nw`Otdhd1G{Vn*w*u@j8&T=xnL;X?H6;{=WaFY+NJfB2(xN`G)LW?4u39;x z6?eSh3Wc@LR&yA2tJj;0{+h6rxF zKyHo}N}@004HA(adG~0solJ(7>?LoXKoH0~bm+xItnZ;3)VJt!?ue|~2C=ylHbPP7 zv2{DH()FXXS_ho-sbto)gk|2V#;BThoE}b1EkNYGT8U#0ItdHG>vOZx8JYN*5jUh5Fdr9#12^ zsEyffqFEQD(u&76zA^9Jklbiz#S|o1EET$ujLJAVDYF znX&4%;vPm-rT<8fDutDIPC@L=zskw49`G%}q#l$1G3atT(w70lgCyfYkg7-=+r7$%E`G?1NjiH)MvnKMWo-ivPSQHbk&_l5tedNp|3NbU^wk0SSXF9ohtM zUqXiOg*8ERKx{wO%BimK)=g^?w=pxB1Vu_x<9jKOcU7N;(!o3~UxyO+*ZCw|jy2}V*Z22~KhmvxoTszc+#EMWXTM6QF*ks% zW47#2B~?wS)6>_ciKe1Fu!@Tc6oN7e+6nriSU;qT7}f@DJiDF@P2jXUv|o|Wh1QPf zLG31d>@CpThA+Ex#y)ny8wkC4x-ELYCXGm1rFI=1C4`I5qboYgDf322B_Nk@#eMZ% znluCKW2GZ{r9HR@VY`>sNgy~s+D_GkqFyz6jgXKD)U|*eKBkJRRIz{gm3tUd*yXmR z(O4&#ZA*us6!^O*TzpKAZ#}B5@}?f=vdnqnRmG}xyt=)2o%<9jj>-4wLP1X-bI{(n zD9#|rN#J;G%LJ&$+Gl2eTRPx6BQC6Uc~YK?nMmktvy^E8#Y*6ZJVZ>Y(cgsVnd!tV z!%twMNznd)?}YCWyy1-#P|2Fu%~}hcTGoy>_uawRTVl=(xo5!%F#A38L109wyh@wm zdy+S8E_&$Gjm=7va-b7@Hv=*sNo0{i8B7=n4ex-mfg`$!n#)v@xxyQCr3m&O1Jxg! z+FXX^jtlw=utuQ+>Yj$`9!E<5-c!|FX(~q`mvt6i*K!L(MHaqZBTtuSA9V~V9Q$G? zC8wAV|#XY=;TQD#H;;dcHVb9I7Vu2nI0hHo)!_{qIa@|2}9d ztpC*Q{4Py~2;~6URN^4FBCBip`QDf|O_Y%iZyA0R`^MQf$ce0JuaV(_=YA`knEMXw zP6TbjYSGXi#B4eX=QiWqb3bEw-N*a;Yg?dsVPpeYFS*&AsqtW1j2D$h$*ZOdEb$8n0 zGET4Igs^cMTXWG{2#A7w_usx=KMmNfi4oAk8!MA8Y=Rh9^*r>jEV(-{I0=rc);`Y) zm+6KHz-;MIy|@2todN&F+Yv1e&b&ZvycbTHpDoZ>FIiUn+M-=%A2C(I*^Yx@VKf(Z zxJOny&WoWcyKodkeN^5))aV|-UBFw{?AGo?;NNFFcKzk+6|gYfA#FR=y@?;3IoQ zUMI=7lwo9gV9fRvYi}Nd)&gQw7(K3=a0#p27u6Q)7JlP#A)piUUF8B3Li&38Xk$@| z9OR+tU~qgd3T3322E))eV)hAAHYIj$TmhH#R+C-&E-}5Qd{3B}gD{MXnsrS;{Erv1 z6IyQ=S2qD>Weqqj#Pd65rDSdK54%boN+a?=CkR|agnIP6;INm0A*4gF;G4PlA^3%b zN{H%#wYu|!3fl*UL1~f+Iu|;cqDax?DBkZWSUQodSDL4Es@u6zA>sIm>^Aq-&X#X8 zI=#-ucD|iAodfOIY4AaBL$cFO@s(xJ#&_@ZbtU+jjSAW^g;_w`FK%aH_hAY=!MTjI zwh_OEJ_25zTQv$#9&u0A11x_cGd92E74AbOrD`~f6Ir9ENNQAV2_J2Ig~mHWhaO5a zc>fYG$zke^S+fBupw+klDkiljJAha z6DnTemhkf>hv`8J*W_#wBj-2w(cVtXbkWWtE(3j@!A-IfF?`r$MhVknTs3D1N`rYN zKth9jZtX#>v#%U@^DVN!;ni#n1)U&H_uB{6pcq7$TqXJX!Q0P7U*JUZyclb~)l*DS zOLpoQfW_3;a0S$#V0SOwVeeqE$Hd^L`$;l_~2giLYd?7!gUYIpOs!jqSL~pI)4`YuB_692~A z^T#YYQ_W3Rakk}$SL&{`H8mc{>j+3eKprw6BK`$vSSIn;s31M~YlJLApJ)+Gi1{^- zw96WnT9M0Vr_D=e=a}${raR{(35Q!g+8`}vOFj1e&Or(_wp2U2aVQP0_jP57 z2(R4E(E$n!xl<}Zx38wO;27wuQ`P#_j!}L2 z2qr;As4D4n2X$-Jd_-!fsbu_D(64i;c4cJnP576x_>Q4WNushFwkBV!kVd(AYFXe{ zaqO5`Qfr!#ETmE(B;u_&FITotv~W}QYFCI!&ENKIb1p4fg*Yv1)EDMb==EjHHWM#{ zGMpqb2-LXdHB@D~pE3|+B392Gh4q)y9jBd$a^&cJM60VEUnLtHQD5i-X6PVF>9m_k zDvG3P(?CzdaIrC8s4cu~N9MEb!Tt(g*GK~gIp1Gyeaw3b7#YPx_1T6i zRi#pAMr~PJKe9P~I+ARa$a!K~)t(4LaVbjva1yd;b1Yz2$7MMc`aLmMl(a^DgN(u? zq2o9&Gif@Tq~Yq+qDfx^F*nCnpuPv%hRFc$I!p74*quLt^M}D_rwl10uMTr!)(*=7 zSC5ea@#;l(h87k4T4x)(o^#l76P-GYJA(pOa&F9YT=fS<*O{4agzba^dIrh0hjls<~APlIz9{ zgRY{OMv2s|`;VCoYVj?InYoq^QWuA&*VDyOn@pPvK8l~g#1~~MGVVvtLDt}>id_Z` zn(ihfL?Y}Y4YX335m*Xx(y+bbukchHrM zycIGp#1*K3$!(tgTsMD2VyUSg^yvCwB8*V~sACE(yq2!MS6f+gsxv^GR|Q7R_euYx z&X+@@H?_oQddGxJYS&ZG-9O(X+l{wcw;W7srpYjZZvanY(>Q1utSiyuuonkjh5J0q zGz6`&meSuxixIPt{UoHVupUbFKIA+3V5(?ijn}(C(v>=v?L*lJF8|yRjl-m#^|krg zLVbFV6+VkoEGNz6he;EkP!Z6|a@n8?yCzX9>FEzLnp21JpU0x!Qee}lwVKA})LZJq zlI|C??|;gZ8#fC3`gzDU%7R87KZyd)H__0c^T^$zo@TBKTP*i{)Gp3E0TZ}s3mKSY zix@atp^j#QnSc5K&LsU38#{lUdwj%xF zcx&l^?95uq9on1m*0gp$ruu||5MQo)XaN>|ngV5Jb#^wWH^5AdYcn_1>H~XtNwJd3 zd9&?orMSSuj=lhO?6)Ay7;gdU#E}pTBa5wFu`nejq##Xd71BHzH2XqLA5 zeLEo;9$}~u0pEu@(?hXB_l;{jQ=7m?~mwj-ME~Tw-OHPrR7K2Xq9eCNwQO$hR z3_A?=`FJctNXA#yQEorVoh{RWxJbdQga zU%K##XEPgy?E|K(=o#IPgnbk7E&5%J=VHube|2%!Qp}@LznjE%VQhJ?L(XJOmFVY~ zo-az+^5!Ck7Lo<7b~XC6JFk>17*_dY;=z!<0eSdFD2L?CSp_XB+?;N+(5;@=_Ss3& zXse>@sA7hpq;IAeIp3hTe9^$DVYf&?)={zc9*hZAV)|UgKoD!1w{UVo8D)Htwi8*P z%#NAn+8sd@b{h=O)dy9EGKbpyDtl@NBZw0}+Wd=@65JyQ2QgU}q2ii;ot1OsAj zUI&+Pz+NvuRv#8ugesT<<@l4L$zso0AQMh{we$tkeG*mpLmOTiy8|dNYhsqhp+q*yfZA`Z)UC*(oxTNPfOFk3RXkbzAEPofVUy zZ3A%mO?WyTRh@WdXz+zD!ogo}gbUMV!YtTNhr zrt@3PcP%5F;_SQ>Ui`Gq-lUe&taU4*h2)6RDh@8G1$o!){k~3)DT87%tQeHYdO?B` zAmoJvG6wWS?=0(Cj?Aqj59`p(SIEvYyPGJ^reI z`Hr?3#U2zI7k0=UmqMD35l`>3xMcWlDv$oo6;b`dZq3d!~)W z=4Qk)lE8&>#HV>?kRLOHZYz83{u7?^KoXmM^pazj8`7OwQ=5I!==; zA!uN`Q#n=Drmzg}@^nG!mJp9ml3ukWk96^6*us*;&>s+7hWfLXtl?a}(|-#=P12>A zon1}yqh^?9!;on?tRd6Fk0knQSLl4vBGb87A_kJNDGyrnpmn48lz_%P{* z_G*3D#IR<2SS54L5^h*%=)4D9NPpji7DZ5&lHD|99W86QN_(|aJ<5C~PX%YB`Qt_W z>jF_Os@kI6R!ub4n-!orS(G6~mKL7()1g=Lf~{D!LR7#wRHfLxTjYr{*c{neyhz#U zbm@WBKozE+kTd+h-mgF+ELWqTKin57P;0b){ zii5=(B%S(N!Z=rAFGnM6iePtvpxB_Q9-oq_xH!URn2_d-H~i;lro8r{-g!k-Ydb6_w5K@FOV?zPF_hi z%rlxBv$lQi%bjsu^7KT~@u#*c$2-;AkuP)hVEN?W5MO8C9snj*EC&|M!aK6o12q3+ z8e?+dH17E!A$tRlbJW~GtMDkMPT=m1g-v67q{sznnWOI$`g(8E!Pf!#KpO?FETxLK z2b^8^@mE#AR1z(DT~R3!nnvq}LG2zDGoE1URR=A2SA z%lN$#V@#E&ip_KZL}Q6mvm(dsS?oHoRf8TWL~1)4^5<3JvvVbEsQqSa3(lF*_mA$g zv`LWarC79G)zR0J+#=6kB`SgjQZ2460W zN%lZt%M@=EN>Wz4I;eH>C0VnDyFe)DBS_2{h6=0ZJ*w%s)QFxLq+%L%e~UQ0mM9ud zm&|r){_<*Om%vlT(K9>dE(3AHjSYro5Y1I?ZjMqWyHzuCE0nyCn`6eq%MEt(aY=M2rIzHeMds)4^Aub^iTIT|%*izG4YH;sT`D9MR(eND-SB+e66LZT z2VX)RJsn${O{D48aUBl|(>ocol$1@glsxisc#GE*=DXHXA?|hJT#{;X{i$XibrA}X zFHJa+ssa2$F_UC(o2k2Z0vwx%Wb(<6_bdDO#=a$0gK2NoscCr;vyx?#cF)JjM%;a| z$^GIlIzvz%Hx3WVU481}_e4~aWcyC|j&BZ@uWW1`bH1y9EWXOxd~f-VE5DpueNofN zv7vZeV<*!A^|36hUE;`#x%MHhL(~?eZ5fhA9Ql3KHTWoAeO-^7&|2)$IcD1r5X#-u zN~N0$6pHPhop@t1_d`dO3#TC0>y5jm>8;$F5_A2& zt#=^IDfYv?JjPPTPNx2TL-Lrl82VClQSLWW_$3=XPbH}xM34)cyW5@lnxy=&h%eRq zv29&h^fMoxjsDnmua(>~OnX{Cq!7vM0M4Mr@_18|YuSKPBKUTV$s^So zc}JlAW&bVz|JY#Eyup6Ny{|P_s0Pq;5*tinH+>5Xa--{ z2;?2PBs((S4{g=G`S?B3Ien`o#5DmUVwzpGuABthYG~OKIY`2ms;33SN9u^I8i_H5`BQ%yOfW+N3r|ufHS_;U;TWT5z;b14n1gX%Pn`uuO z6#>Vl)L0*8yl|#mICWQUtgzeFp9$puHl~m&O+vj3Ox#SxQUa?fY*uK?A;00RiFg(G zK?g=7b5~U4QIK`C*um%=Sw=OJ1eeaV@WZ%hh-3<=lR#(Xesk%?)l4p(EpTwPvN99V@TT)!A8SeFTV+frN=r|5l?K#odjijx2nFgc3kI zC$hVs1S-!z9>xn9MZcRk0YXdYlf~8*LfH$IHKD59H&gLz%6 z#mAYSRJufbRi~LRadwM*G!O2>&U<^d`@<)otXZJJxT@G}4kTx0zPDVhVXwiU)$}5Y z`0iV`8EEh&GlUk&VY9m0Mqr*U&|^Bc?FB`<%{x-o0ATntwIA%(YDcxWs$C)%a%d_@ z?fx!Co+@3p7ha$|pWYD}p6#(PG%_h8K7sQjT_P~|3ZEH0DRxa3~bP&&lPMj3C~!H2QD zq>(f^RUFSqf6K3BMBFy$jiuoSE+DhEq$xLDb7{57 z0B|1pSjYJ5F@cHG%qDZ{ogL$P!BK&sR%zD`gbK#9gRZX17EtAJxN% zys^gb2=X9=7HP}N(iRqt(tot2yyeE%s;L}AcMh;~-W~s_eAe!gIUYdQz5j~T)0trh z>#1U$uOyyl%!Pi(gD&)uHe9Q^27_kHyFCC}n^-KL(=OxHqUfex1YS__RJh0m-S>eM zqAk`aSev*z1lI&-?CycgDm=bdQCp}RqS0_d-4Mf&>u2KyGFxKe8JM1N{GNWw0n$FL z1UDp(h0(1I2Jh9I`?IS}h4R~n zRwRz>8?$fFMB2{UPe^$Ifl;Oc>}@Q9`|8DCeR{?LUQLPfaMsxs8ps=D_aAXORZH~< zdcIOca-F;+D3~M+)Vi4h)I4O3<)$65yI)goQ_vk#fb;Uim>UI4Dv9#2b1;N_Wg>-F zNwKeMKY+su#~NL0uE%_$mw1%ddX2Qs2P!ncM+>wnz}OCQX1!q~oS?OqYU;&ESAAwP z452QWL0&u^mraF#=j_ZeBWhm&F|d!QjwRl^7=Bl7@(43=BkN=3{BRv#QHIk>Umc_w zvP>q|q{lJ=zs|W9%a@8%W>C@MYN1D5{(=Af31+pR#kB`cd0-YlQQTg}+ zL|_h=F9JQ|Gux5c0ehaffHNYLf8VwF+qnM6IjBEI_eceee;o;FY@#~FFVsZjBSp!j z8V*Bgmn{RK!!zqGc;jy)z@Zjo>5{%m1?K}fLEL$l6Dl4f=ye0wNI#)2L=^K(&18Gb zJoj8@WBB;P^T#V)I0`aDSy?$rJU{+-5472NyFp>;Vw43j@3Z=;D2eSfyw5*0Q+&ML zsV&&*3c3$pa`qcaGbEB0*CA~Wp3%PkF?B87FV&rWNb|@GU$LB;l|;YutU*k za1hjUL_BX%G^s;BuzRi4Hl?eqC2z&ZrKh1tZDwnufG$g$LX(j!h%F5(n8D@in3lnX z(*8+3ZT6TVYRcSpM1eMeCps=Fz8q%gyM&B=a7(Vf`4k3dN$IM+`BO^_7HZq4BR|7w z+5kOJ;9_$X%-~arA@qmXSzD|+NMh--%5-9u6t(M=f%&z$<_V#Y_lzn{E$MZZG)+A> zu2E`_Y(MBJ2l*AqvCUmU;yBT}#oQ{V=((mC-QGJwsCOH*a;{1JRTKv7DBNG+M!XL7(^jbv&Qy-o9HNFrmN)-`D3WFtXs>1vBOJpI(=x; zKhJlFdfMf^G#oU(w1+ucMKYPZaDp>$kt=wiYsBCjUY-uz<4JziB>6fXDSLH*2Y z&Px5y`#3!fF=c4>fCMdg-tX582pemU@ZxyFbznL8-=TTo1Sybg9>7h*J^9^~XxXJO z`k9v~=4amxl<;FCV9h2k%?^-ZUzQy^#{JleyH23o1S{r<+t#z6jKS<9rbAM96^1iY zi6{IjauB)UwBhC-_L(MzGCxhhv`?ryc zja_Uwi7$8l!}*vjJppGyp#Wz=*?;jC*xQ&J894rql5A$2giJRtV&DWQh#(+Vs3-5_ z69_tj(>8%z1VtVp>a74r5}j2rG%&;uaTQ|fr&r%ew-HO}76i8`&ki%#)~}q4Y|d$_ zfNp9uc#$#OEca>>MaY6rF`dB|5#S)bghf>>TmmE&S~IFw;PF0UztO6+R-0!TSC?QP z{b(RA_;q3QAPW^XN?qQqu{h<}Vfiv}Rr!lA$C79^1=U>+ng9Dh>v{`?AOZt>CrQ=o zI}=mSnR))8fJpO->rcX?H);oqSQUZ?sR!fH2SoFdcPm5*2y<_u;4h;BqcF*XbwWSv zcJN%!g|L(22Xp!^1?c;T&qm%rpkP&2EQC3JF+SENm$+@7#e!UKD1uQ{TDw43?!b!3 zUooS_rt=xJfa&h?c^hfV>YwQXre3qosz_^c#)FO~d!<)2o}Oxz5HWtr<)1Yw012v4 zhv0w(RfJspDnA^-6Jmr;GkWt%{mAYOm6yPb&Vl&rv@D^K&;#?=X{kaK5FhScNJ_3> z#5u(Saisq2(~pVlrfG#@kLM#Ot~5rZZc%B&h1=gen?R+#t^1bYKf zVvtefX=D$*)39e^2@!~A_}9c${Gf0?1;dk=!Itp#s%0>Io%k`9(bDeI-udd&E6Zfu zcaiv(h`DM3W3Mfda)fYwhB=8RAPkotVt5-z21Ij~Ot9A^SK-1u*zFVK&mF?q1;|wy zrF+XWs^5Q-%Z6I62gTwrRe#F>riVM#fv_TihxSJ6to1X7NVszgivoTa!fPfBBYj94 zuc2m zL_k-<1FoORng190; z+@DGs;NHgGW8%wjH$EpvQ-Hd! znZdIh#!H5nOStiOKNV8}QvY~=VMqtG&p$ByF&%pe_gR`|H5ULg47lk20(Xe=k8ptc zn%EmTI7k9gNE=!IN4WnbymtsKoHn2-cL65z^9cQOSp>XFzo;!h*x1s^0U!<{Y-VZ1 zXJ7zekkYf(`@dZ3F9|?O+*dUL4K4?0@V^>I2;k-a1%ZgY9w2|C5r0R5?80e-|&4yEwkklXmZ)!QSYG) zXBKOz|IPC2W_X!t^cgb^@D=|>r@x$f{3Y+`%NoDT^Y@JIuJ%jxe;es9vi`kJmbnPYT%X}rzs0K#=H)Q`)_L7%?KLLJP+0XJbL&JgdJE{i*){MOFSK z{7XUfXZR-Te}aE8RelNkQV0AQ7RC0TVE^o8c!~K^RQ4GY+xed`|A+zjZ(qij@~zLP zkS@Q0`rpM|UsnI6B;_+vw)^iA{n0%C7N~ql@KXNonIOUIHwgYg4Dcn>OOdc=rUl>M zVEQe|u$P=Kb)TL&-2#4t^Pg0pUQ)dj%6O)#3;zwOe~`_1$@Ef`;F+l=>NlAFFbBS0 zN))`LdKnA;OjQ{B+f;z>i|wCv-CmNs46S`8X-oKRl0V+pKZ%XJWO*6G`OMOs^xG_d zj_7-p06{fybw_P;UzX^eX5Pkcrm04%9rPFa56 zyZE \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..f955316 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/src/main/java/jimbo/pijava/blinkt/BlinktController.java b/src/main/java/jimbo/pijava/blinkt/BlinktController.java new file mode 100644 index 0000000..2fffcc7 --- /dev/null +++ b/src/main/java/jimbo/pijava/blinkt/BlinktController.java @@ -0,0 +1,204 @@ +/* + * Copyright (C) 2016-2017 Jim Darby. + * + * This software is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, If not, see + * . + */ + +package jimbo.pijava.blinkt; + +import com.pi4j.io.gpio.GpioController; +import com.pi4j.io.gpio.GpioFactory; +import com.pi4j.io.gpio.GpioPinDigitalOutput; +import com.pi4j.io.gpio.Pin; +import com.pi4j.io.gpio.RaspiPin; + +/** + * This is a derivative class of Jim Darby's APA102 & Blinkt controllers + * + * @author Jim Darby + * @author HoldYourWaffle + */ +public class BlinktController { + /** The pin we use for the clock */ + private final GpioPinDigitalOutput clk; + + /** The pin we use for data */ + private final GpioPinDigitalOutput dat; + + /** The data for each LED in the chain */ + private final int[] data; + + /** Brightness (0 - 31) field used to set colors */ + private int brightness; + + /** + * Construct an Pimoroni Blinkt! controller + * + * @param gpio The GpioController to use + * @param data_pin The data pin to use + * @param clock_pin The clock pin to use + */ + public BlinktController(GpioController gpio, Pin data_pin, Pin clock_pin) { + dat = gpio.provisionDigitalOutputPin(data_pin); + clk = gpio.provisionDigitalOutputPin(clock_pin); + data = new int[8]; + + reset(); + push(); + } + + /** + * Construct an Pimoroni Blinkt! controller with the default data and clock pin + * + * @param gpio The GpioController to use + */ + public BlinktController(GpioController gpio) { + this(gpio, RaspiPin.GPIO_04, RaspiPin.GPIO_05); + } + + /** Construct a Pimoroni Blinkt! controller with the default {@link GpioController}, data and clock pin */ + public BlinktController() { + this(GpioFactory.getInstance(), RaspiPin.GPIO_04, RaspiPin.GPIO_05); + } + + + + /** Update the LED chain */ + public void push() { + // Transmit preamble + for (int i = 0; i < 4; ++i) + write_byte((byte) 0); + + // Send data + for (int i = 0; i < 8; ++i) + write_led(data[i]); + + // And latch it + latch(); + } + + /** Both {@link #clear()} and {@link #setBrightness(float)} to 0 */ + public void reset() { + clear(); + setBrightness(1); + } + + /** Clear the data for pixel n */ + public void clear(int n) { + data[n] = 0; + } + + /** Clear the data of all pixels */ + public void clear() { + for (int i = 0; i < 8; ++i) + data[i] = 0; + } + + + /** + * Set the brightness field used for {@link #set(int, int, int, int)} + * + * @param brightness The brightness scale factor (0-1) + */ + public void setBrightness(float brightness) { + if (brightness < 0 || brightness > 1) throw new IllegalArgumentException("Invalid brightness "+brightness); + this.brightness = (int) (brightness * 31); + } + + + /** Get {@link #brightness} */ + public float getBrightness() { + return brightness / 31F; + } + + + /** + * Set an LED to a specific red, green, blue and brightness value + * + * @param n The LED number (0-7) + * @param red The red value (0-255) + * @param green The green value (0-255) + * @param blue The blue value (0-255) + * @param brightness The brightness (0-1) + * + * @see #push() + */ + public void set(int n, int red, int green, int blue, float brightness) { + if (n < 0 || n >= 8) throw new IllegalArgumentException("n must be larget than 0 and smaller than 8"); + if (red < 0 || red > 255) throw new IllegalArgumentException("red must be between 0 and 255"); + if (green < 0 || green > 255) throw new IllegalArgumentException("green must be between 0 and 255"); + if (blue < 0 || blue > 255) throw new IllegalArgumentException("blue must be between 0 and 255"); + + data[n] = ((int)(brightness*31) << 24) | (red << 16) | (green << 8) | blue; + } + + /** + * Set a LED to a specific red, green and blue value using a brightness of {@link #brightness} + * + * @param n The LED number (0-7) + * @param red The red value (0-255) + * @param green The green value (0-255) + * @param blue The blue value (0-255) + * + * @see #setBrightness(float) + * @see #push() + */ + public void set(int n, int red, int green, int blue) { + if (n < 0 || n >= 8) throw new IllegalArgumentException("n must be larget than 0 and smaller than 8"); + if (red < 0 || red > 255) throw new IllegalArgumentException("red must be between 0 and 255"); + if (green < 0 || green > 255) throw new IllegalArgumentException("green must be between 0 and 255"); + if (blue < 0 || blue > 255) throw new IllegalArgumentException("blue must be between 0 and 255"); + + data[n] = (brightness << 24) | (red << 16) | (green << 8) | blue; + } + + + + /** Write out a single byte. It goes out MSB first */ + private void write_byte(byte out) { + for (int i = 7; i >= 0; --i) { + dat.setState((out & (1 << i)) != 0); + clk.setState(true); + clk.setState(false); + } + } + + /** Write out a single LEDs information */ + private void write_led(int data) { + write_byte((byte) (0xe0 | ((data >> 24) & 0x1f))); + + write_byte((byte) (data)); + write_byte((byte) (data >> 8)); + write_byte((byte) (data >> 16)); + } + + /** + * Latch the data into the devices. This has prompted much discussion as + * data sheet seems to be a work of fiction. These values seem to work. + * + * In case of any difficulties, blame Gadgetoid: it's all his fault! + */ + private void latch() { + // Transmit zeros not ones! + dat.setState(false); + + // And 36 of them! + for (int i = 0; i < 36; ++i) { + clk.setState(true); + clk.setState(false); + } + } + +}