Skip to content

Commit

Permalink
Support Ganglion v3 firmware detection
Browse files Browse the repository at this point in the history
  • Loading branch information
philippitts committed Sep 22, 2023
1 parent b2a8839 commit f444bfe
Show file tree
Hide file tree
Showing 10 changed files with 166 additions and 111 deletions.
Original file line number Diff line number Diff line change
@@ -1,128 +1,128 @@
package openbci_gui_helpers;

import java.io.BufferedReader;
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.Path;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.ArrayList;

import org.apache.commons.lang3.SystemUtils;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.sun.jna.Library;
import com.sun.jna.Native;

public class GUIHelper
{
private interface DllInterface extends Library
{
int scan_for_ganglions (String serial_port, int timeout_sec, byte[] output, int[] output_len);
public class GUIHelper {
public class GanglionDevice {
public int firmware_version;
public String identifier;
public String mac_address;
}

private interface DllNativeInterface extends Library
{
int scan_for_ganglions (int timeout_sec, byte[] output, int[] output_len);
private interface DllInterface extends Library {
int scan_for_ganglions(String serial_port, int timeout_sec, byte[] output, int[] output_len);
}

private interface DllNativeInterface extends Library {
int scan_for_ganglions(int timeout_sec, byte[] output, int[] output_len);
}

private static DllInterface instance;
private static DllNativeInterface instance_native;
private static final String VERSION = "2.0.1";
private static final String VERSION = "3.0.0";

static
{
static {
System.out.println("OpenBCI_GUI_Helpers Version: " + VERSION);

String lib_name = "libGanglionScan.so";
String lib_native_name = "libGanglionNativeScan.so";
if (SystemUtils.IS_OS_WINDOWS)
{
if (SystemUtils.IS_OS_WINDOWS) {
lib_name = "GanglionScan.dll";
lib_native_name = "GanglionNativeScan.dll";

} else if (SystemUtils.IS_OS_MAC)
{
} else if (SystemUtils.IS_OS_MAC) {
lib_name = "libGanglionScan.dylib";
lib_native_name = "libGanglionNativeScan.dylib";
}

// need to extract libraries from jar
String lib_path = unpack_from_jar (lib_name);
String lib_native_path = unpack_from_jar (lib_native_name);
String lib_path = unpack_from_jar(lib_name);
String lib_native_path = unpack_from_jar(lib_native_name);

instance = (DllInterface) Native.load (lib_path, DllInterface.class);
instance_native = (DllNativeInterface) Native.load (lib_native_path, DllNativeInterface.class);
instance = (DllInterface) Native.load(lib_path, DllInterface.class);
instance_native = (DllNativeInterface) Native.load(lib_native_path, DllNativeInterface.class);
}

private static String unpack_from_jar (String lib_name)
{
private static String unpack_from_jar(String lib_name) {
File file = null;
InputStream link = null;
try
{
file = new File (lib_name);
if (file.exists ())
file.delete ();
link = (GUIHelper.class.getResourceAsStream (lib_name));
try {
file = new File(lib_name);
if (file.exists())
file.delete();
link = (GUIHelper.class.getResourceAsStream(lib_name));
if (SystemUtils.IS_OS_MAC) {
String jarPath = GUIHelper.class.getProtectionDomain().getCodeSource().getLocation().getPath();
File jarFile = new File(jarPath);
String libPathString = jarFile.getParentFile().getAbsolutePath() + File.separator + lib_name;
return libPathString;
} else {
Files.copy (link, file.getAbsoluteFile ().toPath ());
Files.copy(link, file.getAbsoluteFile().toPath());
}
return file.getAbsolutePath();
} catch (Exception io)
{
io.printStackTrace ();
} catch (Exception io) {
io.printStackTrace();
System.err.println("native library: " + lib_name + " is not found in jar file");
System.err.println("file absolute to path: " + file.getAbsoluteFile().toPath());
System.err.println("file get absolute path: " + file.getAbsolutePath());
return "";
}
}

public static Map<String, String> scan_for_ganglions (String port_name, int timeout_sec) throws GanglionError
{
public static GanglionDevice[] scan_for_ganglions(String port_name, int timeout_sec) throws GanglionError {
int[] len = new int[1];
byte[] output_json = new byte[10240];
int ec = instance.scan_for_ganglions (port_name, timeout_sec, output_json, len);
if (ec != GanglionExitCodes.STATUS_OK.get_code ())
{
throw new GanglionError ("Error in scan for ganglions", ec);

int ec = instance.scan_for_ganglions(port_name, timeout_sec, output_json, len);
if (ec != GanglionExitCodes.STATUS_OK.get_code()) {
throw new GanglionError("Error in scan for ganglions", ec);
}
String json = new String (output_json, 0, len[0]);
Gson gson = new Gson ();
Type type = new TypeToken<Map<String, String>> ()
{
}.getType ();
Map<String, String> map = gson.fromJson (json, type);
return map;

String json = new String(output_json, 0, len[0]);
Gson gson = new Gson();

GanglionDevice[] devices = gson.fromJson(json, GanglionDevice[].class);

ArrayList<GanglionDevice> uniqueDevices = new ArrayList<GanglionDevice>();
for (GanglionDevice device : devices) {
if (!uniqueDevices.stream().anyMatch(entry -> entry.mac_address.equals(device.mac_address))) {
uniqueDevices.add(device);
}
}

return uniqueDevices.toArray(new GanglionDevice[uniqueDevices.size()]);
}

public static Map<String, String> scan_for_ganglions (int timeout_sec) throws GanglionError
{
public static GanglionDevice[] scan_for_ganglions(int timeout_sec) throws GanglionError {
int[] len = new int[1];
byte[] output_json = new byte[10240];
int ec = instance_native.scan_for_ganglions (timeout_sec, output_json, len);
if (ec != GanglionExitCodes.STATUS_OK.get_code ())
{
throw new GanglionError ("Error in scan for ganglions", ec);

int ec = instance_native.scan_for_ganglions(timeout_sec, output_json, len);
if (ec != GanglionExitCodes.STATUS_OK.get_code()) {
throw new GanglionError("Error in scan for ganglions", ec);
}
String json = new String (output_json, 0, len[0]);
Gson gson = new Gson ();
Type type = new TypeToken<Map<String, String>> ()
{
}.getType ();
Map<String, String> map = gson.fromJson (json, type);
return map;
}

String json = new String(output_json, 0, len[0]);
Gson gson = new Gson();

GanglionDevice[] devices = gson.fromJson(json, GanglionDevice[].class);

ArrayList<GanglionDevice> uniqueDevices = new ArrayList<GanglionDevice>();
for (GanglionDevice device : devices) {
if (!uniqueDevices.stream().anyMatch(entry -> entry.mac_address.equals(device.mac_address))) {
uniqueDevices.add(device);
}
}

return uniqueDevices.toArray(new GanglionDevice[uniqueDevices.size()]);
}
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,16 @@
package openbci_gui_helpers.examples;

import java.util.Map;

import openbci_gui_helpers.GUIHelper;
import openbci_gui_helpers.GanglionError;
import openbci_gui_helpers.GUIHelper.GanglionDevice;

public class TestDiscovery
{
public class TestDiscovery {

public static void main (String[] args) throws GanglionError
{
Map<String, String> map = GUIHelper.scan_for_ganglions (args[0], 3);
for (Map.Entry<String, String> entry : map.entrySet ())
{
System.out.println ("Key = " + entry.getKey () + ", Value = " + entry.getValue ());
public static void main(String[] args) throws GanglionError {
GanglionDevice[] devices = GUIHelper.scan_for_ganglions(args[0], 3);
for (GanglionDevice device : devices) {
System.out.println("Identifier = " + device.identifier + ", Mac Address = " + device.mac_address
+ ", Firmware = " + device.firmware_version);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,17 @@
package openbci_gui_helpers.examples;

import java.util.Map;

import openbci_gui_helpers.GUIHelper;
import openbci_gui_helpers.GUIHelper.GanglionDevice;
import openbci_gui_helpers.GanglionError;

public class TestNativeDiscovery
{
public class TestNativeDiscovery {

public static void main (String[] args) throws GanglionError
{
Map<String, String> map = GUIHelper.scan_for_ganglions (3);
for (Map.Entry<String, String> entry : map.entrySet ())
{
System.out.println ("Key = " + entry.getKey () + ", Value = " + entry.getValue ());
public static void main(String[] args) throws GanglionError {
GanglionDevice[] devices = GUIHelper.scan_for_ganglions(3);
for (GanglionDevice device : devices) {
System.out.println("Identifier = " + device.identifier + ", Mac Address = " + device.mac_address
+ ", Firmware = " + device.firmware_version);
}
System.out.println ("Completed");
System.out.println("Completed");
}
}
2 changes: 2 additions & 0 deletions modules/bglib/build.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ SET(GANGLION_LIB "GanglionScan")

add_library(
${GANGLION_LIB} SHARED
modules/common/src/serialization.cpp
modules/bglib/src/callbacks.cpp
modules/bglib/src/cmd_def.cpp
modules/bglib/src/stubs.cpp
Expand All @@ -13,6 +14,7 @@ target_include_directories(
${GANGLION_LIB} PUBLIC
3rdparty/json
modules/bglib/include
modules/common/include
)

set_property(TARGET ${GANGLION_LIB} PROPERTY POSITION_INDEPENDENT_CODE ON)
Expand Down
16 changes: 13 additions & 3 deletions modules/bglib/src/callbacks.cpp
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
#include <ctype.h>
#include <iomanip>
#include <map>
#include <list>
#include <sstream>
#include <stdlib.h>
#include <string.h>
#include <string>


#include "cmd_def.h"
#include "openbci_gui_helpers.h"
#include "serialization.h"


namespace GanglionDetails
{
extern int exit_code;
extern std::map<std::string, std::string> devices;
extern std::list<GanglionDevice> devices;
}

void ble_evt_gap_scan_response (const struct ble_msg_gap_scan_response_evt_t *msg)
Expand Down Expand Up @@ -57,7 +59,15 @@ void ble_evt_gap_scan_response (const struct ble_msg_gap_scan_response_evt_t *ms
mac_addr << ":";
}
}
GanglionDetails::devices[std::string (name)] = mac_addr.str ();

uint8_t firmware = strstr (name, "anglion 1.3") == NULL ? 2 : 3;

GanglionDevice device;
device.identifier = name;
device.mac_address = mac_addr.str ();
device.firmware_version = firmware;

GanglionDetails::devices.push_back (device);
GanglionDetails::exit_code = (int)GanglionDetails::GanglionScanExitCodes::STATUS_OK;
}
}
Expand Down
9 changes: 4 additions & 5 deletions modules/bglib/src/openbci_gui_helpers.cpp
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
#include <chrono>
#include <ctype.h>
#include <map>
#include <list>
#include <stdlib.h>
#include <string.h>
#include <string>

#include "cmd_def.h"
#include "openbci_gui_helpers.h"
#include "serialization.h"
#include "uart.h"

#ifdef _WIN32
Expand All @@ -15,14 +16,12 @@
#include <unistd.h>
#endif

#include "json.hpp"

using json = nlohmann::json;

namespace GanglionDetails
{
int exit_code = (int)GanglionScanExitCodes::STATUS_OK;
std::map<std::string, std::string> devices;
std::list<GanglionDevice> devices;

void output (uint8 len1, uint8 *data1, uint16 len2, uint8 *data2)
{
Expand Down Expand Up @@ -138,7 +137,7 @@ int scan_for_ganglions (char *serial_port, int timeout_sec, char *output_json, i
json result (GanglionDetails::devices);
std::string s = result.dump ();
strcpy (output_json, s.c_str ());
*output_len = s.length ();
*output_len = (int)s.length ();
}
ble_cmd_gap_end_procedure ();
uart_close ();
Expand Down
16 changes: 16 additions & 0 deletions modules/common/include/serialization.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#pragma once

#include "json.hpp"

#include <cstdint>
#include <string>

typedef struct GanglionDevice
{
std::string identifier;
std::string mac_address;
uint8_t firmware_version;
} GanglionDevice;

void to_json (nlohmann::json &result, const GanglionDevice &device);
void from_json (const nlohmann::json &string, GanglionDevice &device);
14 changes: 14 additions & 0 deletions modules/common/src/serialization.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#include "serialization.h"

void to_json (nlohmann::json &result, const GanglionDevice &device)
{
result = nlohmann::json {{"identifier", device.identifier}, {"mac_address", device.mac_address},
{"firmware_version", std::to_string (device.firmware_version)}};
}

void from_json (const nlohmann::json &string, GanglionDevice &device)
{
string.at ("identifier").get_to (device.identifier);
string.at ("mac_address").get_to (device.mac_address);
string.at ("firmware_version").get_to (device.firmware_version);
}
2 changes: 2 additions & 0 deletions modules/native-ble/build.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ SET(OPENBCI_GANGLION_NATIVE_LIB "GanglionNativeScan")

add_library(
${OPENBCI_GANGLION_NATIVE_LIB} SHARED
modules/common/src/serialization.cpp
modules/native-ble/src/openbci_gui_native_helpers.cpp
)

target_include_directories(
${OPENBCI_GANGLION_NATIVE_LIB} PUBLIC
modules/native-ble/include
modules/common/include
3rdparty/json
3rdparty/SimpleBLE/simpleble/include/simpleble
)
Expand Down
Loading

0 comments on commit f444bfe

Please sign in to comment.