From 4ab7949b8dcc4664222ac2a5392c00d1bcf23da7 Mon Sep 17 00:00:00 2001 From: Aaron Tang Date: Tue, 27 Aug 2019 15:29:46 -0500 Subject: [PATCH] Added v1.6 builds for C#: Updated build script, source files, and built DLLs. --- builds/csharp/UnityRehamove.dll | Bin 12288 -> 20992 bytes builds/csharp/rehamovelib.dll | Bin 31232 -> 49152 bytes src/csharp/RehamoveDevice.cs | 44 +- src/csharp/SWIGTYPE_p_uint16_t.cs | 28 + src/csharp/build.bat | 34 +- src/csharp/rehamove.cs | 272 ++++++++- src/csharp/rehamovelib.c | 930 ++++++++++++++++++++++++------ src/csharp/rehamovelib.cs | 89 ++- src/csharp/rehamovelib.i | 71 ++- src/csharp/rehamovelibPINVOKE.cs | 82 ++- 10 files changed, 1278 insertions(+), 272 deletions(-) create mode 100644 src/csharp/SWIGTYPE_p_uint16_t.cs diff --git a/builds/csharp/UnityRehamove.dll b/builds/csharp/UnityRehamove.dll index fb5b3fdc0480080265a6b1e1ac794dfddc914916..26b351ad31ea72aa9d107e62d984bbdec492f65a 100644 GIT binary patch literal 20992 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 Z2+<$!+9Cg^<+Uw;ye9v@rT;q-_#Xg4i?aX# diff --git a/builds/csharp/rehamovelib.dll b/builds/csharp/rehamovelib.dll index 53edec59666036342e54ebac398714c7081b3032..25ec2048d37a680ef293fbb441b1e714c815ff16 100644 GIT binary patch literal 49152 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®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 delta 13352 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 +// +// This file was automatically generated by SWIG (http://www.swig.org). +// Version 4.0.0 +// +// Do not make changes to this file unless you know what you are doing--modify +// the SWIG interface file instead. +//------------------------------------------------------------------------------ + + +public class SWIGTYPE_p_uint16_t { + private global::System.Runtime.InteropServices.HandleRef swigCPtr; + + internal SWIGTYPE_p_uint16_t(global::System.IntPtr cPtr, bool futureUse) { + swigCPtr = new global::System.Runtime.InteropServices.HandleRef(this, cPtr); + } + + protected SWIGTYPE_p_uint16_t() { + swigCPtr = new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero); + } + + internal static global::System.Runtime.InteropServices.HandleRef getCPtr(SWIGTYPE_p_uint16_t obj) { + return (obj == null) ? new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero) : obj.swigCPtr; + } +} +} diff --git a/src/csharp/build.bat b/src/csharp/build.bat index 2fbcb36..ad4bd7b 100644 --- a/src/csharp/build.bat +++ b/src/csharp/build.bat @@ -1,21 +1,11 @@ -SET build_directory=../../builds/csharp/ SET precompiled_directory=../../hasomed_precompiled/smpt_rm3_msvc2015_x86_amd64_static +SET dll_build_directory=../../builds/csharp -echo rehamove-integration-lib: Performing the build (C# on Windows) -swig -csharp rehamovelib.i -cl /LD /MD rehamovelib.c rehamovelib_wrap.c /Ferehamovelib.dll /I "%precompiled_directory%/include/low-level/" /I "%precompiled_directory%/include/general" /link "%precompiled_directory%/lib/libsmpt.lib" - -echo rehamove-integration-lib: Moving built files into the builds directory -move rehamovelib.dll "%build_directory%" +echo rehamove-integration-lib: Performing the build (v1.6 C# on Windows) -echo rehamove-integration-lib: Cleaning up intermediate build files -del rehamovelib_wrap.c -del rehamovelib.obj -del rehamovelib_wrap.obj -del rehamovelib.lib -del rehamovelib.exp +swig -csharp rehamovelib.i -echo rehamove-integration-lib: Adding in namespace lines for files used in UnityRehamove.dll +cl /LD /MD rehamovelib.c rehamovelib_wrap.c /Ferehamovelib.dll /I "%precompiled_directory%/include/low-level/" /I "%precompiled_directory%/include/mid-level/" /I "%precompiled_directory%/include/general" /link "%precompiled_directory%/lib/libsmpt.lib" echo }>backspace.cs @@ -39,5 +29,19 @@ echo namespace UnityRehamove {>SWIGTYPE_p_Smpt_device.cs type temp.cs >> SWIGTYPE_p_Smpt_device.cs type backspace.cs >> SWIGTYPE_p_Smpt_device.cs +copy SWIGTYPE_p_uint16_t.cs temp.cs +echo namespace UnityRehamove {>SWIGTYPE_p_uint16_t.cs +type temp.cs >> SWIGTYPE_p_uint16_t.cs +type backspace.cs >> SWIGTYPE_p_uint16_t.cs + del temp.cs -del backspace.cs \ No newline at end of file +del backspace.cs +del rehamovelib_wrap.c +del rehamovelib.exp +del rehamovelib.lib +del rehamovelib.obj +del rehamovelib_wrap.obj + +move rehamovelib.dll "%dll_build_directory%" + +echo rehamove-integration-lib: Build complete. \ No newline at end of file diff --git a/src/csharp/rehamove.cs b/src/csharp/rehamove.cs index 674d039..46a06cc 100644 --- a/src/csharp/rehamove.cs +++ b/src/csharp/rehamove.cs @@ -1,38 +1,270 @@ using UnityEngine; +using System; +using System.Linq; + namespace UnityRehamove { + public class Rehamove { - private RehamoveDevice rehamoveDevice; + public RehamoveDevice rehamove; + public int mode; + + public static string current_version = "v1.6"; + + public static string[] channel0 = { "r", "red" }; + public static string[] channel1 = { "b", "blue" }; + public static string[] channel2 = { "g1", "gray1", "grey1", "black" }; + public static string[] channel3 = { "g2", "gray2", "grey2", "white" }; + + public static int MODE_LOW_LEVEL = 0; + public static int MODE_MID_LEVEL = 1; public Rehamove(string port_name) { - Debug.Log("Rehamove init()"); - rehamoveDevice = rehamovelib.open_port(port_name); + rehamove = rehamovelib.open_port(port_name); + mode = 0; + if (rehamove == null) { + Debug.Log("C# Rehamove init() ERROR!"); + } else { + Debug.Log("C# Rehamove init() SUCCESS."); + } + } + + public string version() { + string c_version = rehamovelib.get_version(); + Debug.Log("Rehamove Version: Python-side " + Rehamove.current_version.ToString() + ", C-side " + c_version); + return Rehamove.current_version; + } + + public int get_mode() { + int result = rehamovelib.get_mode(rehamove); + return result; + } + + public float get_current() { + float result = rehamovelib.get_current(rehamove); + return result; + } + + public int get_pulse_width() { + int result = rehamovelib.get_pulse_width(rehamove); + return result; + } + + public string info() { + if (rehamove == null) { + Debug.Log("C# Rehamove info() ERROR! Rehamove object does not exist."); + return null; + } + int mode = get_mode(); + float current = get_current(); + int pulse_width = get_pulse_width(); + + string output; + if (mode == Rehamove.MODE_LOW_LEVEL) { + output = String.Format("Rehamove device in low-level mode. Mid-level pulse is set to {0} mA and {1} us.", current, pulse_width); + } else if (mode == Rehamove.MODE_MID_LEVEL) { + output = String.Format("Rehamove device in mid-level mode. Mid-level pulse is set to {0} mA and {1} us.", current, pulse_width); + } else { + output = "Rehamove info() ERROR!"; + } + + return output; + } + + public int get_channel(string channel) { + int chosen_channel = 0; // Default + if (channel0.Contains(channel)) { + chosen_channel = 0; + } else if (channel1.Contains(channel)) { + chosen_channel = 1; + } else if (channel2.Contains(channel)) { + chosen_channel = 2; + } else if (channel3.Contains(channel)) { + chosen_channel = 3; + } + return chosen_channel; + } + + public int get_channel(int channel) { + if ((channel < 0) || (channel > 3)) { + channel = 0; // Default + } + return channel; + } + + public int pulse(string channel, float current, int pulse_width) { + int converted_channel = get_channel(channel); + return pulse(converted_channel, current, pulse_width); + } + + public int pulse(int channel, float current, int pulse_width) { + if (rehamove == null) { + Debug.Log("C# Rehamove pulse() ERROR! Rehamove object does not exist."); + return -1; + } + if (mode != MODE_LOW_LEVEL) { + Debug.Log("C# Rehamove pulse() ERROR! Mode must be set to low-level."); + return -1; + } + int result = rehamovelib.pulse(rehamove, channel, current, pulse_width); + if (result != 0) { + Debug.Log("C# Rehamove pulse() ERROR!"); + return -1; + } else { + Debug.Log("C# Rehamove pulse() sent."); + return 0; + } + } + + public int battery() { + if (rehamove == null) { + Debug.Log("C# Rehamove battery() ERROR! Rehamove object does not exist."); + return -1; + } + int result = rehamovelib.battery_request(rehamove); + if (result != 0) { + Debug.Log("C# Rehamove battery() ERROR!"); + return -1; + } else { + int battery_level = rehamovelib.get_battery(rehamove); + Debug.Log("C# Rehamove battery(): " + battery_level.ToString() + "%"); + return battery_level; + } + } + + public int change_mode(int new_mode) { + if (rehamove == null) { + Debug.Log("C# Rehamove change_mode() ERROR! Rehamove object does not exist."); + return -1; + } + int result = rehamovelib.change_mode(rehamove, new_mode); + if (result != 0) { + Debug.Log("C# Rehamove change_mode() ERROR!"); + return -1; + } else { + Debug.Log("C# Rehamove change_mode(): Changed mode to " + mode.ToString() + "."); + mode = new_mode; + return 0; + } + } + + public int set_pulse(float current, int pulse_width) { + if (rehamove == null) { + Debug.Log("C# Rehamove set_pulse() ERROR! Rehamove object does not exist."); + return -1; + } + int result = rehamovelib.set_pulse_data(rehamove, current, pulse_width); + if (result != 0) { + Debug.Log("C# Rehamove set_pulse() ERROR!"); + return -1; + } else { + Debug.Log("C# Rehamove set_pulse(): Set pulse current to " + current.ToString() + " and pulse width to " + pulse_width.ToString() + "."); + return 0; + } } - public int add(int x, int y) { - Debug.Log("Rehamove add()"); - return rehamovelib.add(x, y); + public int run(string channel, float period, int total_milliseconds) { + int chosen_channel = get_channel(channel); + return run(chosen_channel, period, total_milliseconds); } - public void pulse(string channel, int current, int pulse_width) { - Debug.Log("Rehamove pulse()"); - rehamovelib.pulse(rehamoveDevice, channel, current, pulse_width); + public int run(int channel, float period, int total_milliseconds) { + if (rehamove == null) { + Debug.Log("C# Rehamove run() ERROR! Rehamove object does not exist."); + return -1; + } + if (mode != MODE_MID_LEVEL) { + Debug.Log("C# Rehamove run() ERROR! Mode must be set to mid-level."); + return -1; + } + int result = rehamovelib.run(rehamove, channel, period, total_milliseconds); + if (result != 0) { + Debug.Log("C# Rehamove run() ERROR!"); + return -1; + } else { + Debug.Log("C# Rehamove run(): Completed."); + return 0; + } } - public void close() { - Debug.Log("Rehamove close()"); - rehamovelib.close_port(rehamoveDevice); + public int start(string channel, float period) { + int chosen_channel = get_channel(channel); + return start(chosen_channel, period); } - // void OnApplicationQuit() - // { - // Debug.Log("Application ending after " + Time.time + " seconds"); - // rehamovelib.pulse(rehamoveDevice, "blue", 5, 100); - // } + public int start(int channel, float period) { + if (rehamove == null) { + Debug.Log("C# Rehamove start() ERROR! Rehamove object does not exist."); + return -1; + } + if (mode != MODE_MID_LEVEL) { + Debug.Log("C# Rehamove start() ERROR! Mode must be set to mid-level."); + return -1; + } + int result = rehamovelib.midlevel_start(rehamove, channel, period); + if (result != 0) { + Debug.Log("C# Rehamove start() ERROR!"); + return -1; + } else { + Debug.Log("C# Rehamove start(): Completed."); + return 0; + } + } + + public int update() { + if (rehamove == null) { + Debug.Log("C# Rehamove update() ERROR! Rehamove object does not exist."); + return -1; + } + if (mode != MODE_MID_LEVEL) { + Debug.Log("C# Rehamove update() ERROR! Mode must be set to mid-level."); + return -1; + } + int result = rehamovelib.midlevel_update(rehamove); + if (result != 0) { + Debug.Log("C# Rehamove update() ERROR!"); + return -1; + } else { + Debug.Log("C# Rehamove update(): Completed."); + return 0; + } + } + + public int end() { + if (rehamove == null) { + Debug.Log("C# Rehamove end() ERROR! Rehamove object does not exist."); + return -1; + } + if (mode != MODE_MID_LEVEL) { + Debug.Log("C# Rehamove end() ERROR! Mode must be set to mid-level."); + return -1; + } + int result = rehamovelib.midlevel_end(rehamove); + if (result != 0) { + Debug.Log("C# Rehamove end() ERROR!"); + return -1; + } else { + Debug.Log("C# Rehamove end(): Completed."); + return 0; + } + } + + public int close() { + if (rehamove == null) { + Debug.Log("C# RehamoveDevice close() ERROR! RehamoveDevice object does not exist."); + return -1; + } + int result = rehamovelib.close_port(rehamove); + if (result != 0) { + Debug.Log("C# RehamoveDevice close() ERROR!"); + return -1; + } else { + Debug.Log("C# RehamoveDevice close() sent."); + return 0; + } + } ~Rehamove() { - Debug.Log("I'm being destroyed! Add: " + rehamovelib.add(2, 3).ToString()); - // rehamovelib.close_port(rehamoveDevice); - // Debug.Log("done closing port"); + Debug.Log("I'm being destroyed!"); } } } \ No newline at end of file diff --git a/src/csharp/rehamovelib.c b/src/csharp/rehamovelib.c index 264b3c7..9cac3d7 100644 --- a/src/csharp/rehamovelib.c +++ b/src/csharp/rehamovelib.c @@ -1,221 +1,299 @@ +#include "smpt_ll_client.h" +#include "smpt_ml_client.h" #include #include #include -#include -#include "smpt_ll_client.h" -int add(int x, int y); +#if defined(__linux__) +#include /* Timer for Linux */ +#elif defined(_WIN32) +#include /* Timer for Windows */ +#endif -int add(int x, int y) { - return x + y; -} +#define VERSION_NUMBER "v1.6" + +#define TIMEOUT_COUNTER 10000000 + +#define MODE_LOW_LEVEL 0 +#define MODE_MID_LEVEL 1 typedef struct { - char port_name[64]; Smpt_device device; + int battery; + int mode; + float current; + uint16_t pulse_width; } RehamoveDevice; -/* -Function declarations in this section. -*/ +/* FUNCTION DECLARATIONS */ + +// Opening and closing the connection. RehamoveDevice * open_port(const char * port_name); -void close_port(RehamoveDevice * r); -void pulse(RehamoveDevice * r, char * channel, int current, int pulse_width); -void custom_pulse(RehamoveDevice * r, char * channel, int num_points, float c0, int w0, float c1, int w1, float c2, int w2, float c3, int w3, float c4, int w4, float c5, int w5, float c6, int w6, float c7, int w7, float c8, int w8, float c9, int w9, float c10, int w10, float c11, int w11, float c12, int w12, float c13, int w13, float c14, int w14, float c15, int w15); -int battery(RehamoveDevice * r); +int close_port(RehamoveDevice * r); + +// Low-level functionality (the default) -> sending individual pulses. +int initialize_low_level(RehamoveDevice * r); +int stop_low_level(RehamoveDevice * r); +int pulse(RehamoveDevice * r, int channel, float current, int pulse_width); +int custom_pulse(RehamoveDevice * r, int channel, int num_points, float c0, int w0, float c1, int w1, float c2, int w2, float c3, int w3, float c4, int w4, float c5, int w5, float c6, int w6, float c7, int w7, float c8, int w8, float c9, int w9, float c10, int w10, float c11, int w11, float c12, int w12, float c13, int w13, float c14, int w14, float c15, int w15); + +// Mid-level functionality -> setting a recurring pulse. +int change_mode(RehamoveDevice * r, int mode); +int set_pulse_data(RehamoveDevice * r, float current, int pulse_width); +int run(RehamoveDevice * r, int channel, float period, int total_milliseconds); +int midlevel_start(RehamoveDevice * r, int channel, float period); +int midlevel_update(RehamoveDevice * r); +int midlevel_end(RehamoveDevice * r); + +// Global functionality -> can be called in any mode. +char * get_version(); +int get_battery(RehamoveDevice * r); +int get_mode(RehamoveDevice * r); +float get_current(RehamoveDevice * r); +int get_pulse_width(RehamoveDevice * r); +int battery_request(RehamoveDevice * r); + +// Debugging functions -> not intended for users to use. +void print_device(Smpt_device d, const char * filename); +void error_callback(const char * message) { + printf("ERROR CALLBACK: %s\n", message); +} -/* -Actual implementation details below. -*/ +/* FUNCTION DEFINITIONS */ RehamoveDevice * open_port(const char * port_name) { - RehamoveDevice * r = (RehamoveDevice *) calloc(1, sizeof(RehamoveDevice)); - - for (int i = 0; i < strlen(port_name); i++) { - (r->port_name)[i] = *(port_name + i); - } - //(r->port_name)[strlen(port_name)] = '\0'; - //for (int i = 0; i < strlen("COM3"); i++) { + + //smpt_init_error_callback(&error_callback); - //} - //r->port_name = "COM3"; + RehamoveDevice * r = (RehamoveDevice *) calloc(1, sizeof(RehamoveDevice)); - printf("open_port(): Created port_name %s\n", r->port_name); + // Set the defaults. + r->battery = -1; + r->mode = -1; + r->current = 0; + r->pulse_width = 0; Smpt_device device = {0}; - int open_port_result = smpt_open_serial_port(&device, r->port_name); + r->device = device; - FILE * f; - f = fopen("log.txt", "a"); - if (f != NULL) { - if (open_port_result == 0) { - fprintf(f, "open_port(): ERROR! Unable to connect to port %s.\n", r->port_name); - - } - else { - fprintf(f, "open_port(): Successfully opened port.\n"); - } - fclose(f); + bool open_port_result = smpt_open_serial_port(&(r->device), port_name); + if (!open_port_result) { + printf("open_port() ERROR: Opening connection to port %s failed!\n", port_name); + free(r); + return NULL; } - r->device = device; + + // Default is low-level mode, so we will start with that. + int initialize_low_level_result = initialize_low_level(r); + if (initialize_low_level_result) { + printf("open_port() ERROR: Unable to initialize low-level stimulation!\n"); + free(r); + return NULL; + } + + printf("open_port() SUCCESS: Connected to port %s and initialized device.\n", port_name); return r; } -void close_port(RehamoveDevice * r) { - int result = smpt_close_serial_port(&(r->device)); - - FILE * f; - f = fopen("log.txt", "a"); - if (f != NULL) { - if (result == 0) { - fprintf(f, "close_port(): ERROR! Unable to close port %s !\n", r->port_name); - } - else { - fprintf(f, "close_port(): Successfully closed port %s .\n", r->port_name); +int close_port(RehamoveDevice * r) { + if (r == NULL) { + printf("close_port() ERROR: No RehamoveDevice object found!\n"); + return 1; + } + + // Stop the low-level stimulation, if it is still active. + if (r->mode == MODE_LOW_LEVEL) { + int stop_low_level_result = stop_low_level(r); + if (stop_low_level_result) { + printf("close_port() ERROR: Unable to stop low-level stimulation!\n"); + return 1; } - fclose(f); + } + + bool close_port_result = smpt_close_serial_port(&(r->device)); + if (!close_port_result) { + printf("close_port() ERROR! Close port request not sent!\n"); + return 1; } free(r); - return; -} - -void print_channel_config(Smpt_ll_channel_config * s) { - - printf("PRINTING CHANNEL CONFIG\n"); - printf("enable_stimulation: %d\n", s->enable_stimulation); - printf("channel: %d\n", s->channel); - printf("modify_demux: %d\n", s->modify_demux); - printf("number_of_points: %d\n", s->number_of_points); - printf("Smpt_Length_Points: %d\n", Smpt_Length_Points); - printf("points array: "); - for (int i = 0; i < Smpt_Length_Points; i++) { - Smpt_point p = *(s->points + i); - printf("(time %d float %f control_mode %d interpolation_mode %d) ", p.time, p.current, p.control_mode, p.interpolation_mode); - } - printf("\n"); - printf("Smpt_Length_Demux_Config: %d\n", Smpt_Length_Demux_Config); - printf("demux_config array: "); - for (int i = 0; i < Smpt_Length_Demux_Config; i++) { - printf("(%d) ", *(s->demux_config + i)); - } - printf("\n"); - printf("demux_length: %d\n", s->demux_length); - printf("packet_number: %d\n", s->packet_number); + printf("close_port() SUCCESS: Stopped device and closed port successfully.\n"); + return 0; } -void pulse(RehamoveDevice * r, char * channel, int current, int pulse_width) { +int initialize_low_level(RehamoveDevice * r) { + if (r == NULL) { + printf("initialize_low_level() ERROR: No RehamoveDevice object found!\n"); + return 1; + } + if (r->mode == MODE_LOW_LEVEL) { + printf("initialize_low_level() ERROR: Low-level mode already initialized.\n"); + return 0; + } - uint8_t packet_number = 0; /* The packet_number can be used for debugging purposes */ - Smpt_ll_init ll_init = {0}; /* Struct for ll_init command */ - Smpt_ll_channel_config ll_channel_config = {0}; /* Struct for ll_channel_config command */ + uint8_t packet_number = 1; + Smpt_ll_init ll_init = {0}; - /* Clear ll_init struct and set the data */ smpt_clear_ll_init(&ll_init); - - //print_channel_config(&ll_channel_config); - ll_init.packet_number = packet_number; /* Send the ll_init command to stimulation unit */ - smpt_send_ll_init(&(r->device), &ll_init); + bool ll_init_result = smpt_send_ll_init(&(r->device), &ll_init); + if (!ll_init_result) { + printf("initialize_low_level() ERROR: Sending device initialization message failed!\n"); + return 1; + } - packet_number++; + int counter = 0; + while (!smpt_new_packet_received(&(r->device))) { + if (counter > TIMEOUT_COUNTER) { + printf("initialize_low_level() ERROR: Receiving device initialization message timed out!\n"); + return 1; + } + counter += 1; + } - /* Set the data */ - ll_channel_config.enable_stimulation = true; - - // char lowercase[strlen(channel) + 1]; - // for (int i = 0; i < strlen(channel); i++) { - // lowercase[i] = tolower(channel[i]); - // } - // lowercase[strlen(channel)] = '\0'; - for (int i = 0; i < strlen(channel); i++) { - *(channel + i) = tolower(*(channel + i)); - } + Smpt_ack ack; + smpt_last_ack(&(r->device), &ack); - int chosen_channel = Smpt_Channel_Blue; - if (strncmp(channel, "red", strlen("red")) == 0) { - chosen_channel = Smpt_Channel_Red; - } - else if (strncmp(channel, "blue", strlen("blue")) == 0) { - chosen_channel = Smpt_Channel_Blue; - } - else if (strncmp(channel, "black", strlen("gray")) == 0) { - chosen_channel = Smpt_Channel_Black; + if ((ack.result != Smpt_Result_Successful) || (ack.command_number != Smpt_Cmd_Ll_Init_Ack)) { + if (ack.result == Smpt_Result_Not_Initialized_Error) { + printf("initialize_low_level() ERROR: Unsuccessful device initialization response, midlevel could be active! Expected: command %d result %d, Received: command %d result %d.\n", Smpt_Cmd_Ll_Init_Ack, Smpt_Result_Successful, ack.command_number, ack.result); + int end_midlevel_result = midlevel_end(r); + return 1; + } + // Default error message -> specify the code. + printf("initialize_low_level() ERROR: Unsuccessful device initialization response! Expected: command %d result %d, Received: command %d result %d.\n", Smpt_Cmd_Ll_Init_Ack, Smpt_Result_Successful, ack.command_number, ack.result); + return 1; + } else { + Smpt_ll_init_ack init_ack; + smpt_get_ll_init_ack(&(r->device), &init_ack); } - ll_channel_config.channel = chosen_channel; /* Use blue channel */ - ll_channel_config.number_of_points = 3; /* Set the number of points*/ - ll_channel_config.packet_number = packet_number; + // After initializing the low-level stimulation, set the mode in our RehamoveDevice struct. + r->mode = MODE_LOW_LEVEL; - /* Set the stimulation pulse */ - /* First point, current: 20 mA, positive, pulse width: 200 µs */ - ll_channel_config.points[0].current = current; - ll_channel_config.points[0].time = pulse_width; + printf("initialize_low_level() SUCCESS: Device successfully initialized low-level stimulation.\n"); + return 0; +} - /* Second point, pause 100 µs */ - ll_channel_config.points[1].time = pulse_width / 2; +int stop_low_level(RehamoveDevice * r) { + if (r == NULL) { + printf("stop_low_level() ERROR: No RehamoveDevice object found!\n"); + return 1; + } + if (r->mode == MODE_MID_LEVEL) { + printf("stop_low_level() ERROR: Low-level stimulation already stopped.\n"); + return 0; + } - /* Third point, current: -20 mA, negative, pulse width: 200 µs */ - ll_channel_config.points[2].current = current * -1; - ll_channel_config.points[2].time = pulse_width; + uint8_t packet_number = 1; + bool ll_stop_result = smpt_send_ll_stop(&(r->device), packet_number); + if (!ll_stop_result) { + printf("stop_low_level() ERROR: Stopping low-level stimulation request not sent!\n"); + return 1; + } - //print_channel_config(&ll_channel_config); + int counter = 0; + while (!smpt_new_packet_received(&(r->device))) { + if (counter > TIMEOUT_COUNTER) { + printf("stop_low_level() ERROR: Receiving low-level stimulation stop response timed out!\n"); + return 1; + } + } - /* Send the ll_channel_list command to the stimulation unit */ - smpt_send_ll_channel_config(&(r->device), &ll_channel_config); + Smpt_ack ack; + smpt_last_ack(&(r->device), &ack); - //print_channel_config(&ll_channel_config); + if ((ack.result != Smpt_Result_Successful) || (ack.command_number != Smpt_Cmd_Ll_Stop_Ack)) { + // Default error message -> specify the code. + printf("stop_low_level() ERROR: Unsuccessful low-level stimulation stop response! Expected: command %d result %d, Received: command %d result %d.\n", Smpt_Cmd_Ll_Stop_Ack, Smpt_Result_Successful, ack.command_number, ack.result); + return 1; + } - packet_number++; + // After stopping the low-level stimulation, set the mode in our RehamoveDevice struct. + r->mode = MODE_MID_LEVEL; - /* Send the ll_stop command to the stimulation unit */ - smpt_send_ll_stop(&(r->device), packet_number); - //printf("pulse(): Successfully finished.\n"); + printf("stop_low_level() SUCCESS: Device successfully stopped low-level stimulation.\n"); + return 0; } -void custom_pulse(RehamoveDevice * r, char * channel, int num_points, float c0, int w0, float c1, int w1, float c2, int w2, float c3, int w3, float c4, int w4, float c5, int w5, float c6, int w6, float c7, int w7, float c8, int w8, float c9, int w9, float c10, int w10, float c11, int w11, float c12, int w12, float c13, int w13, float c14, int w14, float c15, int w15) { - //printf("C custom_pulse: %p %s, %f %d %f %d %f %d %f %d / %f %d %f %d %f %d %f %d / %f %d %f %d %f %d %f %d / %f %d %f %d %f %d %f %d", r, channel, c0, w0, c1, w1, c2, w2, c3, w3, c4, w4, c5, w5, c6, w6, c7, w7, c8, w8, c9, w9, c10, w10, c11, w11, c12, w12, c13, w13, c14, w14, c15, w15); +int pulse(RehamoveDevice * r, int channel, float current, int pulse_width) { + if (r == NULL) { + printf("pulse() ERROR: No RehamoveDevice object found!\n"); + return 1; + } + if (r->mode != MODE_LOW_LEVEL) { + printf("pulse() ERROR: Not in low-level stimulation mode.\n"); + return 1; + } + + uint8_t packet_number = 1; - uint8_t packet_number = 0; /* The packet_number can be used for debugging purposes */ - Smpt_ll_init ll_init = {0}; /* Struct for ll_init command */ Smpt_ll_channel_config ll_channel_config = {0}; /* Struct for ll_channel_config command */ + /* Set the data */ + ll_channel_config.enable_stimulation = true; + ll_channel_config.channel = channel; + ll_channel_config.number_of_points = 3; /* Set the number of points*/ + ll_channel_config.packet_number = packet_number; + /* Set the stimulation pulse */ + ll_channel_config.points[0].current = current; + ll_channel_config.points[0].time = pulse_width; + ll_channel_config.points[1].time = pulse_width / 2; + ll_channel_config.points[2].current = current * -1; + ll_channel_config.points[2].time = pulse_width; - /* Clear ll_init struct and set the data */ - smpt_clear_ll_init(&ll_init); - - ll_init.packet_number = packet_number; + /* Send the ll_channel_list command to the stimulation unit */ + bool ll_config_result = smpt_send_ll_channel_config(&(r->device), &ll_channel_config); + if (!ll_config_result) { + printf("pulse() ERROR: Pulse command not sent!\n"); + return 1; + } - /* Send the ll_init command to stimulation unit */ - smpt_send_ll_init(&(r->device), &ll_init); + int counter = 0; + while (!smpt_new_packet_received(&(r->device))) { + if (counter > TIMEOUT_COUNTER) { + printf("pulse() ERROR: Receiving pulse response timed out!\n"); + return 1; + } + counter += 1; + } - packet_number++; + Smpt_ack ack; + smpt_last_ack(&(r->device), &ack); - /* Set the data */ - ll_channel_config.enable_stimulation = true; - - // char lowercase[strlen(channel) + 1]; - // for (int i = 0; i < strlen(channel); i++) { - // lowercase[i] = tolower(channel[i]); - // } - // lowercase[strlen(channel)] = '\0'; - for (int i = 0; i < strlen(channel); i++) { - *(channel + i) = tolower(*(channel + i)); + if ((ack.result != Smpt_Result_Successful) || (ack.command_number != Smpt_Cmd_Ll_Channel_Config_Ack)) { + // Common error situation -> electrode error (e.g. electrode not connected). + if (ack.result == Smpt_Result_Electrode_Error) { + printf("pulse() ERROR: Unsuccessful pulse response - electrode error! Expected: command %d result %d, Received: command %d result %d.\n", Smpt_Cmd_Ll_Channel_Config_Ack, Smpt_Result_Successful, ack.command_number, ack.result); + return 1; + } + // Default error message -> specify the code. + printf("pulse() ERROR: Unsuccessful pulse response! Expected: command %d result %d, Received: command %d result %d.\n", Smpt_Cmd_Ll_Channel_Config_Ack, Smpt_Result_Successful, ack.command_number, ack.result); + return 1; + } else { + Smpt_ll_channel_config_ack channel_config_ack; + smpt_get_ll_channel_config_ack(&(r->device), &channel_config_ack); } + return 0; +} - int chosen_channel = Smpt_Channel_Blue; - if (strncmp(channel, "red", strlen("red")) == 0) { - chosen_channel = Smpt_Channel_Red; - } - else if (strncmp(channel, "blue", strlen("blue")) == 0) { - chosen_channel = Smpt_Channel_Blue; +int custom_pulse(RehamoveDevice * r, int channel, int num_points, float c0, int w0, float c1, int w1, float c2, int w2, float c3, int w3, float c4, int w4, float c5, int w5, float c6, int w6, float c7, int w7, float c8, int w8, float c9, int w9, float c10, int w10, float c11, int w11, float c12, int w12, float c13, int w13, float c14, int w14, float c15, int w15) { + + if (r == NULL) { + printf("custom_pulse() ERROR: No RehamoveDevice object found!\n"); + return 1; } - else if (strncmp(channel, "black", strlen("gray")) == 0) { - chosen_channel = Smpt_Channel_Black; + if (r->mode != MODE_LOW_LEVEL) { + printf("pulse() ERROR: Not in low-level stimulation mode.\n"); + return 1; } - ll_channel_config.channel = chosen_channel; /* Use blue channel */ + uint8_t packet_number = 2; + Smpt_ll_channel_config ll_channel_config = {0}; /* Struct for ll_channel_config command */ + /* Set the data */ + ll_channel_config.enable_stimulation = true; + ll_channel_config.channel = channel; ll_channel_config.number_of_points = num_points; /* Set the number of points*/ ll_channel_config.packet_number = packet_number; @@ -253,57 +331,537 @@ void custom_pulse(RehamoveDevice * r, char * channel, int num_points, float c0, ll_channel_config.points[15].current = c15; ll_channel_config.points[15].time = w15; - //print_channel_config(&ll_channel_config); - /* Send the ll_channel_list command to the stimulation unit */ - smpt_send_ll_channel_config(&(r->device), &ll_channel_config); + bool ll_config_result = smpt_send_ll_channel_config(&(r->device), &ll_channel_config); + if (!ll_config_result) { + printf("custom_pulse() ERROR: Pulse command not sent!\n"); + return 1; + } + + int counter = 0; + while (!smpt_new_packet_received(&(r->device))) { + if (counter > TIMEOUT_COUNTER) { + printf("custom_pulse() ERROR: Receiving pulse response timed out!\n"); + return 1; + } + } - packet_number++; + Smpt_ack ack; + smpt_last_ack(&(r->device), &ack); - /* Send the ll_stop command to the stimulation unit */ - smpt_send_ll_stop(&(r->device), packet_number); - //printf("custom_pulse(): Successfully finished.\n"); + if ((ack.result != Smpt_Result_Successful) || (ack.command_number != Smpt_Cmd_Ll_Channel_Config_Ack)) { + // Common error situation -> electrode error (e.g. electrode not connected). + if (ack.result == Smpt_Result_Electrode_Error) { + printf("custom_pulse() ERROR: Unsuccessful pulse response - electrode error! Expected: command %d result %d, Received: command %d result %d.\n", Smpt_Cmd_Ll_Channel_Config_Ack, Smpt_Result_Successful, ack.command_number, ack.result); + return 1; + } + // Default error message -> specify the code. + printf("custom_pulse() ERROR: Unsuccessful pulse response! Expected: command %d result %d, Received: command %d result %d.\n", Smpt_Cmd_Ll_Channel_Config_Ack, Smpt_Result_Successful, ack.command_number, ack.result); + return 1; + } else { + Smpt_ll_channel_config_ack channel_config_ack; + smpt_get_ll_channel_config_ack(&(r->device), &channel_config_ack); + } + return 0; } -int battery(RehamoveDevice * r) { - // Annoyingly have to close and reopen a new port. - smpt_close_serial_port(&(r->device)); - printf("close(): Successfully finished.\n"); - Smpt_device device = {0}; - int open_port_result = smpt_open_serial_port(&device, r->port_name); - if (open_port_result == 0) { - printf("open(): ERROR! Unable to connect to port %s.\n", r->port_name); +int change_mode(RehamoveDevice * r, int mode) { + if (r == NULL) { + printf("change_mode() ERROR: No RehamoveDevice object found!\n"); + return 1; } + + if (mode == MODE_LOW_LEVEL) { + if (r->mode == MODE_LOW_LEVEL) { + printf("change_mode() ERROR: Low-level mode already initialized.\n"); + return 1; + } + int initialize_low_level_result = initialize_low_level(r); + if (initialize_low_level_result) { + printf("change_mode() ERROR: Unable to change to low-level mode!\n"); + return 1; + } + printf("change_mode() SUCCESS: Changed to low-level mode.\n"); + return 0; + } + + else if (mode == MODE_MID_LEVEL) { + if (r->mode == MODE_MID_LEVEL) { + printf("change_mode() ERROR: Mid-level mode already initialized.\n"); + return 1; + } + int stop_low_level_result = stop_low_level(r); + if (stop_low_level_result) { + printf("change_mode() ERROR: Unable to change to mid-level mode!\n"); + return 1; + } + printf("change_mode() SUCCESS: Changed to mid-level mode.\n"); + return 0; + } + else { - printf("open(): Successfully opened port.\n"); + printf("change_mode() ERROR: Invalid mode specified!\n"); + return 1; } - r->device = device; +} + + +int set_pulse_data(RehamoveDevice * r, float current, int pulse_width) { + if (r == NULL) { + printf("set_pulse_data() ERROR: No RehamoveDevice object found!\n"); + return 1; + } + r->current = current; + r->pulse_width = pulse_width; + printf("set_pulse_data(): Set RehamoveDevice struct pulse to current %0.3f pulse_width %d\n", r->current, r->pulse_width); + return 0; +} + + +int get_pulse_data(RehamoveDevice * r) { + if (r == NULL) { + printf("get_pulse_data() ERROR: No RehamoveDevice object found!\n"); + return 1; + } + printf("get_pulse_data(): current %0.3f pulse_width %d\n", r->current, r->pulse_width); + return 0; +} - /* Send the call to get the battery status. Signature is: + +int run(RehamoveDevice * r, int channel, float period, int total_milliseconds) { + if (r == NULL) { + printf("run() ERROR: No RehamoveDevice object found!\n"); + return 1; + } + int seconds = total_milliseconds / 1000; + int remainder = total_milliseconds % 1000; + printf("total_milliseconds %d seconds %d remainder %d\n", total_milliseconds, seconds, remainder); + + Smpt_ml_init ml_init = {0}; + smpt_clear_ml_init(&ml_init); - SMPT_API bool smpt_send_get_battery_status ( Smpt_device *const device, - uint8_t packet_number - ) - */ - uint8_t packet_number = 42; /* The packet_number can be used for debugging purposes */ - bool send_result = smpt_send_get_battery_status(&(r->device), packet_number); + bool ml_init_result = smpt_send_ml_init(&(r->device), &ml_init); + if (!ml_init_result) { + printf("ml_init() ERROR: Sending device mid-level initialization message failed!\n"); + return 1; + } int counter = 0; while (!smpt_new_packet_received(&(r->device))) { + if (counter > TIMEOUT_COUNTER) { + printf("ml_init() ERROR: Receiving device mid-level initialization message timed out!\n"); + return 1; + } + counter += 1; + } + + Smpt_ack ack; + smpt_last_ack(&(r->device), &ack); + + if ((ack.result != Smpt_Result_Successful) || (ack.command_number != Smpt_Cmd_Ml_Init_Ack)) { + // Default error message -> specify the code. + printf("ml_init() ERROR: Unsuccessful device mid-level initialization response! Expected: command %d result %d, Received: command %d result %d.\n", Smpt_Cmd_Ml_Init_Ack, Smpt_Result_Successful, ack.command_number, ack.result); + return 1; + } + Smpt_ml_update ml_update = {0}; + smpt_clear_ml_update(&ml_update); + ml_update.enable_channel[channel] = true; + ml_update.channel_config[channel].number_of_points = 3; + ml_update.channel_config[channel].ramp = 0; + ml_update.channel_config[channel].period = period; + /* Set the stimulation pulse */ + ml_update.channel_config[channel].points[0].current = r->current; + ml_update.channel_config[channel].points[0].time = r->pulse_width; + ml_update.channel_config[channel].points[1].time = (r->pulse_width) / 2; + ml_update.channel_config[channel].points[2].current = (r->current) * -1; + ml_update.channel_config[channel].points[2].time = r->pulse_width; + + bool ml_update_result = smpt_send_ml_update(&(r->device), &ml_update); + if (!ml_update_result) { + printf("ml_update_result() ERROR: Sending device mid-level update message failed!\n"); + return 1; + } + + counter = 0; + while (!smpt_new_packet_received(&(r->device))) { + if (counter > TIMEOUT_COUNTER) { + printf("ml_update_result() ERROR: Receiving device mid-level update message timed out!\n"); + return 1; + } counter += 1; + } + + smpt_last_ack(&(r->device), &ack); + + if ((ack.result != Smpt_Result_Successful) || (ack.command_number != Smpt_Cmd_Ml_Update_Ack)) { + // Default error message -> specify the code. + printf("ml_update_result() ERROR: Unsuccessful device mid-level update response! Expected: command %d result %d, Received: command %d result %d.\n", Smpt_Cmd_Ml_Update_Ack, Smpt_Result_Successful, ack.command_number, ack.result); + return 1; } + + Smpt_ml_get_current_data ml_get_current_data = {0}; + ml_get_current_data.data_selection[Smpt_Ml_Data_Stimulation] = true; + + for (int i = 0; i <= seconds; i++) { + // Every second, we send a keep-alive update. We must always start with at least one. + bool keep_alive_result = smpt_send_ml_get_current_data(&(r->device), &ml_get_current_data); + if (!keep_alive_result) { + printf("keep_alive_result() ERROR: Sending device alive message failed!\n"); + return 1; + } + + counter = 0; + while (!smpt_new_packet_received(&(r->device))) { + if (counter > TIMEOUT_COUNTER) { + printf("keep_alive_result() ERROR: Receiving device alive message timed out!\n"); + return 1; + } + counter += 1; + } + + smpt_last_ack(&(r->device), &ack); + + if ((ack.result != Smpt_Result_Successful) || (ack.command_number != Smpt_Cmd_Ml_Get_Current_Data_Ack)) { + // Default error message -> specify the code. + printf("keep_alive_result() ERROR: Unsuccessful device alive response! Expected: command %d result %d, Received: command %d result %d.\n", Smpt_Cmd_Ml_Get_Current_Data_Ack, Smpt_Result_Successful, ack.command_number, ack.result); + return 1; + } + + if (i == seconds) { + break; + } + #if defined(__linux__) + usleep(1000000); + #elif defined(_WIN32) + Sleep(1000); + #endif + } + + // Before sending the stop message, wait for the remainder of milliseconds. + #if defined(__linux__) + usleep(1000 * remainder); + #elif defined(_WIN32) + Sleep(remainder); + #endif + + bool ml_stop_result = smpt_send_ml_stop(&(r->device), smpt_packet_number_generator_next(&(r->device))); + if (!ml_stop_result) { + printf("ml_stop_result() ERROR: Sending device stop message failed!\n"); + return 1; + } + + counter = 0; + while (!smpt_new_packet_received(&(r->device))) { + if (counter > TIMEOUT_COUNTER) { + printf("ml_stop_result() ERROR: Receiving device stop message timed out!\n"); + return 1; + } + counter += 1; + } + + smpt_last_ack(&(r->device), &ack); + + if ((ack.result != Smpt_Result_Successful) || (ack.command_number != Smpt_Cmd_Ml_Stop_Ack)) { + // Default error message -> specify the code. + printf("ml_stop_result() ERROR: Unsuccessful device stop response! Expected: command %d result %d, Received: command %d result %d.\n", Smpt_Cmd_Ml_Stop_Ack, Smpt_Result_Successful, ack.command_number, ack.result); + return 1; + } + + printf("run() SUCCESS: Ran pulses of %0.2f mA and %d us on a period of %0.2f us for a total of %d ms.\n", r->current, r->pulse_width, period, total_milliseconds); + return 0; +} + + +int midlevel_start(RehamoveDevice * r, int channel, float period) { + if (r == NULL) { + printf("midlevel_start() ERROR: No RehamoveDevice object found!\n"); + return 1; + } + + Smpt_ml_init ml_init = {0}; + smpt_clear_ml_init(&ml_init); + + bool ml_init_result = smpt_send_ml_init(&(r->device), &ml_init); + if (!ml_init_result) { + printf("ml_init() ERROR: Sending device mid-level initialization message failed!\n"); + return 1; + } + + int counter = 0; + while (!smpt_new_packet_received(&(r->device))) { + if (counter > TIMEOUT_COUNTER) { + printf("ml_init() ERROR: Receiving device mid-level initialization message timed out!\n"); + return 1; + } + counter += 1; + } + + Smpt_ack ack; + smpt_last_ack(&(r->device), &ack); + + if ((ack.result != Smpt_Result_Successful) || (ack.command_number != Smpt_Cmd_Ml_Init_Ack)) { + // Default error message -> specify the code. + printf("ml_init() ERROR: Unsuccessful device mid-level initialization response! Expected: command %d result %d, Received: command %d result %d.\n", Smpt_Cmd_Ml_Init_Ack, Smpt_Result_Successful, ack.command_number, ack.result); + return 1; + } + + Smpt_ml_update ml_update = {0}; + smpt_clear_ml_update(&ml_update); + ml_update.enable_channel[channel] = true; + ml_update.channel_config[channel].number_of_points = 3; + ml_update.channel_config[channel].ramp = 0; + ml_update.channel_config[channel].period = period; + /* Set the stimulation pulse */ + ml_update.channel_config[channel].points[0].current = r->current; + ml_update.channel_config[channel].points[0].time = r->pulse_width; + ml_update.channel_config[channel].points[1].time = (r->pulse_width) / 2; + ml_update.channel_config[channel].points[2].current = (r->current) * -1; + ml_update.channel_config[channel].points[2].time = r->pulse_width; + + bool ml_update_result = smpt_send_ml_update(&(r->device), &ml_update); + if (!ml_update_result) { + printf("ml_update_result() ERROR: Sending device mid-level update message failed!\n"); + return 1; + } + + counter = 0; + while (!smpt_new_packet_received(&(r->device))) { + if (counter > TIMEOUT_COUNTER) { + printf("ml_update_result() ERROR: Receiving device mid-level update message timed out!\n"); + return 1; + } + counter += 1; + } + + smpt_last_ack(&(r->device), &ack); + + if ((ack.result != Smpt_Result_Successful) || (ack.command_number != Smpt_Cmd_Ml_Update_Ack)) { + // Default error message -> specify the code. + printf("ml_update_result() ERROR: Unsuccessful device mid-level update response! Expected: command %d result %d, Received: command %d result %d.\n", Smpt_Cmd_Ml_Update_Ack, Smpt_Result_Successful, ack.command_number, ack.result); + return 1; + } + + int keep_alive_result = midlevel_update(r); + if (keep_alive_result) { + printf("midlevel_start() ERROR: Unsuccessful keep alive.\n"); + return 1; + } + return 0; +} + + +int midlevel_update(RehamoveDevice * r) { + if (r == NULL) { + printf("midlevel_update() ERROR: No RehamoveDevice object found!\n"); + return 1; + } + + Smpt_ml_get_current_data ml_get_current_data = {0}; + ml_get_current_data.data_selection[Smpt_Ml_Data_Stimulation] = true; + + bool keep_alive_result = smpt_send_ml_get_current_data(&(r->device), &ml_get_current_data); + if (!keep_alive_result) { + printf("keep_alive_result() ERROR: Sending device alive message failed!\n"); + return 1; + } + + int counter = 0; + while (!smpt_new_packet_received(&(r->device))) { + if (counter > TIMEOUT_COUNTER) { + printf("keep_alive_result() ERROR: Receiving device alive message timed out!\n"); + return 1; + } + counter += 1; + } + + Smpt_ack ack; + smpt_last_ack(&(r->device), &ack); + + if ((ack.result != Smpt_Result_Successful) || (ack.command_number != Smpt_Cmd_Ml_Get_Current_Data_Ack)) { + // Default error message -> specify the code. + printf("keep_alive_result() ERROR: Unsuccessful device alive response! Expected: command %d result %d, Received: command %d result %d.\n", Smpt_Cmd_Ml_Get_Current_Data_Ack, Smpt_Result_Successful, ack.command_number, ack.result); + return 1; + } + + return 0; +} + + +int midlevel_end(RehamoveDevice * r) { + if (r == NULL) { + printf("midlevel_end() ERROR: No RehamoveDevice object found!\n"); + return 1; + } + + bool ml_stop_result = smpt_send_ml_stop(&(r->device), smpt_packet_number_generator_next(&(r->device))); + if (!ml_stop_result) { + printf("ml_stop_result() ERROR: Sending device stop message failed!\n"); + return 1; + } + + int counter = 0; + while (!smpt_new_packet_received(&(r->device))) { + if (counter > TIMEOUT_COUNTER) { + printf("ml_stop_result() ERROR: Receiving device stop message timed out!\n"); + return 1; + } + counter += 1; + } + Smpt_ack ack; smpt_last_ack(&(r->device), &ack); - Smpt_get_battery_status_ack battery_ack; - smpt_get_get_battery_status_ack(&(r->device), &battery_ack); + if ((ack.result != Smpt_Result_Successful) || (ack.command_number != Smpt_Cmd_Ml_Stop_Ack)) { + // Default error message -> specify the code. + printf("ml_stop_result() ERROR: Unsuccessful device stop response! Expected: command %d result %d, Received: command %d result %d.\n", Smpt_Cmd_Ml_Stop_Ack, Smpt_Result_Successful, ack.command_number, ack.result); + return 1; + } + + return 0; +} + + +char * get_version() { + return VERSION_NUMBER; +} + + +int get_battery(RehamoveDevice * r) { + if (r == NULL) { + printf("get_battery() ERROR: No RehamoveDevice object found!\n"); + return -1; + } + return r->battery; +} + +int get_mode(RehamoveDevice * r) { + if (r == NULL) { + printf("get_mode() ERROR: No RehamoveDevice object found!\n"); + return -1; + } + return r->mode; +} + +float get_current(RehamoveDevice * r) { + if (r == NULL) { + printf("get_current() ERROR: No RehamoveDevice object found!\n"); + return -1; + } + return r->current; +} + +int get_pulse_width(RehamoveDevice * r) { + if (r == NULL) { + printf("get_pulse_width() ERROR: No RehamoveDevice object found!\n"); + return 0; + } + return (int) r->pulse_width; +} + +int battery_request(RehamoveDevice * r) { + if (r == NULL) { + printf("battery_request() ERROR: No RehamoveDevice object found!\n"); + return 1; + } + + uint8_t packet_number = 42; + bool battery_result = smpt_send_get_battery_status(&(r->device), packet_number); + if (!battery_result) { + printf("battery_result() ERROR: Battery request not sent!\n"); + return 1; + } + + int counter = 0; + while (!smpt_new_packet_received(&(r->device))) { + if (counter > TIMEOUT_COUNTER) { + printf("battery_result() ERROR: Receiving battery response timed out!\n"); + return 1; + } + } - int battery_level = battery_ack.battery_level; + Smpt_ack ack; + smpt_last_ack(&(r->device), &ack); - printf("Battery life is at %d %%.\n", battery_level); - return battery_level; + if ((ack.result != Smpt_Result_Successful) || (ack.command_number != Smpt_Cmd_Get_Battery_Status_Ack)) { + // Default error message -> specify the code. + printf("battery_result() ERROR: Unsuccessful battery response! Expected: command %d result %d, Received: command %d result %d.\n", Smpt_Cmd_Get_Battery_Status_Ack, Smpt_Result_Successful, ack.command_number, ack.result); + return 1; + } else { + Smpt_get_battery_status_ack battery_ack; + smpt_get_get_battery_status_ack(&(r->device), &battery_ack); + r->battery = battery_ack.battery_level; + } + return 0; } + +/* FOR DEBUGGING */ + +void print_device(Smpt_device d, const char * filename) { + + FILE * file = fopen(filename, "w+, css=UTF-8"); + if (file == NULL) { + printf("Could not print to file %s\n", filename); + return; + } + + fprintf(file, "PRINTING DEVICE.\n"); + fprintf(file, "packet_length %d\n", d.packet_length); + fprintf(file, "packet array of size %d: ", Smpt_Length_Max_Packet_Size); + for (int i = 0; i < Smpt_Length_Max_Packet_Size; i++) { + fprintf(file, "%d ", (d.packet)[i]); + } + fprintf(file, "\n"); + fprintf(file, "cmd_list c:\n"); + Smpt_cmd_list c = d.cmd_list; + fprintf(file, "c.acks_length %d\n", c.acks_length); + fprintf(file, "c.acks_current_index %d\n", c.acks_current_index); + fprintf(file, "c.acks array of size %d: ( ", Smpt_Length_Number_Of_Acks); + for (int i = 0; i < Smpt_Length_Number_Of_Acks; i++) { + Smpt_ack a = *(c.acks + i); + fprintf(file, "[packet %d command %d result %d] ", a.packet_number, a.command_number, a.result); + } + fprintf(file, ")\n"); + fprintf(file, "c.requests_current_index %d\n", c.requests_current_index); + fprintf(file, "c.requests_expected_index %d\n", c.requests_expected_index); + fprintf(file, "c.number_of_expected %d\n", c.number_of_expected); + fprintf(file, "c.requests array of size %d: ( ", Smpt_Length_Number_Of_Acks); + for (int i = 0; i < Smpt_Length_Number_Of_Acks; i++) { + Smpt_cmd a = *(c.requests + i); + fprintf(file, "[packet %d command %d] ", a.packet_number, a.command_number); + } + fprintf(file, ")\n"); + fprintf(file, "c.new_ack_available %d\n", c.new_ack_available); + //fprintf(file, "serial_port_handle %p\n", d.serial_port_handle_); + fprintf(file, "current_packet_number %d\n", d.current_packet_number); + fprintf(file, "serial_port_name array of size %d: ( ", Smpt_Length_Serial_Port_Chars); + for (int i = 0; i < Smpt_Length_Serial_Port_Chars; i++) { + fprintf(file, "%c ", *(d.serial_port_name + i)); + } + fprintf(file, ")\n"); + fprintf(file, "packet_input_buffer p:\n"); + Packet_input_buffer p = d.packet_input_buffer; + fprintf(file, "p.buffer %p\n", p.buffer); + fprintf(file, "p.buffer_state %p\n", p.buffer_state); + fprintf(file, "p.write_row_length_count %d\n", p.write_row_length_count); + fprintf(file, "p.write_row_count %d\n", p.write_row_count); + fprintf(file, "p.read_row_count %d\n", p.read_row_count); + fprintf(file, "p.ignore_next_byte %d\n", p.ignore_next_byte); + fprintf(file, "p.number_of_rows %d\n", p.number_of_rows); + fprintf(file, "p.row_length %d\n", p.row_length); + fprintf(file, "packet_input_buffer_data array of size (%d * %d): ( ", Smpt_Length_Packet_Input_Buffer_Rows, Smpt_Length_Max_Packet_Size); + for (int i = 0; i < Smpt_Length_Packet_Input_Buffer_Rows * Smpt_Length_Max_Packet_Size; i++) { + fprintf(file, "%d ", *(d.packet_input_buffer_data + i)); + } + fprintf(file, ")\n"); + fprintf(file, "packet_input_buffer_state array of size %d: ( ", Smpt_Length_Packet_Input_Buffer_Rows); + for (int i = 0; i < Smpt_Length_Packet_Input_Buffer_Rows; i++) { + fprintf(file, "%d ", *(d.packet_input_buffer_state + i)); + } + fprintf(file, ")\n"); + fprintf(file, "END PRINT DEVICE.\n"); + fclose(file); +} \ No newline at end of file diff --git a/src/csharp/rehamovelib.cs b/src/csharp/rehamovelib.cs index ce9530c..71f82a1 100644 --- a/src/csharp/rehamovelib.cs +++ b/src/csharp/rehamovelib.cs @@ -11,31 +11,94 @@ namespace UnityRehamove { public class rehamovelib { - public static int add(int x, int y) { - int ret = rehamovelibPINVOKE.add(x, y); - return ret; - } - public static RehamoveDevice open_port(string port_name) { global::System.IntPtr cPtr = rehamovelibPINVOKE.open_port(port_name); RehamoveDevice ret = (cPtr == global::System.IntPtr.Zero) ? null : new RehamoveDevice(cPtr, false); return ret; } - public static void close_port(RehamoveDevice r) { - rehamovelibPINVOKE.close_port(RehamoveDevice.getCPtr(r)); + public static int close_port(RehamoveDevice r) { + int ret = rehamovelibPINVOKE.close_port(RehamoveDevice.getCPtr(r)); + return ret; + } + + public static int initialize_low_level(RehamoveDevice r) { + int ret = rehamovelibPINVOKE.initialize_low_level(RehamoveDevice.getCPtr(r)); + return ret; + } + + public static int stop_low_level(RehamoveDevice r) { + int ret = rehamovelibPINVOKE.stop_low_level(RehamoveDevice.getCPtr(r)); + return ret; } - public static void pulse(RehamoveDevice r, string channel, int current, int pulse_width) { - rehamovelibPINVOKE.pulse(RehamoveDevice.getCPtr(r), channel, current, pulse_width); + public static int pulse(RehamoveDevice r, int channel, float current, int pulse_width) { + int ret = rehamovelibPINVOKE.pulse(RehamoveDevice.getCPtr(r), channel, current, pulse_width); + return ret; + } + + public static int custom_pulse(RehamoveDevice r, int channel, int num_points, float c0, int w0, float c1, int w1, float c2, int w2, float c3, int w3, float c4, int w4, float c5, int w5, float c6, int w6, float c7, int w7, float c8, int w8, float c9, int w9, float c10, int w10, float c11, int w11, float c12, int w12, float c13, int w13, float c14, int w14, float c15, int w15) { + int ret = rehamovelibPINVOKE.custom_pulse(RehamoveDevice.getCPtr(r), channel, num_points, c0, w0, c1, w1, c2, w2, c3, w3, c4, w4, c5, w5, c6, w6, c7, w7, c8, w8, c9, w9, c10, w10, c11, w11, c12, w12, c13, w13, c14, w14, c15, w15); + return ret; + } + + public static int change_mode(RehamoveDevice r, int mode) { + int ret = rehamovelibPINVOKE.change_mode(RehamoveDevice.getCPtr(r), mode); + return ret; + } + + public static int set_pulse_data(RehamoveDevice r, float current, int pulse_width) { + int ret = rehamovelibPINVOKE.set_pulse_data(RehamoveDevice.getCPtr(r), current, pulse_width); + return ret; + } + + public static int run(RehamoveDevice r, int channel, float period, int total_milliseconds) { + int ret = rehamovelibPINVOKE.run(RehamoveDevice.getCPtr(r), channel, period, total_milliseconds); + return ret; } - public static void custom_pulse(RehamoveDevice r, string channel, int num_points, float c0, int w0, float c1, int w1, float c2, int w2, float c3, int w3, float c4, int w4, float c5, int w5, float c6, int w6, float c7, int w7, float c8, int w8, float c9, int w9, float c10, int w10, float c11, int w11, float c12, int w12, float c13, int w13, float c14, int w14, float c15, int w15) { - rehamovelibPINVOKE.custom_pulse(RehamoveDevice.getCPtr(r), channel, num_points, c0, w0, c1, w1, c2, w2, c3, w3, c4, w4, c5, w5, c6, w6, c7, w7, c8, w8, c9, w9, c10, w10, c11, w11, c12, w12, c13, w13, c14, w14, c15, w15); + public static int midlevel_start(RehamoveDevice r, int channel, float period) { + int ret = rehamovelibPINVOKE.midlevel_start(RehamoveDevice.getCPtr(r), channel, period); + return ret; + } + + public static int midlevel_update(RehamoveDevice r) { + int ret = rehamovelibPINVOKE.midlevel_update(RehamoveDevice.getCPtr(r)); + return ret; + } + + public static int midlevel_end(RehamoveDevice r) { + int ret = rehamovelibPINVOKE.midlevel_end(RehamoveDevice.getCPtr(r)); + return ret; + } + + public static string get_version() { + string ret = rehamovelibPINVOKE.get_version(); + return ret; + } + + public static int get_battery(RehamoveDevice r) { + int ret = rehamovelibPINVOKE.get_battery(RehamoveDevice.getCPtr(r)); + return ret; + } + + public static int get_mode(RehamoveDevice r) { + int ret = rehamovelibPINVOKE.get_mode(RehamoveDevice.getCPtr(r)); + return ret; + } + + public static float get_current(RehamoveDevice r) { + float ret = rehamovelibPINVOKE.get_current(RehamoveDevice.getCPtr(r)); + return ret; + } + + public static int get_pulse_width(RehamoveDevice r) { + int ret = rehamovelibPINVOKE.get_pulse_width(RehamoveDevice.getCPtr(r)); + return ret; } - public static int battery(RehamoveDevice r) { - int ret = rehamovelibPINVOKE.battery(RehamoveDevice.getCPtr(r)); + public static int battery_request(RehamoveDevice r) { + int ret = rehamovelibPINVOKE.battery_request(RehamoveDevice.getCPtr(r)); return ret; } diff --git a/src/csharp/rehamovelib.i b/src/csharp/rehamovelib.i index 1923d3b..f38b175 100644 --- a/src/csharp/rehamovelib.i +++ b/src/csharp/rehamovelib.i @@ -1,32 +1,67 @@ %module rehamovelib %{ -#include -#include -#include -#include #include "smpt_ll_client.h" +#include "smpt_ml_client.h" typedef struct { - char port_name[64]; - Smpt_device device; + Smpt_device device; + int battery; + int mode; + float current; + uint16_t pulse_width; } RehamoveDevice; -extern int add(int x, int y); extern RehamoveDevice * open_port(const char * port_name); -extern void close_port(RehamoveDevice * r); -extern void pulse(RehamoveDevice * r, char * channel, int current, int pulse_width); -extern void custom_pulse(RehamoveDevice * r, char * channel, int num_points, float c0, int w0, float c1, int w1, float c2, int w2, float c3, int w3, float c4, int w4, float c5, int w5, float c6, int w6, float c7, int w7, float c8, int w8, float c9, int w9, float c10, int w10, float c11, int w11, float c12, int w12, float c13, int w13, float c14, int w14, float c15, int w15); -extern int battery(RehamoveDevice * r); +extern int close_port(RehamoveDevice * r); + +extern int initialize_low_level(RehamoveDevice * r); +extern int stop_low_level(RehamoveDevice * r); +extern int pulse(RehamoveDevice * r, int channel, float current, int pulse_width); +extern int custom_pulse(RehamoveDevice * r, int channel, int num_points, float c0, int w0, float c1, int w1, float c2, int w2, float c3, int w3, float c4, int w4, float c5, int w5, float c6, int w6, float c7, int w7, float c8, int w8, float c9, int w9, float c10, int w10, float c11, int w11, float c12, int w12, float c13, int w13, float c14, int w14, float c15, int w15); + +extern int change_mode(RehamoveDevice * r, int mode); +extern int set_pulse_data(RehamoveDevice * r, float current, int pulse_width); +extern int run(RehamoveDevice * r, int channel, float period, int total_milliseconds); +extern int midlevel_start(RehamoveDevice * r, int channel, float period); +extern int midlevel_update(RehamoveDevice * r); +extern int midlevel_end(RehamoveDevice * r); + +extern char * get_version(); +extern int get_battery(RehamoveDevice * r); +extern int get_mode(RehamoveDevice * r); +extern float get_current(RehamoveDevice * r); +extern int get_pulse_width(RehamoveDevice * r); +extern int get_battery(RehamoveDevice * r); +extern int battery_request(RehamoveDevice * r); + %} typedef struct { - char port_name[64]; - Smpt_device device; + Smpt_device device; + int battery; + int mode; + float current; + uint16_t pulse_width; } RehamoveDevice; -extern int add(int x, int y); extern RehamoveDevice * open_port(const char * port_name); -extern void close_port(RehamoveDevice * r); -extern void pulse(RehamoveDevice * r, char * channel, int current, int pulse_width); -extern void custom_pulse(RehamoveDevice * r, char * channel, int num_points, float c0, int w0, float c1, int w1, float c2, int w2, float c3, int w3, float c4, int w4, float c5, int w5, float c6, int w6, float c7, int w7, float c8, int w8, float c9, int w9, float c10, int w10, float c11, int w11, float c12, int w12, float c13, int w13, float c14, int w14, float c15, int w15); -extern int battery(RehamoveDevice * r); \ No newline at end of file +extern int close_port(RehamoveDevice * r); + +extern int initialize_low_level(RehamoveDevice * r); +extern int stop_low_level(RehamoveDevice * r); +extern int pulse(RehamoveDevice * r, int channel, float current, int pulse_width); +extern int custom_pulse(RehamoveDevice * r, int channel, int num_points, float c0, int w0, float c1, int w1, float c2, int w2, float c3, int w3, float c4, int w4, float c5, int w5, float c6, int w6, float c7, int w7, float c8, int w8, float c9, int w9, float c10, int w10, float c11, int w11, float c12, int w12, float c13, int w13, float c14, int w14, float c15, int w15); + +extern int change_mode(RehamoveDevice * r, int mode); +extern int set_pulse_data(RehamoveDevice * r, float current, int pulse_width); +extern int run(RehamoveDevice * r, int channel, float period, int total_milliseconds); +extern int midlevel_start(RehamoveDevice * r, int channel, float period); +extern int midlevel_update(RehamoveDevice * r); +extern int midlevel_end(RehamoveDevice * r); + +extern char * get_version(); +extern int get_battery(RehamoveDevice * r); +extern int get_mode(RehamoveDevice * r); +extern float get_current(RehamoveDevice * r); +extern int get_pulse_width(RehamoveDevice * r); +extern int battery_request(RehamoveDevice * r); \ No newline at end of file diff --git a/src/csharp/rehamovelibPINVOKE.cs b/src/csharp/rehamovelibPINVOKE.cs index 0a18617..42efe12 100644 --- a/src/csharp/rehamovelibPINVOKE.cs +++ b/src/csharp/rehamovelibPINVOKE.cs @@ -193,40 +193,94 @@ static rehamovelibPINVOKE() { } - [global::System.Runtime.InteropServices.DllImport("rehamovelib", EntryPoint="CSharp_RehamoveDevice_port_name_set")] - public static extern void RehamoveDevice_port_name_set(global::System.Runtime.InteropServices.HandleRef jarg1, string jarg2); - - [global::System.Runtime.InteropServices.DllImport("rehamovelib", EntryPoint="CSharp_RehamoveDevice_port_name_get")] - public static extern string RehamoveDevice_port_name_get(global::System.Runtime.InteropServices.HandleRef jarg1); - [global::System.Runtime.InteropServices.DllImport("rehamovelib", EntryPoint="CSharp_RehamoveDevice_device_set")] public static extern void RehamoveDevice_device_set(global::System.Runtime.InteropServices.HandleRef jarg1, global::System.Runtime.InteropServices.HandleRef jarg2); [global::System.Runtime.InteropServices.DllImport("rehamovelib", EntryPoint="CSharp_RehamoveDevice_device_get")] public static extern global::System.IntPtr RehamoveDevice_device_get(global::System.Runtime.InteropServices.HandleRef jarg1); + [global::System.Runtime.InteropServices.DllImport("rehamovelib", EntryPoint="CSharp_RehamoveDevice_battery_set")] + public static extern void RehamoveDevice_battery_set(global::System.Runtime.InteropServices.HandleRef jarg1, int jarg2); + + [global::System.Runtime.InteropServices.DllImport("rehamovelib", EntryPoint="CSharp_RehamoveDevice_battery_get")] + public static extern int RehamoveDevice_battery_get(global::System.Runtime.InteropServices.HandleRef jarg1); + + [global::System.Runtime.InteropServices.DllImport("rehamovelib", EntryPoint="CSharp_RehamoveDevice_mode_set")] + public static extern void RehamoveDevice_mode_set(global::System.Runtime.InteropServices.HandleRef jarg1, int jarg2); + + [global::System.Runtime.InteropServices.DllImport("rehamovelib", EntryPoint="CSharp_RehamoveDevice_mode_get")] + public static extern int RehamoveDevice_mode_get(global::System.Runtime.InteropServices.HandleRef jarg1); + + [global::System.Runtime.InteropServices.DllImport("rehamovelib", EntryPoint="CSharp_RehamoveDevice_current_set")] + public static extern void RehamoveDevice_current_set(global::System.Runtime.InteropServices.HandleRef jarg1, float jarg2); + + [global::System.Runtime.InteropServices.DllImport("rehamovelib", EntryPoint="CSharp_RehamoveDevice_current_get")] + public static extern float RehamoveDevice_current_get(global::System.Runtime.InteropServices.HandleRef jarg1); + + [global::System.Runtime.InteropServices.DllImport("rehamovelib", EntryPoint="CSharp_RehamoveDevice_pulse_width_set")] + public static extern void RehamoveDevice_pulse_width_set(global::System.Runtime.InteropServices.HandleRef jarg1, global::System.Runtime.InteropServices.HandleRef jarg2); + + [global::System.Runtime.InteropServices.DllImport("rehamovelib", EntryPoint="CSharp_RehamoveDevice_pulse_width_get")] + public static extern global::System.IntPtr RehamoveDevice_pulse_width_get(global::System.Runtime.InteropServices.HandleRef jarg1); + [global::System.Runtime.InteropServices.DllImport("rehamovelib", EntryPoint="CSharp_new_RehamoveDevice")] public static extern global::System.IntPtr new_RehamoveDevice(); [global::System.Runtime.InteropServices.DllImport("rehamovelib", EntryPoint="CSharp_delete_RehamoveDevice")] public static extern void delete_RehamoveDevice(global::System.Runtime.InteropServices.HandleRef jarg1); - [global::System.Runtime.InteropServices.DllImport("rehamovelib", EntryPoint="CSharp_add")] - public static extern int add(int jarg1, int jarg2); - [global::System.Runtime.InteropServices.DllImport("rehamovelib", EntryPoint="CSharp_open_port")] public static extern global::System.IntPtr open_port(string jarg1); [global::System.Runtime.InteropServices.DllImport("rehamovelib", EntryPoint="CSharp_close_port")] - public static extern void close_port(global::System.Runtime.InteropServices.HandleRef jarg1); + public static extern int close_port(global::System.Runtime.InteropServices.HandleRef jarg1); + + [global::System.Runtime.InteropServices.DllImport("rehamovelib", EntryPoint="CSharp_initialize_low_level")] + public static extern int initialize_low_level(global::System.Runtime.InteropServices.HandleRef jarg1); + + [global::System.Runtime.InteropServices.DllImport("rehamovelib", EntryPoint="CSharp_stop_low_level")] + public static extern int stop_low_level(global::System.Runtime.InteropServices.HandleRef jarg1); [global::System.Runtime.InteropServices.DllImport("rehamovelib", EntryPoint="CSharp_pulse")] - public static extern void pulse(global::System.Runtime.InteropServices.HandleRef jarg1, string jarg2, int jarg3, int jarg4); + public static extern int pulse(global::System.Runtime.InteropServices.HandleRef jarg1, int jarg2, float jarg3, int jarg4); [global::System.Runtime.InteropServices.DllImport("rehamovelib", EntryPoint="CSharp_custom_pulse")] - public static extern void custom_pulse(global::System.Runtime.InteropServices.HandleRef jarg1, string jarg2, int jarg3, float jarg4, int jarg5, float jarg6, int jarg7, float jarg8, int jarg9, float jarg10, int jarg11, float jarg12, int jarg13, float jarg14, int jarg15, float jarg16, int jarg17, float jarg18, int jarg19, float jarg20, int jarg21, float jarg22, int jarg23, float jarg24, int jarg25, float jarg26, int jarg27, float jarg28, int jarg29, float jarg30, int jarg31, float jarg32, int jarg33, float jarg34, int jarg35); + public static extern int custom_pulse(global::System.Runtime.InteropServices.HandleRef jarg1, int jarg2, int jarg3, float jarg4, int jarg5, float jarg6, int jarg7, float jarg8, int jarg9, float jarg10, int jarg11, float jarg12, int jarg13, float jarg14, int jarg15, float jarg16, int jarg17, float jarg18, int jarg19, float jarg20, int jarg21, float jarg22, int jarg23, float jarg24, int jarg25, float jarg26, int jarg27, float jarg28, int jarg29, float jarg30, int jarg31, float jarg32, int jarg33, float jarg34, int jarg35); + + [global::System.Runtime.InteropServices.DllImport("rehamovelib", EntryPoint="CSharp_change_mode")] + public static extern int change_mode(global::System.Runtime.InteropServices.HandleRef jarg1, int jarg2); + + [global::System.Runtime.InteropServices.DllImport("rehamovelib", EntryPoint="CSharp_set_pulse_data")] + public static extern int set_pulse_data(global::System.Runtime.InteropServices.HandleRef jarg1, float jarg2, int jarg3); + + [global::System.Runtime.InteropServices.DllImport("rehamovelib", EntryPoint="CSharp_run")] + public static extern int run(global::System.Runtime.InteropServices.HandleRef jarg1, int jarg2, float jarg3, int jarg4); + + [global::System.Runtime.InteropServices.DllImport("rehamovelib", EntryPoint="CSharp_midlevel_start")] + public static extern int midlevel_start(global::System.Runtime.InteropServices.HandleRef jarg1, int jarg2, float jarg3); + + [global::System.Runtime.InteropServices.DllImport("rehamovelib", EntryPoint="CSharp_midlevel_update")] + public static extern int midlevel_update(global::System.Runtime.InteropServices.HandleRef jarg1); + + [global::System.Runtime.InteropServices.DllImport("rehamovelib", EntryPoint="CSharp_midlevel_end")] + public static extern int midlevel_end(global::System.Runtime.InteropServices.HandleRef jarg1); + + [global::System.Runtime.InteropServices.DllImport("rehamovelib", EntryPoint="CSharp_get_version")] + public static extern string get_version(); + + [global::System.Runtime.InteropServices.DllImport("rehamovelib", EntryPoint="CSharp_get_battery")] + public static extern int get_battery(global::System.Runtime.InteropServices.HandleRef jarg1); + + [global::System.Runtime.InteropServices.DllImport("rehamovelib", EntryPoint="CSharp_get_mode")] + public static extern int get_mode(global::System.Runtime.InteropServices.HandleRef jarg1); + + [global::System.Runtime.InteropServices.DllImport("rehamovelib", EntryPoint="CSharp_get_current")] + public static extern float get_current(global::System.Runtime.InteropServices.HandleRef jarg1); + + [global::System.Runtime.InteropServices.DllImport("rehamovelib", EntryPoint="CSharp_get_pulse_width")] + public static extern int get_pulse_width(global::System.Runtime.InteropServices.HandleRef jarg1); - [global::System.Runtime.InteropServices.DllImport("rehamovelib", EntryPoint="CSharp_battery")] - public static extern int battery(global::System.Runtime.InteropServices.HandleRef jarg1); + [global::System.Runtime.InteropServices.DllImport("rehamovelib", EntryPoint="CSharp_battery_request")] + public static extern int battery_request(global::System.Runtime.InteropServices.HandleRef jarg1); } }