├── Firmata
├── pom.xml
└── src
│ └── main
│ └── java
│ └── name
│ └── antonsmirnov
│ └── firmata
│ ├── BytesHelper.java
│ ├── Firmata.java
│ ├── FormatHelper.java
│ ├── IFirmata.java
│ ├── InitListener.java
│ ├── message
│ ├── AnalogMessage.java
│ ├── DigitalMessage.java
│ ├── FirmwareVersionMessage.java
│ ├── I2cConfigMessage.java
│ ├── I2cReadRequestMessage.java
│ ├── I2cReplyMessage.java
│ ├── I2cRequestMessage.java
│ ├── Message.java
│ ├── ProtocolVersionMessage.java
│ ├── ReportAnalogPinMessage.java
│ ├── ReportDigitalPortMessage.java
│ ├── ReportFirmwareVersionMessage.java
│ ├── ReportProtocolVersionMessage.java
│ ├── SamplingIntervalMessage.java
│ ├── ServoConfigMessage.java
│ ├── SetPinModeMessage.java
│ ├── StringSysexMessage.java
│ ├── SysexMessage.java
│ ├── SystemResetMessage.java
│ └── factory
│ │ ├── BoardMessageFactory.java
│ │ ├── MessageFactory.java
│ │ ├── MessageValidationException.java
│ │ └── arduino
│ │ ├── Diecimila.java
│ │ ├── Duemilanove.java
│ │ ├── Fio.java
│ │ ├── Mega.java
│ │ ├── Mega2560.java
│ │ ├── Mini.java
│ │ ├── Nano.java
│ │ └── Uno.java
│ ├── reader
│ ├── AnalogMessageReader.java
│ ├── BaseSysexMessageReader.java
│ ├── DigitalMessageReader.java
│ ├── FirmwareVersionMessageReader.java
│ ├── I2cReplyMessageReader.java
│ ├── IMessageReader.java
│ ├── ProtocolVersionMessageReader.java
│ ├── StringSysexMessageReader.java
│ └── SysexMessageReader.java
│ ├── wrapper
│ ├── AndFilter.java
│ ├── DateMessagePropertyManager.java
│ ├── DigitalPortWrapper.java
│ ├── DirectionMessageFilter.java
│ ├── DirectionMessagePropertyManager.java
│ ├── IMessageFilter.java
│ ├── IMessagePropertyManager.java
│ ├── MessagePropertyManager.java
│ ├── MessageWithProperties.java
│ ├── MessagesHistoryWrapper.java
│ ├── OrFilter.java
│ ├── PinModeWrapper.java
│ ├── ReportAutostopWrapper.java
│ └── StubMessageFilter.java
│ └── writer
│ ├── AnalogMessageWriter.java
│ ├── DigitalMessageWriter.java
│ ├── I2cConfigMessageWriter.java
│ ├── I2cRequestMessageWriter.java
│ ├── IMessageWriter.java
│ ├── ReportAnalogPinMessageWriter.java
│ ├── ReportDigitalPortMessageWriter.java
│ ├── ReportProtocolVersionMessageWriter.java
│ ├── SamplingIntervalMessageWriter.java
│ ├── ServoConfigMessageWriter.java
│ ├── SetPinModeMessageWriter.java
│ ├── SysexMessageWriter.java
│ └── SystemResetMessageWriter.java
├── FirmataTests
├── pom.xml
└── src
│ ├── main
│ └── java
│ │ └── name
│ │ └── antonsmirnov
│ │ └── firmata
│ │ ├── FirmataWaiter.java
│ │ ├── OriginalFirmata.java
│ │ ├── TestSerial.java
│ │ └── WaitException.java
│ └── test
│ └── java
│ └── name
│ └── antonsmirnov
│ └── firmata
│ └── tests
│ ├── AnalogMessageTest.java
│ ├── BaseFirmataTest.java
│ ├── BytesHelperTest.java
│ ├── DigitalMessageTest.java
│ ├── FirmataWrappersTest.java
│ ├── FirmwareVersionMessageTest.java
│ ├── I2cConfigMessageTest.java
│ ├── I2cReadRequestMessageTest.java
│ ├── I2cReplyMessageTest.java
│ ├── I2cRequestMessageTest.java
│ ├── MessageValidationTest.java
│ ├── ProtocolVersionMessageTest.java
│ ├── ReportAnalogPinMessageTest.java
│ ├── ReportDigitalPortMessageTest.java
│ ├── ReportFirmwareVersionMessageTest.java
│ ├── ReportProtocolVersionMessageTest.java
│ ├── SamplingIntervalMessageTest.java
│ ├── ServoConfigMessageTest.java
│ ├── SetPinModeMessageTest.java
│ ├── StringSysexMessageTest.java
│ ├── SysexMessageTest.java
│ ├── SystemResetMessageTest.java
│ └── hardware
│ ├── BaseHardwareTest.java
│ ├── DigitalWriteHardwareTest.java
│ ├── EchoStringHardwareTest.java
│ ├── HMC5883LHardwareTest.java
│ ├── ReadDigitalPortHardwareTest.java
│ └── ReportProtocolHardwareTest.java
├── IndepProcessingSerial
├── pom.xml
└── src
│ └── main
│ └── java
│ ├── name
│ └── antonsmirnov
│ │ └── firmata
│ │ └── serial
│ │ └── IndepProcessingSerialAdapter.java
│ └── processing
│ └── serial
│ └── IndepProcessingSerial.java
├── ProcessingSerial
├── pom.xml
├── res
│ ├── install_processing_core.bat
│ └── install_processing_serial.bat
└── src
│ └── main
│ └── java
│ └── name
│ └── antonsmirnov
│ └── firmata
│ └── serial
│ └── ProcessingSerialAdapter.java
├── README
├── Serial
├── pom.xml
└── src
│ ├── main
│ └── java
│ │ └── name
│ │ └── antonsmirnov
│ │ └── firmata
│ │ └── serial
│ │ ├── BufferingSerialWrapper.java
│ │ ├── ByteArrayByteBufferAdapter.java
│ │ ├── IByteBuffer.java
│ │ ├── ISerial.java
│ │ ├── ISerialListener.java
│ │ ├── QueueByteBufferAdapter.java
│ │ ├── SerialException.java
│ │ ├── SocketSerialAdapter.java
│ │ └── StreamingSerialAdapter.java
│ └── test
│ └── java
│ └── name
│ └── antonsmirnov
│ └── firmata
│ └── serial
│ ├── WritebackSerial.java
│ └── tests
│ ├── BufferingSerialWrapperTest.java
│ ├── SocketSerialAdapterTest.java
│ └── StreamingSerialAdapterTest.java
└── pom.xml
/Firmata/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 |
8 | name.antonsmirnov.firmata
9 | parent
10 | 1.0
11 |
12 |
13 | name.antonsmirnov.firmata
14 | Firmata
15 | 2.6
16 | Firmata
17 |
18 |
19 |
20 | Anton Smirnov
21 | dev@antonsmirnov.name
22 |
23 |
24 |
25 | Firmata implementation (with Serial API dependency and with no impl dependency)
26 |
27 |
28 |
29 | name.antonsmirnov.firmata.serial
30 | Serial
31 | 1.1
32 |
33 |
34 |
35 | org.slf4j
36 | slf4j-api
37 | 1.6.4
38 |
39 |
40 |
41 | junit
42 | junit
43 | 4.8.1
44 | test
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/Firmata/src/main/java/name/antonsmirnov/firmata/BytesHelper.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata;
2 |
3 | import java.nio.ByteBuffer;
4 |
5 | /**
6 | * Helps to prepare bytes data
7 | */
8 | public class BytesHelper {
9 |
10 | /**
11 | * @param channel command channel
12 | * @return command channel mask
13 | */
14 | public static int ENCODE_CHANNEL(int channel) {
15 | return channel & 0x0F;
16 | }
17 |
18 | /**
19 | * Decode command from byte
20 | *
21 | * @param incomingByte
22 | * @return
23 | */
24 | public static int DECODE_COMMAND(int incomingByte) {
25 | return incomingByte < 0xF0
26 | ? incomingByte & 0xF0
27 | : incomingByte;
28 | }
29 |
30 | /**
31 | * Decode channel from byte
32 | *
33 | * @param incomingByte
34 | * @return
35 | */
36 | public static int DECODE_CHANNEL(int incomingByte) {
37 | return incomingByte & 0x0F;
38 | }
39 |
40 | /**
41 | * Return less significant byte
42 | *
43 | * @param value value
44 | * @return less significant byte
45 | */
46 | public static int LSB(int value) {
47 | return value & 0x7F;
48 | }
49 |
50 | /**
51 | * Return most significant byte
52 | *
53 | * @param value value
54 | * @return most significant byte
55 | */
56 | public static int MSB(int value) {
57 | return (value >> 7) & 0x7F;
58 | }
59 |
60 | /**
61 | * Return byte from LSB and MSB
62 | *
63 | * @param lsb less significant byte
64 | * @param msb most significant byte
65 | * @return byte
66 | */
67 | public static int DECODE_BYTE(int lsb, int msb) {
68 | return (msb << 7) + lsb;
69 | }
70 |
71 | /**
72 | * Decode string that was encoded using LSB(byte), MSB(byte)
73 | *
74 | * @param buffer buffer
75 | * @param startIndex start index
76 | * @param endIndex end index
77 | * @return decoded string
78 | */
79 | public static String DECODE_STRING(byte[] buffer, int startIndex, int endIndex) {
80 | StringBuilder sb = new StringBuilder();
81 | int offset = startIndex;
82 | int length = (endIndex - startIndex + 1) / 2;
83 | for (int i=0; i= 0; eachBit--) {
191 | mask |= (eachBit == bit ? 0 : 1);
192 | if (eachBit > 0)
193 | mask <<= 1;
194 | }
195 | return mask;
196 | }
197 |
198 | /**
199 | * Get mask for port to set pin in LOW
200 | *
201 | * @param pinInPort = [0,7]
202 | * @return
203 | */
204 | private static int pinMaskLow(int pinInPort) {
205 | return bitMaskLow(pinInPort);
206 | }
207 |
208 | /**
209 | * Get pin in port index using absolute pin index
210 | *
211 | * @param pin any
212 | * @return pin = [0,7]
213 | */
214 | public static int pinInPort(int pin) {
215 | return pin % BITS_IN_BYTE;
216 | }
217 |
218 | /**
219 | * Set HIGH or LOW pin value for port values
220 | *
221 | * @param portValues
222 | * @param pinInPort = [0, 7]
223 | * @param highLevel pin level is High level
224 | * @return
225 | */
226 | public static int setPin(int portValues, int pinInPort, boolean highLevel) {
227 | if (highLevel) {
228 | return portValues | pinMaskHigh(pinInPort);
229 | } else {
230 | return portValues & pinMaskLow(pinInPort);
231 | }
232 | }
233 |
234 | public static int setBit(int byteValue, int bit, boolean highLevel) {
235 | if (highLevel) {
236 | return byteValue | pinMaskHigh(bit);
237 | } else {
238 | return byteValue & pinMaskLow(bit);
239 | }
240 | }
241 |
242 | /**
243 | * Check if pin level is High
244 | *
245 | * @param portValues portValues
246 | * @param pinInPort = [0,7]
247 | * @return
248 | */
249 | public static boolean getPin(int portValues, int pinInPort) {
250 | return (portValues & BytesHelper.pinMaskHigh(pinInPort)) > 0;
251 | }
252 | }
253 |
--------------------------------------------------------------------------------
/Firmata/src/main/java/name/antonsmirnov/firmata/FormatHelper.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata;
2 |
3 | /**
4 | * Helps to format values
5 | */
6 | public class FormatHelper {
7 |
8 | // default delimiter
9 | private static final String HEX_PREFIX = "0x";
10 |
11 | public static final String SPACE = " ";
12 | public static final String QUOTE = "'";
13 |
14 | public String formatBinary(int value) {
15 | StringBuilder sb = new StringBuilder();
16 | formatBinary(value, sb);
17 | return sb.toString();
18 | }
19 |
20 | protected void formatBinary(int value, StringBuilder sb) {
21 | sb.append(HEX_PREFIX);
22 | sb.append(Integer.toHexString(value).toUpperCase());
23 | }
24 |
25 | public String formatBinaryData(int[] binaryData, String delimiter, String prefix, String postfix) {
26 | StringBuilder sb = new StringBuilder(prefix);
27 | for (int i = 0; i < binaryData.length; i++) {
28 | formatBinary(binaryData[i], sb);
29 | if (i < binaryData.length-1)
30 | sb.append(delimiter);
31 | }
32 | sb.append(postfix);
33 | return sb.toString();
34 | }
35 |
36 | public String formatBinaryData(int[] binaryData) {
37 | return formatBinaryData(binaryData, SPACE, QUOTE, QUOTE);
38 | }
39 |
40 | public String formatBinaryData(byte[] binaryData, String delimiter, String prefix, String postfix) {
41 | int[] intArray = new int[binaryData.length];
42 | for (int i=0; i modes = new HashMap();
13 |
14 | /**
15 | * Pin mode enumeration
16 | * (can be used as 'mode' parameter value for type-safety)
17 | */
18 | public enum PIN_MODE {
19 |
20 | /**
21 | * Pin works as input
22 | */
23 | INPUT(0),
24 |
25 | /**
26 | * Pin works as output
27 | */
28 | OUTPUT(1),
29 |
30 | /**
31 | * Pin works as analog input
32 | */
33 | ANALOG(2),
34 |
35 | /**
36 | * Pin works as analog PWM output
37 | */
38 | PWM(3),
39 |
40 | /**
41 | * Ping workds as servo
42 | */
43 | SERVO(4);
44 |
45 | private int mode;
46 |
47 | public int getMode() {
48 | return mode;
49 | }
50 |
51 | private PIN_MODE(int mode) {
52 | this.mode = mode;
53 | modes.put(mode, this);
54 | }
55 |
56 | public static PIN_MODE find(int mode) {
57 | return modes.get(mode);
58 | }
59 | }
60 |
61 | protected SetPinModeMessage() {
62 | super();
63 | }
64 |
65 | /**
66 | *
67 | * @param pin
68 | * @param mode (use PIN_MODE enum for type-safety)
69 | * @see name.antonsmirnov.firmata.message.SetPinModeMessage.PIN_MODE
70 | */
71 | public SetPinModeMessage(int pin, int mode) {
72 | this();
73 | setPin(pin);
74 | setMode(mode);
75 | }
76 |
77 | private int pin;
78 |
79 | public int getPin() {
80 | return pin;
81 | }
82 |
83 | public void setPin(int pin) {
84 | this.pin = pin;
85 | }
86 |
87 | private int mode;
88 |
89 | public int getMode() {
90 | return mode;
91 | }
92 |
93 | public void setMode(int mode) {
94 | this.mode = mode;
95 | }
96 |
97 | @Override
98 | public boolean equals(Object obj) {
99 | if (!super.equals(obj))
100 | return false;
101 |
102 | SetPinModeMessage message = (SetPinModeMessage)obj;
103 | return message != null &&
104 | message.getPin() == getPin() &&
105 | message.getMode() == getMode();
106 | }
107 |
108 | @Override
109 | public String toString() {
110 | return MessageFormat.format("SetPinModeMessage[pin={0}, mode={1}]", pin, mode);
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/Firmata/src/main/java/name/antonsmirnov/firmata/message/StringSysexMessage.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.message;
2 |
3 | import java.text.MessageFormat;
4 |
5 | /**
6 | * String sysex message
7 | */
8 | public class StringSysexMessage extends SysexMessage {
9 |
10 | // Sysex command byte
11 | public static final int COMMAND = 0x71;
12 |
13 | public StringSysexMessage() {
14 | super(COMMAND, null);
15 | }
16 |
17 | public StringSysexMessage(String data) {
18 | this();
19 | setData(data);
20 | }
21 |
22 | @Override
23 | public String toString() {
24 | return MessageFormat.format("StringSysexMessage[data=\"{0}\"]", getData());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Firmata/src/main/java/name/antonsmirnov/firmata/message/SysexMessage.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.message;
2 |
3 | import java.text.MessageFormat;
4 |
5 | /**
6 | * Sysex message
7 | *
8 | */
9 | public class SysexMessage extends Message {
10 |
11 | public SysexMessage() {
12 | super();
13 | }
14 |
15 | /**
16 | * Constructor
17 | *
18 | * @param command sysex command (NOT firmata command)
19 | * @param data sysex command data
20 | */
21 | public SysexMessage(int command, String data) {
22 | this();
23 | setCommand(command);
24 | setData(data);
25 | }
26 |
27 | private int command;
28 |
29 | public int getCommand() {
30 | return command;
31 | }
32 |
33 | public void setCommand(int command) {
34 | this.command = command;
35 | }
36 |
37 | private String data;
38 |
39 | public String getData() {
40 | return data;
41 | }
42 |
43 | public void setData(String data) {
44 | this.data = data;
45 | }
46 |
47 | @Override
48 | public boolean equals(Object obj) {
49 | if (!super.equals(obj))
50 | return false;
51 |
52 | SysexMessage message = (SysexMessage)obj;
53 | return message != null &&
54 | message.getCommand() == getCommand() &&
55 | (
56 | (message.getData() == null && getData() == null)
57 | ||
58 | (message.getData() != null && message.getData().equals(getData()))
59 | );
60 | }
61 |
62 | @Override
63 | public String toString() {
64 | return MessageFormat.format("SysexMessage[command={0}, data=\"{1}\"]", command, data);
65 | }
66 |
67 | }
68 |
--------------------------------------------------------------------------------
/Firmata/src/main/java/name/antonsmirnov/firmata/message/SystemResetMessage.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.message;
2 |
3 | /**
4 | * System reset message
5 | */
6 | public class SystemResetMessage extends Message {
7 |
8 | public SystemResetMessage() {
9 | super();
10 | }
11 |
12 | @Override
13 | public String toString() {
14 | return "SystemResetMessage[]";
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Firmata/src/main/java/name/antonsmirnov/firmata/message/factory/BoardMessageFactory.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.message.factory;
2 |
3 | import name.antonsmirnov.firmata.message.*;
4 |
5 | import java.text.MessageFormat;
6 | import java.util.Arrays;
7 |
8 | /**
9 | * MessageFactory implementation with pins config
10 | */
11 | public abstract class BoardMessageFactory implements MessageFactory {
12 |
13 | public static final int MIN_PIN = 0;
14 |
15 | protected int minPin;
16 | protected int maxPin;
17 | protected int[] analogOutPins;
18 | protected int[] analogInPins;
19 |
20 | public int getMinPin() {
21 | return minPin;
22 | }
23 |
24 | public int getMaxPin() {
25 | return maxPin;
26 | }
27 |
28 | public int[] getAnalogInPins() {
29 | return analogInPins;
30 | }
31 |
32 | public int[] getAnalogOutPins() {
33 | return analogOutPins;
34 | }
35 |
36 | protected static int[] union(int[] array1, int[] array2) {
37 | int[] array = new int[array1.length + array2.length];
38 | System.arraycopy(array1, 0, array, 0, array1.length);
39 | System.arraycopy(array2, 0, array, array1.length, array2.length);
40 | return array;
41 | }
42 |
43 | protected static int[] arrayFromTo(int from, int to) {
44 | int[] array = new int[to - from + 1];
45 | for (int i=0; i maxPin)
64 | throw new MessageValidationException(
65 | MessageFormat.format("Allowed pin values are [{0}-{1}]", minPin, maxPin));
66 | }
67 |
68 | protected void validatePort(int port) throws MessageValidationException {
69 | int ports = (int)Math.ceil((maxPin + 1) / 8.0);
70 | if (port < 0 || port > ports)
71 | throw new MessageValidationException(
72 | MessageFormat.format("Allowed port values are [{0}-{1}]", 0, ports));
73 | }
74 |
75 | protected void validateAnalogIn(int pin) throws MessageValidationException {
76 | int[] array = analogInPins;
77 | if (Arrays.binarySearch(array, pin) < 0)
78 | throw new MessageValidationException(
79 | MessageFormat.format("Allowed analog in pins are [{0}]", arrayToString(array)));
80 | }
81 |
82 | public boolean isAnalogIn(int pin) {
83 | try {
84 | validateAnalogIn(pin);
85 | return true;
86 | } catch (MessageValidationException e) {
87 | return false;
88 | }
89 | }
90 |
91 | protected void validateAnalogOut(int pin) throws MessageValidationException {
92 | int[] array = analogOutPins;
93 | if (Arrays.binarySearch(array, pin) < 0)
94 | throw new MessageValidationException(
95 | MessageFormat.format("Allowed analog out (PWM) pins are [{0}]", arrayToString(array)));
96 | }
97 |
98 | public boolean isAnalogOut(int pin) {
99 | try {
100 | validateAnalogOut(pin);
101 | return true;
102 | } catch (MessageValidationException e) {
103 | return false;
104 | }
105 | }
106 |
107 | protected String arrayToString(int[] array) {
108 | StringBuilder sb = new StringBuilder();
109 | for (int i=0; i0)
111 | sb.append(", ");
112 | sb.append(array[i]);
113 | }
114 | return sb.toString();
115 | }
116 |
117 | protected void validateMode(int mode) throws MessageValidationException {
118 | SetPinModeMessage.PIN_MODE enumValue = SetPinModeMessage.PIN_MODE.find(mode);
119 | if (enumValue == null)
120 | throw new MessageValidationException(
121 | MessageFormat.format("Allowed modes are [{0}]", SetPinModeMessage.PIN_MODE.values()));
122 | }
123 |
124 | protected void validateDigitalValue(int value) throws MessageValidationException {
125 | if (value != 0 && value != 1)
126 | throw new MessageValidationException("Allowed digital values are [0; 1]");
127 | }
128 |
129 | protected void validateDigitalMask(int value) throws MessageValidationException {
130 | if (value < 0 || value > 255)
131 | throw new MessageValidationException("Allowed digital mask values are [0-255]");
132 | }
133 |
134 | private void validateAnalogValue(int value) throws MessageValidationException {
135 | if (value < 0 || value > 255)
136 | throw new MessageValidationException("Allowed analog values are [0-255]");
137 | }
138 |
139 | public ReportDigitalPortMessage digitalRead(int port) throws MessageValidationException {
140 | validatePort(port);
141 |
142 | return new ReportDigitalPortMessage(port, true);
143 | }
144 |
145 | public ReportAnalogPinMessage analogRead(int pin) throws MessageValidationException {
146 | validatePin(pin);
147 | validateAnalogIn(pin);
148 |
149 | return new ReportAnalogPinMessage(pin, true);
150 | }
151 |
152 | public SetPinModeMessage pinMode(int pin, int mode) throws MessageValidationException {
153 | validatePin(pin);
154 | validateMode(mode);
155 |
156 | // analog in
157 | if (mode == SetPinModeMessage.PIN_MODE.ANALOG.getMode())
158 | validateAnalogIn(pin);
159 |
160 | // analog out
161 | if (mode == SetPinModeMessage.PIN_MODE.PWM.getMode())
162 | validateAnalogOut(pin);
163 |
164 | return new SetPinModeMessage(pin, mode);
165 | }
166 |
167 | public DigitalMessage digitalWrite(int port, int value) throws MessageValidationException {
168 | validatePort(port);
169 | validateDigitalMask(value);
170 |
171 | return new DigitalMessage(port, value);
172 | }
173 |
174 | public AnalogMessage analogWrite(int pin, int value) throws MessageValidationException {
175 | validatePin(pin);
176 | validateAnalogOut(pin);
177 | validateAnalogValue(value);
178 |
179 | return new AnalogMessage(pin, value);
180 | }
181 |
182 | }
183 |
--------------------------------------------------------------------------------
/Firmata/src/main/java/name/antonsmirnov/firmata/message/factory/MessageFactory.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.message.factory;
2 |
3 | import name.antonsmirnov.firmata.message.*;
4 |
5 | /**
6 | * Builds Messages
7 | * (build SAFE messages with pins, modes validation according to hardware features)
8 | */
9 | public interface MessageFactory {
10 |
11 | /**
12 | * Read digital value fom the pin
13 | *
14 | * @param port port
15 | * @return firmata message
16 | */
17 | ReportDigitalPortMessage digitalRead(int port) throws MessageValidationException;
18 |
19 | /**
20 | * Read analog value from the pin
21 | *
22 | * @param pin pin
23 | * @return firmata message
24 | */
25 | ReportAnalogPinMessage analogRead(int pin) throws MessageValidationException;
26 |
27 | /**
28 | * Set a digital pin to input or output mode
29 | *
30 | * @param pin pin
31 | * @param mode message
32 | * @see SetPinModeMessage.PIN_MODE
33 | * @return firmata message
34 | */
35 | SetPinModeMessage pinMode(int pin, int mode) throws MessageValidationException;
36 |
37 | /**
38 | * Write to a digital pin
39 | *
40 | * @param port port
41 | * @param value pins mask
42 | * @return firmata message
43 | */
44 | DigitalMessage digitalWrite(int port, int value) throws MessageValidationException;
45 |
46 | /**
47 | * Write an analog value (PWM-wave) to a pin.
48 | *
49 | * @param pin pin
50 | * @return firmata message
51 | */
52 | AnalogMessage analogWrite(int pin, int value) throws MessageValidationException;
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/Firmata/src/main/java/name/antonsmirnov/firmata/message/factory/MessageValidationException.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.message.factory;
2 |
3 | /**
4 | * Message parameters are invalid
5 | * (most likely to hardware features)
6 | */
7 | public class MessageValidationException extends Exception {
8 |
9 | public MessageValidationException(String message) {
10 | super(message);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/Firmata/src/main/java/name/antonsmirnov/firmata/message/factory/arduino/Diecimila.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.message.factory.arduino;
2 |
3 | import name.antonsmirnov.firmata.message.factory.BoardMessageFactory;
4 |
5 | /**
6 | * Arduino Diecimila board
7 | * http://arduino.cc/en/Main/ArduinoBoardDiecimila
8 | */
9 | public class Diecimila extends BoardMessageFactory {
10 |
11 | public final static int MAX_PIN = 13;
12 |
13 | public Diecimila() {
14 | super(MIN_PIN, MAX_PIN, arrayFromTo(0, 5), new int[] { 3,5,6,9,10,11 });
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Firmata/src/main/java/name/antonsmirnov/firmata/message/factory/arduino/Duemilanove.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.message.factory.arduino;
2 |
3 | import name.antonsmirnov.firmata.message.factory.BoardMessageFactory;
4 |
5 | /**
6 | * Arduino Duemilanove board
7 | * http://arduino.cc/en/Main/ArduinoBoardDuemilanove
8 | */
9 | public class Duemilanove extends BoardMessageFactory {
10 |
11 | public final static int MAX_PIN = 13;
12 |
13 | public Duemilanove() {
14 | super(MIN_PIN, MAX_PIN, arrayFromTo(0, 5), new int[] { 3,5,6,9,10,11 });
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Firmata/src/main/java/name/antonsmirnov/firmata/message/factory/arduino/Fio.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.message.factory.arduino;
2 |
3 | import name.antonsmirnov.firmata.message.factory.BoardMessageFactory;
4 |
5 | /**
6 | * Arduino Fio board
7 | * http://arduino.cc/en/Main/ArduinoBoardFio
8 | */
9 | public class Fio extends BoardMessageFactory {
10 |
11 | public final static int MAX_PIN = 13;
12 |
13 | public Fio() {
14 | super(MIN_PIN, MAX_PIN, arrayFromTo(0, 7), new int[] { 3,5,6,9,10,11 });
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Firmata/src/main/java/name/antonsmirnov/firmata/message/factory/arduino/Mega.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.message.factory.arduino;
2 |
3 | import name.antonsmirnov.firmata.message.factory.BoardMessageFactory;
4 |
5 | /**
6 | * Arduino Mega board
7 | * http://arduino.cc/en/Main/ArduinoBoardMega
8 | */
9 | public class Mega extends BoardMessageFactory {
10 |
11 | public final static int MAX_PIN = 54;
12 |
13 | public Mega() {
14 | super(MIN_PIN, MAX_PIN, arrayFromTo(0, 15), union(arrayFromTo(2, 13), arrayFromTo(44, 46)));
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Firmata/src/main/java/name/antonsmirnov/firmata/message/factory/arduino/Mega2560.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.message.factory.arduino;
2 |
3 | import name.antonsmirnov.firmata.message.factory.BoardMessageFactory;
4 |
5 | /**
6 | * Arduino Mega 2560 board
7 | * http://arduino.cc/en/Main/ArduinoBoardMega2560
8 | */
9 | public class Mega2560 extends BoardMessageFactory {
10 |
11 | public final static int MAX_PIN = 54;
12 |
13 | public Mega2560() {
14 | super(MIN_PIN, MAX_PIN, arrayFromTo(0, 15), union(arrayFromTo(2, 13), arrayFromTo(44, 46)));
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Firmata/src/main/java/name/antonsmirnov/firmata/message/factory/arduino/Mini.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.message.factory.arduino;
2 |
3 | import name.antonsmirnov.firmata.message.factory.BoardMessageFactory;
4 |
5 | /**
6 | * Arduino Mini board
7 | * http://arduino.cc/en/Main/ArduinoBoardMini
8 | */
9 | public class Mini extends BoardMessageFactory {
10 |
11 | public final static int MAX_PIN = 13;
12 |
13 | public Mini() {
14 | super(MIN_PIN, MAX_PIN, arrayFromTo(0, 7), new int[] { 3,5,6,9,10,11 });
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Firmata/src/main/java/name/antonsmirnov/firmata/message/factory/arduino/Nano.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.message.factory.arduino;
2 |
3 | import name.antonsmirnov.firmata.message.factory.BoardMessageFactory;
4 |
5 | /**
6 | * Arduino Nano board
7 | * http://arduino.cc/en/Main/ArduinoBoardNano
8 | */
9 | public class Nano extends BoardMessageFactory {
10 |
11 | public final static int MAX_PIN = 13;
12 |
13 | public Nano() {
14 | super(MIN_PIN, MAX_PIN, arrayFromTo(0, 7), new int[] { 3,5,6,9,10,11 });
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Firmata/src/main/java/name/antonsmirnov/firmata/message/factory/arduino/Uno.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.message.factory.arduino;
2 |
3 | import name.antonsmirnov.firmata.message.factory.BoardMessageFactory;
4 |
5 | /**
6 | * Arduino Uno board
7 | * http://arduino.cc/en/Main/ArduinoBoardUno
8 | */
9 | public class Uno extends BoardMessageFactory {
10 |
11 | public final static int MAX_PIN = 13;
12 |
13 | public Uno() {
14 | super(MIN_PIN, MAX_PIN, arrayFromTo(0, 5), new int[] { 3,5,6,9,10,11 });
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Firmata/src/main/java/name/antonsmirnov/firmata/reader/AnalogMessageReader.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.reader;
2 |
3 | import name.antonsmirnov.firmata.IFirmata;
4 | import name.antonsmirnov.firmata.message.AnalogMessage;
5 | import name.antonsmirnov.firmata.writer.AnalogMessageWriter;
6 |
7 | import static name.antonsmirnov.firmata.BytesHelper.DECODE_BYTE;
8 | import static name.antonsmirnov.firmata.BytesHelper.DECODE_CHANNEL;
9 |
10 | /**
11 | * MessageReader for AnalogMessage
12 | */
13 | public class AnalogMessageReader implements IMessageReader {
14 |
15 | public boolean canRead(byte[] buffer, int bufferLength, int command) {
16 | return command == AnalogMessageWriter.COMMAND;
17 | }
18 |
19 | private boolean isHandling;
20 |
21 | public void startReading() {
22 | isHandling = true;
23 | message = new AnalogMessage();
24 | }
25 |
26 | public void read(byte[] buffer, int length) {
27 | if (length == 2) {
28 | message.setPin(DECODE_CHANNEL(buffer[0]));
29 | } else {
30 | message.setValue(DECODE_BYTE(buffer[1], buffer[2]));
31 | isHandling = false;
32 | }
33 | }
34 |
35 | public boolean finishedReading() {
36 | return !isHandling;
37 | }
38 |
39 | private AnalogMessage message;
40 |
41 | public AnalogMessage getMessage() {
42 | return message;
43 | }
44 |
45 | public void fireEvent(IFirmata.Listener listener) {
46 | listener.onAnalogMessageReceived(getMessage());
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/Firmata/src/main/java/name/antonsmirnov/firmata/reader/BaseSysexMessageReader.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.reader;
2 |
3 | import name.antonsmirnov.firmata.message.SysexMessage;
4 | import name.antonsmirnov.firmata.writer.SysexMessageWriter;
5 |
6 | import static name.antonsmirnov.firmata.BytesHelper.*;
7 |
8 | /**
9 | * Base MessageReader for SysexMessage
10 | */
11 | public abstract class BaseSysexMessageReader
12 | implements IMessageReader {
13 |
14 | private Byte sysexCommand;
15 |
16 | public BaseSysexMessageReader(Byte sysexCommand) {
17 | this.sysexCommand = sysexCommand;
18 | }
19 |
20 | public boolean canRead(byte[] buffer, int bufferLength, int command) {
21 | return (bufferLength == 1 && buffer[0] == (byte) SysexMessageWriter.COMMAND_START) // is sysex message?
22 | ||
23 | (bufferLength == 2 && (sysexCommand == null || sysexCommand.equals(buffer[1]))) // is needed sysex command
24 | ||
25 | (bufferLength == 3 && sysexCommand != null);
26 | }
27 |
28 | protected boolean isReading;
29 |
30 | public void startReading() {
31 | isReading = true;
32 | }
33 |
34 | protected ConcreteSysexMessage message;
35 |
36 | public void read(byte[] buffer, int length) {
37 | byte incomingByte = buffer[length-1];
38 |
39 | if (incomingByte == (byte) SysexMessageWriter.COMMAND_END) {
40 | isReading = false;
41 |
42 | message = buildSysexMessage(buffer, length);
43 | }
44 | }
45 |
46 | /**
47 | * Build SysexMessage from incoming buffer
48 | *
49 | * @param buffer buffer (start from COMMAND_START byte, ends with COMMAND_END byte)
50 | * @param bufferLength buffer length
51 | * @return SysexMessage command or inherited message
52 | */
53 | protected abstract ConcreteSysexMessage buildSysexMessage(byte[] buffer, int bufferLength);
54 |
55 | public ConcreteSysexMessage getMessage() {
56 | return message;
57 | }
58 |
59 | public boolean finishedReading() {
60 | return !isReading;
61 | }
62 |
63 | protected void validateSysexDataLength(int startIndex, int endIndex) {
64 | if ((endIndex - startIndex + 1) % 2 != 0)
65 | throw new RuntimeException("Sysex command data length should be even");
66 | }
67 |
68 | // extract string from buffer
69 | protected String extractStringFromBuffer(byte[] buffer, int startIndex, int endIndex) {
70 | validateSysexDataLength(startIndex, endIndex);
71 | return DECODE_STRING(buffer, startIndex, endIndex);
72 | }
73 |
74 | // extract integer array from buffer
75 | protected int[] extractIntArrayFromBuffer(byte[] buffer, int startIndex, int endIndex) {
76 | validateSysexDataLength(startIndex, endIndex);
77 | return DECODE_INT_ARRAY(buffer, startIndex, endIndex);
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/Firmata/src/main/java/name/antonsmirnov/firmata/reader/DigitalMessageReader.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.reader;
2 |
3 | import name.antonsmirnov.firmata.IFirmata;
4 | import name.antonsmirnov.firmata.message.DigitalMessage;
5 | import name.antonsmirnov.firmata.writer.DigitalMessageWriter;
6 |
7 | import static name.antonsmirnov.firmata.BytesHelper.DECODE_BYTE;
8 | import static name.antonsmirnov.firmata.BytesHelper.DECODE_CHANNEL;
9 |
10 | /**
11 | * MessageReader for DigitalMessage
12 | */
13 | public class DigitalMessageReader implements IMessageReader {
14 |
15 | public boolean canRead(byte[] buffer, int bufferLength, int command) {
16 | return command == DigitalMessageWriter.COMMAND;
17 | }
18 |
19 | private boolean isHandling;
20 |
21 | public void startReading() {
22 | isHandling = true;
23 | message = new DigitalMessage();
24 | }
25 |
26 | public void read(byte[] buffer, int length) {
27 | if (length == 2) {
28 | message.setPort(DECODE_CHANNEL(buffer[0]));
29 | } else {
30 | message.setValue(DECODE_BYTE(buffer[1], buffer[2]));
31 | isHandling = false;
32 | }
33 | }
34 |
35 | public boolean finishedReading() {
36 | return !isHandling;
37 | }
38 |
39 | private DigitalMessage message;
40 |
41 | public DigitalMessage getMessage() {
42 | return message;
43 | }
44 |
45 | public void fireEvent(IFirmata.Listener listener) {
46 | listener.onDigitalMessageReceived(getMessage());
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/Firmata/src/main/java/name/antonsmirnov/firmata/reader/FirmwareVersionMessageReader.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.reader;
2 |
3 | import name.antonsmirnov.firmata.IFirmata;
4 | import name.antonsmirnov.firmata.message.FirmwareVersionMessage;
5 | import name.antonsmirnov.firmata.message.ReportFirmwareVersionMessage;
6 |
7 | /**
8 | * MessageReader for FirmwareVersionMessage
9 | */
10 | public class FirmwareVersionMessageReader extends BaseSysexMessageReader {
11 |
12 | public FirmwareVersionMessageReader() {
13 | super((byte)ReportFirmwareVersionMessage.COMMAND);
14 | }
15 |
16 | @Override
17 | protected FirmwareVersionMessage buildSysexMessage(byte[] buffer, int bufferLength) {
18 | FirmwareVersionMessage message = new FirmwareVersionMessage();
19 | message.setMajor(buffer[2]);
20 | message.setMinor(buffer[3]);
21 | // skip 4 first bytes - COMMAND_START, sysex command byte, major, minor
22 | message.setName(extractStringFromBuffer(buffer, 4, bufferLength - 2));
23 | return message;
24 | }
25 |
26 | public void fireEvent(IFirmata.Listener listener) {
27 | listener.onFirmwareVersionMessageReceived(message);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Firmata/src/main/java/name/antonsmirnov/firmata/reader/I2cReplyMessageReader.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.reader;
2 |
3 | import name.antonsmirnov.firmata.IFirmata;
4 | import name.antonsmirnov.firmata.message.I2cReplyMessage;
5 |
6 | import static name.antonsmirnov.firmata.BytesHelper.*;
7 |
8 | /**
9 | * MessageReader for I2cReplyMessage
10 | */
11 | public class I2cReplyMessageReader extends BaseSysexMessageReader {
12 |
13 | public I2cReplyMessageReader() {
14 | super((byte)I2cReplyMessage.COMMAND);
15 | }
16 |
17 | @Override
18 | protected I2cReplyMessage buildSysexMessage(byte[] buffer, int bufferLength) {
19 | I2cReplyMessage message = new I2cReplyMessage();
20 | // skip 2 first bytes - COMMAND_START and sysex command byte
21 | message.setSlaveAddress(DECODE_BYTE(buffer[2], buffer[3]));
22 | message.setRegister(DECODE_BYTE(buffer[4], buffer[5]));
23 | message.setBinaryData(extractIntArrayFromBuffer(buffer, 6, bufferLength - 2));
24 | // message.getData() is not used
25 | return message;
26 | }
27 |
28 | public void fireEvent(IFirmata.Listener listener) {
29 | listener.onI2cMessageReceived(getMessage());
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Firmata/src/main/java/name/antonsmirnov/firmata/reader/IMessageReader.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.reader;
2 |
3 | import name.antonsmirnov.firmata.IFirmata;
4 | import name.antonsmirnov.firmata.message.Message;
5 |
6 | /**
7 | * Message reader
8 | */
9 | public interface IMessageReader {
10 |
11 | /**
12 | * Can read command
13 | *
14 | * @param buffer incoming buffer
15 | * @param bufferLength current buffer length
16 | * @return true if it's his command message type
17 | */
18 | boolean canRead(byte[] buffer, int bufferLength, int command);
19 |
20 | /**
21 | * Start handling message
22 | */
23 | void startReading();
24 |
25 | /**
26 | * Read next message byte
27 | *
28 | * @param buffer incoming buffer
29 | * @param length current buffer length
30 | */
31 | public void read(byte[] buffer, int length);
32 |
33 | /**
34 | * Has it finished message handling
35 | *
36 | * @return is it has received all the message bytes
37 | */
38 | boolean finishedReading();
39 |
40 | /**
41 | * Message if it finished handling
42 | * (check finishedReading before)
43 | * @return
44 | */
45 | ConcreteMessage getMessage();
46 |
47 | /**
48 | * Invoke Firmata listener
49 | * @param listener
50 | */
51 | void fireEvent(IFirmata.Listener listener);
52 | }
53 |
--------------------------------------------------------------------------------
/Firmata/src/main/java/name/antonsmirnov/firmata/reader/ProtocolVersionMessageReader.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.reader;
2 |
3 | import name.antonsmirnov.firmata.IFirmata;
4 | import name.antonsmirnov.firmata.message.ProtocolVersionMessage;
5 | import name.antonsmirnov.firmata.writer.ReportProtocolVersionMessageWriter;
6 |
7 | /**
8 | * MessageReader for ProtocolVersionMessage
9 | */
10 | public class ProtocolVersionMessageReader implements IMessageReader {
11 |
12 | public boolean canRead(byte[] buffer, int bufferLength, int command) {
13 | return bufferLength == 1
14 | &&
15 | buffer[0] == (byte) ReportProtocolVersionMessageWriter.COMMAND;
16 | }
17 |
18 | private boolean isHandling;
19 |
20 | public void startReading() {
21 | isHandling = true;
22 | message = new ProtocolVersionMessage();
23 | }
24 |
25 | public void read(byte[] buffer, int length) {
26 | byte incomingByte = buffer[length-1];
27 | if (length == 2) {
28 | message.setMajor(incomingByte);
29 | } else {
30 | message.setMinor(incomingByte);
31 | isHandling = false;
32 | }
33 | }
34 |
35 | public boolean finishedReading() {
36 | return !isHandling;
37 | }
38 |
39 | private ProtocolVersionMessage message;
40 |
41 | public ProtocolVersionMessage getMessage() {
42 | return message;
43 | }
44 |
45 | public void fireEvent(IFirmata.Listener listener) {
46 | listener.onProtocolVersionMessageReceived(getMessage());
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/Firmata/src/main/java/name/antonsmirnov/firmata/reader/StringSysexMessageReader.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.reader;
2 |
3 | import name.antonsmirnov.firmata.IFirmata;
4 | import name.antonsmirnov.firmata.message.StringSysexMessage;
5 |
6 | /**
7 | * MessageReader for StringSysexMessage
8 | */
9 | public class StringSysexMessageReader extends BaseSysexMessageReader {
10 |
11 | public StringSysexMessageReader() {
12 | super((byte)StringSysexMessage.COMMAND);
13 | }
14 |
15 | @Override
16 | protected StringSysexMessage buildSysexMessage(byte[] buffer, int bufferLength) {
17 | StringSysexMessage message = new StringSysexMessage();
18 | // skip 2 first bytes - COMMAND_START and sysex command byte
19 | message.setData(extractStringFromBuffer(buffer, 2, bufferLength - 2));
20 | return message;
21 | }
22 |
23 | public void fireEvent(IFirmata.Listener listener) {
24 | listener.onStringSysexMessageReceived(getMessage());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Firmata/src/main/java/name/antonsmirnov/firmata/reader/SysexMessageReader.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.reader;
2 |
3 | import name.antonsmirnov.firmata.IFirmata;
4 | import name.antonsmirnov.firmata.message.SysexMessage;
5 |
6 | /**
7 | * MessageReader for SysexMessage
8 | */
9 | public class SysexMessageReader extends BaseSysexMessageReader {
10 |
11 | public SysexMessageReader() {
12 | super(null);
13 | // null means that 'no command byte specified'
14 | }
15 |
16 | @Override
17 | protected SysexMessage buildSysexMessage(byte[] buffer, int bufferLength) {
18 | SysexMessage message = new SysexMessage();
19 | message.setCommand(buffer[1]);
20 | // skip 2 first bytes - COMMAND_START and sysex command byte
21 | message.setData(extractStringFromBuffer(buffer, 2, bufferLength - 2));
22 | return message;
23 | }
24 |
25 | public void fireEvent(IFirmata.Listener listener) {
26 | listener.onSysexMessageReceived(message);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Firmata/src/main/java/name/antonsmirnov/firmata/wrapper/AndFilter.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.wrapper;
2 |
3 | /**
4 | * All filters should allow data
5 | */
6 | public class AndFilter implements IMessageFilter{
7 |
8 | private IMessageFilter[] filters;
9 |
10 | public AndFilter(IMessageFilter... filters) {
11 | this.filters = filters;
12 | }
13 |
14 | public boolean isAllowed(MessageWithProperties data) {
15 | for (IMessageFilter eachFilter : filters)
16 | if (!eachFilter.isAllowed(data))
17 | return false;
18 |
19 | return true;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Firmata/src/main/java/name/antonsmirnov/firmata/wrapper/DateMessagePropertyManager.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.wrapper;
2 |
3 | import java.util.Date;
4 | import java.util.GregorianCalendar;
5 |
6 | /**
7 | * Date for the message
8 | */
9 | public class DateMessagePropertyManager extends MessagePropertyManager {
10 |
11 | private static final String KEY = "date";
12 |
13 | public DateMessagePropertyManager() {
14 | super(KEY);
15 | }
16 |
17 | @Override
18 | protected Date createProperty() {
19 | return GregorianCalendar.getInstance().getTime();
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Firmata/src/main/java/name/antonsmirnov/firmata/wrapper/DigitalPortWrapper.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.wrapper;
2 |
3 | import name.antonsmirnov.firmata.IFirmata;
4 | import name.antonsmirnov.firmata.message.DigitalMessage;
5 | import name.antonsmirnov.firmata.message.Message;
6 | import name.antonsmirnov.firmata.serial.SerialException;
7 |
8 | import java.util.HashMap;
9 | import java.util.Map;
10 |
11 | public class DigitalPortWrapper implements IFirmata {
12 |
13 | private IFirmata firmata;
14 |
15 | public DigitalPortWrapper(IFirmata firmata) {
16 | this.firmata = firmata;
17 | }
18 |
19 | public void addListener(Listener listener) {
20 | firmata.addListener(listener);
21 | }
22 |
23 | public void removeListener(Listener listener) {
24 | firmata.removeListener(listener);
25 | }
26 |
27 | public boolean containsListener(Listener listener) {
28 | return firmata.containsListener(listener);
29 | }
30 |
31 | public void clearListeners() {
32 | firmata.clearListeners();
33 | }
34 |
35 | private Map portValues = new HashMap();
36 |
37 | public Map getPortValues() {
38 | return portValues;
39 | }
40 |
41 | public void clear() {
42 | portValues.clear();
43 | }
44 |
45 | public void send(Message message) throws SerialException {
46 | firmata.send(message);
47 |
48 | if (message instanceof DigitalMessage) {
49 | DigitalMessage digitalMessage = (DigitalMessage) message;
50 | portValues.put(digitalMessage.getPort(), digitalMessage.getValue());
51 | }
52 | }
53 |
54 | public void onDataReceived(int incomingByte) {
55 | firmata.onDataReceived(incomingByte);
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/Firmata/src/main/java/name/antonsmirnov/firmata/wrapper/DirectionMessageFilter.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.wrapper;
2 |
3 | /**
4 | * Filter to filter only messages which have according direction property
5 | */
6 | public class DirectionMessageFilter implements IMessageFilter {
7 |
8 | private DirectionMessagePropertyManager propertyManager;
9 |
10 | public DirectionMessageFilter(DirectionMessagePropertyManager propertyManager) {
11 | this.propertyManager = propertyManager;
12 | }
13 |
14 | public boolean isAllowed(MessageWithProperties data) {
15 | return (propertyManager.get(data).equals(propertyManager.isIncoming()));
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Firmata/src/main/java/name/antonsmirnov/firmata/wrapper/DirectionMessagePropertyManager.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.wrapper;
2 |
3 | /**
4 | * Direction for the message: incoming/outcoming
5 | */
6 | public class DirectionMessagePropertyManager extends MessagePropertyManager {
7 |
8 | private static final String KEY = "isIncoming";
9 |
10 | private boolean isIncoming;
11 |
12 | public boolean isIncoming() {
13 | return isIncoming;
14 | }
15 |
16 | public DirectionMessagePropertyManager(boolean isIncoming) {
17 | super(KEY);
18 | this.isIncoming = isIncoming;
19 | }
20 |
21 | @Override
22 | protected Boolean createProperty() {
23 | return isIncoming;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Firmata/src/main/java/name/antonsmirnov/firmata/wrapper/IMessageFilter.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.wrapper;
2 |
3 | /**
4 | * Filters messages
5 | */
6 | public interface IMessageFilter {
7 |
8 | /**
9 | * Return true if message is allowed and should not be filtered
10 | */
11 | boolean isAllowed(MessageWithProperties data);
12 | }
13 |
--------------------------------------------------------------------------------
/Firmata/src/main/java/name/antonsmirnov/firmata/wrapper/IMessagePropertyManager.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.wrapper;
2 |
3 | import java.util.Map;
4 |
5 | /**
6 | * Property for the message
7 | */
8 | public interface IMessagePropertyManager {
9 | ConcretePropertyClass get(MessageWithProperties data);
10 | void set(MessageWithProperties data);
11 | }
12 |
--------------------------------------------------------------------------------
/Firmata/src/main/java/name/antonsmirnov/firmata/wrapper/MessagePropertyManager.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.wrapper;
2 |
3 | /**
4 | * Abstract message property
5 | */
6 | public abstract class MessagePropertyManager
7 | implements IMessagePropertyManager {
8 |
9 | private String key;
10 |
11 | public MessagePropertyManager(String key) {
12 | this.key = key;
13 | }
14 |
15 | public ConcretePropertyClass get(MessageWithProperties data) {
16 | return (ConcretePropertyClass)data.getProperty(key);
17 | }
18 |
19 | public void set(MessageWithProperties data) {
20 | ConcretePropertyClass property = createProperty();
21 | data.setProperty(key, property);
22 | }
23 |
24 | /**
25 | * set concrete property
26 | */
27 | protected abstract ConcretePropertyClass createProperty();
28 | }
29 |
--------------------------------------------------------------------------------
/Firmata/src/main/java/name/antonsmirnov/firmata/wrapper/MessageWithProperties.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.wrapper;
2 |
3 | import name.antonsmirnov.firmata.message.Message;
4 |
5 | import java.io.Serializable;
6 | import java.util.HashMap;
7 | import java.util.Map;
8 |
9 | /**
10 | * Message with associated properties
11 | */
12 | public class MessageWithProperties implements Serializable {
13 |
14 | public MessageWithProperties(Message message) {
15 | setMessage(message);
16 | }
17 |
18 | private Message message;
19 |
20 | public Message getMessage() {
21 | return message;
22 | }
23 |
24 | public void setMessage(Message message) {
25 | this.message = message;
26 | }
27 |
28 | private Map properties = new HashMap();
29 |
30 | public Object getProperty(String key) {
31 | return properties.get(key);
32 | }
33 |
34 | public void setProperty(String key, Object property) {
35 | properties.put(key, property);
36 | }
37 |
38 | @Override
39 | public String toString() {
40 | return message.toString() + " -> " + properties.toString();
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Firmata/src/main/java/name/antonsmirnov/firmata/wrapper/MessagesHistoryWrapper.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.wrapper;
2 |
3 | import name.antonsmirnov.firmata.IFirmata;
4 | import name.antonsmirnov.firmata.message.*;
5 | import name.antonsmirnov.firmata.serial.SerialException;
6 |
7 | import java.util.*;
8 | import java.util.concurrent.CopyOnWriteArrayList;
9 |
10 | /**
11 | * Wrapper which remembers sent and received commands
12 | *
13 | * Every message stores map of properties.
14 | * Concrete IMessageProperty inheritor sets and gets concrete property
15 | */
16 | public class MessagesHistoryWrapper implements IFirmata, IFirmata.Listener {
17 |
18 | private IMessagePropertyManager[] propertyManagers;
19 |
20 | public MessagesHistoryWrapper(IFirmata firmata, IMessagePropertyManager... propertyManagers) {
21 | this.firmata = firmata;
22 | this.propertyManagers = propertyManagers;
23 | firmata.addListener(this);
24 |
25 | clear();
26 | }
27 |
28 | private IFirmata firmata;
29 |
30 | public void addListener(Listener listener) {
31 | firmata.addListener(listener);
32 | }
33 |
34 | public void removeListener(Listener listener) {
35 | firmata.removeListener(listener);
36 | }
37 |
38 | public boolean containsListener(Listener listener) {
39 | return firmata.containsListener(listener);
40 | }
41 |
42 | public void clearListeners() {
43 | firmata.clearListeners();
44 | }
45 |
46 | private List messages = new ArrayList();
47 |
48 | private DirectionMessagePropertyManager receivedPropertyManager = new DirectionMessagePropertyManager(true);
49 | private IMessageFilter receivedFilter = new DirectionMessageFilter(receivedPropertyManager);
50 |
51 | private DirectionMessagePropertyManager sentPropertyManager = new DirectionMessagePropertyManager(false);
52 | private IMessageFilter sentFilter = new DirectionMessageFilter(sentPropertyManager);
53 |
54 | protected void addCommonProperties(MessageWithProperties data) {
55 | for (IMessagePropertyManager eachPropertyManager : propertyManagers)
56 | eachPropertyManager.set(data);
57 | }
58 |
59 | protected void rememberReceivedMessage(Message message) {
60 | MessageWithProperties newData = new MessageWithProperties(message);
61 |
62 | // common properties
63 | addCommonProperties(newData);
64 |
65 | // 'incoming' property
66 | receivedPropertyManager.set(newData);
67 |
68 | messages.add(newData);
69 | }
70 |
71 | private void rememberSentMessage(Message message) {
72 | MessageWithProperties newData = new MessageWithProperties(message);
73 |
74 | // common properties
75 | addCommonProperties(newData);
76 |
77 | // 'incoming' property
78 | sentPropertyManager.set(newData);
79 |
80 | messages.add(newData);
81 | }
82 |
83 | private IMessageFilter stubMessageFilter = new StubMessageFilter();
84 |
85 | /**
86 | * Get all messages
87 | * @return messages
88 | */
89 | public List getMessages() {
90 | return getMessages(stubMessageFilter);
91 | }
92 |
93 | /**
94 | * Get filtered messages
95 | * @return messages
96 | */
97 | public List getMessages(IMessageFilter filter) {
98 | List filteredMessages = new CopyOnWriteArrayList();
99 |
100 | for (MessageWithProperties eachMessage : messages)
101 | if (filter.isAllowed(eachMessage))
102 | filteredMessages.add(eachMessage);
103 |
104 | return filteredMessages;
105 | }
106 |
107 | /**
108 | * Get received messages
109 | * @return received messages
110 | */
111 | public List getReceivedMessages() {
112 | return getMessages(receivedFilter);
113 | }
114 |
115 | /**
116 | * Get sent messages
117 | * @return sent messages
118 | */
119 | public List getSentMessages() {
120 | return getMessages(sentFilter);
121 | }
122 |
123 | /**
124 | * Get last received message
125 | * @return received message or NULL
126 | */
127 | public MessageWithProperties getLastReceivedMessageWithProperties() {
128 | List receivedMessages = getReceivedMessages();
129 | return receivedMessages.size() > 0
130 | ? receivedMessages.get(receivedMessages.size() - 1)
131 | : null;
132 | }
133 |
134 | /**
135 | * Clear history
136 | * (should be invoked on serial.stop())
137 | */
138 | public void clear() {
139 | messages.clear();
140 | }
141 |
142 | public void onAnalogMessageReceived(AnalogMessage message) {
143 | rememberReceivedMessage(message);
144 | }
145 |
146 | public void onDigitalMessageReceived(DigitalMessage message) {
147 | rememberReceivedMessage(message);
148 | }
149 |
150 | public void onFirmwareVersionMessageReceived(FirmwareVersionMessage message) {
151 | rememberReceivedMessage(message);
152 | }
153 |
154 | public void onProtocolVersionMessageReceived(ProtocolVersionMessage message) {
155 | rememberReceivedMessage(message);
156 | }
157 |
158 | public void onSysexMessageReceived(SysexMessage message) {
159 | rememberReceivedMessage(message);
160 | }
161 |
162 | public void onStringSysexMessageReceived(StringSysexMessage message) {
163 | rememberReceivedMessage(message);
164 | }
165 |
166 | public void onI2cMessageReceived(I2cReplyMessage message) {
167 | rememberReceivedMessage(message);
168 | }
169 |
170 | public void onUnknownByteReceived(int byteValue) {
171 | // nothing
172 | }
173 |
174 | public void send(Message message) throws SerialException {
175 | firmata.send(message);
176 |
177 | rememberSentMessage(message);
178 | }
179 |
180 | public void onDataReceived(int incomingByte) {
181 | firmata.onDataReceived(incomingByte);
182 | }
183 | }
184 |
--------------------------------------------------------------------------------
/Firmata/src/main/java/name/antonsmirnov/firmata/wrapper/OrFilter.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.wrapper;
2 |
3 | /**
4 | * At least one filter should allow data
5 | */
6 | public class OrFilter implements IMessageFilter {
7 |
8 | private IMessageFilter[] filters;
9 |
10 | public OrFilter(IMessageFilter... filters) {
11 | this.filters = filters;
12 | }
13 |
14 | public boolean isAllowed(MessageWithProperties data) {
15 | for (IMessageFilter eachFilter : filters)
16 | if (eachFilter.isAllowed(data))
17 | return true;
18 |
19 | return false;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Firmata/src/main/java/name/antonsmirnov/firmata/wrapper/PinModeWrapper.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.wrapper;
2 |
3 | import name.antonsmirnov.firmata.IFirmata;
4 | import name.antonsmirnov.firmata.message.Message;
5 | import name.antonsmirnov.firmata.message.SetPinModeMessage;
6 | import name.antonsmirnov.firmata.serial.SerialException;
7 |
8 | import java.util.HashMap;
9 | import java.util.Map;
10 |
11 | /**
12 | * Wrapper which remembers pin modes
13 | */
14 | public class PinModeWrapper implements IFirmata {
15 |
16 | /**
17 | * Set pin mode event listener
18 | */
19 | public static interface Listener {
20 | void onSetPinMode(int pin, int mode);
21 | }
22 |
23 | private IFirmata firmata;
24 | private Listener listener;
25 |
26 | public void addListener(IFirmata.Listener listener) {
27 | firmata.addListener(listener);
28 | }
29 |
30 | public void removeListener(IFirmata.Listener listener) {
31 | firmata.removeListener(listener);
32 | }
33 |
34 | public boolean containsListener(IFirmata.Listener listener) {
35 | return firmata.containsListener(listener);
36 | }
37 |
38 | public void clearListeners() {
39 | firmata.clearListeners();
40 | }
41 |
42 | // pins configuration
43 | private Map pinsConfig = new HashMap();
44 |
45 | /**
46 | * Get remembered pin modes
47 | * @return pin modes
48 | */
49 | public Map getPinsConfig() {
50 | return pinsConfig;
51 | }
52 |
53 | public PinModeWrapper(IFirmata firmata) {
54 | this(firmata, null);
55 | }
56 |
57 | /**
58 | * Constructor
59 | * @param firmata wrapped firmata
60 | * @param listener set pin mode event listener
61 | */
62 | public PinModeWrapper(IFirmata firmata, Listener listener) {
63 | this.firmata = firmata;
64 | this.listener = listener;
65 |
66 | clear();
67 | }
68 |
69 | /**
70 | * Clear pins config
71 | * (should be invoked on serial.stop())
72 | */
73 | public void clear() {
74 | pinsConfig.clear();
75 | }
76 |
77 | public void send(Message message) throws SerialException {
78 | firmata.send(message);
79 |
80 | if (message instanceof SetPinModeMessage) {
81 | SetPinModeMessage setPinModeMessage = (SetPinModeMessage) message;
82 |
83 | // remember
84 | pinsConfig.put(setPinModeMessage.getPin(), setPinModeMessage.getMode());
85 |
86 | // fire event
87 | if (listener != null)
88 | listener.onSetPinMode(setPinModeMessage.getPin(), setPinModeMessage.getMode());
89 | }
90 | }
91 |
92 | public void onDataReceived(int incomingByte) {
93 | firmata.onDataReceived(incomingByte);
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/Firmata/src/main/java/name/antonsmirnov/firmata/wrapper/ReportAutostopWrapper.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.wrapper;
2 |
3 | import name.antonsmirnov.firmata.IFirmata;
4 | import name.antonsmirnov.firmata.message.*;
5 | import name.antonsmirnov.firmata.serial.SerialException;
6 |
7 | import java.util.HashSet;
8 | import java.util.Set;
9 |
10 | /**
11 | * Disables pin state reporting after first state message received
12 | */
13 | public class ReportAutostopWrapper extends IFirmata.StubListener implements IFirmata {
14 |
15 | private IFirmata firmata;
16 |
17 | public ReportAutostopWrapper(IFirmata firmata) {
18 | this.firmata = firmata;
19 | }
20 |
21 | public void addListener(Listener listener) {
22 | firmata.addListener(listener);
23 | }
24 |
25 | public void removeListener(Listener listener) {
26 | firmata.removeListener(listener);
27 | }
28 |
29 | public boolean containsListener(Listener listener) {
30 | return firmata.containsListener(listener);
31 | }
32 |
33 | public void clearListeners() {
34 | firmata.clearListeners();
35 | }
36 |
37 | // active reporting pins
38 | private Set digitalReporting = new HashSet(); // integer - port
39 | private Set analogReporting = new HashSet(); // integer - pin
40 |
41 | public void send(Message message) throws SerialException {
42 | firmata.send(message);
43 |
44 | // digital
45 | if (message instanceof ReportDigitalPortMessage) {
46 | ReportDigitalPortMessage digitalMessage = (ReportDigitalPortMessage) message;
47 | if (digitalMessage.isEnable())
48 | digitalReporting.add(digitalMessage.getPort());
49 | }
50 |
51 | // analog
52 | if (message instanceof ReportAnalogPinMessage) {
53 | ReportAnalogPinMessage analogMessage = (ReportAnalogPinMessage) message;
54 | if (analogMessage.isEnable())
55 | analogReporting.add(analogMessage.getPin());
56 | }
57 | }
58 |
59 | @Override
60 | public void onAnalogMessageReceived(AnalogMessage message) {
61 | if (analogReporting.contains(message.getPin())) {
62 | analogReporting.remove(message.getPin());
63 |
64 | disableAnalogReporting(message);
65 | }
66 | }
67 |
68 | private void disableAnalogReporting(AnalogMessage message) {
69 | try {
70 | firmata.send(new ReportAnalogPinMessage(message.getPin(), false));
71 | } catch (SerialException e) {
72 | // TODO: fix (bad)
73 | }
74 | }
75 |
76 | @Override
77 | public void onDigitalMessageReceived(DigitalMessage message) {
78 | if (digitalReporting.contains(message.getPort())) {
79 | digitalReporting.remove(message.getPort());
80 |
81 | disableDigitalReporting(message);
82 | }
83 | }
84 |
85 | private void disableDigitalReporting(DigitalMessage message) {
86 | try {
87 | firmata.send(new ReportDigitalPortMessage(message.getPort(), false));
88 | } catch (SerialException e) {
89 | // TODO: fix (bad)
90 | }
91 | }
92 |
93 | public void clear() {
94 | digitalReporting.clear();
95 | analogReporting.clear();
96 | }
97 |
98 | public void onDataReceived(int incomingByte) {
99 | firmata.onDataReceived(incomingByte);
100 | }
101 |
102 |
103 | }
104 |
--------------------------------------------------------------------------------
/Firmata/src/main/java/name/antonsmirnov/firmata/wrapper/StubMessageFilter.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.wrapper;
2 |
3 | /**
4 | * Filter stub : all messages are allowed
5 | */
6 | public class StubMessageFilter implements IMessageFilter {
7 |
8 | public boolean isAllowed(MessageWithProperties data) {
9 | return true;
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Firmata/src/main/java/name/antonsmirnov/firmata/writer/AnalogMessageWriter.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.writer;
2 |
3 | import name.antonsmirnov.firmata.message.AnalogMessage;
4 | import name.antonsmirnov.firmata.serial.ISerial;
5 | import name.antonsmirnov.firmata.serial.SerialException;
6 |
7 | import static name.antonsmirnov.firmata.BytesHelper.*;
8 |
9 | /**
10 | * MessageWriter for AnalogMessage
11 | */
12 | public class AnalogMessageWriter implements IMessageWriter {
13 |
14 | public static final int COMMAND = 0xE0;
15 |
16 | public void write(AnalogMessage message, ISerial serial) throws SerialException {
17 | serial.write(COMMAND | ENCODE_CHANNEL(message.getPin()));
18 | serial.write(LSB(message.getValue()));
19 | serial.write(MSB(message.getValue()));
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Firmata/src/main/java/name/antonsmirnov/firmata/writer/DigitalMessageWriter.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.writer;
2 |
3 | import name.antonsmirnov.firmata.message.DigitalMessage;
4 | import name.antonsmirnov.firmata.serial.ISerial;
5 | import name.antonsmirnov.firmata.serial.SerialException;
6 |
7 | import static name.antonsmirnov.firmata.BytesHelper.*;
8 |
9 | /**
10 | * MessageWriter for DigitalMessage
11 | */
12 | public class DigitalMessageWriter implements IMessageWriter {
13 |
14 | public static final int COMMAND = 0x90;
15 |
16 | public void write(DigitalMessage message, ISerial serial) throws SerialException {
17 | serial.write(COMMAND | ENCODE_CHANNEL(message.getPort()));
18 | serial.write(LSB(message.getValue()));
19 | serial.write(MSB(message.getValue()));
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Firmata/src/main/java/name/antonsmirnov/firmata/writer/I2cConfigMessageWriter.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.writer;
2 |
3 | import name.antonsmirnov.firmata.message.I2cConfigMessage;
4 | import name.antonsmirnov.firmata.serial.ISerial;
5 | import name.antonsmirnov.firmata.serial.SerialException;
6 |
7 | import static name.antonsmirnov.firmata.BytesHelper.LSB;
8 | import static name.antonsmirnov.firmata.BytesHelper.MSB;
9 |
10 | /**
11 | * MessageWriter for I2cConfigMessage
12 | */
13 | public class I2cConfigMessageWriter extends SysexMessageWriter {
14 |
15 | @Override
16 | protected void writeData(I2cConfigMessage message, ISerial serial) throws SerialException {
17 | // can not use super.writeData() because it works with String
18 | writeI2cConfigData(message, serial);
19 | }
20 |
21 | private void writeI2cConfigData(I2cConfigMessage message, ISerial serial) throws SerialException {
22 | byte[] buffer = new byte[3];
23 |
24 | buffer[0] = (byte)(message.isOn() ? 1 : 0);
25 | buffer[1] = (byte)LSB(message.getDelay());
26 | buffer[2] = (byte)MSB(message.getDelay());
27 |
28 | serial.write(buffer);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Firmata/src/main/java/name/antonsmirnov/firmata/writer/I2cRequestMessageWriter.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.writer;
2 |
3 | import name.antonsmirnov.firmata.message.I2cRequestMessage;
4 | import name.antonsmirnov.firmata.serial.ISerial;
5 | import name.antonsmirnov.firmata.serial.SerialException;
6 |
7 | import static name.antonsmirnov.firmata.BytesHelper.*;
8 |
9 | /**
10 | * MessageWriter for I2cRequestMessage
11 | */
12 | public class I2cRequestMessageWriter extends SysexMessageWriter {
13 |
14 | @Override
15 | protected void writeData(ConcreteRequestMessage message, ISerial serial) throws SerialException {
16 | // can not use super.writeData() because it works with String
17 | writeI2cRequestData(message, serial);
18 | }
19 |
20 | private void writeI2cRequestData(ConcreteRequestMessage message, ISerial serial) throws SerialException {
21 | byte[] buffer = new byte[2];
22 |
23 | buffer[0] = (byte)LSB(message.getSlaveAddress());
24 | int modeByte = 0;
25 |
26 | modeByte = setBit(modeByte, 7, false); // {7: always 0}
27 | modeByte = setBit(modeByte, 6, false); // {6: reserved}
28 | modeByte = setBit(modeByte, 5, message.isTenBitsMode()); // {5: address mode, 1 means 10-bit mode}
29 |
30 | // 4-3 bits are modes
31 | modeByte |= (byte)(message.getMode().getValue() << 3); // {4-3: read/write, 00 => write, 01 => read once, 10 => read continuously, 11 => stop reading}
32 |
33 | // 0-2 bits
34 | if (message.isTenBitsMode())
35 | modeByte |= MSB(message.getSlaveAddress() & 7); // {2-0: slave address MSB in 10-bit mode, not used in 7-bit mode}
36 |
37 | buffer[1] = (byte)modeByte;
38 | serial.write(buffer);
39 |
40 | int[] binaryData = message.getBinaryData();
41 | if (binaryData != null) {
42 | byte[] dataBuffer = ENCODE_INT_ARRAY(binaryData);
43 | serial.write(dataBuffer);
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/Firmata/src/main/java/name/antonsmirnov/firmata/writer/IMessageWriter.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.writer;
2 |
3 | import name.antonsmirnov.firmata.message.Message;
4 | import name.antonsmirnov.firmata.serial.ISerial;
5 | import name.antonsmirnov.firmata.serial.SerialException;
6 |
7 | /**
8 | * Message writer
9 | */
10 | public interface IMessageWriter {
11 |
12 | /**
13 | * Write command to Serial
14 | */
15 | void write(ConcreteMessage message, ISerial serial) throws SerialException;
16 | }
17 |
--------------------------------------------------------------------------------
/Firmata/src/main/java/name/antonsmirnov/firmata/writer/ReportAnalogPinMessageWriter.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.writer;
2 |
3 | import name.antonsmirnov.firmata.message.ReportAnalogPinMessage;
4 | import name.antonsmirnov.firmata.serial.ISerial;
5 | import name.antonsmirnov.firmata.serial.SerialException;
6 |
7 | import static name.antonsmirnov.firmata.BytesHelper.ENCODE_CHANNEL;
8 |
9 | /**
10 | * MessageWriter for ReportAnalogPinMessage
11 | */
12 | public class ReportAnalogPinMessageWriter implements IMessageWriter {
13 |
14 | public static final int COMMAND = 0xC0;
15 |
16 | public void write(ReportAnalogPinMessage message, ISerial serial) throws SerialException {
17 | serial.write(COMMAND | ENCODE_CHANNEL(message.getPin()));
18 | serial.write(message.isEnable() ? 1 : 0);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Firmata/src/main/java/name/antonsmirnov/firmata/writer/ReportDigitalPortMessageWriter.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.writer;
2 |
3 | import name.antonsmirnov.firmata.message.ReportDigitalPortMessage;
4 | import name.antonsmirnov.firmata.serial.ISerial;
5 | import name.antonsmirnov.firmata.serial.SerialException;
6 |
7 | import static name.antonsmirnov.firmata.BytesHelper.ENCODE_CHANNEL;
8 |
9 | /**
10 | * MessageWriter for ReportDigitalPortMessage
11 | */
12 | public class ReportDigitalPortMessageWriter implements IMessageWriter {
13 |
14 | public static final int COMMAND = 0xD0;
15 |
16 | public void write(ReportDigitalPortMessage message, ISerial serial) throws SerialException {
17 | serial.write(COMMAND | ENCODE_CHANNEL(message.getPort()));
18 | serial.write(message.isEnable() ? 1 : 0);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Firmata/src/main/java/name/antonsmirnov/firmata/writer/ReportProtocolVersionMessageWriter.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.writer;
2 |
3 | import name.antonsmirnov.firmata.message.ReportProtocolVersionMessage;
4 | import name.antonsmirnov.firmata.serial.ISerial;
5 | import name.antonsmirnov.firmata.serial.SerialException;
6 |
7 | /**
8 | * MessageWriter for ReportProtocolVersionMessage
9 | */
10 | public class ReportProtocolVersionMessageWriter implements IMessageWriter {
11 |
12 | public static final int COMMAND = 0xF9;
13 |
14 | public void write(ReportProtocolVersionMessage message, ISerial serial) throws SerialException {
15 | serial.write(COMMAND);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Firmata/src/main/java/name/antonsmirnov/firmata/writer/SamplingIntervalMessageWriter.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.writer;
2 |
3 | import name.antonsmirnov.firmata.message.SamplingIntervalMessage;
4 | import name.antonsmirnov.firmata.serial.ISerial;
5 | import name.antonsmirnov.firmata.serial.SerialException;
6 |
7 | import static name.antonsmirnov.firmata.BytesHelper.*;
8 |
9 | /**
10 | * MessageWriter for SamplingIntervalMessage
11 | */
12 | public class SamplingIntervalMessageWriter extends SysexMessageWriter {
13 |
14 | @Override
15 | protected void writeData(SamplingIntervalMessage message, ISerial serial) throws SerialException {
16 | // can not use super.writeData() because it works with String
17 | writeIntervalData(message, serial);
18 | }
19 |
20 | private void writeIntervalData(SamplingIntervalMessage message, ISerial serial) throws SerialException {
21 | byte[] buffer = new byte[2];
22 |
23 | buffer[0] = (byte)LSB(message.getInterval());
24 | buffer[1] = (byte)MSB(message.getInterval());
25 |
26 | serial.write(buffer);
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/Firmata/src/main/java/name/antonsmirnov/firmata/writer/ServoConfigMessageWriter.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.writer;
2 |
3 | import name.antonsmirnov.firmata.message.ServoConfigMessage;
4 | import name.antonsmirnov.firmata.serial.ISerial;
5 | import name.antonsmirnov.firmata.serial.SerialException;
6 |
7 | import static name.antonsmirnov.firmata.BytesHelper.*;
8 |
9 | /**
10 | * MessageWriter for ServoConfigMessage
11 | */
12 | public class ServoConfigMessageWriter extends SysexMessageWriter {
13 |
14 | @Override
15 | protected void writeData(ServoConfigMessage message, ISerial serial) throws SerialException {
16 | // can not use super.writeData() because it works with String
17 | writeServoData(message, serial);
18 | }
19 |
20 | private void writeServoData(ServoConfigMessage message, ISerial serial) throws SerialException {
21 | byte[] buffer = new byte[7];
22 | buffer[0] = (byte)message.getPin();
23 |
24 | buffer[1] = (byte)LSB(message.getMinPulse());
25 | buffer[2] = (byte)MSB(message.getMinPulse());
26 |
27 | buffer[3] = (byte)LSB(message.getMaxPulse());
28 | buffer[4] = (byte)MSB(message.getMaxPulse());
29 |
30 | buffer[5] = (byte)LSB(message.getAngle());
31 | buffer[6] = (byte)MSB(message.getAngle());
32 |
33 | serial.write(buffer);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Firmata/src/main/java/name/antonsmirnov/firmata/writer/SetPinModeMessageWriter.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.writer;
2 |
3 | import name.antonsmirnov.firmata.message.SetPinModeMessage;
4 | import name.antonsmirnov.firmata.serial.ISerial;
5 | import name.antonsmirnov.firmata.serial.SerialException;
6 |
7 | /**
8 | * MessageWriter for SetPinModeMessage
9 | */
10 | public class SetPinModeMessageWriter implements IMessageWriter {
11 |
12 | public static final int COMMAND = 0xF4;
13 |
14 | public void write(SetPinModeMessage message, ISerial serial) throws SerialException {
15 | serial.write(COMMAND);
16 | serial.write(message.getPin());
17 | serial.write(message.getMode());
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Firmata/src/main/java/name/antonsmirnov/firmata/writer/SysexMessageWriter.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.writer;
2 |
3 | import name.antonsmirnov.firmata.message.SysexMessage;
4 | import name.antonsmirnov.firmata.serial.ISerial;
5 | import name.antonsmirnov.firmata.serial.SerialException;
6 |
7 | import static name.antonsmirnov.firmata.BytesHelper.ENCODE_STRING;
8 |
9 | /**
10 | * MessageWriter for SysexMessage and inheritors
11 | */
12 | public class SysexMessageWriter implements IMessageWriter {
13 |
14 | public static final int COMMAND_START = 0xF0;
15 | public static final int COMMAND_END = 0xF7;
16 |
17 | public void write(ConcreteSysexMessage message, ISerial serial) throws SerialException {
18 | serial.write(COMMAND_START);
19 | writeCommand(message, serial);
20 | writeData(message, serial);
21 | serial.write(COMMAND_END);
22 | }
23 |
24 | protected void writeCommand(ConcreteSysexMessage message, ISerial serial) throws SerialException {
25 | serial.write(message.getCommand());
26 | }
27 |
28 | protected void writeData(ConcreteSysexMessage message, ISerial serial) throws SerialException {
29 | if (message.getData() != null) {
30 | byte[] dataBytes = ENCODE_STRING(message.getData());
31 | serial.write(dataBytes);
32 | }
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/Firmata/src/main/java/name/antonsmirnov/firmata/writer/SystemResetMessageWriter.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.writer;
2 |
3 | import name.antonsmirnov.firmata.message.SystemResetMessage;
4 | import name.antonsmirnov.firmata.serial.ISerial;
5 | import name.antonsmirnov.firmata.serial.SerialException;
6 |
7 | /**
8 | * MessageWriter for SystemResetMessage
9 | */
10 | public class SystemResetMessageWriter implements IMessageWriter {
11 |
12 | public static final int COMMAND = 0xFF;
13 |
14 | public void write(SystemResetMessage message, ISerial serial) throws SerialException {
15 | serial.write(COMMAND);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/FirmataTests/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 |
8 | name.antonsmirnov.firmata
9 | parent
10 | 1.0
11 |
12 |
13 | name.antonsmirnov.firmata
14 | FirmataTests
15 | 2.4
16 | FirmataTests
17 |
18 |
19 |
20 | Anton Smirnov
21 | dev@antonsmirnov.name
22 |
23 |
24 |
25 | Firmata real hardware interaction Tests
26 |
27 |
28 |
29 | name.antonsmirnov.firmata
30 | Firmata
31 | 2.6
32 |
33 |
34 |
35 |
36 | org.slf4j
37 | slf4j-simple
38 | 1.6.4
39 | test
40 |
41 |
42 |
43 | name.antonsmirnov.firmata.serial
44 | IndepProcessingSerial
45 | 1.2
46 | test
47 |
48 |
49 |
50 | junit
51 | junit
52 | 4.8.1
53 | test
54 |
55 |
56 |
57 |
58 |
59 |
60 | org.apache.maven.plugins
61 | maven-surefire-plugin
62 | 2.10
63 |
64 |
65 |
66 | **/*HardwareTest.java
67 |
68 |
69 |
70 |
71 |
72 |
73 |
--------------------------------------------------------------------------------
/FirmataTests/src/main/java/name/antonsmirnov/firmata/FirmataWaiter.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata;
2 |
3 | import name.antonsmirnov.firmata.message.Message;
4 | import name.antonsmirnov.firmata.wrapper.MessagesHistoryWrapper;
5 | import org.slf4j.Logger;
6 | import org.slf4j.LoggerFactory;
7 |
8 | /**
9 | * Wait for incoming message from firmata
10 | */
11 | public class FirmataWaiter {
12 |
13 | private Logger log = LoggerFactory.getLogger(getClass());
14 |
15 | private final int WAIT_INCREMENT = 10; // ms
16 |
17 | private MessagesHistoryWrapper firmata;
18 |
19 | public FirmataWaiter(IFirmata firmata) {
20 | this.firmata = new MessagesHistoryWrapper(firmata);
21 | }
22 |
23 | private int waited;
24 |
25 | public void waitSeconds(int seconds, Class extends Message> messageClass) throws WaitException {
26 | waited = 0;
27 | int wait = seconds * 1000; // sec -> ms
28 |
29 | log.info("Started waiting {} ...", messageClass != null
30 | ? "for " + messageClass.getSimpleName()
31 | : "");
32 |
33 | while (true) {
34 | try {
35 | Thread.sleep(WAIT_INCREMENT);
36 | } catch (InterruptedException e) {
37 | throw new RuntimeException(e);
38 | }
39 |
40 | if (firmata.getLastReceivedMessageWithProperties() == null
41 | ||
42 | (
43 | firmata.getLastReceivedMessageWithProperties() != null
44 | &&
45 | messageClass != null
46 | &&
47 | !firmata.getLastReceivedMessageWithProperties().getMessage().getClass().equals(messageClass)
48 | )) {
49 | waited += WAIT_INCREMENT;
50 | if (waited > wait)
51 | throw new WaitException(messageClass);
52 | } else {
53 | break;
54 | }
55 | }
56 | }
57 |
58 | public void waitSeconds(int seconds) throws WaitException {
59 | waitSeconds(seconds, null);
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/FirmataTests/src/main/java/name/antonsmirnov/firmata/OriginalFirmata.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata;
2 |
3 | import name.antonsmirnov.firmata.serial.ISerial;
4 | import name.antonsmirnov.firmata.serial.SerialException;
5 |
6 | /**
7 | * Almost original Firmata (Arduino.java) 1.5.1
8 | */
9 | public class OriginalFirmata {
10 |
11 | private ISerial serial;
12 |
13 | public ISerial getSerial() {
14 | return serial;
15 | }
16 |
17 | public void setSerial(ISerial serial) {
18 | this.serial = serial;
19 | }
20 |
21 | public OriginalFirmata(ISerial serial) {
22 | setSerial(serial);
23 | }
24 |
25 | /**
26 | * Constant to set a pin to input mode (in a call to pinMode()).
27 | */
28 | public static final int INPUT = 0;
29 | /**
30 | * Constant to set a pin to output mode (in a call to pinMode()).
31 | */
32 | public static final int OUTPUT = 1;
33 | /**
34 | * Constant to set a pin to analog mode (in a call to pinMode()).
35 | */
36 | public static final int ANALOG = 2;
37 | /**
38 | * Constant to set a pin to PWM mode (in a call to pinMode()).
39 | */
40 | public static final int PWM = 3;
41 | /**
42 | * Constant to set a pin to servo mode (in a call to pinMode()).
43 | */
44 | public static final int SERVO = 4;
45 | /**
46 | * Constant to set a pin to shiftIn/shiftOut mode (in a call to pinMode()).
47 | */
48 | public static final int SHIFT = 5;
49 | /**
50 | * Constant to set a pin to I2C mode (in a call to pinMode()).
51 | */
52 | public static final int I2C = 6;
53 |
54 | /**
55 | * Constant to send a high value (+5 volts) to a pin (in a call to
56 | * digitalWrite()).
57 | */
58 | public static final int LOW = 0;
59 | /**
60 | * Constant to send a low value (0 volts) to a pin (in a call to
61 | * digitalWrite()).
62 | */
63 | public static final int HIGH = 1;
64 |
65 | private final int MAX_DATA_BYTES = 32;
66 |
67 | private final int DIGITAL_MESSAGE = 0x90; // send data for a digital port
68 | private final int ANALOG_MESSAGE = 0xE0; // send data for an analog pin (or PWM)
69 | private final int REPORT_ANALOG = 0xC0; // enable analog input by pin #
70 | private final int REPORT_DIGITAL = 0xD0; // enable digital input by port
71 | private final int SET_PIN_MODE = 0xF4; // set a pin to INPUT/OUTPUT/PWM/etc
72 | private final int REPORT_VERSION = 0xF9; // report firmware version
73 | private final int SYSTEM_RESET = 0xFF; // reset from MIDI
74 | private final int START_SYSEX = 0xF0; // start a MIDI SysEx message
75 | private final int END_SYSEX = 0xF7; // end a MIDI SysEx message
76 |
77 | int waitForData = 0;
78 | int executeMultiByteCommand = 0;
79 | int multiByteChannel = 0;
80 | int[] storedInputData = new int[MAX_DATA_BYTES];
81 | boolean parsingSysex;
82 | int sysexBytesRead;
83 |
84 | int[] digitalOutputData = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
85 | int[] digitalInputData = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
86 | int[] analogInputData = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
87 |
88 | int majorVersion = 0;
89 | int minorVersion = 0;
90 |
91 | /**
92 | * Returns the last known value read from the digital pin: HIGH or LOW.
93 | *
94 | * @param pin the digital pin whose value should be returned (from 2 to 13,
95 | * since pins 0 and 1 are used for serial communication)
96 | */
97 | public int digitalRead(int pin) {
98 | return (digitalInputData[pin >> 3] >> (pin & 0x07)) & 0x01;
99 | }
100 |
101 | /**
102 | * Returns the last known value read from the analog pin: 0 (0 volts) to
103 | * 1023 (5 volts).
104 | *
105 | * @param pin the analog pin whose value should be returned (from 0 to 5)
106 | */
107 | public int analogRead(int pin) {
108 | return analogInputData[pin];
109 | }
110 |
111 | /**
112 | * Set a digital pin to input or output mode.
113 | *
114 | * @param pin the pin whose mode to set (from 2 to 13)
115 | * @param mode either Arduino.INPUT or Arduino.OUTPUT
116 | */
117 | public void pinMode(int pin, int mode) throws SerialException {
118 | serial.write(SET_PIN_MODE);
119 | serial.write(pin);
120 | serial.write(mode);
121 | }
122 |
123 | /**
124 | * Write to a digital pin (the pin must have been put into output mode with
125 | * pinMode()).
126 | *
127 | * @param pin the pin to send to (from 2 to 13)
128 | * @param value the value to send: Arduino.LOW (0 volts) or Arduino.HIGH
129 | * (5 volts)
130 | */
131 | public void digitalWrite(int pin, int value) throws SerialException {
132 | int portNumber = (pin >> 3) & 0x0F;
133 |
134 | if (value == 0)
135 | digitalOutputData[portNumber] &= ~(1 << (pin & 0x07));
136 | else
137 | digitalOutputData[portNumber] |= (1 << (pin & 0x07));
138 |
139 | serial.write(DIGITAL_MESSAGE | portNumber);
140 | serial.write(digitalOutputData[portNumber] & 0x7F);
141 | serial.write(digitalOutputData[portNumber] >> 7);
142 | }
143 |
144 | /**
145 | * Write an analog value (PWM-wave) to a digital pin.
146 | *
147 | * @param pin the pin to send to (must be 9, 10, or 11, as those are they
148 | * only ones which support hardware pwm)
149 | * @param value: 0 being the lowest (always off), and 255 the highest
150 | * (always on)
151 | */
152 | public void analogWrite(int pin, int value) throws SerialException {
153 | pinMode(pin, PWM);
154 | serial.write(ANALOG_MESSAGE | (pin & 0x0F));
155 | serial.write(value & 0x7F);
156 | serial.write(value >> 7);
157 | }
158 |
159 | private void setDigitalInputs(int portNumber, int portData) {
160 | digitalInputData[portNumber] = portData;
161 | }
162 |
163 | private void setAnalogInput(int pin, int value) {
164 | analogInputData[pin] = value;
165 | }
166 |
167 | private void setVersion(int majorVersion, int minorVersion) {
168 | this.majorVersion = majorVersion;
169 | this.minorVersion = minorVersion;
170 | }
171 |
172 | public void processByte(int inputData) {
173 | int command;
174 |
175 | if (parsingSysex) {
176 | if (inputData == END_SYSEX) {
177 | parsingSysex = false;
178 | //processSysexMessage();
179 | } else {
180 | storedInputData[sysexBytesRead] = inputData;
181 | sysexBytesRead++;
182 | }
183 | } else if (waitForData > 0 && inputData < 128) {
184 | waitForData--;
185 | storedInputData[waitForData] = inputData;
186 |
187 | if (executeMultiByteCommand != 0 && waitForData == 0) {
188 | //we got everything
189 | switch (executeMultiByteCommand) {
190 | case DIGITAL_MESSAGE:
191 | setDigitalInputs(multiByteChannel, (storedInputData[0] << 7) + storedInputData[1]);
192 | break;
193 | case ANALOG_MESSAGE:
194 | setAnalogInput(multiByteChannel, (storedInputData[0] << 7) + storedInputData[1]);
195 | break;
196 | case REPORT_VERSION:
197 | setVersion(storedInputData[1], storedInputData[0]);
198 | break;
199 | }
200 | }
201 | } else {
202 | if (inputData < 0xF0) {
203 | command = inputData & 0xF0;
204 | multiByteChannel = inputData & 0x0F;
205 | } else {
206 | command = inputData;
207 | // commands in the 0xF* range don't use channel data
208 | }
209 | switch (command) {
210 | case DIGITAL_MESSAGE:
211 | case ANALOG_MESSAGE:
212 | case REPORT_VERSION:
213 | waitForData = 2;
214 | executeMultiByteCommand = command;
215 | break;
216 | }
217 | }
218 | }
219 |
220 | private void processInput() throws SerialException {
221 | processByte(serial.read());
222 | }
223 | }
224 |
--------------------------------------------------------------------------------
/FirmataTests/src/main/java/name/antonsmirnov/firmata/TestSerial.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata;
2 |
3 | import name.antonsmirnov.firmata.serial.ISerial;
4 | import name.antonsmirnov.firmata.serial.ISerialListener;
5 |
6 | import java.io.ByteArrayOutputStream;
7 | import java.io.IOException;
8 | import java.util.ArrayList;
9 | import java.util.List;
10 | import java.util.concurrent.ConcurrentLinkedQueue;
11 |
12 | /**
13 | * Test ISerial implementation
14 | * (for usage in tests)
15 | */
16 | public class TestSerial implements ISerial {
17 |
18 | public TestSerial() {
19 | initInputStream();
20 | initOutputStream();
21 | }
22 |
23 | private List listeners = new ArrayList();
24 |
25 | public void addListener(ISerialListener listener) {
26 | listeners.add(listener);
27 | }
28 |
29 | public void removeListener(ISerialListener listener) {
30 | listeners.remove(listener);
31 | }
32 |
33 | private void initOutputStream() {
34 | outputStream = new ByteArrayOutputStream();
35 | }
36 |
37 | private void initInputStream() {
38 | inputStream = new ConcurrentLinkedQueue();
39 | }
40 |
41 | private ConcurrentLinkedQueue inputStream = new ConcurrentLinkedQueue();
42 |
43 | public ByteArrayOutputStream getOutputStream() {
44 | return outputStream;
45 | }
46 |
47 | private ByteArrayOutputStream outputStream;
48 |
49 | public void start() {
50 | }
51 |
52 | public void stop() {
53 | }
54 |
55 | public boolean isStopping() {
56 | return false;
57 | }
58 |
59 | public int available() {
60 | return inputStream.size();
61 | }
62 |
63 | public void clear() {
64 | initInputStream();
65 | initOutputStream();
66 | }
67 |
68 | public int read() {
69 | return inputStream.poll();
70 | }
71 |
72 | public void write(int what) {
73 | outputStream.write(what);
74 | }
75 |
76 | public void write(byte[] bytes) {
77 | try {
78 | outputStream.write(bytes);
79 | } catch (IOException e) {
80 | throw new RuntimeException(e);
81 | }
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/FirmataTests/src/main/java/name/antonsmirnov/firmata/WaitException.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata;
2 |
3 | import name.antonsmirnov.firmata.message.Message;
4 |
5 | /**
6 | * Wait exception for FirmataWaiter
7 | */
8 | public class WaitException extends Exception {
9 |
10 | private Class messageClass;
11 |
12 | public Class getMessageClass() {
13 | return messageClass;
14 | }
15 |
16 | public WaitException(Class extends Message> messageClass) {
17 | super("No expected incoming message");
18 | this.messageClass = messageClass;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/FirmataTests/src/test/java/name/antonsmirnov/firmata/tests/AnalogMessageTest.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.tests;
2 |
3 | import name.antonsmirnov.firmata.message.AnalogMessage;
4 | import name.antonsmirnov.firmata.message.SetPinModeMessage;
5 | import name.antonsmirnov.firmata.serial.SerialException;
6 | import org.junit.Test;
7 |
8 | import java.util.Arrays;
9 |
10 | /**
11 | * Test for AnalogMessage
12 | */
13 | public class AnalogMessageTest extends BaseFirmataTest {
14 |
15 | @Test
16 | // compare original impl output and new impl output
17 | public void testWrite() throws SerialException {
18 | serial.clear();
19 |
20 | for (int pin = 0; pin < PIN_MAX; pin++)
21 | for (int value = 0; value < BYTE_MAX; value++) {
22 |
23 | // old Firmata impl
24 | serial.clear();
25 | originalFirmata.analogWrite(pin, value);
26 | final byte[] oldOutput = serial.getOutputStream().toByteArray();
27 |
28 | // new Firmata impl
29 | serial.clear();
30 | firmata.send(new SetPinModeMessage(pin, SetPinModeMessage.PIN_MODE.PWM.getMode()));
31 | firmata.send(new AnalogMessage(pin, value));
32 | final byte[] newOutput = serial.getOutputStream().toByteArray();
33 |
34 | assertTrue(Arrays.equals(oldOutput, newOutput));
35 | }
36 | }
37 |
38 | @Test
39 | public void testRead() throws SerialException {
40 | for (int pin = 0; pin < PIN_MAX; pin++)
41 | for (int value = 0; value < BYTE_MAX; value++) {
42 | // create output
43 | serial.clear();
44 | AnalogMessage outcomingMessage = new AnalogMessage(pin, value);
45 | firmata.send(outcomingMessage);
46 | final byte[] newOutput = serial.getOutputStream().toByteArray();
47 |
48 | // feed output to input
49 | for (byte eachByte : newOutput)
50 | firmata.onDataReceived(eachByte);
51 |
52 | // compare original command and received command
53 | assertNotNull(historyFirmataWrapper.getLastReceivedMessageWithProperties());
54 | assertEquals(outcomingMessage, historyFirmataWrapper.getLastReceivedMessageWithProperties().getMessage());
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/FirmataTests/src/test/java/name/antonsmirnov/firmata/tests/BaseFirmataTest.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.tests;
2 |
3 | import junit.framework.TestCase;
4 | import name.antonsmirnov.firmata.*;
5 | import name.antonsmirnov.firmata.IFirmata;
6 | import name.antonsmirnov.firmata.wrapper.MessagesHistoryWrapper;
7 |
8 | /**
9 | * Base Firmata Test
10 | */
11 | public abstract class BaseFirmataTest extends TestCase {
12 |
13 | protected static final int PIN_MAX = 16;
14 | protected static final int PORT_MAX = 3;
15 | protected static final int BYTE_MAX = 255;
16 |
17 | protected TestSerial serial;
18 |
19 | // original impl
20 | protected OriginalFirmata originalFirmata;
21 |
22 | // new impl
23 | protected Firmata impl;
24 | protected IFirmata firmata;
25 | protected MessagesHistoryWrapper historyFirmataWrapper;
26 |
27 | @Override
28 | protected void setUp() throws Exception {
29 | serial = new TestSerial();
30 | originalFirmata = new OriginalFirmata(serial);
31 |
32 | impl = new Firmata(serial);
33 | historyFirmataWrapper = new MessagesHistoryWrapper(impl);
34 |
35 | firmata = historyFirmataWrapper;
36 | }
37 |
38 | protected void feedToFirmata(byte[] input) {
39 | for (byte eachByte : input)
40 | firmata.onDataReceived(eachByte);
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/FirmataTests/src/test/java/name/antonsmirnov/firmata/tests/BytesHelperTest.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.tests;
2 |
3 | import junit.framework.TestCase;
4 | import name.antonsmirnov.firmata.BytesHelper;
5 | import org.junit.Test;
6 |
7 | /**
8 | * Tests for BytesHelper
9 | */
10 | public class BytesHelperTest extends TestCase {
11 | //0 //1 //2
12 | private int[] portByPin = {0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2};
13 | private int[] pinInPort = {0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7};
14 |
15 | @Test
16 | public void testPortByPin() {
17 | for (int pin = 0; pin < portByPin.length; pin++)
18 | assertEquals(portByPin[pin], BytesHelper.portByPin(pin));
19 | }
20 |
21 | @Test
22 | public void testPinInPort() {
23 | for (int pin = 0; pin < pinInPort.length; pin++)
24 | assertEquals(pinInPort[pin], BytesHelper.pinInPort(pin));
25 | }
26 |
27 | @Test
28 | public void testSetPin_High_One() {
29 | for (int pin = 0; pin < BytesHelper.BITS_IN_BYTE; pin++) {
30 | assertEquals((int)Math.pow(2, pin), BytesHelper.setPin(0, pin, true));
31 | }
32 | }
33 |
34 | @Test
35 | public void testSetPin_High_All() {
36 | int portValues = 0;
37 | for (int pin = 0; pin < BytesHelper.BITS_IN_BYTE; pin++) {
38 | // accumulating all bits values
39 | int currentBitValue = (int)Math.pow(2, pin);
40 | portValues += currentBitValue;
41 |
42 | assertEquals(portValues, BytesHelper.setPin(portValues, pin, true));
43 | }
44 | }
45 |
46 | @Test
47 | public void testSetPin_Low_One() {
48 | for (int pin = 0; pin < BytesHelper.BITS_IN_BYTE; pin++) {
49 | assertEquals(
50 | BytesHelper.BYTE_MAX_VALUE - (int)Math.pow(2, pin),
51 | BytesHelper.setPin(BytesHelper.BYTE_MAX_VALUE, pin, false));
52 | }
53 | }
54 |
55 | @Test
56 | public void testSetPin_Low_All() {
57 | int portValues = BytesHelper.BYTE_MAX_VALUE;
58 | for (int pin = 0; pin < BytesHelper.BITS_IN_BYTE; pin++) {
59 | // accumulating all bits values
60 | int currentBitValue = (int)Math.pow(2, pin);
61 | portValues -= currentBitValue;
62 |
63 | assertEquals(portValues, BytesHelper.setPin(portValues, pin, false));
64 | }
65 | }
66 |
67 | @Test
68 | public void testPinGet_High_One() {
69 | for (int setPin=0; setPin messages, Message message) {
80 | for (MessageWithProperties eachMessage : messages)
81 | if (eachMessage.getMessage() == message)
82 | return;
83 |
84 | fail("Message not found in history");
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/FirmataTests/src/test/java/name/antonsmirnov/firmata/tests/FirmwareVersionMessageTest.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.tests;
2 |
3 | import name.antonsmirnov.firmata.message.FirmwareVersionMessage;
4 | import name.antonsmirnov.firmata.message.ReportFirmwareVersionMessage;
5 | import name.antonsmirnov.firmata.reader.FirmwareVersionMessageReader;
6 | import name.antonsmirnov.firmata.wrapper.MessageWithProperties;
7 | import name.antonsmirnov.firmata.writer.SysexMessageWriter;
8 | import org.junit.Test;
9 |
10 | import java.nio.ByteBuffer;
11 |
12 | import static name.antonsmirnov.firmata.BytesHelper.ENCODE_STRING;
13 |
14 | /**
15 | * Test for FirmwareVersionMessage
16 | */
17 | public class FirmwareVersionMessageTest extends BaseFirmataTest {
18 |
19 | private final FirmwareVersionMessage expectedMessage = new FirmwareVersionMessage(1, 2, "abc");
20 |
21 | private byte[] getInput() {
22 | final byte[] NAME = expectedMessage.getName().getBytes();
23 |
24 | // prepare input
25 | byte[] input = new byte[5 + NAME.length * 2];
26 | // 5: start byte + sysex command byte + major byte + minor byte + end byte
27 | // 2: each name byte is encoded into 2 bytes
28 |
29 | int offset = 0;
30 | input[offset++] = (byte) SysexMessageWriter.COMMAND_START;
31 | input[offset++] = (byte)ReportFirmwareVersionMessage.COMMAND;
32 | input[offset++] = (byte)expectedMessage.getMajor();
33 | input[offset++] = (byte)expectedMessage.getMinor();
34 | ENCODE_STRING(NAME, ByteBuffer.wrap(input), offset);
35 | offset += 2 * NAME.length;
36 | input[offset] = (byte) SysexMessageWriter.COMMAND_END;
37 |
38 | return input;
39 | }
40 |
41 | @Test
42 | public void testDeserialize() {
43 | byte[] input = getInput();
44 |
45 | // feed input
46 | FirmwareVersionMessageReader reader = new FirmwareVersionMessageReader();
47 | reader.startReading();
48 | // from 2 (not 0), because COMMAND_START and sysex command bytes were walked during canRead()
49 | for (int i=2; i receivedMessages = historyFirmataWrapper.getReceivedMessages();
123 | assertTrue(receivedMessages.size() > 0);
124 |
125 | for (int i=0; i
2 |
5 | 4.0.0
6 |
7 |
8 | name.antonsmirnov.firmata
9 | parent
10 | 1.0
11 |
12 |
13 | name.antonsmirnov.firmata.serial
14 | IndepProcessingSerial
15 | 1.2
16 | IndepProcessingSerial
17 |
18 | Processing Serial adapter as Serial API impl (with no processing.* dependencies)
19 |
20 |
21 |
22 | name.antonsmirnov.firmata.serial
23 | Serial
24 | 1.1
25 |
26 |
27 |
28 | com.neuronrobotics
29 | nrjavaserial
30 | 3.7.5.1
31 |
32 |
33 |
34 | junit
35 | junit
36 | 4.8.1
37 | test
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/IndepProcessingSerial/src/main/java/name/antonsmirnov/firmata/serial/IndepProcessingSerialAdapter.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.serial;
2 |
3 | import processing.serial.IndepProcessingSerial;
4 |
5 | import java.util.ArrayList;
6 | import java.util.List;
7 |
8 | /**
9 | * "ISerial" adapter for RXTX "Serial" class
10 | */
11 | public class IndepProcessingSerialAdapter implements ISerial, IndepProcessingSerial.Listener {
12 |
13 | private IndepProcessingSerial indepProcessingSerial;
14 |
15 | public IndepProcessingSerial getIndepProcessingSerial() {
16 | return indepProcessingSerial;
17 | }
18 |
19 | public void onDataReceived() {
20 | for (ISerialListener eachListener : listeners)
21 | eachListener.onDataReceived(this);
22 | }
23 |
24 | public IndepProcessingSerialAdapter(IndepProcessingSerial indepProcessingSerial) {
25 | this.indepProcessingSerial = indepProcessingSerial;
26 | indepProcessingSerial.setListener(this);
27 | }
28 |
29 | private List listeners = new ArrayList();
30 |
31 | public void addListener(ISerialListener listener) {
32 | listeners.add(listener);
33 | }
34 |
35 | public void removeListener(ISerialListener listener) {
36 | listeners.remove(listener);
37 | }
38 |
39 | private boolean isStopping;
40 |
41 | public void start() {
42 | isStopping = false;
43 | indepProcessingSerial.start();
44 | }
45 |
46 | public void stop() {
47 | isStopping = true;
48 | indepProcessingSerial.stop();
49 | }
50 |
51 | public boolean isStopping() {
52 | return isStopping;
53 | }
54 |
55 | public int available() {
56 | return indepProcessingSerial.available();
57 | }
58 |
59 | public void clear() {
60 | indepProcessingSerial.clear();
61 | }
62 |
63 | public int read() {
64 | return indepProcessingSerial.read();
65 | }
66 |
67 | public void write(int outcomingByte) {
68 | indepProcessingSerial.write((byte)outcomingByte);
69 | }
70 |
71 | public void write(byte[] outcomingBytes) {
72 | indepProcessingSerial.write(outcomingBytes);
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/ProcessingSerial/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 |
8 | name.antonsmirnov.firmata
9 | parent
10 | 1.0
11 |
12 |
13 | name.antonsmirnov.firmata.serial
14 | ProcessingSerial
15 | 1.1
16 | ProcessingSerial
17 |
18 | Processing Serial adapter as Serial API impl
19 |
20 |
25 |
26 |
27 |
28 | name.antonsmirnov.firmata.serial
29 | Serial
30 | 1.1
31 |
32 |
33 |
34 | org.processing
35 | serial
36 | 1.5.1
37 |
38 |
39 |
--------------------------------------------------------------------------------
/ProcessingSerial/res/install_processing_core.bat:
--------------------------------------------------------------------------------
1 | mvn install:install-file -Dfile=./lib/core.jar -DgroupId=org.processing -DartifactId=core -Dversion=1.5.1 -Dpackaging=jar -DgeneratePom=true
--------------------------------------------------------------------------------
/ProcessingSerial/res/install_processing_serial.bat:
--------------------------------------------------------------------------------
1 | mvn install:install-file -Dfile=./modes/java/libraries/serial/library/serial.jar -DgroupId=org.processing -DartifactId=serial -Dversion=1.5.1 -Dpackaging=jar -DgeneratePom=true
--------------------------------------------------------------------------------
/ProcessingSerial/src/main/java/name/antonsmirnov/firmata/serial/ProcessingSerialAdapter.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.serial;
2 |
3 | import processing.serial.Serial;
4 |
5 | /**
6 | * "ISerial" adapter for Processing "Serial" class
7 | */
8 | public class ProcessingSerialAdapter implements ISerial {
9 |
10 | private Serial processingSerial;
11 |
12 | public Serial getProcessingSerial() {
13 | return processingSerial;
14 | }
15 |
16 | public void addListener(ISerialListener listener) {
17 | throw new RuntimeException("ProcessingSerial does not have listener property. Instead it invokes parent.serialEvent(Serial) directly;");
18 | }
19 |
20 | public void removeListener(ISerialListener listener) {
21 | throw new RuntimeException("ProcessingSerial does not have listener property. Instead it invokes parent.serialEvent(Serial) directly;");
22 | }
23 |
24 | public ProcessingSerialAdapter(Serial processingSerial) {
25 | this.processingSerial = processingSerial;
26 | }
27 |
28 | public void start() {
29 | // nothing (ProcessingSerial is opened in constructor)
30 | isStopping = false;
31 | }
32 |
33 | private boolean isStopping;
34 |
35 | public void stop() {
36 | isStopping = true;
37 | processingSerial.stop();
38 | }
39 |
40 | public boolean isStopping() {
41 | return isStopping;
42 | }
43 |
44 | public int available() {
45 | return processingSerial.available();
46 | }
47 |
48 | public void clear() {
49 | processingSerial.clear();
50 | }
51 |
52 | public int read() {
53 | return processingSerial.read();
54 | }
55 |
56 | public void write(int outcomingByte) {
57 | processingSerial.write(outcomingByte);
58 | }
59 |
60 | public void write(byte[] outcomingBytes) {
61 | processingSerial.write(outcomingBytes);
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/README:
--------------------------------------------------------------------------------
1 | 4ntoine/Firmata
2 | https://github.com/4ntoine/Firmata
3 |
4 | Firmata 2.2 pure Java implementation
5 |
6 | Licensed under Apache License 2.0
7 |
--------------------------------------------------------------------------------
/Serial/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 |
8 | name.antonsmirnov.firmata
9 | parent
10 | 1.0
11 |
12 |
13 | name.antonsmirnov.firmata.serial
14 | Serial
15 | 1.1
16 | Serial API
17 |
18 | Serial API
19 |
20 |
21 |
22 |
23 | org.slf4j
24 | slf4j-api
25 | 1.6.4
26 |
27 |
28 |
29 |
30 | org.slf4j
31 | slf4j-simple
32 | 1.6.4
33 | test
34 |
35 |
36 |
37 | junit
38 | junit
39 | 4.8.1
40 | test
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 | org.apache.maven.plugins
49 | maven-surefire-plugin
50 | 2.10
51 |
52 |
53 |
54 | **/SocketSerialAdapterTest.java
55 |
56 |
57 |
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/Serial/src/main/java/name/antonsmirnov/firmata/serial/BufferingSerialWrapper.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.serial;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 | import java.util.concurrent.atomic.AtomicBoolean;
6 |
7 | /**
8 | * Perform buffered reading from the port
9 | * (thread-safe, not bounded)
10 | */
11 | public class BufferingSerialWrapper implements ISerial, ISerialListener {
12 |
13 | private IByteBuffer buffer;
14 |
15 | private int threadPriority = Thread.NORM_PRIORITY;
16 |
17 | public int getThreadPriority() {
18 | return threadPriority;
19 | }
20 |
21 | /**
22 | * Buffer reading thread priority
23 | *
24 | * @param threadPriority buffer reading thread priority
25 | */
26 | public void setThreadPriority(int threadPriority) {
27 | this.threadPriority = threadPriority;
28 | }
29 |
30 | private ISerial serial;
31 |
32 | public BufferingSerialWrapper(ISerial serial, IByteBuffer buffer) {
33 | this.serial = serial;
34 | this.serial.addListener(this);
35 |
36 | this.buffer = buffer;
37 | }
38 |
39 | public int available() {
40 | return buffer.size();
41 | }
42 |
43 | private List listeners = new ArrayList();
44 |
45 | public void addListener(ISerialListener listener) {
46 | listeners.add(listener);
47 | }
48 |
49 | public void removeListener(ISerialListener listener) {
50 | listeners.remove(listener);
51 | }
52 |
53 | public void start() throws SerialException {
54 | startReadingThread();
55 | serial.start();
56 | }
57 |
58 | // flag for the thread to exit
59 | private AtomicBoolean shouldStop = new AtomicBoolean();
60 |
61 | public AtomicBoolean getShouldStop() {
62 | return shouldStop;
63 | }
64 |
65 | /**
66 | * Buffer reading thread
67 | */
68 | private class BufferReadingThread extends Thread {
69 |
70 | public void run() {
71 | while (!shouldStop.get()) {
72 | if (available() > 0) {
73 | for (ISerialListener eachListener : listeners)
74 | eachListener.onDataReceived(this);
75 | }
76 | }
77 | }
78 | }
79 |
80 | private BufferReadingThread readingThread;
81 |
82 | private void startReadingThread() {
83 | readingThread = new BufferReadingThread();
84 | shouldStop.set(false);
85 | readingThread.start();
86 | }
87 |
88 | public void stop() throws SerialException {
89 | stopReadingThread();
90 | serial.stop();
91 |
92 | clear();
93 | }
94 |
95 | public boolean isStopping() {
96 | return shouldStop.get();
97 | }
98 |
99 | private void stopReadingThread() {
100 | if (readingThread == null)
101 | return;
102 |
103 | // set exit flag
104 | shouldStop.set(true);
105 | readingThread = null;
106 | }
107 |
108 | public void clear() {
109 | buffer.clear();
110 | }
111 |
112 | public int read() {
113 | return buffer.get();
114 | }
115 |
116 | public void write(int outcomingByte) throws SerialException {
117 | serial.write(outcomingByte);
118 | }
119 |
120 | public void write(byte[] outcomingBytes) throws SerialException {
121 | serial.write(outcomingBytes);
122 | }
123 |
124 | public void onDataReceived(ConcreteSerialImpl serialImpl) {
125 | // add incoming byte into buffer
126 | try {
127 | buffer.add((byte)serial.read());
128 | } catch (SerialException e) {
129 | onException(e);
130 | }
131 | }
132 |
133 | public void onException(Throwable e) {
134 | for (ISerialListener eachListener : listeners)
135 | eachListener.onException(e);
136 | }
137 | }
138 |
--------------------------------------------------------------------------------
/Serial/src/main/java/name/antonsmirnov/firmata/serial/ByteArrayByteBufferAdapter.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.serial;
2 |
3 | import java.util.concurrent.atomic.AtomicInteger;
4 |
5 | /**
6 | * Adapts byte[] to be used as IByteBuffer
7 | */
8 | public class ByteArrayByteBufferAdapter implements IByteBuffer {
9 |
10 | private byte[] array;
11 |
12 | public ByteArrayByteBufferAdapter(byte[] array) {
13 | this.array = array;
14 | reset();
15 | }
16 |
17 | private void reset() {
18 | readIndex.set(0);
19 | writeIndex.set(0);
20 | }
21 |
22 | private AtomicInteger readIndex = new AtomicInteger();
23 | private AtomicInteger writeIndex = new AtomicInteger();
24 |
25 | public void add(byte value) {
26 | array[writeIndex.getAndIncrement()] = value;
27 | }
28 |
29 | public byte get() {
30 | if (size() <= 0)
31 | return -1;
32 |
33 | byte outcomingByte = array[readIndex.getAndIncrement()];
34 |
35 | // if reached written count
36 | if (readIndex == writeIndex) {
37 | reset();
38 | }
39 |
40 | return outcomingByte;
41 | }
42 |
43 | public void clear() {
44 | reset();
45 | }
46 |
47 | public int size() {
48 | return writeIndex.get() - readIndex.get();
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/Serial/src/main/java/name/antonsmirnov/firmata/serial/IByteBuffer.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.serial;
2 |
3 | /**
4 | * Byte buffer interface
5 | * (can not use java.util.Queue interface because it works with Objects but not with Primitives)
6 | */
7 | public interface IByteBuffer {
8 |
9 | /**
10 | * Add data
11 | * @param value byte data
12 | */
13 | void add(byte value);
14 |
15 | /**
16 | * Get data
17 | * @return byte data
18 | */
19 | byte get();
20 |
21 | /**
22 | * Clear data
23 | */
24 | void clear();
25 |
26 | /**
27 | * Buffered data size
28 | * (not buffer size)
29 | * @return buffered data size
30 | */
31 | int size();
32 | }
33 |
--------------------------------------------------------------------------------
/Serial/src/main/java/name/antonsmirnov/firmata/serial/ISerial.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.serial;
2 |
3 | /**
4 | * Serial interface
5 | * (methods required for Firmata only)
6 | */
7 | public interface ISerial {
8 |
9 | /**
10 | * Set serial events listener
11 | * @param listener serial events listener
12 | */
13 | void addListener(ISerialListener listener);
14 |
15 | /**
16 | * Remove serial events listener
17 | * @param listener
18 | */
19 | void removeListener(ISerialListener listener);
20 |
21 | /**
22 | * Start talking to serial
23 | */
24 | void start() throws SerialException;
25 |
26 | /**
27 | * Stop talking to serial
28 | */
29 | void stop() throws SerialException;
30 |
31 | /**
32 | * Serial is stopping
33 | * @return
34 | */
35 | boolean isStopping();
36 |
37 | /**
38 | * Returns the number of bytes that have been read from serial
39 | * and are waiting to be dealt with by the user.
40 | */
41 | int available() throws SerialException;
42 |
43 | /**
44 | * Clear buffers
45 | */
46 | void clear() throws SerialException;
47 |
48 | /**
49 | * Read byte from serial
50 | * (check available() before)
51 | */
52 | int read() throws SerialException;
53 |
54 | /**
55 | * Write byte to serial
56 | * @param outcomingByte outcoming byte
57 | */
58 | void write(int outcomingByte) throws SerialException;
59 |
60 | /**
61 | * Write outcoming bytes to serial
62 | * @param outcomingBytes bytes to write
63 | */
64 | void write(byte[] outcomingBytes) throws SerialException;
65 | }
66 |
--------------------------------------------------------------------------------
/Serial/src/main/java/name/antonsmirnov/firmata/serial/ISerialListener.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.serial;
2 |
3 | /**
4 | * Serial events listener
5 | */
6 | public interface ISerialListener {
7 |
8 | /**
9 | * Data received from serial event
10 | *
11 | * @param serialImpl serial implementation (ucan be used to specify serial)
12 | */
13 | void onDataReceived(ConcreteSerialImpl serialImpl);
14 |
15 | /**
16 | * Exception in serial
17 | *
18 | * @param e
19 | */
20 | void onException(Throwable e);
21 | }
22 |
--------------------------------------------------------------------------------
/Serial/src/main/java/name/antonsmirnov/firmata/serial/QueueByteBufferAdapter.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.serial;
2 |
3 | import java.util.Queue;
4 |
5 | /**
6 | * Adapts java.util.Queue to be used as IByteBuffer
7 | */
8 | public class QueueByteBufferAdapter implements IByteBuffer {
9 |
10 | private Queue queue;
11 |
12 | public QueueByteBufferAdapter(Queue queue) {
13 | this.queue = queue;
14 | }
15 |
16 | public void add(byte value) {
17 | queue.add(value);
18 | }
19 |
20 | public byte get() {
21 | return queue.poll();
22 | }
23 |
24 | public void clear() {
25 | queue.clear();
26 | }
27 |
28 | public int size() {
29 | return queue.size();
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Serial/src/main/java/name/antonsmirnov/firmata/serial/SerialException.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.serial;
2 |
3 | /**
4 | * Serial exception
5 | */
6 | public class SerialException extends Exception {
7 |
8 | public SerialException(Exception e) {
9 | super(e);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/Serial/src/main/java/name/antonsmirnov/firmata/serial/SocketSerialAdapter.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.serial;
2 |
3 | import java.io.IOException;
4 | import java.io.Serializable;
5 | import java.net.Socket;
6 |
7 | /**
8 | * Serial adapter for regular TCP socket
9 | */
10 | public class SocketSerialAdapter extends StreamingSerialAdapter implements Serializable {
11 |
12 | private transient Socket socket;
13 |
14 | private String address;
15 | private int port;
16 |
17 | public SocketSerialAdapter(String address, int port) {
18 | this.address = address;
19 | this.port = port;
20 | }
21 |
22 | @Override
23 | public void start() throws SerialException {
24 | try {
25 | socket = new Socket(address, port);
26 | setInStream(socket.getInputStream());
27 | setOutStream(socket.getOutputStream());
28 | } catch (IOException e) {
29 | throw new SerialException(e);
30 | }
31 | super.start();
32 | }
33 |
34 | @Override
35 | public void stop() throws SerialException {
36 | setStopReading();
37 |
38 | try {
39 | if (socket != null)
40 | socket.close();
41 | } catch (IOException e) {
42 | throw new SerialException(e);
43 | }
44 | super.stop();
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/Serial/src/main/java/name/antonsmirnov/firmata/serial/StreamingSerialAdapter.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.serial;
2 |
3 | import java.io.IOException;
4 | import java.io.InputStream;
5 | import java.io.OutputStream;
6 | import java.util.ArrayList;
7 | import java.util.List;
8 | import java.util.concurrent.atomic.AtomicBoolean;
9 |
10 | /**
11 | * Adapts InputStream and OutputStream to be used as ISerial
12 | */
13 | public class StreamingSerialAdapter implements ISerial {
14 |
15 | private transient InputStream inStream;
16 | private transient OutputStream outStream;
17 |
18 | public InputStream getInStream() {
19 | return inStream;
20 | }
21 |
22 | public void setInStream(InputStream inStream) {
23 | this.inStream = inStream;
24 | }
25 |
26 | public OutputStream getOutStream() {
27 | return outStream;
28 | }
29 |
30 | public void setOutStream(OutputStream outStream) {
31 | this.outStream = outStream;
32 | }
33 |
34 | public StreamingSerialAdapter() {
35 | // InputStream and OutputStream should be set before start()
36 | }
37 |
38 | public StreamingSerialAdapter(InputStream inStream, OutputStream outStream) {
39 | this();
40 | setInStream(inStream);
41 | setOutStream(outStream);
42 | }
43 |
44 | private List listeners = new ArrayList();
45 |
46 | public void addListener(ISerialListener listener) {
47 | listeners.add(listener);
48 | }
49 |
50 | public void removeListener(ISerialListener listener) {
51 | listeners.remove(listener);
52 | }
53 |
54 | private ReadingThread thread;
55 |
56 | private AtomicBoolean shouldStop = new AtomicBoolean();
57 |
58 | /**
59 | * Threads, that reads InputStream
60 | */
61 | private class ReadingThread extends Thread implements Thread.UncaughtExceptionHandler{
62 |
63 | public ReadingThread() {
64 | setUncaughtExceptionHandler(this);
65 | }
66 |
67 | public void uncaughtException(Thread t, Throwable e) {
68 | handleException(e);
69 | }
70 |
71 | private void handleException(Throwable e) {
72 | if (!shouldStop.get())
73 | for (ISerialListener eachListener : listeners)
74 | eachListener.onException(e);
75 | }
76 |
77 | @Override
78 | public void run() {
79 | while (!shouldStop.get()) {
80 | try {
81 | if (inStream.available() > 0)
82 | for (ISerialListener eachListener : listeners)
83 | eachListener.onDataReceived(StreamingSerialAdapter.this);
84 | } catch (IOException e) {
85 | handleException(e);
86 | break;
87 | }
88 | }
89 |
90 | try {
91 | inStream.close();
92 | } catch (IOException e) {}
93 | }
94 | }
95 |
96 | public void start() throws SerialException {
97 | if (thread != null)
98 | return;
99 |
100 | thread = new ReadingThread();
101 | shouldStop.set(false);
102 | thread.start();
103 | }
104 |
105 | public void stop() throws SerialException {
106 | if (thread == null)
107 | return;
108 |
109 | setStopReading();
110 | thread = null;
111 | try {
112 | outStream.close();
113 | } catch (IOException e) {}
114 | }
115 |
116 | protected void setStopReading() {
117 | shouldStop.set(true);
118 | }
119 |
120 | public boolean isStopping() {
121 | return shouldStop.get();
122 | }
123 |
124 | public int available() throws SerialException {
125 | try {
126 | return inStream.available();
127 | } catch (IOException e) {
128 | return checkIsStoppingOrThrow(e, 0);
129 | }
130 | }
131 |
132 | public void clear() throws SerialException {
133 | try {
134 | inStream.reset();
135 | } catch (IOException e) {
136 | checkIsStoppingOrThrow(e);
137 | }
138 | }
139 |
140 | private void checkIsStoppingOrThrow(IOException e) throws SerialException {
141 | checkIsStoppingOrThrow(e, 0);
142 | }
143 |
144 | private int checkIsStoppingOrThrow(IOException e, int value) throws SerialException {
145 | if (shouldStop.get()) {
146 | return value;
147 | } else {
148 | throw new SerialException(e);
149 | }
150 | }
151 |
152 | public int read() throws SerialException {
153 | try {
154 | return inStream.read();
155 | } catch (IOException e) {
156 | return checkIsStoppingOrThrow(e, -1);
157 | }
158 | }
159 |
160 | public void write(int outcomingByte) throws SerialException {
161 | try {
162 | outStream.write(outcomingByte);
163 | } catch (IOException e) {
164 | checkIsStoppingOrThrow(e);
165 | }
166 | }
167 |
168 | public void write(byte[] outcomingBytes) throws SerialException {
169 | try {
170 | outStream.write(outcomingBytes);
171 | } catch (IOException e) {
172 | checkIsStoppingOrThrow(e);
173 | }
174 | }
175 | }
176 |
--------------------------------------------------------------------------------
/Serial/src/test/java/name/antonsmirnov/firmata/serial/WritebackSerial.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.serial;
2 |
3 | import java.io.IOException;
4 | import java.io.PipedInputStream;
5 | import java.io.PipedOutputStream;
6 |
7 | /**
8 | * WriteBack Serial
9 | * (written bytes are returned back as input bytes)
10 | */
11 | public class WritebackSerial extends StreamingSerialAdapter {
12 |
13 | private PipedInputStream pipedInStream;
14 | private PipedOutputStream pipedOutStream;
15 |
16 | public WritebackSerial() {
17 | super();
18 |
19 | pipedOutStream = new PipedOutputStream();
20 | try {
21 | pipedInStream = new PipedInputStream(pipedOutStream);
22 | } catch (IOException e) {
23 | throw new RuntimeException(e);
24 | }
25 |
26 | setInStream(pipedInStream);
27 | setOutStream(pipedOutStream);
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/Serial/src/test/java/name/antonsmirnov/firmata/serial/tests/BufferingSerialWrapperTest.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.serial.tests;
2 |
3 | import junit.framework.TestCase;
4 | import name.antonsmirnov.firmata.serial.*;
5 | import org.junit.Test;
6 | import org.slf4j.Logger;
7 | import org.slf4j.LoggerFactory;
8 |
9 | import java.util.concurrent.ConcurrentLinkedQueue;
10 | import java.util.concurrent.atomic.AtomicInteger;
11 |
12 | /**
13 | * Test for BufferingSerialWrapper
14 | */
15 | public class BufferingSerialWrapperTest extends TestCase {
16 |
17 | private final Logger log = LoggerFactory.getLogger(getClass());
18 |
19 | private static final byte MIN_VALUE = Byte.MIN_VALUE;
20 | private static final byte MAX_VALUE = Byte.MAX_VALUE;
21 |
22 | private static final int SLEEP_DELAY = 100;
23 | private static final int SLEEP_MAX = 20 * 1000; // 20 sec
24 |
25 | /**
26 | * Thread that simulates incoming bytes in TestSerial
27 | */
28 | public class WriterThread extends Thread {
29 |
30 | private ISerial serial;
31 | private byte minValue;
32 | private byte maxValue;
33 |
34 | public WriterThread(ISerial serial, byte minValue, byte maxValue) {
35 | super();
36 | setPriority(Thread.MAX_PRIORITY);
37 |
38 | this.serial = serial;
39 | this.minValue = minValue;
40 | this.maxValue = maxValue;
41 | }
42 |
43 | @Override
44 | public void run() {
45 | super.run();
46 |
47 | for (int i=minValue; i<=maxValue; i++) {
48 | byte outcomingByte = (byte)i;
49 | log.info("Put '{}' to buffer", outcomingByte);
50 | try {
51 | serial.write(outcomingByte);
52 | } catch (SerialException e) {
53 | log.error("serial exception", e);
54 | }
55 | }
56 | }
57 | }
58 |
59 | private WriterThread writingThread;
60 |
61 | private AtomicInteger maxRead = new AtomicInteger();
62 | final ISerial serial = new WritebackSerial();
63 |
64 | @Test
65 | // ConcurrentLinkedQueue as buffer
66 | public void testQueue() throws InterruptedException, SerialException {
67 | testWriteRead(new QueueByteBufferAdapter(new ConcurrentLinkedQueue()));
68 | }
69 |
70 | @Test
71 | // byte[] as buffer
72 | public void testByteArray() throws InterruptedException, SerialException {
73 | testWriteRead(new ByteArrayByteBufferAdapter(new byte[256]));
74 | }
75 |
76 | private void testWriteRead(IByteBuffer buffer) throws InterruptedException, SerialException {
77 | final BufferingSerialWrapper bufferingWrapper = new BufferingSerialWrapper(serial, buffer);
78 |
79 | // reading thread is slower than writing to check buffer filling
80 | bufferingWrapper.setThreadPriority(Thread.MIN_PRIORITY);
81 |
82 | bufferingWrapper.start();
83 |
84 | writingThread = new WriterThread(serial, MIN_VALUE, MAX_VALUE);
85 | bufferingWrapper.addListener(new ISerialListener() {
86 | public void onDataReceived(Object serialImpl) {
87 | byte incomingByte = (byte) bufferingWrapper.read();
88 | maxRead.set(incomingByte);
89 | final int available = bufferingWrapper.available();
90 | log.info("Read '{}' from buffer (size={})", maxRead.intValue(), available);
91 | }
92 |
93 | public void onException(Throwable e) {
94 | log.error("serial exception", e);
95 | }
96 | });
97 |
98 | // start simulating incoming bytes
99 | writingThread.start();
100 |
101 | int slept = 0;
102 | while (maxRead.get() < (MAX_VALUE-1)) {
103 | Thread.sleep(SLEEP_DELAY);
104 | slept += SLEEP_DELAY;
105 | if (slept > SLEEP_MAX)
106 | throw new RuntimeException("did not receive the last value");
107 | }
108 |
109 | bufferingWrapper.stop();
110 |
111 | assertEquals(0, buffer.size());
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/Serial/src/test/java/name/antonsmirnov/firmata/serial/tests/SocketSerialAdapterTest.java:
--------------------------------------------------------------------------------
1 | package name.antonsmirnov.firmata.serial.tests;
2 |
3 | import junit.framework.TestCase;
4 | import name.antonsmirnov.firmata.serial.ISerial;
5 | import name.antonsmirnov.firmata.serial.ISerialListener;
6 | import name.antonsmirnov.firmata.serial.SerialException;
7 | import name.antonsmirnov.firmata.serial.SocketSerialAdapter;
8 | import org.junit.Test;
9 | import org.slf4j.Logger;
10 | import org.slf4j.LoggerFactory;
11 |
12 | import java.util.ArrayList;
13 | import java.util.List;
14 |
15 | /**
16 | * Test for SocketSerialAdapter
17 | */
18 | public class SocketSerialAdapterTest extends TestCase implements ISerialListener {
19 |
20 | private final Logger log = LoggerFactory.getLogger(getClass());
21 |
22 | private ISerial serial;
23 |
24 | private List readBytes = new ArrayList();
25 |
26 | @Override
27 | protected void setUp() throws Exception {
28 | super.setUp();
29 |
30 | serial = new SocketSerialAdapter(IP, PORT);
31 | serial.addListener(this);
32 |
33 | serial.start();
34 | }
35 |
36 | public void onDataReceived(Object serialImpl) {
37 | try {
38 | byte incomingByte = (byte) serial.read();
39 | readBytes.add(incomingByte);
40 |
41 | log.info("Received byte: " + incomingByte + " " + new Character((char)incomingByte));
42 | } catch (SerialException e) {
43 | onException(e);
44 | }
45 | }
46 |
47 | public void onException(Throwable e) {
48 | log.error("Serial error", e);
49 | }
50 |
51 | private static final String IP = "192.168.168.169";
52 | private static final int PORT = 1000;
53 |
54 | private final byte[] MESSAGE = "ABC1234567890".getBytes();
55 |
56 | @Test
57 | // incoming bytes array should be exactly the same as sent bytes array
58 | public void testEcho() throws SerialException, InterruptedException {
59 | serial.write(MESSAGE);
60 |
61 | Thread.sleep(5 * 1000); // waiting 5 seconds
62 |
63 | assertEquals(MESSAGE.length, readBytes.size());
64 | for (int i=0; i
2 |
5 | 4.0.0
6 |
7 | name.antonsmirnov.firmata
8 | parent
9 | 1.0
10 | pom
11 |
12 | parent
13 |
14 |
15 |
16 | Anton Smirnov
17 | dev@antonsmirnov.name
18 |
19 |
20 |
21 |
22 |
23 |
24 | true
25 | org.apache.maven.plugins
26 | maven-compiler-plugin
27 | 2.3.2
28 |
29 | 1.5
30 | 1.5
31 |
32 |
33 |
34 |
35 |
36 |
37 | ./Serial
38 | ./Firmata
39 | ./FirmataTests
40 | ./ProcessingSerial
41 | ./IndepProcessingSerial
42 |
43 |
44 |
--------------------------------------------------------------------------------