Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.ociweb.iot.hardware.HardwareImpl Maven / Gradle / Ivy
package com.ociweb.iot.hardware;
import static com.ociweb.iot.hardware.HardwareConnection.DEFAULT_AVERAGE_WINDOW_MS;
import java.io.File;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.concurrent.locks.ReentrantLock;
import com.ociweb.iot.maker.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.ociweb.gl.api.Behavior;
import com.ociweb.gl.api.MsgCommandChannel;
import com.ociweb.gl.api.MsgRuntime;
import com.ociweb.gl.impl.BuilderImpl;
import com.ociweb.gl.impl.ChildClassScanner;
import com.ociweb.gl.impl.schema.IngressMessages;
import com.ociweb.gl.impl.schema.MessagePubSub;
import com.ociweb.gl.impl.schema.MessageSubscription;
import com.ociweb.gl.impl.schema.TrafficAckSchema;
import com.ociweb.gl.impl.schema.TrafficOrderSchema;
import com.ociweb.gl.impl.schema.TrafficReleaseSchema;
import com.ociweb.gl.impl.stage.TrafficCopStage;
import com.ociweb.iot.hardware.impl.DirectHardwareAnalogDigitalOutputStage;
import com.ociweb.iot.hardware.impl.SerialDataReaderStage;
import com.ociweb.iot.hardware.impl.SerialDataWriterStage;
import com.ociweb.iot.hardware.impl.SerialInputSchema;
import com.ociweb.iot.hardware.impl.SerialOutputSchema;
import com.ociweb.iot.hardware.impl.edison.EdisonConstants;
import com.ociweb.iot.impl.AnalogListenerBase;
import com.ociweb.iot.impl.CalibrationListenerBase;
import com.ociweb.iot.impl.DigitalListenerBase;
import com.ociweb.iot.impl.I2CListenerBase;
import com.ociweb.iot.impl.ImageListenerBase;
import com.ociweb.iot.impl.LocationListenerBase;
import com.ociweb.iot.impl.RotaryListenerBase;
import com.ociweb.iot.impl.SerialListenerBase;
import com.ociweb.iot.maker.LinuxImageCaptureStage;
import com.ociweb.iot.transducer.AnalogListenerTransducer;
import com.ociweb.iot.transducer.CalibrationListenerTransducer;
import com.ociweb.iot.transducer.DigitalListenerTransducer;
import com.ociweb.iot.transducer.I2CListenerTransducer;
import com.ociweb.iot.transducer.ImageListenerTransducer;
import com.ociweb.iot.transducer.LocationListenerTransducer;
import com.ociweb.iot.transducer.RotaryListenerTransducer;
import com.ociweb.iot.transducer.SerialListenerTransducer;
import com.ociweb.pronghorn.image.ImageGraphBuilder;
import com.ociweb.pronghorn.image.schema.CalibrationStatusSchema;
import com.ociweb.pronghorn.image.schema.LocationModeSchema;
import com.ociweb.pronghorn.iot.ReactiveIoTListenerStage;
import com.ociweb.pronghorn.iot.ReadDeviceInputStage;
import com.ociweb.pronghorn.iot.i2c.I2CBacking;
import com.ociweb.pronghorn.iot.i2c.I2CJFFIStage;
import com.ociweb.pronghorn.iot.i2c.impl.I2CNativeLinuxBacking;
import com.ociweb.pronghorn.iot.rs232.RS232Client;
import com.ociweb.pronghorn.iot.rs232.RS232Clientable;
import com.ociweb.pronghorn.iot.schema.GroveRequestSchema;
import com.ociweb.pronghorn.iot.schema.GroveResponseSchema;
import com.ociweb.pronghorn.iot.schema.I2CCommandSchema;
import com.ociweb.pronghorn.iot.schema.I2CResponseSchema;
import com.ociweb.pronghorn.image.schema.ImageSchema;
import com.ociweb.pronghorn.network.schema.ClientHTTPRequestSchema;
import com.ociweb.pronghorn.network.schema.NetPayloadSchema;
import com.ociweb.pronghorn.network.schema.NetResponseSchema;
import com.ociweb.pronghorn.pipe.Pipe;
import com.ociweb.pronghorn.pipe.PipeConfig;
import com.ociweb.pronghorn.pipe.util.hash.IntHashTable;
import com.ociweb.pronghorn.stage.PronghornStage;
import com.ociweb.pronghorn.stage.math.ProbabilitySchema;
import com.ociweb.pronghorn.stage.route.ReplicatorStage;
import com.ociweb.pronghorn.stage.scheduling.GraphManager;
import com.ociweb.pronghorn.stage.test.PipeCleanerStage;
import com.ociweb.pronghorn.util.math.PMath;
import com.ociweb.pronghorn.util.math.ScriptedSchedule;
public abstract class HardwareImpl extends BuilderImpl implements Hardware {
private static final int MAX_MOVING_AVERAGE_SUPPORTED = 101; //TOOD: is this still needed, remove???
private static final HardwareConnection[] EMPTY = new HardwareConnection[0];
protected boolean configCamera = false;
protected boolean configI2C; //Humidity, LCD need I2C address so..
protected long debugI2CRateLastTime;
protected HardwareConnection[] digitalInputs; //Button, Motion
protected HardwareConnection[] digitalOutputs;//Relay Buzzer
protected HardwareConnection[] analogInputs; //Light, UV, Moisture
protected HardwareConnection[] pwmOutputs; //Servo //(only 3, 5, 6, 9, 10, 11 when on edison)
protected I2CConnection[] i2cInputs;
protected I2CConnection[] i2cOutputs;
private static final int DEFAULT_LENGTH = 16;
private static final int DEFAULT_PAYLOAD_SIZE = 128;
private static final boolean DEFAULT_EVERY_VALUE = false;
private int i2cBus;
protected I2CBacking i2cBackingInternal;
protected static final long MS_TO_NS = 1_000_000;
private static final Logger logger = LoggerFactory.getLogger(HardwareImpl.class);
protected final IODevice[] deviceOnPort= new IODevice[Port.values().length];
private String loadLocationDataFilePath = null;
private String saveLocationDataFilePath = generateFilePath("savedLocation",".dat");
/////////////////
///Pipes for initial startup declared subscriptions. (Not part of graph)
private final int maxStartupSubs = 64;
private final int maxTopicLengh = 128;
private Pipe tempPipeOfStartupSubscriptions;
/////////////////
/////////////////
protected ReentrantLock devicePinConfigurationLock = new ReentrantLock();
protected RS232Client rs232Client;
protected String rs232ClientDevice = "/dev/ttyMFD1";//custom hardware should override this edison value
protected Baud rs232ClientBaud = Baud.B_____9600;
protected String bluetoothDevice = null;
private static final boolean debug = false;
private int IDX_PIN = -1;
private int IDX_I2C = -1;
private int IDX_SER = -1;
private int imageFrameTriggerRateMicros = 333;
private int imageWidth = LinuxImageCaptureStage.DEFAULT_FRAME_WIDTH;
private int imageHeight = LinuxImageCaptureStage.DEFAULT_FRAME_HEIGHT;
private Path testImageSource = null;
public Hardware setImageTriggerRate(int triggerRateMicros) {
this.imageFrameTriggerRateMicros = triggerRateMicros;
return this;
}
public Hardware setImageSize(int width, int height) {
this.imageWidth = width;
this.imageHeight = height;
return this;
}
@Override
public Hardware setLocationDataFilePath(String path) {
this.loadLocationDataFilePath = path;
return this;
}
public Hardware setTestImageSource(Path path) throws UnsupportedOperationException {
if (!isTestHardware()) {
throw new UnsupportedOperationException("Test image data is only allowed on test hardware.");
}
this.testImageSource = path;
return this;
}
public IODevice getConnectedDevice(Port p) {
return deviceOnPort[p.ordinal()];
}
public HardwareImpl(GraphManager gm, String[] args, int i2cBus) {
this(gm, args, i2cBus, false, false, EMPTY,EMPTY,EMPTY,EMPTY,EMPTY);
}
protected HardwareImpl(GraphManager gm, String[] args, int i2cBus, boolean publishTime, boolean configI2C, HardwareConnection[] multiDigitalInput,
HardwareConnection[] digitalInputs, HardwareConnection[] digitalOutputs, HardwareConnection[] pwmOutputs, HardwareConnection[] analogInputs) {
super(gm, args);
ReactiveIoTListenerStage.initOperators(operators);
this.pcm.addConfig(new PipeConfig(NetPayloadSchema.instance,
2, //only a few requests when FogLight
MINIMUM_TLS_BLOB_SIZE));
this.pcm.addConfig(new PipeConfig(SerialInputSchema.instance,
DEFAULT_LENGTH,
DEFAULT_PAYLOAD_SIZE));
this.i2cBus = i2cBus;
this.configI2C = configI2C; //may be removed.
this.digitalInputs = digitalInputs;
this.digitalOutputs = digitalOutputs;
this.pwmOutputs = pwmOutputs;
this.analogInputs = analogInputs;
this.getTempPipeOfStartupSubscriptions().initBuffers();
}
public I2CBacking getI2CBacking() {
if (null == i2cBackingInternal) {
i2cBackingInternal = getI2CBacking((byte)i2cBus, false);
}
return i2cBackingInternal;
}
private static I2CBacking getI2CBacking(byte deviceNum, boolean reportError) {
long start = System.currentTimeMillis();
try {
return new I2CNativeLinuxBacking().configure(deviceNum);
} catch (Throwable t) {
if (reportError) {
logger.info("warning could not find the i2c bus", t);
}
//avoid non error case that is used to detect which hardware is running.
return null;
} finally {
logger.info("duration of getI2CBacking {} ", System.currentTimeMillis()-start);
}
}
protected HardwareConnection[] growHardwareConnections(HardwareConnection[] original, HardwareConnection toAdd) {
final int len = original.length;
//Validate that what we are adding is safe
int i = len;
while (--i>=0) {
if (original[i].register == toAdd.register) {
throw new UnsupportedOperationException("This connection "+toAdd.register+" already has attachment "+original[i].twig+" so the attachment "+toAdd.twig+" can not be added.");
}
}
//Grow the array
HardwareConnection[] result = new HardwareConnection[len+1];
System.arraycopy(original, 0, result, 0, len);
result[len] = toAdd;
return result;
}
protected I2CConnection[] growI2CConnections(I2CConnection[] original, I2CConnection toAdd){
if (null==original) {
return new I2CConnection[] {toAdd};
} else {
int l = original.length;
I2CConnection[] result = new I2CConnection[l+1];
System.arraycopy(original, 0, result, 0, l);
result[l] = toAdd;
return result;
}
}
protected Hardware internalConnectAnalog(IODevice t, int connection, int customRate, int customAverageMS, boolean everyValue) {
if (t.isInput()) {
assert(!t.isOutput());
analogInputs = growHardwareConnections(analogInputs, new HardwareConnection(t,connection, customRate, customAverageMS, everyValue));
} else {
assert(t.isOutput());
pwmOutputs = growHardwareConnections(pwmOutputs, new HardwareConnection(t,connection, customRate, customAverageMS, everyValue));
}
return this;
}
protected Hardware internalConnectDigital(IODevice t, int connection, int customRate, int customAverageMS, boolean everyValue) {
if (t.isInput()) {
assert(!t.isOutput());
digitalInputs = growHardwareConnections(digitalInputs, new HardwareConnection(t,connection, customRate, customAverageMS, everyValue));
} else {
assert(t.isOutput());
digitalOutputs = growHardwareConnections(digitalOutputs, new HardwareConnection(t,connection, customRate, customAverageMS, everyValue));
}
return this;
}
@Override
public Hardware connect(I2CIODevice t){
logger.debug("Connecting I2C Device "+t.getClass());
if(t.isInput()){
i2cInputs = growI2CConnections(i2cInputs, t.getI2CConnection());
}
if(t.isOutput()){
i2cOutputs = growI2CConnections(i2cOutputs, t.getI2CConnection());
}
this.useI2C();
return this;
}
@Override
public Hardware connect(I2CIODevice t, int customRateMS){
logger.debug("Connecting I2C Device "+t.getClass());
if(t.isInput()){
i2cInputs = growI2CConnections(i2cInputs, new I2CConnection(t.getI2CConnection(),customRateMS));
}
if(t.isOutput()){
i2cOutputs = growI2CConnections(i2cOutputs, t.getI2CConnection());
}
this.useI2C();
return this;
}
public Hardware useSerial(Baud baud) {
this.rs232ClientBaud = baud;
return this;
}
/**
*
* @param baud
* @param device Name of the port. On UNIX systems this will typically
* be of the form /dev/ttyX, where X is a port number. On
* Windows systems this will typically of the form COMX,
* where X is again a port number.
*/
public Hardware useSerial(Baud baud, String device) {
this.rs232ClientBaud = baud;
this.rs232ClientDevice = device;
return this;
}
public Hardware useI2C() {
this.configI2C = true;
return this;
}
public Hardware useCamera() {
this.configCamera = true;
return this;
}
@Deprecated //would be nice if we did not have to do this.
public Hardware useI2C(int bus) {
this.configI2C = true;
this.i2cBus = bus;
return this;
}
public boolean isUseI2C() {
return this.configI2C;
}
public abstract HardwarePlatformType getPlatformType();
public abstract int read(Port port); //Platform specific
public abstract void write(Port port, int value); //Platform specific
public int maxAnalogMovingAverage() {
return MAX_MOVING_AVERAGE_SUPPORTED;
}
public void coldSetup(){
System.out.println("");
}
protected HardwareConnection[] buildUsedLines() {
HardwareConnection[] result = new HardwareConnection[digitalInputs.length+
digitalOutputs.length+
pwmOutputs.length+
analogInputs.length+
(configI2C?2:0)];
int pos = 0;
System.arraycopy(digitalInputs, 0, result, pos, digitalInputs.length);
pos+=digitalInputs.length;
findDup(result,pos,digitalOutputs, false);
System.arraycopy(digitalOutputs, 0, result, pos, digitalOutputs.length);
pos+=digitalOutputs.length;
findDup(result,pos,pwmOutputs, false);
System.arraycopy(pwmOutputs, 0, result, pos, pwmOutputs.length);
pos+=pwmOutputs.length;
findDup(result,pos,analogInputs, true);
int j = analogInputs.length;
while (--j>=0) {
result[pos++] = new HardwareConnection(analogInputs[j].twig,(int) EdisonConstants.ANALOG_CONNECTOR_TO_PIN[analogInputs[j].register]);
}
if (configI2C) {
findDup(result,pos,EdisonConstants.i2cPins, false);
System.arraycopy(EdisonConstants.i2cPins, 0, result, pos, EdisonConstants.i2cPins.length);
pos+=EdisonConstants.i2cPins.length;
}
return result;
}
private static void findDup(HardwareConnection[] base, int baseLimit, HardwareConnection[] items, boolean mapAnalogs) {
int i = items.length;
while (--i>=0) {
int j = baseLimit;
while (--j>=0) {
if (mapAnalogs ? base[j].register == EdisonConstants.ANALOG_CONNECTOR_TO_PIN[items[i].register] : base[j]==items[i]) {
throw new UnsupportedOperationException("Connector "+items[i]+" is assigned more than once.");
}
}
}
}
public void shutdown() {
super.shutdown();
//can be overridden by specific hardware impl if shutdown is supported.
}
private void createUARTInputStage(Pipe masterUARTPipe) {
RS232Clientable client = buildSerialClient();
new SerialDataReaderStage(this.gm, masterUARTPipe, client);
}
protected RS232Clientable buildSerialClient() {
if (null==rs232Client) {
//custom hardware can override this
rs232Client = new RS232Client(rs232ClientDevice, rs232ClientBaud);
}
return rs232Client;
}
protected void createADInputStage(Pipe masterResponsePipe) {
//NOTE: rate is NOT set since stage sets and configs its own rate based on polling need.
ReadDeviceInputStage adInputStage = new ReadDeviceInputStage(this.gm, masterResponsePipe, this);
}
protected void createI2COutputInputStage(MsgRuntime,?,?> runtime, Pipe[] i2cPipes,
Pipe[] masterI2CgoOut, Pipe[] masterI2CackIn, Pipe masterI2CResponsePipe) {
if (hasI2CInputs()) {
I2CJFFIStage i2cJFFIStage = new I2CJFFIStage(gm, runtime, masterI2CgoOut, i2cPipes, masterI2CackIn, masterI2CResponsePipe, this);
} else {
//TODO: build an output only version of this stage because there is nothing to read
I2CJFFIStage i2cJFFIStage = new I2CJFFIStage(gm, runtime, masterI2CgoOut, i2cPipes, masterI2CackIn, masterI2CResponsePipe, this);
}
}
protected void createADOutputStage(MsgRuntime,?,?> runtime, Pipe[] requestPipes, Pipe[] masterPINgoOut, Pipe[] masterPINackIn) {
DirectHardwareAnalogDigitalOutputStage adOutputStage = new DirectHardwareAnalogDigitalOutputStage(gm, runtime, requestPipes, masterPINgoOut, masterPINackIn, this);
}
public boolean isListeningToSerial(Object listener) {
return listener instanceof SerialListenerBase
|| !ChildClassScanner.visitUsedByClass(null, listener, deepListener, SerialListenerTransducer.class);
}
public boolean isListeningToCamera(Object listener) {
return listener instanceof ImageListenerBase
|| !ChildClassScanner.visitUsedByClass(null, listener, deepListener, ImageListenerTransducer.class);
}
public boolean isListeningToLocationViaCamera(Object listener) {
return listener instanceof LocationListenerBase
|| !ChildClassScanner.visitUsedByClass(null, listener, deepListener, LocationListenerTransducer.class);
}
public boolean isListeningToTrainingViaCamera(Object listener) {
return listener instanceof CalibrationListenerBase
|| !ChildClassScanner.visitUsedByClass(null, listener, deepListener, CalibrationListenerTransducer.class);
}
public boolean isListeningToI2C(Object listener) {
return listener instanceof I2CListenerBase
|| !ChildClassScanner.visitUsedByClass(null, listener, deepListener, I2CListenerTransducer.class);
}
public boolean isListeningToPins(Object listener) {
return listener instanceof DigitalListenerBase ||
listener instanceof AnalogListenerBase ||
listener instanceof RotaryListenerBase
|| !ChildClassScanner.visitUsedByClass(null, listener, deepListener, DigitalListenerTransducer.class)
|| !ChildClassScanner.visitUsedByClass(null, listener, deepListener, AnalogListenerTransducer.class)
|| !ChildClassScanner.visitUsedByClass(null, listener, deepListener, RotaryListenerTransducer.class);
}
private Pipe getTempPipeOfStartupSubscriptions() {
if (null==tempPipeOfStartupSubscriptions) {
final PipeConfig messagePubSubConfig = new PipeConfig(MessagePubSub.instance, maxStartupSubs,maxTopicLengh);
tempPipeOfStartupSubscriptions = new Pipe(messagePubSubConfig);
}
return tempPipeOfStartupSubscriptions;
}
public boolean hasI2CInputs() {
return this.i2cInputs!=null && this.i2cInputs.length>0;
}
public I2CConnection[] getI2CInputs() {
return null==i2cInputs?new I2CConnection[0]:i2cInputs;
}
public HardwareConnection[] getAnalogInputs() {
return analogInputs;
}
public HardwareConnection[] getDigitalInputs() {
return digitalInputs;
}
public ScriptedSchedule buildI2CPollSchedule() {
I2CConnection[] localInputs = getI2CInputs();
long[] schedulePeriods = new long[localInputs.length];
for (int i = 0; i < localInputs.length; i++) {
schedulePeriods[i] = localInputs[i].responseMS*MS_TO_NS;
}
logger.info("Known I2C rates: {}",Arrays.toString(schedulePeriods));
return PMath.buildScriptedSchedule(schedulePeriods);
}
public boolean hasDigitalOrAnalogInputs() {
return (analogInputs.length+digitalInputs.length)>0;
}
public boolean hasDigitalOrAnalogOutputs() {
return (pwmOutputs.length+digitalOutputs.length)>0;
}
public HardwareConnection[] combinedADConnections() {
HardwareConnection[] localAInputs = getAnalogInputs();
HardwareConnection[] localDInputs = getDigitalInputs();
int totalCount = localAInputs.length + localDInputs.length;
HardwareConnection[] results = new HardwareConnection[totalCount];
System.arraycopy(localAInputs, 0, results, 0, localAInputs.length);
System.arraycopy(localDInputs, 0, results, localAInputs.length, localDInputs.length);
return results;
}
public ScriptedSchedule buildADPollSchedule() {
HardwareConnection[] localAInputs = getAnalogInputs();
HardwareConnection[] localDInputs = getDigitalInputs();
int totalCount = localAInputs.length + localDInputs.length;
if (0==totalCount) {
return null;
}
long[] schedulePeriods = new long[totalCount];
int j = 0;
for (int i = 0; i < localAInputs.length; i++) {
schedulePeriods[j++] = localAInputs[i].responseMS*MS_TO_NS;
}
for (int i = 0; i < localDInputs.length; i++) {
schedulePeriods[j++] = localDInputs[i].responseMS*MS_TO_NS;
}
//analogs then the digitals
return PMath.buildScriptedSchedule(schedulePeriods);
}
public byte convertToPort(byte connection) {
return connection;
}
@Override
public Hardware connect(ADIODevice t, Port port, int customRateMS, int customAvgWindowMS, boolean everyValue) {
int portsLeft = t.pinsUsed();
while (--portsLeft >= 0){
deviceOnPort[port.ordinal()] = t;
if (0 != (port.mask&Port.IS_ANALOG)) {
internalConnectAnalog(t, port.port, customRateMS, customAvgWindowMS, everyValue);
}
else if (0 != (port.mask&Port.IS_DIGITAL)) {
internalConnectDigital(t, port.port, customRateMS, customAvgWindowMS, everyValue);
}
port = Port.nextPort(port);
}
return this;
}
@Override
public Hardware connect(ADIODevice t, Port port, int customRateMS, int customAvgWindowMS) {
return connect(t,port,customRateMS, customAvgWindowMS ,DEFAULT_EVERY_VALUE);
}
@Override
public Hardware connect(ADIODevice t, Port port, int customRateMS) {
return connect(t,port,customRateMS, DEFAULT_AVERAGE_WINDOW_MS ,false);
}
@Override
public Hardware connect(ADIODevice t, Port port, int customRateMS, boolean everyValue) {
return connect(t,port,customRateMS, DEFAULT_AVERAGE_WINDOW_MS ,everyValue);
}
@Override
public Hardware connect(ADIODevice t, Port port) {
return connect (t, port, t.defaultPullRateMS(),DEFAULT_AVERAGE_WINDOW_MS,false);
}
public void releasePinOutTraffic(int count, MsgCommandChannel> gcc) {
MsgCommandChannel.publishGo(count, IDX_PIN, gcc);
}
public void releaseI2CTraffic(int count, MsgCommandChannel> gcc) {
MsgCommandChannel.publishGo(count, IDX_I2C, gcc);
}
@Override
public void releasePubSubTraffic(int count, MsgCommandChannel> gcc) {
MsgCommandChannel.publishGo(count, IDX_MSG, gcc);
}
public static String generateFilePath(String prefix, String suffix) {
String home = System.getenv().get("HOME");
if (null==home) {
return tempFilePath(prefix, suffix);
} else {
try {
File createTempFile = File.createTempFile(prefix, suffix, new File(home));
String absolutePath = createTempFile.getAbsolutePath();
createTempFile.delete();
return absolutePath;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
public static String tempFilePath(String prefix, String suffix) {
try {
File createTempFile = File.createTempFile(prefix, suffix);
String absolutePath = createTempFile.getAbsolutePath();
createTempFile.delete();
return absolutePath;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public void buildStages(MsgRuntime runtime) {
IntHashTable subscriptionPipeLookup2 = MsgRuntime.getSubPipeLookup(runtime);
Pipe[] i2cResponsePipes = GraphManager.allPipesOfTypeWithNoProducer(gm, I2CResponseSchema.instance);
Pipe[] responsePipes = GraphManager.allPipesOfTypeWithNoProducer(gm, GroveResponseSchema.instance);
Pipe[] serialOutputPipes = GraphManager.allPipesOfTypeWithNoConsumer(gm, SerialOutputSchema.instance);
Pipe[] i2cPipes = GraphManager.allPipesOfTypeWithNoConsumer(gm, I2CCommandSchema.instance);
Pipe[] pinRequestPipes = GraphManager.allPipesOfTypeWithNoConsumer(gm, GroveRequestSchema.instance);
Pipe[] serialInputPipes = GraphManager.allPipesOfTypeWithNoProducer(gm, SerialInputSchema.instance);
Pipe[] httpClientResponsePipes = GraphManager.allPipesOfTypeWithNoProducer(gm, NetResponseSchema.instance);
Pipe[] subscriptionPipes = GraphManager.allPipesOfTypeWithNoProducer(gm, MessageSubscription.instance);
Pipe[] orderPipes = GraphManager.allPipesOfTypeWithNoConsumer(gm, TrafficOrderSchema.instance);
Pipe[] httpClientRequestPipes = GraphManager.allPipesOfTypeWithNoConsumer(gm, ClientHTTPRequestSchema.instance);
Pipe[] messagePubSub = GraphManager.allPipesOfTypeWithNoConsumer(gm, MessagePubSub.instance);
Pipe[] ingressMessagePipes = GraphManager.allPipesOfTypeWithNoConsumer(gm, IngressMessages.instance);
//TODO: must pull out those pubSub Pipes for direct connections
//TODO: new MessageSchema for direct messages from point to point
// create the pipe instead of pub sub and attach?
//TODO: declare up front once in connections, direct connect topics
// upon seeing these we build a new pipe
int commandChannelCount = orderPipes.length;
int eventSchemas = 0;
IDX_PIN = pinRequestPipes.length>0 ? eventSchemas++ : -1;
IDX_I2C = (isUseI2C() || i2cPipes.length>0 || i2cResponsePipes.length > 0) ? eventSchemas++ : -1; //the 'or' check is to ensure that reading without a cmd channel works
IDX_MSG = (IntHashTable.isEmpty(subscriptionPipeLookup2) && subscriptionPipes.length==0 && messagePubSub.length==0) ? -1 : eventSchemas++;
IDX_NET = useNetClient(httpClientRequestPipes) ? eventSchemas++ : -1;
IDX_SER = serialOutputPipes.length>0 ? eventSchemas++ : -1;
// logger.info("build stages pin {}",IDX_PIN);
// logger.info("build stages i2c {}",IDX_I2C);
// logger.info("build stages msg {}",IDX_MSG);
// logger.info("build stages net {}",IDX_NET);
// logger.info("build stages ser {}",IDX_SER);
long timeout = 12_000; //12 seconds
//TODO: can we share this while with the parent BuilderImpl, I think so..
int maxGoPipeId = 0;
int t = commandChannelCount;
Pipe[][] masterGoOut = new Pipe[eventSchemas][0];
Pipe[][] masterAckIn = new Pipe[eventSchemas][0];
if (IDX_PIN >= 0) {
masterGoOut[IDX_PIN] = new Pipe[pinRequestPipes.length];
masterAckIn[IDX_PIN] = new Pipe[pinRequestPipes.length];
}
if (IDX_I2C >= 0) {
masterGoOut[IDX_I2C] = new Pipe[i2cPipes.length];
masterAckIn[IDX_I2C] = new Pipe[i2cPipes.length];
}
if (IDX_MSG >= 0) {
masterGoOut[IDX_MSG] = new Pipe[messagePubSub.length];
masterAckIn[IDX_MSG] = new Pipe[messagePubSub.length];
}
if (IDX_NET >= 0) {
masterGoOut[IDX_NET] = new Pipe[httpClientRequestPipes.length];
masterAckIn[IDX_NET] = new Pipe[httpClientRequestPipes.length];
}
if (IDX_SER >=0) {
masterGoOut[IDX_SER] = new Pipe[serialOutputPipes.length];
masterAckIn[IDX_SER] = new Pipe[serialOutputPipes.length];
}
while (--t>=0) {
//Only returns the features associated with this pipe, eg only those needing a cop.
int features = getFeatures(gm, orderPipes[t]);
Pipe[] goOut = new Pipe[eventSchemas];
Pipe[] ackIn = new Pipe[eventSchemas];
boolean isDynamicMessaging = (features&Behavior.DYNAMIC_MESSAGING) != 0;
boolean isNetRequester = (features&Behavior.NET_REQUESTER) != 0;
boolean isPinWriter = (features&FogRuntime.PIN_WRITER) != 0;
boolean isI2CWriter = (features&FogRuntime.I2C_WRITER) != 0;
boolean isSerialWriter = (features&FogRuntime.SERIAL_WRITER) != 0;
boolean hasConnections = false;
if (isDynamicMessaging && IDX_MSG>=0) {
hasConnections = true;
maxGoPipeId = populateGoAckPipes(maxGoPipeId, masterGoOut, masterAckIn, goOut, ackIn, IDX_MSG);
}
if (isNetRequester && IDX_NET>=0) {
hasConnections = true;
maxGoPipeId = populateGoAckPipes(maxGoPipeId, masterGoOut, masterAckIn, goOut, ackIn, IDX_NET);
}
if (isPinWriter && IDX_PIN>=0) {
hasConnections = true;
maxGoPipeId = populateGoAckPipes(maxGoPipeId, masterGoOut, masterAckIn, goOut, ackIn, IDX_PIN);
}
if (isI2CWriter && IDX_I2C>=0) {
hasConnections = true;
maxGoPipeId = populateGoAckPipes(maxGoPipeId, masterGoOut, masterAckIn, goOut, ackIn, IDX_I2C);
}
if (isSerialWriter && IDX_SER>=0) {
hasConnections = true;
maxGoPipeId = populateGoAckPipes(maxGoPipeId, masterGoOut, masterAckIn, goOut, ackIn, IDX_SER);
}
if (true | hasConnections) {
TrafficCopStage trafficCopStage = new TrafficCopStage(gm, timeout, orderPipes[t], ackIn, goOut, runtime, this);
} else {
//this optimization can no longer be done due to the use of shutdown on command channel.
// revisit this later...
//TODO: we can reintroduce this as long has we have a stage here which does shutdown on -1;
PipeCleanerStage.newInstance(gm, orderPipes[t]);
}
}
initChannelBlocker(maxGoPipeId);
buildHTTPClientGraph(runtime, httpClientResponsePipes, httpClientRequestPipes, masterGoOut, masterAckIn);
if (IDX_MSG <0) {
logger.trace("saved some resources by not starting up the unused pub sub service.");
} else {
createMessagePubSubStage(
runtime,
subscriptionPipeLookup2, ingressMessagePipes,
messagePubSub,
masterGoOut[IDX_MSG], masterAckIn[IDX_MSG],
subscriptionPipes);
}
//////////////////
//only build and connect I2C if it is used for either in or out
//////////////////
Pipe masterI2CResponsePipe = null;
if (i2cResponsePipes.length>0) {
if (i2cResponsePipes.length==1) {
//skip ReplicatorStage for only single listener
masterI2CResponsePipe = i2cResponsePipes[0];
// PronghornStage stage = GraphManager.getRingConsumer(gm, masterI2CResponsePipe.id);
//set the rete faster...
} else {
//TODO: get the pipe definitions?
masterI2CResponsePipe = I2CResponseSchema.instance.newPipe(FogRuntime.i2cResponseDefaultLength, FogRuntime.i2cResponseDefaultMaxPayload);
ReplicatorStage.newInstance(gm, masterI2CResponsePipe, i2cResponsePipes);
//TODO: make this replicator go faster rate as well..
}
}
if (i2cPipes.length>0 || (null!=masterI2CResponsePipe)) {
createI2COutputInputStage(runtime, i2cPipes, masterGoOut[IDX_I2C], masterAckIn[IDX_I2C], masterI2CResponsePipe);
}
//////////////
//only build and connect gpio input responses if it is used
//////////////
if (responsePipes.length>1) {
Pipe masterResponsePipe = GroveResponseSchema.instance.newPipe(DEFAULT_LENGTH, DEFAULT_PAYLOAD_SIZE);
ReplicatorStage.newInstance(gm, masterResponsePipe, responsePipes);
createADInputStage(masterResponsePipe);
} else {
if (responsePipes.length==1) {
createADInputStage(responsePipes[0]);
}
}
/////////////
//only build serial output if data is sent
/////////////
if (serialOutputPipes.length>0) {
assert(null!=masterGoOut[IDX_SER]);
assert(serialOutputPipes.length == masterGoOut[IDX_SER].length) : serialOutputPipes.length+" == "+masterGoOut[IDX_SER].length;
createSerialOutputStage(runtime, serialOutputPipes, masterGoOut[IDX_SER], masterAckIn[IDX_SER]);
}
//////////////
//only build serial input if the data is consumed
//////////////
if (serialInputPipes.length>1) {
Pipe masterUARTPipe = new Pipe(pcm.getConfig(SerialInputSchema.class));
new ReplicatorStage(gm, masterUARTPipe, serialInputPipes);
createUARTInputStage(masterUARTPipe);
} else {
if (serialInputPipes.length==1) {
createUARTInputStage(serialInputPipes[0]);
} else {
}
}
//////////////
//setup location detection from images
//////////////
//if empty then we have no behaviors listening to training results
Pipe[] calibrationDone = GraphManager.allPipesOfTypeWithNoProducer(gm, CalibrationStatusSchema.instance);
//if empty then we have no behaviors reading location data
Pipe[] probLocation = GraphManager.allPipesOfTypeWithNoProducer(gm, ProbabilitySchema.instance);
//if empty then we have behavior command channel controlling training on/off mode.
Pipe[] modeSelectionPipe = GraphManager.allPipesOfTypeWithNoConsumer(gm, LocationModeSchema.instance);
////////
if (calibrationDone.length>0 || probLocation.length>0 || modeSelectionPipe.length>0) {
if (modeSelectionPipe.length>1) {
throw new UnsupportedOperationException("Can not support more than 1 behavior/command channel turning on/off learning mode");
}
Pipe imagePipe = newImageSchemaPipe();
Pipe rootCalibrationDone;
if (calibrationDone.length>1) {
rootCalibrationDone = PipeConfig.pipe(calibrationDone[0].config().shrink2x());
ReplicatorStage.newInstance(gm, rootCalibrationDone, calibrationDone);
} else {
if (calibrationDone.length==1) {
rootCalibrationDone = calibrationDone[0];
} else {
rootCalibrationDone = null;
}
}
Pipe rootProbLocation;
if (probLocation.length>1) {
rootProbLocation = PipeConfig.pipe(probLocation[0].config().shrink2x());
ReplicatorStage.newInstance(gm, rootProbLocation, probLocation);
} else {
if (probLocation.length==1) {
rootProbLocation = probLocation[0];
} else {
rootProbLocation = null;
}
}
ImageGraphBuilder.buildLocationDetectionGraph(gm, loadLocationDataFilePath, saveLocationDataFilePath, imagePipe,
modeSelectionPipe.length==0 ? null :modeSelectionPipe[0],
rootProbLocation,
rootCalibrationDone);
}
///////////////
//only build image input if the data is consumed
///////////////
Pipe[] imageInputPipes = GraphManager.allPipesOfTypeWithNoProducer(gm, ImageSchema.instance);//done late to ensure we capture new consumers
if (imageInputPipes.length > 1) {
Pipe masterImagePipe = PipeConfig.pipe(imageInputPipes[0].config().shrink2x());
ReplicatorStage.newInstance(gm, masterImagePipe, imageInputPipes);
if (!isTestHardware()) {
new LinuxImageCaptureStage(gm, masterImagePipe, imageFrameTriggerRateMicros, imageWidth, imageHeight);
} else {
new LinuxImageCaptureStage(gm, masterImagePipe, imageFrameTriggerRateMicros, imageWidth, imageHeight, testImageSource);
}
} else if (imageInputPipes.length == 1){
if (!isTestHardware()) {
new LinuxImageCaptureStage(gm, imageInputPipes[0], imageFrameTriggerRateMicros, imageWidth, imageHeight);
} else {
new LinuxImageCaptureStage(gm, imageInputPipes[0], imageFrameTriggerRateMicros, imageWidth, imageHeight, testImageSource);
}
}
///////////////
//only build direct pin output when we detected its use
///////////////
if (IDX_PIN>=0) {
createADOutputStage(runtime, pinRequestPipes, masterGoOut[IDX_PIN], masterAckIn[IDX_PIN]);
}
}
private String featureName(final int c) {
if (c == IDX_I2C) {
//FogRuntime.I2C_WRITER;
return "I2C_WRITER";
}
if (c == IDX_MSG) {
//Behavior.DYNAMIC_MESSAGING;
return "DYNAMIC_MESSAGING";
}
if (c == IDX_NET) { //TODO: where is the responder??
//Behavior.NET_REQUESTER;
return "NET_REQUESTER";
}
if (c == IDX_PIN) {
//FogRuntime.PIN_WRITER;
return "PIN_WRITER";
}
if (c == IDX_SER) {
//FogRuntime.SERIAL_WRITER;
return "SERIAL_WRITER";
}
return null;
}
protected void createSerialOutputStage(MsgRuntime,?,?> runtime, Pipe[] serialOutputPipes,
Pipe[] masterGoOut, Pipe[] masterAckIn) {
new SerialDataWriterStage(gm, runtime, serialOutputPipes, masterGoOut, masterAckIn,
this, this.buildSerialClient());
}
public Pipe newImageSchemaPipe() {
//room for 2 images so the first can be consumed while we write the second
return new Pipe(new PipeConfig(ImageSchema.instance,
(int)(1.5*(LinuxImageCaptureStage.DEFAULT_FRAME_HEIGHT + 1)),
LinuxImageCaptureStage.DEFAULT_ROW_SIZE * 3));
}
public Pipe newLocationSchemaPipe() {
return ProbabilitySchema.instance.newPipe(4, 1<<12);
}
public Pipe newCalibrationSchemaPipe() {
return CalibrationStatusSchema.instance.newPipe(4, 0);
}
public static int serialIndex(HardwareImpl hardware) {
return hardware.IDX_SER;
}
public static int i2cIndex(HardwareImpl hardware) {
return hardware.IDX_I2C;
}
@Override
public int pubSubIndex() {
return IDX_MSG;
}
@Override
public int netIndex() {
return IDX_NET;
}
public boolean isTestHardware() {
return false;
}
}