Skip to content

Commit

Permalink
Merge pull request #59 from kurbatov/fix/37-digital-pin-value-message
Browse files Browse the repository at this point in the history
Fix/37 digital pin value message
  • Loading branch information
kurbatov committed Feb 3, 2023
2 parents b1683f6 + 44f1ca3 commit d16a63f
Show file tree
Hide file tree
Showing 8 changed files with 244 additions and 116 deletions.
34 changes: 30 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ runs Firmata protocol from your java program.
- Interaction with a board and its pins in object-oriented style
- Communication over serial port, network or custom transport layer
- Abstraction over details of the protocol
- Provides an UI component that visualize the current state of every pin and
allows changing their mode and state
- Allows communicating with I2C devices
- Provides a UI component that visualize the current state of pins and allows
changing their mode and state
- Allows communicating with I2C devices connected to the board

## Installation

Expand All @@ -22,10 +22,36 @@ Add the following dependency to `pom.xml` of your project:
<dependency>
<groupId>com.github.kurbatov</groupId>
<artifactId>firmata4j</artifactId>
<version>2.3.8</version>
<version>2.3.9</version>
</dependency>
```

If you want to connect to the device via serial port (which is the most probable
case), please include one of the following libraries as a dependency into
the `pom.xml`:

```xml
<!-- only one of the following -->
<dependency>
<groupId>com.fazecast</groupId>
<artifactId>jSerialComm</artifactId>
<version>2.6.2</version>
</dependency>
<!-- or -->
<dependency>
<groupId>com.fazecast</groupId>
<artifactId>jssc</artifactId>
<version>2.9.4</version>
</dependency>
```

**jssc** is an older library that worked just fine until recently. Now it reveals
[issues on **GraalVM** and latest updates of **Windows 10**](https://github.com/kurbatov/firmata4j/issues/42).
**firmata4j** was using **jssc** by default in versions prior to **2.3.9**.

**jSerialComm** has proven itself to be working on **GraalVM** and latest
updates of **Windows 10**.

## Usage
General scenario of usage is following:
```java
Expand Down
26 changes: 26 additions & 0 deletions README_ru.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,32 @@ Java.
</dependency>
```

Если вы хотите подключаться к устройству по последовательному порту (что весьма
вероятно), добавьте одну из следующих библиотек в файл `pom.xml`:

```xml
<!-- только одну из библиотек -->
<dependency>
<groupId>com.fazecast</groupId>
<artifactId>jSerialComm</artifactId>
<version>2.6.2</version>
</dependency>
<!-- или -->
<dependency>
<groupId>com.fazecast</groupId>
<artifactId>jssc</artifactId>
<version>2.9.4</version>
</dependency>
```

**jscc** - более старая библиотека, которая работала без нареканий до последнего
времени. Сейчас обнаружились [проблемы в работе на **GraalVM** и с последними
обновлениями **Windows 10**](https://github.com/kurbatov/firmata4j/issues/42).
**firmata4j** использовала **jssc** по-умолчанию во всех версиях до **2.3.9**.

**jSerialComm** показала себя как рабочий вариант на **GraalVM** и с последними
обновлениями **Windows 10**.

## Использование
Основной сценарий использования:
```java
Expand Down
1 change: 1 addition & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
<groupId>io.github.java-native</groupId>
<artifactId>jssc</artifactId>
<version>${jssc.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.fazecast</groupId>
Expand Down
25 changes: 18 additions & 7 deletions src/main/java/org/firmata4j/firmata/FirmataMessageFactory.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2014 Oleg Kurbatov (o.v.kurbatov@gmail.com)
* Copyright (c) 2014-2021 Oleg Kurbatov (o.v.kurbatov@gmail.com)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Expand Down Expand Up @@ -212,22 +212,33 @@ public static byte[] setMode(byte pinId, Pin.Mode mode) {
}

/**
* Creates Firmata message to set digital values of port's pins.<br/>
* Creates Firmata message to set digital values of port's pins.<br>
* Digital value should be assigned to a set of pins at once. A set of pins
* is called port.<br/>
* is called port.<br>
* A port contains 8 pins. Digital value of every pin in a set transfers in
* one byte. Every bit in the byte represents state of pin's output.
*
* @param portId index of a port
* @param value values of port's pins
* @return Firmata message to set digital output
*/
public static byte[] setDigitalPinValue(byte portId, byte value) {
public static byte[] setDigitalPortValue(byte portId, byte value) {
return new byte[]{(byte) (DIGITAL_MESSAGE | (portId & 0x0F)), (byte) (value & 0x7F), (byte) ((value >>> 7) & 0x7F)};
}

/**
* Creates Firmata message to set digital values of a pin.
*
* @param pinId index of a pin
* @param value value of the pin (0 or 1)
* @return Firmata message to set the value of a digital output pin
*/
public static byte[] setDigitalPinValue(byte pinId, byte value) {
return new byte[]{SET_DIGITAL_PIN_VALUE, pinId, value};
}

/**
* Creates Firmata message to set value of an output pin in PWM mode.<br/>
* Creates Firmata message to set value of an output pin in PWM mode.<br>
* If pin id is beyond 15th or value is greater than we can put into
* standard analog message, extended analog message is built.
*
Expand Down Expand Up @@ -255,7 +266,7 @@ public static byte[] setAnalogPinValue(byte pinId, long value) {
}

/**
* Creates a message to set sampling interval.<br/>
* Creates a message to set sampling interval.<br>
* The sampling interval sets how often analog data and i2c data is reported
* to the client. The default value is 19 milliseconds.
*
Expand All @@ -272,7 +283,7 @@ public static byte[] setSamplingInterval(int value) {
}

/**
* Builds servo configuration message.<br/>
* Builds servo configuration message.<br>
* The core idea is to just add a "config" message, then use
* {@link #setMode(byte, org.firmata4j.Pin.Mode)} to attach/detach Servo
* support to a pin. Then the normal {@link #setAnalogPinValue(byte, long)}
Expand Down
25 changes: 4 additions & 21 deletions src/main/java/org/firmata4j/firmata/FirmataPin.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2014 Oleg Kurbatov (o.v.kurbatov@gmail.com)
* Copyright (c) 2014-2021 Oleg Kurbatov (o.v.kurbatov@gmail.com)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Expand Down Expand Up @@ -132,28 +132,11 @@ public synchronized void setValue(long value) throws IOException, IllegalStateEx
byte[] message;
long newValue;
if (currentMode == Mode.OUTPUT) {
//have to calculate the value of whole port (8-pin set) the pin sits in
byte portId = (byte) (pinId / 8);
byte pinInPort = (byte) (pinId % 8);
byte portValue = 0;
for (int i = 0; i < 8; i++) {
Pin p = device.getPin(portId * 8 + i);
if (p.getMode() == Mode.OUTPUT && p.getValue() > 0) {
portValue |= 1 << i;
}
}
byte bitmask = (byte) (1 << pinInPort);
boolean val = value > 0;
if (val) {
portValue |= bitmask;
} else {
portValue &= ((byte) ~bitmask);
}
message = FirmataMessageFactory.setDigitalPinValue(portId, portValue);
newValue = val ? 1 : 0;
newValue = value > 0 ? 1 : 0;
message = FirmataMessageFactory.setDigitalPortValue(pinId, (byte) newValue);
} else if (currentMode == Mode.ANALOG || currentMode == Mode.PWM || currentMode == Mode.SERVO) {
message = FirmataMessageFactory.setAnalogPinValue(pinId, value);
newValue = value;
message = FirmataMessageFactory.setAnalogPinValue(pinId, newValue);
} else {
throw new IllegalStateException(String.format("Port %d is in %s mode and its value cannot be set.", pinId, currentMode));
}
Expand Down
106 changes: 106 additions & 0 deletions src/main/java/org/firmata4j/transport/JSSCTransport.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2014-2021 Oleg Kurbatov (o.v.kurbatov@gmail.com)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.firmata4j.transport;

import java.io.IOException;
import jssc.SerialPort;
import jssc.SerialPortEvent;
import jssc.SerialPortEventListener;
import jssc.SerialPortException;
import org.firmata4j.Parser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Transfers data via serial port using jssc library.
*
* @author Ali Kia
*/
public class JSSCTransport implements TransportInterface, SerialPortEventListener {
private Parser parser;

private final SerialPort port;

private static final Logger LOGGER = LoggerFactory.getLogger(JSSCTransport.class);

public JSSCTransport(String portName) {
this.port = new SerialPort(portName);
}

@Override
public void start() throws IOException {
if (!port.isOpened()) {
try {
port.openPort();
port.setParams(
SerialPort.BAUDRATE_57600,
SerialPort.DATABITS_8,
SerialPort.STOPBITS_1,
SerialPort.PARITY_NONE);
port.setEventsMask(SerialPort.MASK_RXCHAR);
port.addEventListener(this);
} catch (SerialPortException ex) {
throw new IOException("Cannot start firmata device", ex);
}
}
}

@Override
public void stop() throws IOException {
try {
if (port.isOpened()) {
port.purgePort(SerialPort.PURGE_RXCLEAR | SerialPort.PURGE_TXCLEAR);
port.closePort();
}
} catch (SerialPortException ex) {
throw new IOException("Cannot properly stop firmata device", ex);
}
}

@Override
public void write(byte[] bytes) throws IOException {
try {
port.writeBytes(bytes);
} catch (SerialPortException ex) {
throw new IOException("Cannot send message to device", ex);
}
}

@Override
public void setParser(Parser parser) {
this.parser = parser;
}

@Override
public void serialEvent(SerialPortEvent event) {
// queueing data from input buffer to processing by FSM logic
if (event.isRXCHAR() && event.getEventValue() > 0) {
try {
parser.parse(port.readBytes());
} catch (SerialPortException ex) {
LOGGER.error("Cannot read from device", ex);
}
}
}
}
Loading

0 comments on commit d16a63f

Please sign in to comment.