/**
*
* Copyright (c) 2009-2016 Freedomotic team
* http://freedomotic.com
*
* This file is part of Freedomotic
*
* 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 2, 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 Freedomotic; see the file COPYING. If not, see
* <http://www.gnu.org/licenses/>.
*/
package com.freedomotic.plugins.devices.usb4relaybrd;
import com.freedomotic.api.EventTemplate;
import com.freedomotic.api.Protocol;
import com.freedomotic.app.Freedomotic;
import com.freedomotic.exceptions.UnableToExecuteException;
import com.freedomotic.model.ds.Tuples;
import com.freedomotic.reactions.Command;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.ftdi.*;
import com.freedomotic.events.ProtocolRead;
import java.util.logging.Logger;
public class Usb4RelayBrd extends Protocol {
private static final Logger LOG = Logger.getLogger(Usb4RelayBrd.class.getName());
final int POLLING_WAIT;
private static Map<String, FTDevice> boards;
private int relayStatus = 0;
private int relayBitStatus[] = {-1, -1, -1, -1};
List<FTDevice> fTDevices;
Map<String, String> boardsAddressAlias = new HashMap<String, String>();
public Usb4RelayBrd() {
//every plugin needs a name and a manifest XML file
super("USB4RelayBrd", "/usb4relaybrd/usb4relaybrd-manifest.xml");
POLLING_WAIT = configuration.getIntProperty("time-between-reads", 1000);
//POLLING_WAIT is the value of the property "time-between-reads" or 2000 millisecs,
//default value if the property does not exist in the manifest
setPollingWait(POLLING_WAIT); //millisecs interval between hardware device status reads
// load the list of boards address alias
boardsAddressAlias = configuration.getTuples().getTuple(0);
}
@Override
protected void onShowGui() {
/**
* uncomment the line below to add a GUI to this plugin the GUI can be
* started with a right-click on plugin list on the desktop frontend
* (com.freedomotic.jfrontend plugin)
*/
//bindGuiToPlugin(new HelloWorldGui(this));
}
@Override
protected void onHideGui() {
//implement here what to do when the this plugin GUI is closed
//for example you can change the plugin description
setDescription("My GUI is now hidden");
}
@Override
protected void onRun() {
int result = 0;
String relayStatusValue = null;
//at the end of this method the system waits POLLINGTIME
//before calling it again. The result is this log message is printed
//every 2 seconds (2000 millisecs)
for (FTDevice fTDevice : fTDevices) {
result = readFromFTDevice(fTDevice);
//System.out.println("Received status " + result); //FOR DEBUG
// if relays status changed
if (!(result == relayStatus)) {
//System.out.println("Relay status changed"); //FOR DEBUG
relayStatus = result; // update the stored relays status
if ((result & 2) == 0) {
//System.out.println("Relay 1 is OFF"); //FOR DEBUG
relayBitStatus[0] = 0;
sendEvent("R1", "relay.status", "0");
} else {
//System.out.println("Relay 1 is ON"); //FOR DEBUG
relayBitStatus[0] = 1;
sendEvent("R1", "relay.status", "1");
}
if ((result & 8) == 0) {
//System.out.println("Relay 2 is OFF"); //FOR DEBUG
relayBitStatus[1] = 0;
sendEvent("R2", "relay.status", "0");
} else {
//System.out.println("Relay 2 is ON"); //FOR DEBUG
relayBitStatus[1] = 1;
sendEvent("R2", "relay.status", "1");
}
if ((result & 32) == 0) {
//System.out.println("Relay 3 is OFF"); // FOR DEBUG
relayBitStatus[2] = 0;
sendEvent("R3", "relay.status", "0");
} else {
//System.out.println("Relay 3 is ON"); // FOR DEBUG
relayBitStatus[2] = 1;
sendEvent("R3", "relay.status", "1");
}
if ((result & 128) == 0) {
//System.out.println("Relay 4 is OFF"); //FOR DEBUG
relayBitStatus[3] = 0;
sendEvent("R4", "relay.status", "0");
} else {
//System.out.println("Relay 4 is ON"); //FOR DEBUG
relayBitStatus[3] = 1;
sendEvent("R4", "relay.status", "1");
}
}
}
}
@Override
protected void onStart() {
loadDevices();
LOG.info("Usb4RelayBrd plugin started");
setDescription("Usb4RelayBrd started");
}
@Override
protected void onStop() {
for (FTDevice fTDevice : fTDevices) {
try {
fTDevice.close();
} catch (FTD2XXException ex) {
LOG.severe("Usb4RelayBrd FTD2XX exception " + ex.toString());
}
// clear the boards list
fTDevices = null;
LOG.info("Usb4RelayBrd plugin stopped");
setDescription("Usb4RelayBrd stopped");
}
}
@Override
protected void onCommand(Command c) throws IOException, UnableToExecuteException {
Integer newStatus = 0;
String binaryString = null;
Integer address = 0;
Integer pos = 0;
char status;
FTDevice usb4Relay = fTDevices.get(0);
if (c.getProperty("control").equalsIgnoreCase("ALLON")) {
usb4Relay.write(255); // switch ON all relays
System.out.println("All Relays ON");
} else if (c.getProperty("control").equalsIgnoreCase("ALLOFF")) {
usb4Relay.write(0); // switch OFF all relays
System.out.println("All Relays OFF");
} else {
// retrieve the relay number
address = Integer.valueOf(c.getProperty("address").substring(1, c.getProperty("address").length()));
newStatus = readFromFTDevice(usb4Relay);
// convert the integer relayStatus into a binary string
binaryString = Integer.toBinaryString(relayStatus);
// Integer.toBinaryString removes leading 0 so the first is added if needed
if (binaryString.length() < 8) {
binaryString = "0" + binaryString;
}
//System.out.println("Stringa binaria " + binaryString);
// revert the string
StringBuffer reverse = new StringBuffer(binaryString).reverse();
if (c.getProperty("control").equalsIgnoreCase("ON")) {
status = '1';
} else {
status = '0';
}
// detect from the relay number which bit must be changed
switch (address) {
case 1:
pos = 1;
break;
case 2:
pos = 3;
break;
case 3:
pos = 5;
break;
case 4:
pos = 7;
break;
}
// change the bit mapped to the relay
reverse.setCharAt(pos, status);
// revert the string for decimal convertion
String reverseModified = new StringBuffer(reverse.toString()).reverse().toString();
// write on the serial the new relays status
usb4Relay.write(Integer.parseInt(reverseModified, 2));
}
usb4Relay = null;
}
@Override
protected boolean canExecute(Command c) {
//don't mind this method for now
throw new UnsupportedOperationException("Not supported yet.");
}
@Override
protected void onEvent(EventTemplate event) {
//don't mind this method for now
throw new UnsupportedOperationException("Not supported yet.");
}
// load devices connected
private void loadDevices() {
//boards = new HashMap(); // not used now
try {
fTDevices = FTDevice.getDevices();
for (FTDevice fTDevice : fTDevices) {
//boards.put(fTDevice.getDevSerialNumber(), fTDevice);
// open the device
fTDevice.open();
// 170 represents in decimal the pins mask 1,3,5,7
int mask = 170;
// set Asynchronous BitBangMode and output pins mask
fTDevice.setBitMode((byte) mask, BitModes.BITMODE_ASYNC_BITBANG);
// set baudate
fTDevice.setBaudRate(921600);
// set serial line parameters
fTDevice.setDataCharacteristics(WordLength.BITS_8, StopBits.STOP_BITS_1, Parity.PARITY_NONE);
}
} catch (FTD2XXException ex) {
LOG.severe("Usb4RelayBrd FTD2XX exception " + ex.toString());
}
if (fTDevices.size() == 0) {
this.stop();
setDescription("Usb4RelayBrd stopped. No board detected");
}
}
// this method sends a freedomotic event every time a relay status changes
private void sendEvent(String objectAddress, String eventProperty, String eventValue) {
ProtocolRead event = new ProtocolRead(this, "usb4relaybrd", objectAddress);
event.addProperty(eventProperty, eventValue);
event.addProperty("object.class", "Light");
event.addProperty("object.name", objectAddress);
//publish the event on the messaging bus
this.notifyEvent(event);
}
// this method reads a byte from an FTDevice and converts it to integer
private int readFromFTDevice(FTDevice usb4Relay) {
int readValue = 0;
byte[] received = new byte[1];
try {
usb4Relay.purgeBuffer(true, true);
usb4Relay.purgeBuffer(true, true);
usb4Relay.read(received, 0, 1);
readValue = (int) received[0] & 0xff; //mask the sign bit
} catch (FTD2XXException ex) {
LOG.severe("Usb4RelayBrd FTD2XX exception " + ex.toString());
}
return (readValue);
}
// this method retrieve a key from value in a hashmap
// NOT USED
public static Object getKeyFromValue(Map hm, Object value) {
for (Object o : hm.keySet()) {
if (hm.get(o).equals(value)) {
return o;
}
}
return null;
}
}