Skip to content

Commit a6364cb

Browse files
committed
#454 Add explicit FFM structures, implemented direct and smbus i2c
1 parent 5d5a1ed commit a6364cb

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+1706
-616
lines changed

plugins/pi4j-plugin-ffm/pom.xml

Lines changed: 1 addition & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,8 @@
1515
<name>Pi4J :: PLUGIN :: FFM API Providers</name>
1616
<description>Pi4J Library Plugin for FFM API Providers</description>
1717
<packaging>jar</packaging>
18+
1819
<dependencies>
19-
<!-- https://mvnrepository.com/artifact/io.github.digitalsmile.native/annotation -->
20-
<dependency>
21-
<groupId>io.github.digitalsmile.native</groupId>
22-
<artifactId>annotation</artifactId>
23-
<version>1.1.5</version>
24-
<scope>compile</scope>
25-
</dependency>
2620
<dependency>
2721
<groupId>org.slf4j</groupId>
2822
<artifactId>slf4j-api</artifactId>
@@ -53,11 +47,6 @@
5347
<source>24</source>
5448
<target>24</target>
5549
<annotationProcessorPaths>
56-
<annotationProcessorPath>
57-
<groupId>io.github.digitalsmile.native</groupId>
58-
<artifactId>annotation-processor</artifactId>
59-
<version>1.1.5</version>
60-
</annotationProcessorPath>
6150
<annotationProcessorPath>
6251
<groupId>org.openjdk.jmh</groupId>
6352
<artifactId>jmh-generator-annprocess</artifactId>
@@ -69,26 +58,6 @@
6958
</plugins>
7059
</pluginManagement>
7160
<plugins>
72-
<plugin>
73-
<groupId>org.codehaus.mojo</groupId>
74-
<artifactId>properties-maven-plugin</artifactId>
75-
<version>1.2.1</version>
76-
<executions>
77-
<execution>
78-
<goals>
79-
<goal>set-system-properties</goal>
80-
</goals>
81-
<configuration>
82-
<properties>
83-
<property>
84-
<name>linux-headers</name>
85-
<value>6.8.0-52-generic</value>
86-
</property>
87-
</properties>
88-
</configuration>
89-
</execution>
90-
</executions>
91-
</plugin>
9261
<!-- DOWNLOAD RUNTIME DEPENDENCIES -->
9362
<plugin>
9463
<groupId>org.apache.maven.plugins</groupId>

plugins/pi4j-plugin-ffm/src/main/java/com/pi4j/plugin/ffm/FFMPlugin.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import com.pi4j.extension.PluginService;
77
import com.pi4j.plugin.ffm.providers.gpio.DigitalInputFFMProviderImpl;
88
import com.pi4j.plugin.ffm.providers.gpio.DigitalOutputFFMProviderImpl;
9-
import com.pi4j.plugin.ffm.providers.i2c.FFMI2CProviderImpl;
9+
import com.pi4j.plugin.ffm.providers.i2c.I2CFFMProviderImpl;
1010
import com.pi4j.plugin.ffm.providers.pwm.FFMPwmProviderImpl;
1111
import com.pi4j.plugin.ffm.providers.spi.FFMSpiProviderImpl;
1212
import com.pi4j.provider.Provider;
@@ -21,7 +21,7 @@ public void initialize(PluginService service) {
2121
this.providers = new Provider[]{
2222
new DigitalInputFFMProviderImpl(),
2323
new DigitalOutputFFMProviderImpl(),
24-
new FFMI2CProviderImpl(),
24+
new I2CFFMProviderImpl(),
2525
new FFMSpiProviderImpl(),
2626
new FFMPwmProviderImpl()
2727
};
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package com.pi4j.plugin.ffm.common;
2+
3+
import java.lang.foreign.MemoryLayout;
4+
import java.lang.foreign.MemorySegment;
5+
import java.lang.invoke.MethodHandle;
6+
7+
public interface Pi4JLayout {
8+
9+
/**
10+
* Method-helper for calling handle with specified {@link MemorySegment} to access the data behind it.
11+
*
12+
* @param handle valid method handle
13+
* @param buffer memory buffer, containing data
14+
* @return new memory segment with data to be accessed
15+
* @throws Throwable if any exception occurs during invokeExact call
16+
*/
17+
default MemorySegment invokeExact(MethodHandle handle, MemorySegment buffer) throws Throwable {
18+
return (MemorySegment) handle.invokeExact(buffer, 0L);
19+
}
20+
21+
/**
22+
* Gets the {@link MemoryLayout} of the structure.
23+
*
24+
* @return memory layout of the structure
25+
*/
26+
MemoryLayout getMemoryLayout();
27+
28+
/**
29+
* Converts {@link MemorySegment} buffer to a class / object structure.
30+
*
31+
* @param buffer memory segment to convert from
32+
* @param <T> type of converted class / object structure
33+
* @return new class / object structure from a given buffer
34+
* @throws Throwable unchecked exception
35+
*/
36+
<T extends Pi4JLayout> T from(MemorySegment buffer) throws Throwable;
37+
38+
/**
39+
* Converts a class / object structure into a {@link MemorySegment} buffer.
40+
*
41+
* @param buffer buffer to be filled with class / object structure
42+
* @throws Throwable unchecked exception
43+
*/
44+
void to(MemorySegment buffer) throws Throwable;
45+
46+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package com.pi4j.plugin.ffm.common;
2+
3+
import java.lang.foreign.*;
4+
import java.lang.invoke.MethodHandle;
5+
import java.lang.invoke.VarHandle;
6+
import java.util.Arrays;
7+
8+
public class Pi4JNative implements SegmentAllocator {
9+
protected static final Arena ARENA = Arena.ofConfined();
10+
protected static final SymbolLookup LIBC_LIB = Linker.nativeLinker().defaultLookup();
11+
12+
// Captured state for errno
13+
private static final StructLayout CAPTURED_STATE_LAYOUT = Linker.Option.captureStateLayout();
14+
// Errno var handle
15+
private static final VarHandle ERRNO_HANDLE = CAPTURED_STATE_LAYOUT.varHandle(
16+
MemoryLayout.PathElement.groupElement("errno"));
17+
18+
private static final AddressLayout POINTER = ValueLayout.ADDRESS.withTargetLayout(
19+
MemoryLayout.sequenceLayout(1024, ValueLayout.JAVA_BYTE));
20+
// Strerror method handle
21+
private static final MethodHandle STR_ERROR = Linker.nativeLinker().downcallHandle(
22+
Linker.nativeLinker().defaultLookup().find("strerror").orElseThrow(),
23+
FunctionDescriptor.of(POINTER, ValueLayout.JAVA_INT));
24+
25+
26+
/**
27+
* Process the error and raise exception method.
28+
*
29+
* @param callResult result of the call
30+
* @param capturedState state of errno
31+
* @param method string representation of called method
32+
* @param args arguments called to function
33+
*/
34+
public static void processError(int callResult, MemorySegment capturedState, String method, Object... args) {
35+
if (callResult < 0) {
36+
try {
37+
int errno = (int) ERRNO_HANDLE.get(capturedState, 0L);
38+
var errnoStr = (MemorySegment) STR_ERROR.invokeExact(errno);
39+
throw new RuntimeException("Error during call to method " + method + " with data '" + Arrays.toString(args) + "': " +
40+
errnoStr.getString(0) + " (" + errno + ")");
41+
} catch (Throwable e) {
42+
throw new RuntimeException(e.getMessage(), e);
43+
}
44+
}
45+
}
46+
47+
@Override
48+
public MemorySegment allocate(long byteSize, long byteAlignment) {
49+
return ARENA.allocate(byteSize, byteAlignment);
50+
}
51+
52+
public MemorySegment allocateCapturedState() {
53+
return allocate(CAPTURED_STATE_LAYOUT);
54+
}
55+
56+
public void close() {
57+
ARENA.close();
58+
}
59+
60+
}

plugins/pi4j-plugin-ffm/src/main/java/com/pi4j/plugin/ffm/common/file/FileDescriptor.java

Lines changed: 0 additions & 20 deletions
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
1-
package com.pi4j.plugin.ffm2.file;
1+
package com.pi4j.plugin.ffm.common.file;
22

3-
import io.github.digitalsmile.annotation.function.NativeCall;
4-
import io.github.digitalsmile.annotation.types.interfaces.NativeMemoryContext;
3+
import com.pi4j.plugin.ffm.common.Pi4JNative;
54

6-
import java.lang.foreign.*;
5+
import java.lang.foreign.FunctionDescriptor;
6+
import java.lang.foreign.Linker;
7+
import java.lang.foreign.ValueLayout;
78
import java.lang.invoke.MethodHandle;
89

9-
class FileDescriptorContext implements NativeMemoryContext {
10-
private static final Arena ARENA = Arena.ofAuto();
11-
12-
private static final SymbolLookup LIBC_LIB = Linker.nativeLinker().defaultLookup();
10+
class FileDescriptorContext extends Pi4JNative {
1311

1412
static final MethodHandle OPEN64 = Linker.nativeLinker().downcallHandle(
1513
LIBC_LIB.find("open64").orElseThrow(),
@@ -29,26 +27,4 @@ class FileDescriptorContext implements NativeMemoryContext {
2927
LIBC_LIB.find("write").orElseThrow(),
3028
FunctionDescriptor.of(ValueLayout.JAVA_INT, ValueLayout.JAVA_INT, ValueLayout.ADDRESS),
3129
Linker.Option.captureCallState("errno"));
32-
33-
@Override
34-
public MemorySegment allocate(long byteSize, long byteAlignment) {
35-
return ARENA.allocate(byteSize, byteAlignment);
36-
}
37-
38-
@Override
39-
public void checkIsCreatedByArena(MemorySegment segment) {
40-
if ((!ARENA.scope().equals(segment.scope()) || !NativeCall.createdInContext(segment.scope())) && !Arena.global().scope().equals(segment.scope())) {
41-
throw new IllegalArgumentException("The scope of the MemorySegment arena is not the same as the scope of the arena");
42-
}
43-
}
44-
45-
@Override
46-
public Arena getArena() {
47-
return ARENA;
48-
}
49-
50-
@Override
51-
public void close() {
52-
ARENA.close();
53-
}
5430
}
Original file line numberDiff line numberDiff line change
@@ -1,63 +1,55 @@
1-
package com.pi4j.plugin.ffm2.file;
2-
3-
import com.pi4j.plugin.ffm.common.file.FileDescriptor;
4-
import io.github.digitalsmile.annotation.NativeMemoryException;
5-
import io.github.digitalsmile.annotation.function.NativeCall;
1+
package com.pi4j.plugin.ffm.common.file;
62

73
import java.lang.foreign.ValueLayout;
84

9-
public class FileDescriptorNative extends NativeCall implements FileDescriptor {
10-
public FileDescriptorNative() {
11-
super(new FileDescriptorContext());
12-
}
5+
import static com.pi4j.plugin.ffm.common.Pi4JNative.processError;
6+
7+
public class FileDescriptorNative {
8+
private final FileDescriptorContext context = new FileDescriptorContext();
139

14-
@Override
15-
public int open(String path, int openFlag) throws NativeMemoryException {
10+
public int open(String path, int openFlag) {
1611
try {
1712
var pathMemorySegment = context.allocateFrom(path);
18-
var capturedState = context.allocate(CAPTURED_STATE_LAYOUT);
13+
var capturedState = context.allocateCapturedState();
1914
var callResult = (int) FileDescriptorContext.OPEN64.invoke(capturedState, pathMemorySegment, openFlag);
2015
processError(callResult, capturedState, "open", pathMemorySegment, openFlag);
2116
return callResult;
2217
} catch (Throwable e) {
23-
throw new NativeMemoryException(e.getMessage(), e);
18+
throw new RuntimeException(e.getMessage(), e);
2419
}
2520
}
2621

27-
@Override
28-
public void close(int fd) throws NativeMemoryException {
22+
public void close(int fd) {
2923
try {
30-
var capturedState = context.allocate(CAPTURED_STATE_LAYOUT);
24+
var capturedState = context.allocateCapturedState();
3125
var callResult = (int) FileDescriptorContext.CLOSE.invoke(capturedState, fd);
3226
processError(callResult, capturedState, "close", fd);
3327
} catch (Throwable e) {
34-
throw new NativeMemoryException(e.getMessage(), e);
28+
throw new RuntimeException(e.getMessage(), e);
3529
}
3630
}
3731

38-
@Override
39-
public byte[] read(int fd, byte[] buffer, int size) throws NativeMemoryException {
32+
public byte[] read(int fd, byte[] buffer, int size) {
4033
try {
4134
var bufferMemorySegment = context.allocateFrom(ValueLayout.JAVA_BYTE, buffer);
42-
var capturedState = context.allocate(CAPTURED_STATE_LAYOUT);
35+
var capturedState = context.allocateCapturedState();
4336
var callResult = (int) FileDescriptorContext.READ.invoke(capturedState, fd, bufferMemorySegment, size);
4437
processError(callResult, capturedState, "read", fd, bufferMemorySegment, size);
4538
return bufferMemorySegment.toArray(ValueLayout.JAVA_BYTE);
4639
} catch (Throwable e) {
47-
throw new NativeMemoryException(e.getMessage(), e);
40+
throw new RuntimeException(e.getMessage(), e);
4841
}
4942
}
5043

51-
@Override
52-
public int write(int fd, byte[] data) throws NativeMemoryException {
44+
public int write(int fd, byte[] data) {
5345
try {
5446
var dataMemorySegment = context.allocateFrom(ValueLayout.JAVA_BYTE, data);
55-
var capturedState = context.allocate(CAPTURED_STATE_LAYOUT);
47+
var capturedState = context.allocateCapturedState();
5648
var callResult = (int) FileDescriptorContext.WRITE.invoke(capturedState, fd, dataMemorySegment);
5749
processError(callResult, capturedState, "write", fd, dataMemorySegment);
5850
return callResult;
5951
} catch (Throwable e) {
60-
throw new NativeMemoryException(e.getMessage(), e);
52+
throw new RuntimeException(e.getMessage(), e);
6153
}
6254
}
6355
}

plugins/pi4j-plugin-ffm/src/main/java/com/pi4j/plugin/ffm/common/gpio/GPIO.java

Lines changed: 0 additions & 26 deletions
This file was deleted.

plugins/pi4j-plugin-ffm/src/main/java/com/pi4j/plugin/ffm2/gpio/GpioConstants.java renamed to plugins/pi4j-plugin-ffm/src/main/java/com/pi4j/plugin/ffm/common/gpio/GpioConstants.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.pi4j.plugin.ffm2.gpio;
1+
package com.pi4j.plugin.ffm.common.gpio;
22

33
/**
44
* Source: NO_POSITION

0 commit comments

Comments
 (0)