diff --git a/src/main/java/io/mapsmessaging/network/io/impl/lora/device/LoRaDevice.java b/src/main/java/io/mapsmessaging/network/io/impl/lora/device/LoRaDevice.java index 5227b6e28..23ce5cc69 100644 --- a/src/main/java/io/mapsmessaging/network/io/impl/lora/device/LoRaDevice.java +++ b/src/main/java/io/mapsmessaging/network/io/impl/lora/device/LoRaDevice.java @@ -25,11 +25,23 @@ import java.io.IOException; import java.util.LinkedHashMap; import java.util.Map; +import java.util.concurrent.atomic.LongAdder; +import lombok.Getter; public class LoRaDevice { - final Logger logger; + @Getter + private final LongAdder packetsSent = new LongAdder(); + @Getter + private final LongAdder packetsReceived = new LongAdder(); + @Getter + private final LongAdder bytesReceived = new LongAdder(); + @Getter + private final LongAdder bytesSent = new LongAdder(); + @Getter private final LoRaDeviceConfig config; + + final Logger logger; private int radioHandle; private final Map registeredEndPoint; @@ -86,6 +98,7 @@ public void log(String message) { void handleIncomingPacket(LoRaDatagram datagram) { LoRaEndPoint endPoint = registeredEndPoint.get(datagram.getTo()); if (endPoint != null) { + packetsReceived.increment(); endPoint.queue(datagram); } else { logger.log(ServerLogMessages.LORA_DEVICE_NO_REGISTERED_ENDPOINT, datagram.getTo()); @@ -94,6 +107,8 @@ void handleIncomingPacket(LoRaDatagram datagram) { public synchronized boolean write(byte[] buffer, int length, byte from, byte to) { if (radioHandle >= 0) { + bytesSent.add(length); + packetsSent.increment(); return write(radioHandle, buffer, length, from, to); } return false; @@ -101,7 +116,11 @@ public synchronized boolean write(byte[] buffer, int length, byte from, byte to) public synchronized long read(byte[] buffer, int length) { if (radioHandle >= 0) { - return read(radioHandle, buffer, length); + long read = read(radioHandle, buffer, length); + if(read > 0){ + bytesReceived.add(read); + } + return read; } return -1; } diff --git a/src/main/java/io/mapsmessaging/network/io/impl/lora/device/LoRaDeviceManager.java b/src/main/java/io/mapsmessaging/network/io/impl/lora/device/LoRaDeviceManager.java index d2de57a03..2ffecf4a7 100644 --- a/src/main/java/io/mapsmessaging/network/io/impl/lora/device/LoRaDeviceManager.java +++ b/src/main/java/io/mapsmessaging/network/io/impl/lora/device/LoRaDeviceManager.java @@ -47,12 +47,13 @@ public static LoRaDeviceManager getInstance() { // private final List physicalDevices = new ArrayList<>(); private final AtomicBoolean active = new AtomicBoolean(false); + private final LoRaDeviceManagerConfig deviceConfig; private LoRaDeviceManager() { synchronized (physicalDevices) { + deviceConfig = LoRaDeviceManagerConfig.getInstance(); try { System.loadLibrary("LoRaDevice"); - LoRaDeviceManagerConfig deviceConfig = LoRaDeviceManagerConfig.getInstance(); for(LoRaDeviceConfig config:deviceConfig.getDeviceConfigList()){ LoRaDevice device = new LoRaDevice(config); physicalDevices.add(device); @@ -64,6 +65,10 @@ private LoRaDeviceManager() { } } + public List getDevices() { + return new ArrayList<>(physicalDevices); + } + public LoRaDevice getDevice(EndPointURL url) { synchronized (physicalDevices) { for (LoRaDevice device : physicalDevices) { diff --git a/src/main/java/io/mapsmessaging/rest/api/impl/lora/LoRaDeviceApi.java b/src/main/java/io/mapsmessaging/rest/api/impl/lora/LoRaDeviceApi.java new file mode 100644 index 000000000..26a490d16 --- /dev/null +++ b/src/main/java/io/mapsmessaging/rest/api/impl/lora/LoRaDeviceApi.java @@ -0,0 +1,119 @@ +/* + * Copyright [ 2020 - 2024 ] [Matthew Buckton] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.mapsmessaging.rest.api.impl.lora; + +import static io.mapsmessaging.rest.api.Constants.URI_PATH; + +import io.mapsmessaging.config.lora.LoRaDeviceConfig; +import io.mapsmessaging.network.io.impl.lora.device.LoRaDevice; +import io.mapsmessaging.network.io.impl.lora.device.LoRaDeviceManager; +import io.mapsmessaging.rest.api.impl.BaseRestApi; +import io.mapsmessaging.rest.data.lora.LoRaDeviceInfo; +import io.mapsmessaging.rest.data.lora.LoRaListResponse; +import io.mapsmessaging.rest.responses.BaseResponse; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.ws.rs.*; +import jakarta.ws.rs.core.MediaType; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; +import javax.servlet.http.HttpServletResponse; + +@Tag(name = "LoRa Device Management") +@Path(URI_PATH) +public class LoRaDeviceApi extends BaseRestApi { + + @GET + @Path("/device/lora") + @Produces({MediaType.APPLICATION_JSON}) + public LoRaListResponse getAllLoRaDevices() { + checkAuthentication(); + LoRaDeviceManager deviceManager = LoRaDeviceManager.getInstance(); + List deviceInfos = new ArrayList<>(); + for(LoRaDevice device : deviceManager.getDevices()) { + deviceInfos.add(createInfo(device)); + } + return new LoRaListResponse(request, deviceInfos); + } + + @GET + @Path("/device/lora/{deviceName}") + @Produces({MediaType.APPLICATION_JSON}) + public LoRaDeviceInfo getLoRaDevice(@PathParam("deviceName") String deviceName) { + checkAuthentication(); + LoRaDeviceManager deviceManager = LoRaDeviceManager.getInstance(); + LoRaDeviceConfig deviceConfig = null; + LoRaDeviceInfo deviceInfo = new LoRaDeviceInfo(); + if (deviceName != null && !deviceName.isEmpty()) { + List lookup = deviceManager.getDevices().stream() + .filter(device -> deviceName.equals(device.getName())) + .collect(Collectors.toList()); + if(!lookup.isEmpty()) { + deviceInfo = createInfo(lookup.get(0)); + } + } + + if (deviceConfig == null) { + response.setStatus(HttpServletResponse.SC_NOT_FOUND); + } + return deviceInfo; + } + + @POST + @Path("/device/lora") + @Consumes({MediaType.APPLICATION_JSON}) + @Produces({MediaType.APPLICATION_JSON}) + public BaseResponse addLoRaDevice(LoRaDeviceInfo newDevice) { + checkAuthentication(); + LoRaDeviceManager deviceManager = LoRaDeviceManager.getInstance(); + return new BaseResponse(request); +// response.setStatus(500); + // return new BaseResponse(request); + } + + @DELETE + @Path("/device/lora/{deviceId}") + @Produces({MediaType.APPLICATION_JSON}) + public BaseResponse deleteLoRaDevice(@PathParam("deviceId") String deviceId) { + checkAuthentication(); + LoRaDeviceManager deviceManager = LoRaDeviceManager.getInstance(); +// if (deviceManager.deleteDevice(UUID.fromString(deviceId))) + return new BaseResponse(request); +// } +// response.setStatus(500); +// return new BaseResponse(request); + } + + private LoRaDeviceInfo createInfo(LoRaDevice device) { + LoRaDeviceInfo deviceInfo = new LoRaDeviceInfo(); + LoRaDeviceConfig loRaDeviceConfig = device.getConfig(); + deviceInfo.setName(device.getName()); + deviceInfo.setCs(loRaDeviceConfig.getCs()); + deviceInfo.setIrq(loRaDeviceConfig.getIrq()); + deviceInfo.setCadTimeout(loRaDeviceConfig.getCadTimeout()); + deviceInfo.setPower(loRaDeviceConfig.getPower()); + deviceInfo.setFrequency(loRaDeviceConfig.getFrequency()); + deviceInfo.setRst(loRaDeviceConfig.getRst()); + deviceInfo.setRadio(loRaDeviceConfig.getRadio()); + deviceInfo.setBytesReceived(device.getBytesReceived().sum()); + deviceInfo.setBytesSent(device.getBytesSent().sum()); + deviceInfo.setPacketsReceived(device.getPacketsReceived().sum()); + deviceInfo.setPacketsSent(device.getPacketsSent().sum()); + return deviceInfo; + } +} diff --git a/src/main/java/io/mapsmessaging/rest/data/lora/LoRaDeviceInfo.java b/src/main/java/io/mapsmessaging/rest/data/lora/LoRaDeviceInfo.java new file mode 100644 index 000000000..77e701bc8 --- /dev/null +++ b/src/main/java/io/mapsmessaging/rest/data/lora/LoRaDeviceInfo.java @@ -0,0 +1,46 @@ +/* + * Copyright [ 2020 - 2024 ] [Matthew Buckton] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.mapsmessaging.rest.data.lora; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.ToString; + +@Data +@AllArgsConstructor +@ToString +@NoArgsConstructor +public class LoRaDeviceInfo { + + private String name; + private String radio; + + private int cs; + private int irq; + private int rst; + private int power; + private int cadTimeout; + private float frequency; + + private long bytesSent; + private long bytesReceived; + private long packetsSent; + private long packetsReceived; + +} diff --git a/src/main/java/io/mapsmessaging/rest/data/lora/LoRaListResponse.java b/src/main/java/io/mapsmessaging/rest/data/lora/LoRaListResponse.java new file mode 100644 index 000000000..a114a292a --- /dev/null +++ b/src/main/java/io/mapsmessaging/rest/data/lora/LoRaListResponse.java @@ -0,0 +1,35 @@ +/* + * Copyright [ 2020 - 2024 ] [Matthew Buckton] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.mapsmessaging.rest.data.lora; + +import io.mapsmessaging.rest.responses.BaseResponse; +import jakarta.servlet.http.HttpServletRequest; +import java.util.List; +import lombok.Getter; + +public class LoRaListResponse extends BaseResponse { + + @Getter + private final List data; + + + public LoRaListResponse(HttpServletRequest request, List data) { + super(request); + this.data = data; + } +} \ No newline at end of file