package org.myrobotlab.service; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import org.myrobotlab.framework.Platform; import org.myrobotlab.framework.Service; import org.myrobotlab.framework.ServiceType; import org.myrobotlab.i2c.I2CFactory; import org.myrobotlab.logging.Level; import org.myrobotlab.logging.LoggerFactory; import org.myrobotlab.logging.Logging; import org.myrobotlab.logging.LoggingFactory; import org.myrobotlab.service.interfaces.DeviceControl; import org.myrobotlab.service.interfaces.I2CControl; import org.myrobotlab.service.interfaces.I2CController; import org.slf4j.Logger; import com.pi4j.io.gpio.GpioController; import com.pi4j.io.gpio.GpioPinDigitalMultipurpose; import com.pi4j.io.gpio.GpioPinDigitalOutput; import com.pi4j.io.gpio.PinMode; import com.pi4j.io.gpio.PinPullResistance; import com.pi4j.io.gpio.RaspiPin; import com.pi4j.io.i2c.I2CBus; import com.pi4j.io.i2c.I2CDevice; import com.pi4j.wiringpi.SoftPwm; /** * * RasPi - This is the MyRobotLab Service for the Raspberry Pi. It should allow * all control offered by the great Pi4J project. * * More Info : http://pi4j.com/ * */ // TODO Ensure that only one instance of RasPi can execute on each RaspBerry PI public class RasPi extends Service implements I2CController { public static class I2CDeviceMap { public I2CBus bus; public I2CDevice device; public String serviceName; } private static final long serialVersionUID = 1L; public final static Logger log = LoggerFactory.getLogger(RasPi.class.getCanonicalName()); // the 2 pins for I2C on the raspberry GpioController gpio; // FIXME - do a GpioPinDigitalOutput gpio01; GpioPinDigitalOutput gpio03; // i2c bus public static I2CBus i2c; transient HashMap<String, I2CDeviceMap> i2cDevices = new HashMap<String, I2CDeviceMap>(); public static void main(String[] args) { LoggingFactory.getInstance().configure(); LoggingFactory.getInstance().setLevel(Level.DEBUG); /* * RasPi.displayString(1, 70, "1"); * * RasPi.displayString(1, 70, "abcd"); * * RasPi.displayString(1, 70, "1234"); * * * //RasPi raspi = new RasPi("raspi"); */ // raspi.writeDisplay(busAddress, deviceAddress, data) int i = 0; Runtime.createAndStart(String.format("ras%d", i), "Runtime"); Runtime.createAndStart(String.format("rasPi%d", i), "RasPi"); Runtime.createAndStart(String.format("rasGUI%d", i), "GUIService"); Runtime.createAndStart(String.format("rasPython%d", i), "Python"); // Runtime.createAndStart(String.format("rasClock%d",i), "Clock"); Runtime.createAndStart(String.format("rasRemote%d", i), "RemoteAdapter"); } /* * FIXME - make these methods createDigitalAndPwmPin public * GpioPinDigitalOutput provisionDigitalOutputPin */ public RasPi(String n) { super(n); Platform platform = Platform.getLocalInstance(); log.info(String.format("platform is %s", platform)); log.info(String.format("architecture is %s", platform.getArch())); if ("arm".equals(platform.getArch()) || "armv7.hfp".equals(platform.getArch())) { log.info("Executing on Raspberry PI"); // init gpio /* * log.info("Initiating GPIO"); gpio = GpioFactory.getInstance(); * log.info("GPIO Initiated"); */ // init i2c try { log.info("Initiating i2c"); i2c = I2CFactory.getInstance(I2CBus.BUS_1); log.info("i2c initiated"); } catch (IOException e) { // TODO Auto-generated catch block log.error("i2c initiation failed"); Logging.logError(e); } // TODO Check if the is correct. I don't think it is /Mats // GPIO pins should be provisioned in the CreateDevice /* * gpio01 = gpio.provisionDigitalOutputPin(RaspiPin.GPIO_01); gpio03 = * gpio.provisionDigitalOutputPin(RaspiPin.GPIO_03); */ } else { // we should be running on a Raspberry Pi log.error("architecture is not arm"); } } // FIXME - create low level I2CDevice @Override public void createI2cDevice(I2CControl control, int busAddress, int deviceAddress) { try { I2CDevice device = i2c.getDevice(deviceAddress); I2CBus bus = I2CFactory.getInstance(busAddress); String key = String.format("%d.%d", busAddress, deviceAddress); I2CDeviceMap devicedata = new I2CDeviceMap(); if (i2cDevices.containsKey(key)) { log.error(String.format("Device %s %s %s already exists.", busAddress, deviceAddress, control.getName())); } else devicedata.bus = bus; devicedata.device = device; devicedata.serviceName = control.getName(); i2cDevices.put(key, devicedata); log.info(String.format("Created device for %s with busAddress %s deviceaddress %s key %s", control.getName(), busAddress, deviceAddress, key)); // PCF8574GpioProvider pcf = new PCF8574GpioProvider(busAddress, // deviceAddress); // I2CDevice device = bus.getDevice(deviceAddress); // PCF8574GpioProvider p = new PCF8574GpioProvider(busAddress, // deviceAddress); // p.setValue(pin, value) /* * if ("com.pi4j.gpio.extension.pcf.PCF8574GpioProvider".equals(type)) { * Device d = new Device(); d.bus = bus; d.device = (I2CDevice) new * PCF8574GpioProvider(busAddress, deviceAddress); d.type = * d.device.getClass().getCanonicalName();// "PCF8574GpioProvider"; // // * full type // name devices.put(key, d); return d.device; * * * } else { log.error("could not create device %s", type); return null; } */ } catch (Exception e) { Logging.logError(e); } } @Override public void releaseI2cDevice(I2CControl control, int busAddress, int deviceAddress) { String key = String.format("%d.%d", busAddress, deviceAddress); i2cDevices.remove(key); } // FIXME - return array public Integer[] scanI2CDevices(int busAddress) { log.info("scanning through I2C devices"); ArrayList<Integer> list = new ArrayList<Integer>(); try { /* * From its name we can easily deduce that it provides a communication * link between ICs (integrated circuits). I2C is multimaster and can * support a maximum of 112 devices on the bus. The specification declares * that 128 devices can be connected to the I2C bus, but it also defines * 16 reserved addresses. */ I2CBus bus = I2CFactory.getInstance(busAddress); for (int i = 0; i < 128; ++i) { I2CDevice device = bus.getDevice(i); if (device != null) { try { device.read(); list.add(i); /* * sb.append(i); sb.append(" "); */ log.info(String.format("found device on address %d", i)); } catch (Exception e) { log.warn(String.format("bad read on address %d", i)); } } } } catch (Exception e) { Logging.logError(e); } Integer[] ret = list.toArray(new Integer[list.size()]); return ret; } public void testGPIOOutput() { GpioPinDigitalMultipurpose pin = gpio.provisionDigitalMultipurposePin(RaspiPin.GPIO_02, PinMode.DIGITAL_INPUT, PinPullResistance.PULL_DOWN); log.info("Pin: {}", pin); } public void testPWM() { try { // initialize wiringPi library com.pi4j.wiringpi.Gpio.wiringPiSetup(); // create soft-pwm pins (min=0 ; max=100) SoftPwm.softPwmCreate(1, 0, 100); // continuous loop while (true) { // fade LED to fully ON for (int i = 0; i <= 100; i++) { SoftPwm.softPwmWrite(1, i); Thread.sleep(100); } // fade LED to fully OFF for (int i = 100; i >= 0; i--) { SoftPwm.softPwmWrite(1, i); Thread.sleep(100); } } } catch (Exception e) { } } @Override public void i2cWrite(I2CControl control, int busAddress, int deviceAddress, byte[] buffer, int size) { String key = String.format("%d.%d", busAddress, deviceAddress); I2CDeviceMap devicedata = i2cDevices.get(key); try { devicedata.device.write(buffer, 0, size); } catch (IOException e) { // TODO Auto-generated catch block Logging.logError(e); } } @Override public int i2cRead(I2CControl control, int busAddress, int deviceAddress, byte[] buffer, int size) { int bytesRead = 0; String key = String.format("%d.%d", busAddress, deviceAddress); I2CDeviceMap devicedata = i2cDevices.get(key); try { bytesRead = devicedata.device.read(buffer, 0, buffer.length); } catch (IOException e) { // TODO Auto-generated catch block Logging.logError(e); } return bytesRead; } @Override public int i2cWriteRead(I2CControl control, int busAddress, int deviceAddress, byte[] writeBuffer, int writeSize, byte[] readBuffer, int readSize) { String key = String.format("%d.%d", busAddress, deviceAddress); I2CDeviceMap devicedata = i2cDevices.get(key); try { devicedata.device.read(writeBuffer, 0, writeBuffer.length, readBuffer, 0, readBuffer.length); } catch (IOException e) { // TODO Auto-generated catch block Logging.logError(e); } return readBuffer.length; } /** * This static method returns all the details of the class without it having * to be constructed. It has description, categories, dependencies, and peer * definitions. * * @return ServiceType - returns all the data * */ static public ServiceType getMetaData() { ServiceType meta = new ServiceType(RasPi.class.getCanonicalName()); meta.addDescription("Raspberry Pi service used for accessing specific RasPi hardware such as I2C"); meta.addCategory("i2c", "control"); meta.setSponsor("Mats"); meta.addDependency("com.pi4j.pi4j", "1.1-SNAPSHOT"); return meta; } @Override public void deviceAttach(DeviceControl device, Object... conf) throws Exception { // TODO Auto-generated method stub } @Override public void deviceDetach(DeviceControl device) { // TODO Auto-generated method stub } }