
com.ociweb.iot.maker.FogCommandChannel Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of foglight Show documentation
Show all versions of foglight Show documentation
FogLight is a lightweight runtime that enables makers of all ages and skill levels to create highly
performant apps for embedded devices like Raspberry Pi's.
The newest version!
package com.ociweb.iot.maker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.ociweb.gl.api.MsgCommandChannel;
import com.ociweb.gl.api.Writable;
import com.ociweb.iot.hardware.HardwareImpl;
import com.ociweb.iot.hardware.impl.SerialDataSchema;
import com.ociweb.iot.hardware.impl.SerialOutputSchema;
import com.ociweb.pronghorn.image.schema.LocationModeSchema;
import com.ociweb.pronghorn.iot.schema.GroveRequestSchema;
import com.ociweb.pronghorn.iot.schema.I2CCommandSchema;
import com.ociweb.pronghorn.pipe.DataOutputBlobWriter;
import com.ociweb.pronghorn.pipe.Pipe;
import com.ociweb.pronghorn.pipe.PipeConfig;
import com.ociweb.pronghorn.pipe.PipeConfigManager;
import com.ociweb.pronghorn.pipe.PipeWriter;
import com.ociweb.pronghorn.stage.scheduling.GraphManager;
/**
* Represents a dedicated channel for communicating with a single device
* or resource on an IoT system.
*
*/
public abstract class FogCommandChannel extends MsgCommandChannel {
private static final Logger logger = LoggerFactory.getLogger(FogCommandChannel.class);
public static final int SIZE_OF_I2C_COMMAND = Pipe.sizeOf(I2CCommandSchema.instance, I2CCommandSchema.MSG_COMMAND_7);
protected Pipe i2cOutput;
protected Pipe pinOutput;
protected Pipe serialOutput;
protected Pipe locationModeOutput = null;
public static final int ANALOG_BIT = 0x40; //added to connection to track if this is the analog .0vs digital
protected static final long MS_TO_NS = 1_000_000;
protected int runningI2CCommandCount;
protected int maxCommands=-1;
public static final int I2C_WRITER = 1<<29;
public static final int PIN_WRITER = 1<<28;
public static final int SERIAL_WRITER = 1<<27;
public static final int BT_WRITER = 1<<26;
public static final int IMG_LOC_MODE = 1<<25;
protected FogCommandChannel(GraphManager gm, HardwareImpl hardware,
int features, int parallelInstanceId,
PipeConfigManager pcm) {
super(gm, hardware, features, parallelInstanceId, pcm);
if ((I2C_WRITER & features) != 0) {
hardware.useI2C();//critical for hardware to know that I2C is really really in use.
}
}
public LocationModeService newLocationModeSerivce() {
return new LocationModeService(this);
}
public LocationModeService newLocationModeSerivce(int commandCountCapacity, int maxMessageSize) {
return new LocationModeService(this, commandCountCapacity, maxMessageSize);
}
public I2CService newI2CService() {
return new I2CService(this);
}
public I2CService newI2CService(int commandCountCapacity, int maxMessageSize) {
return new I2CService(this, commandCountCapacity, maxMessageSize);
}
@Deprecated
public void ensureI2CWriting() {
if (maxCommands>=0) {
throw new UnsupportedOperationException("Too late, this method must be called in define behavior.");
}
this.initFeatures |= I2C_WRITER;
}
@Deprecated
public void ensureI2CWriting(int commandCountCapacity, int maxMessageSize) {
if (maxCommands>=0) {
throw new UnsupportedOperationException("Too late, this method must be called in define behavior.");
}
growCommandCountRoom(this, commandCountCapacity);
this.initFeatures |= I2C_WRITER;
PipeConfig config = pcm.getConfig(I2CCommandSchema.class);
if (isTooSmall(commandCountCapacity, maxMessageSize, config)) {
this.pcm.addConfig(Math.max(config.minimumFragmentsOnPipe(), commandCountCapacity),
Math.max(config.maxVarLenSize(), maxMessageSize), I2CCommandSchema.class);
}
}
public PinService newPinService() {
return new PinService(this);
}
public PinService newPinService(int commandCountCapacity, int maxMessageSize) {
return new PinService(this,commandCountCapacity,maxMessageSize);
}
@Deprecated
public void ensurePinWriting() {
if (maxCommands>=0) {
throw new UnsupportedOperationException("Too late, this method must be called in define behavior.");
}
this.initFeatures |= PIN_WRITER;
}
@Deprecated
public void ensurePinWriting(int commandCountCapacity, int maxMessageSize) {
if (maxCommands>=0) {
throw new UnsupportedOperationException("Too late, this method must be called in define behavior.");
}
growCommandCountRoom(this, commandCountCapacity);
this.initFeatures |= PIN_WRITER;
PipeConfig config = pcm.getConfig(GroveRequestSchema.class);
if (isTooSmall(commandCountCapacity, maxMessageSize, config)) {
this.pcm.addConfig(Math.max(config.minimumFragmentsOnPipe(), commandCountCapacity),
Math.max(config.maxVarLenSize(), maxMessageSize), GroveRequestSchema.class);
}
}
@Deprecated
public void ensureSerialWriting() {
if (maxCommands>=0) {
throw new UnsupportedOperationException("Too late, this method must be called in define behavior.");
}
this.initFeatures |= SERIAL_WRITER;
}
@Deprecated
public void ensureSerialWriting(int commandCountCapacity, int maxMessageSize) {
if (maxCommands>=0) {
throw new UnsupportedOperationException("Too late, this method must be called in define behavior.");
}
growCommandCountRoom(this, commandCountCapacity);
this.initFeatures |= SERIAL_WRITER;
PipeConfig config = pcm.getConfig(SerialOutputSchema.class);
if (isTooSmall(commandCountCapacity, maxMessageSize, config)) {
this.pcm.addConfig(Math.max(config.minimumFragmentsOnPipe(), commandCountCapacity),
Math.max(config.maxVarLenSize(), maxMessageSize), SerialOutputSchema.class);
}
}
public SerialService newSerialService() {
return new SerialService(this);
}
public SerialService newSerialService(int commandCountCapacity, int maxMessageSize) {
return new SerialService(this,commandCountCapacity,maxMessageSize);
}
protected int usedFeaturesNeedingCop() {
//when looking at features that requires cops, eg go pipes we ignore
//the following since they do not use cops but are features;
int filteredFeatures = super.usedFeaturesNeedingCop();
if (0!=(IMG_LOC_MODE&filteredFeatures)) {
filteredFeatures ^= IMG_LOC_MODE;//cop not supported for turning on and off training mode. TODO: may want to add as feature.
}
return filteredFeatures;
}
@Override
protected void secondShutdownMsg() {
if (!sentEOF(i2cOutput)) {
if (!sentEOF(pinOutput)) {
if (!sentEOF(serialOutput)) {
super.secondShutdownMsg();
}
}
}
}
@Override
public Pipe>[] getOutputPipes() {
//we must wait till this last possible moment to build.
buildFogPipes();
return super.getOutputPipes();
}
private void buildFogPipes() {
if (maxCommands<0) { //this block will set maxCommands
//logger.trace("created new FogCommandChannel {}",this.initFeatures);
boolean setupPins = (PIN_WRITER & this.initFeatures) != 0;
if (setupPins) {
System.out.println("new Grove pipe for this command Channel "+this.hashCode());
this.pinOutput = new Pipe(pcm.getConfig(GroveRequestSchema.class));
} else {
this.pinOutput = null;
}
boolean setupSerial = (0 != (this.initFeatures & SERIAL_WRITER));//if feature bit is on then set for write...
if (setupSerial) {
logger.trace("created pipes for serial write");
serialOutput = newSerialOutputPipe(pcm.getConfig(SerialOutputSchema.class), builder);
} else {
serialOutput = null;
}
boolean setupLocationMode = (0 != (this.initFeatures & IMG_LOC_MODE));
if (setupLocationMode) {
locationModeOutput = PipeConfig.pipe(pcm.getConfig(LocationModeSchema.class));
}
boolean setupI2C = (I2C_WRITER & this.initFeatures) != 0;
if (setupI2C) {
//yes i2c usage
optionalOutputPipes = new Pipe>[]{
this.pinOutput,
this.i2cOutput = new Pipe(pcm.getConfig(I2CCommandSchema.class))
};
maxCommands = i2cOutput.sizeOfSlabRing/SIZE_OF_I2C_COMMAND;
} else {
//logger.trace("warning i2c was not set up");
i2cOutput=null;
maxCommands = 0;
//non i2c usage (TODO: THIS IS NEW CODE UNDER TEST)
optionalOutputPipes = new Pipe>[]{
this.pinOutput
};
}
//////////////////////////
//////////////////////////
int optionalPipeCount = 0;
if (null != serialOutput) {
optionalPipeCount++;
}
if (null != pinOutput) {
optionalPipeCount++;
}
if (null != i2cOutput) {
optionalPipeCount++;
}
if (null != locationModeOutput) {
optionalPipeCount++;
}
optionalOutputPipes = new Pipe>[optionalPipeCount];
if (null != locationModeOutput) {
optionalOutputPipes[(int) (byte)--optionalPipeCount] = locationModeOutput;
}
if (null!=serialOutput) {
optionalOutputPipes[(int) (byte)--optionalPipeCount] = serialOutput;
}
if (null!=i2cOutput) {
optionalOutputPipes[(int) (byte)(--optionalPipeCount)] = i2cOutput;
}
if (null!=pinOutput) {//always last??
optionalOutputPipes[--optionalPipeCount] = pinOutput;
}
}
}
private static Pipe newSerialOutputPipe(PipeConfig config,HardwareImpl hardware) {
return new Pipe(config) {
@SuppressWarnings("unchecked")
@Override
protected DataOutputBlobWriter createNewBlobWriter() {
return new SerialWriter(this);
}
};
}
protected boolean enterBlockOk() {
return aBool.compareAndSet(false, true);
}
protected boolean exitBlockOk() {
return aBool.compareAndSet(true, false);
}
/**
* Causes this channel to delay processing any actions on a given {@link Port}
* until the specified amount of time has elapsed.
*
* @param port Port to temporarily stop processing actions on.
* @param durationMilli Milliseconds until the port will process actions again.
*
* @return True if blocking was successful, and false otherwise.
*/
@Deprecated
public abstract boolean block(Port port, long durationMilli);
/**
* Causes this channel to delay processing any actions on a given {@link Port}
* until the specified UNIX time is reached.
*
* @param port Port to temporarily stop processing actions on.
* @param time Time, in milliseconds, since the UNIX epoch that indicates
* when actions should resume processing.
*
* @return True if blocking was successful, and false otherwise.
*/
public abstract boolean blockUntil(Port port, long time);
/**
* Sets the value of an analog/digital port on this command channel.
*
* @param port {@link Port} to set the value of.
* @param value true is set to on full and false is set to off full.
*
* @return True if the port could be set, and false otherwise.
*/
public abstract boolean setValue(Port port, boolean value);
/**
* Sets the value of an analog/digital port on this command channel.
*
* @param port {@link Port} to set the value of.
* @param value Value to set the port to.
*
* @return True if the port could be set, and false otherwise.
*/
public abstract boolean setValue(Port port, int value);
/**
* Sets the value of an analog/digital port on this command channel and then
* delays processing of all future actions on this port until a specified
* amount of time passes.
*
* @param port {@link Port} to set the value of.
* @param value Value to set the port to.
* @param durationMilli Time in milliseconds to delay processing of future actions
* on this port.
*
* @return True if the port could be set, and false otherwise.
*/
public abstract boolean setValueAndBlock(Port port, boolean value, long durationMilli);
/**
* Sets the value of an analog/digital port on this command channel and then
* delays processing of all future actions on this port until a specified
* amount of time passes.
*
* @param port {@link Port} to set the value of.
* @param value Value to set the port to.
* @param durationMilli Time in milliseconds to delay processing of future actions
* on this port.
*
* @return True if the port could be set, and false otherwise.
*/
public abstract boolean setValueAndBlock(Port port, int value, long durationMilli);
/**
* "Pulses" a given port, setting its state to True/On and them immediately
* setting its state to False/Off.
*
* @param port {@link Port} to pulse.
*
* @return True if the port could be pulsed, and false otherwise.
*/
public abstract boolean digitalPulse(Port port);
/**
* "Pulses" a given port, setting its state to True/On and them immediately
* setting its state to False/Off.
*
* @param port {@link Port} to pulse.
* @param durationNanos Time in nanoseconds to sustain the pulse for.
*
* @return True if the port could be pulsed, and false otherwise.
*/
public abstract boolean digitalPulse(Port port, long durationNanos);
@Deprecated
public boolean publishSerial(Writable writable) {
assert(writable != null);
assert((0 != (initFeatures & SERIAL_WRITER))) : "CommandChannel must be created with SERIAL_WRITER flag";
if (goHasRoom() &&
PipeWriter.tryWriteFragment(serialOutput, SerialDataSchema.MSG_CHUNKEDSTREAM_1)) {
SerialWriter pw = (SerialWriter) Pipe.outputStream(serialOutput);
//logger.warn("pw is {}", pw);
pw.openField(SerialDataSchema.MSG_CHUNKEDSTREAM_1_FIELD_BYTEARRAY_2, this);
writable.write(pw);//TODO: cool feature, writable to return false to abandon write..
pw.closeHighLevelField(SerialDataSchema.MSG_CHUNKEDSTREAM_1_FIELD_BYTEARRAY_2);
PipeWriter.publishWrites(serialOutput);
MsgCommandChannel.publishGo(1, HardwareImpl.serialIndex(builder), this);
return true;
} else {
return false;
}
}
/**
* Opens an I2C connection.
*
* @param targetAddress I2C address to open a connection to.
*
* @return An {@link DataOutputBlobWriter} with an {@link I2CCommandSchema} that's
* connected to the specified target address.
*
*/
@Deprecated
public DataOutputBlobWriter i2cCommandOpen(int targetAddress) {
assert((0 != (initFeatures & I2C_WRITER))) : "CommandChannel must be created with I2C_WRITER flag";
assert(enterBlockOk()) : "Concurrent usage error, ensure this never called concurrently";
try {
if (PipeWriter.tryWriteFragment(i2cOutput, I2CCommandSchema.MSG_COMMAND_7)) {
PipeWriter.writeInt(i2cOutput, I2CCommandSchema.MSG_COMMAND_7_FIELD_ADDRESS_12, targetAddress);
DataOutputBlobWriter writer = PipeWriter.outputStream(i2cOutput);
DataOutputBlobWriter.openField(writer);
return writer;
} else {
throw new UnsupportedOperationException("Pipe is too small for large volume of i2c data");
}
} finally {
assert(exitBlockOk()) : "Concurrent usage error, ensure this never called concurrently";
}
}
/**
* Triggers a delay for a given I2C address.
*
* @param targetAddress I2C address to trigger a delay on.
* @param durationNanos Time in nanoseconds to delay.
*/
@Deprecated
public void i2cDelay(int targetAddress, long durationNanos) {
assert((0 != (initFeatures & I2C_WRITER))) : "CommandChannel must be created with I2C_WRITER flag";
assert(enterBlockOk()) : "Concurrent usage error, ensure this never called concurrently";
try {
if (++runningI2CCommandCount > maxCommands) {
throw new UnsupportedOperationException("too many commands, found "+runningI2CCommandCount+" but only left room for "+maxCommands);
}
if (goHasRoom() && PipeWriter.tryWriteFragment(i2cOutput, I2CCommandSchema.MSG_BLOCKCONNECTION_20)) {
PipeWriter.writeInt(i2cOutput, I2CCommandSchema.MSG_BLOCKCONNECTION_20_FIELD_CONNECTOR_11, targetAddress);
PipeWriter.writeInt(i2cOutput, I2CCommandSchema.MSG_BLOCKCONNECTION_20_FIELD_ADDRESS_12, targetAddress);
PipeWriter.writeLong(i2cOutput, I2CCommandSchema.MSG_BLOCKCONNECTION_20_FIELD_DURATIONNANOS_13, durationNanos);
PipeWriter.publishWrites(i2cOutput);
}else {
throw new UnsupportedOperationException("Pipe is too small for large volume of i2c data");
}
} finally {
assert(exitBlockOk()) : "Concurrent usage error, ensure this never called concurrently";
}
}
@Deprecated
public boolean i2cIsReady() {
return i2cIsReady(1);
}
/**
* @return True if the I2C bus is ready for communication, and false otherwise.
*/
@Deprecated
public boolean i2cIsReady(int requestedCommandCount) {
assert((0 != (initFeatures & I2C_WRITER))) : "CommandChannel must be created with I2C_WRITER flag";
assert(null!=i2cOutput) : "pipe must not be null";
assert(Pipe.isInit(i2cOutput)) : "pipe must be initialized";
return goHasRoom() && PipeWriter.hasRoomForFragmentOfSize(i2cOutput, SIZE_OF_I2C_COMMAND*requestedCommandCount);
}
/**
* Flushes all awaiting I2C data to the I2C bus for consumption.
*/
@Deprecated
public void i2cFlushBatch() {
assert ((0 != (initFeatures & I2C_WRITER))) : "CommandChannel must be created with I2C_WRITER flag";
if (runningI2CCommandCount > 0) {
assert (enterBlockOk()) : "Concurrent usage error, ensure this never called concurrently";
try {
FogCommandChannel.releaseI2CTraffic(this);
runningI2CCommandCount = 0;
} finally {
assert (exitBlockOk()) : "Concurrent usage error, ensure this never called concurrently";
}
}
}
@Deprecated
public int i2cCommandClose(DataOutputBlobWriter writer) {
assert((0 != (initFeatures & I2C_WRITER))) : "CommandChannel must be created with I2C_WRITER flag";
assert(enterBlockOk()) : "Concurrent usage error, ensure this never called concurrently";
try {
if (++runningI2CCommandCount > maxCommands) {
throw new UnsupportedOperationException("too many commands, found "+runningI2CCommandCount+" but only left room for "+maxCommands);
}
int bytesWritten = DataOutputBlobWriter.closeHighLevelField(writer, I2CCommandSchema.MSG_COMMAND_7_FIELD_BYTEARRAY_2);
PipeWriter.publishWrites(i2cOutput);
return bytesWritten;
} finally {
assert(exitBlockOk()) : "Concurrent usage error, ensure this never called concurrently";
}
}
@Deprecated
public void i2cCommandClose() {
i2cCommandClose(PipeWriter.outputStream(i2cOutput));
}
public static void releaseI2CTraffic(FogCommandChannel cmd) {
cmd.builder.releaseI2CTraffic(cmd.runningI2CCommandCount, cmd);
}
/**
* start shutdown of the runtime, this can be vetoed or postponed by any shutdown listeners
*/
public void requestShutdown() {
assert(enterBlockOk()) : "Concurrent usage error, ensure this never called concurrently";
try {
builder.requestShutdown();
} finally {
assert(exitBlockOk()) : "Concurrent usage error, ensure this never called concurrently";
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy