commit 2650ca4b5efeb698d01000ac02ecdf65ed3671f8 Author: Bob McMahon Date: Sat Mar 7 15:59:12 2026 -0800 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5bc44d2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +env/ +hub_manager.py~ +arc.txt diff --git a/acronam_env.sh b/acronam_env.sh new file mode 100644 index 0000000..26fb5a7 --- /dev/null +++ b/acronam_env.sh @@ -0,0 +1,22 @@ +cd ~/Code/acroname + +cat > umber_env.sh << 'EOF' +# --- Umber Networks / Fi-Wi Dev Environment --- +ACRO_BASE="$HOME/Code/acroname" +if [ -d "$ACRO_BASE/env" ]; then + source "$ACRO_BASE/env/bin/activate" +fi +# Acroname Hub Management for Fi-Wi Rig +export ACRONAME_PATH="$HOME/Code/acroname/hub_manager.py" +alias hub-status='$ACRONAME_PATH status all' +alias hub-on='$ACRONAME_PATH on' +alias hub-off='$ACRONAME_PATH off' +alias hub-verify='$ACRONAME_PATH verify' +alias hub-setup='$ACRONAME_PATH setup' +alias hub-reboot='$ACRONAME_PATH reboot' +alias hub-reboot-force='$ACRONAME_PATH reboot-force' +EOF + +git add umber_env.sh +git commit -m "Add Fi-Wi dev environment setup and hub aliases" +git push diff --git a/acronam_setup.sh b/acronam_setup.sh new file mode 100755 index 0000000..60be25b --- /dev/null +++ b/acronam_setup.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +# Define the environment name +VENV_NAME="env" + +echo "--- Starting Python VENV setup on $(hostname) ---" + +# 1. Update package list and ensure venv/pip are installed +sudo apt update +sudo apt install -y python3-venv python3-pip + +# 2. Create the virtual environment +if [ ! -d "$VENV_NAME" ]; then + echo "Creating virtual environment: $VENV_NAME" + python3 -m venv $VENV_NAME +else + echo "Virtual environment '$VENV_NAME' already exists." +fi + +# 3. Activate the environment +source $VENV_NAME/bin/activate + +# 4. Upgrade pip and install brainstem +echo "Upgrading pip and installing BrainStem SDK..." +pip install --upgrade pip +pip install brainstem + +# 5. Optional: Install common networking tools for your iperf2 testing +# pip install numpy matplotlib # if you plan on plotting results later + +echo "--- Setup Complete ---" +echo "To start using the environment, run: source $VENV_NAME/bin/activate" diff --git a/api/examples/c_cpp/BrainStem2-Application-Notes/brainstem_network.cpp b/api/examples/c_cpp/BrainStem2-Application-Notes/brainstem_network.cpp new file mode 100755 index 0000000..fe259d6 --- /dev/null +++ b/api/examples/c_cpp/BrainStem2-Application-Notes/brainstem_network.cpp @@ -0,0 +1,147 @@ +/**************************************************************** + * Filename: brainstem_network.cpp + * Prepared By: James Dudley + * Date Prepared: March 12, 2018 + * Date Revised: March 12, 2018 + * Revision: 0.0.1 + ***************************************************************/ + +#include "BrainStem2/BrainStem-all.h" +#include + + +#define USB_CHANNEL 0 +#define RAIL0_SET_VOLTAGE 2200000 // Set voltage for MTM-PM-1 Rail 0 +#define RAIL1_SET_VOLTAGE 2800000 // Set voltage for MTM-IO-SERIAL Rail 1 +#define CYCLE_TIME 20 // Time to pause between readings, ms + +int main(int argc, const char * argv[]) { + // Create each MTM object + // Apply a module offset of 24 to the MTM-PM-1 module (determined by the DIP switch + // on the development board + aMTMIOSerial ioserial; + aMTMPM1 pm; + pm.setModuleAddress(aMTMPM1_MODULE_BASE_ADDRESS + 24); + aMTMUSBStem stem; + + // Initialize error tracker + aErr err = aErrNone; + + // Discover and connect to MTM-IO-SERIAL object + // First, get a list of all available USB modules (Note: MTM-PM-1 shows up because there's + // a pass-through USB channel on the MTM-IO-SERIAL, which is connected to the MTM-PM-1 edge + // connector USB on the development board) + list spec_list; + err = Link::sDiscover(USB, &spec_list); + + // + list::iterator it; + for (it = spec_list.begin(); it != spec_list.end(); ++it) { + if (it->model == aMODULE_TYPE_MTMIOSerial_1) { + err = ioserial.connect(USB, it->serial_num); + if (err != aErrNone) { + printf("Error connecting to MTM-IO-Serial: %d\n", err); + return 0; + } + break; + } + } + if (!ioserial.isConnected()) { + printf("Error finding MTM-IO-SERIAL module: no MTM-IO-SERIAL link Spec discovered/n"); + return 0; + } + + err = pm.connectThroughLinkModule(&ioserial); + if (err != aErrNone) { + printf("Error connecting to MTM-PM-1: %d\n", err); + return 0; + } + err = stem.connectThroughLinkModule(&ioserial); + if (err != aErrNone) { + printf("Error connecting to MTM-USBStem: %d\n", err); + return 0; + } + + err = ioserial.system.routeToMe(1); + if (err != aErrNone) { + printf("Error setting MTM-IO-SERIAL routeToMe: %d\n", err); + return 0; + } + + // 1 - Set MTM-PM-1 Rail 0 and measure the voltage using MTM-USBSTEM A2D0 + err = pm.rail[0].setVoltage(RAIL0_SET_VOLTAGE); + if (err != aErrNone) { + printf("Error setting Rail 0 voltage to %.3fV: %d\n", (float) RAIL0_SET_VOLTAGE / 1e6, err); + return 0; + } + + err = pm.rail[0].setEnable(1); + if (err != aErrNone) { + printf("Error enabling Rail 0: %d\n", err); + return 0; + } + + aTime_MSSleep(CYCLE_TIME); + + int32_t a2d0_voltage; + err = stem.analog[0].getVoltage(&a2d0_voltage); + if (err != aErrNone) { + printf("Error reading A2D0 voltage: %d\n", err); + return 0; + } + + printf("* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n"); + printf("MTM-PM-1 Rail 0: %.3fV\n", (float) RAIL0_SET_VOLTAGE / 1e6); + printf("MTM-USBSTEM A2D0: %.3fV\n", (float) a2d0_voltage / 1e6); + printf("* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n"); + + // 2 - (optional) Toggle MTM-IO-SERIAL USB channel on/off + err = ioserial.usb.setPortEnable(USB_CHANNEL); + if (err != aErrNone) { + printf("Error enabling USB channel %d: %d\n", USB_CHANNEL, err); + return 0; + } + + printf("Verify USB device enumeration (optional) and press Enter to continue...\n"); + std::cin.get(); + + err = ioserial.usb.setPortDisable(USB_CHANNEL); + if (err != aErrNone) { + printf("Error disabling USB channel %d: %d\n", USB_CHANNEL, err); + return 0; + } + + + // 3 - Set MTM-IO-SERIAL Rail 1 and measure the voltage using MTM-USBSTEM A2D1 + err = ioserial.rail[1].setVoltage(RAIL1_SET_VOLTAGE); + if (err != aErrNone) { + printf("Error setting Rail 1 voltage to %.3f: %d\n", (float) RAIL1_SET_VOLTAGE / 1e6, err); + return 0; + } + + err = ioserial.rail[1].setEnable(1); + if (err != aErrNone) { + printf("Error enabling Rail 1: %d\n", err); + return 0; + } + + aTime_MSSleep(CYCLE_TIME); + + int32_t a2d1_voltage; + err = stem.analog[1].getVoltage(&a2d1_voltage); + if (err != aErrNone) { + printf("Error reading A2D1 voltage: %d\n", err); + return 0; + } + + printf("* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n"); + printf("MTM-IO-SERIAL Rail 1: %.3fV\n", (float) RAIL1_SET_VOLTAGE / 1e6); + printf("MTM-USBSTEM A2D1: %.3fV\n", (float) a2d1_voltage / 1e6); + printf("* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n"); + + stem.disconnect(); + pm.disconnect(); + ioserial.disconnect(); + + return 0; +} diff --git a/api/examples/c_cpp/BrainStem2-Application-Notes/brainstem_network.py b/api/examples/c_cpp/BrainStem2-Application-Notes/brainstem_network.py new file mode 100755 index 0000000..82fa6b1 --- /dev/null +++ b/api/examples/c_cpp/BrainStem2-Application-Notes/brainstem_network.py @@ -0,0 +1,110 @@ +############################################################################### +# Filename: brainstem_network.py +# Prepared By: James Dudley +# Date Prepared: March 7, 2018 +# Date Revised: March 7, 2018 +# Revision: 0.0.1 +############################################################################### + +import brainstem # Import BrainStem API +from brainstem.result import Result # For easy access to error constants +from time import sleep, time + +USB_CHANNEL = 0 +RAIL0_SET_VOLTAGE = 2200000 # Set voltage for MTM-PM-1 Rail 0 +RAIL1_SET_VOLTAGE = 2800000 # Set voltage for MTM-IO-SERIAL Rail 1 +CYCLE_TIME = 0.02 # Time to pause between readings, seconds + +# Generic function to run BrainStem commands with error checking +def step(func, func_str, *args): + print '>> ' + func_str[0].upper() + func_str[1:] # Capitalize first letter of string + res = func(*args) + err = val = res + if isinstance(val, Result): + err = res.error + val = res.value + else: + err = Result.NO_ERROR + + if err is not Result.NO_ERROR: + raise Exception('Error %s: %d' % (func_str, err)) + + return val + + +def main(): + # Create each MTM object + # Apply a module offset of 24 to the MTM-PM-1 module (determined by the DIP switch on the development board) + ioserial = brainstem.stem.MTMIOSerial() # Uses default module address + # Module offset is applied simply to demonstrate module offset, and is not strictly required in this case + # Make sure the DIP switch for MTM-PM-1 is set to 1-1-0-0 (0b1100 * 2 = offset of 24) + pm = brainstem.stem.MTMPM1(brainstem.stem.MTMPM1.BASE_ADDRESS + 24) + stem = brainstem.stem.MTMUSBStem() # Uses default module address + + # Initialize error tracker + err = Result.NO_ERROR + + try: + # Discover and connect to MTM-IO-SERIAL object + # First, get a list of all available USB modules (Note: MTM-PM-1 shows up because there's a pass-through + # USB channel on the MTM-IO-SERIAL, which is connected to the MTM-PM-1 edge connector USB on the development board) + spec_array = step(brainstem.discover.findAllModules, 'discover USB modules', brainstem.link.Spec.USB) + # Next, iterate through each link Spec in the array and connect if it's the MTM-IO-SERIAL module + for spec in spec_array: + if spec.model == brainstem.defs.MODEL_MTM_IOSERIAL: + step(ioserial.connectFromSpec, 'connecting to MTM-IO-SERIAL from spec', spec) + break + connection_status = step(ioserial.isConnected, 'checking MTM-IO-SERIAL connection status') + if connection_status is not True: + raise Excepetion('Error finding MTM-IO-SERIAL module: no MTM-IO-SERIAL link Spec discovered') + + # Connect the MTM-PM-1 and MTM-USBSTEM modules over the BrainStem network, + # using the MTM-IO-SERIAL as the primary module. + step(pm.connectThroughLinkModule, 'connecting to MTM-PM-1 over BS network', ioserial) + step(stem.connectThroughLinkModule, 'connecting to MTM-USBSTEM over BS network', ioserial) + + # Set both modules to route through the MTM-IO-SERIAL module (turn "ON" ioserial.routeToMe) + step(ioserial.system.routeToMe, 'setting MTM-IO-SERIAL routeToMe', 1) + + # Try out a few examples of functionality from each MTM module + + # 1 - Set MTM-PM-1 Rail 0 and measure the voltage using MTM-USBSTEM A2D0 + step(pm.rail[0].setVoltage, 'setting Rail 0 voltage to %.3fV' % (RAIL0_SET_VOLTAGE/1.e6), RAIL0_SET_VOLTAGE) + step(pm.rail[0].setEnable, 'enabling Rail 0', 1) + sleep(CYCLE_TIME) + a2d0_voltage = step(stem.analog[0].getVoltage, 'reading A2D0 voltage') + + print '* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *' + print 'MTM-PM-1 Rail 0: %.3fV' % (RAIL0_SET_VOLTAGE/1.e6) + print 'MTM-USBSTEM A2D0: %.3fV' % (a2d0_voltage / 1.e6) + print '* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *' + + # 2 - (optional) Toggle MTM-IO-SERIAL USB channel on/off + step(ioserial.usb.setPortEnable, 'enabling USB channel %d' % USB_CHANNEL, USB_CHANNEL) + raw_input('Verify USB device enumeration (optional) and press Enter to continue...') + step(ioserial.usb.setPortDisable, 'disabling USB channel %d' % USB_CHANNEL, USB_CHANNEL) + + # 3 - Set MTM-IO-SERIAL Rail 1 and measure the voltage using MTM-USBSTEM A2D1 + step(ioserial.rail[1].setVoltage, 'setting Rail 1 voltage to %.3fV' % (RAIL1_SET_VOLTAGE/1.e6), RAIL1_SET_VOLTAGE) + step(ioserial.rail[1].setEnable, 'enabling Rail 1', 1) + sleep(CYCLE_TIME) + a2d1_voltage = step(stem.analog[1].getVoltage, 'reading A2D1 voltage') + print '* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *' + print 'MTM-IO-SERIAL Rail 1: %.3fV' % (RAIL1_SET_VOLTAGE/1.e6) + print 'MTM-USBSTEM A2D1: %.3fV' % (a2d1_voltage / 1.e6) + print '* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *' + + except Exception as exc: + print exc + + finally: + stem.disconnect() # Clean up possible remaining connections + pm.disconnect() + ioserial.disconnect() + del stem # Clean up MTM objects + del pm + del ioserial + + +if __name__ == '__main__': + main() diff --git a/api/examples/c_cpp/BrainStem2-Application-Notes/continuity_test.cpp b/api/examples/c_cpp/BrainStem2-Application-Notes/continuity_test.cpp new file mode 100755 index 0000000..9308545 --- /dev/null +++ b/api/examples/c_cpp/BrainStem2-Application-Notes/continuity_test.cpp @@ -0,0 +1,99 @@ +/**************************************************************** + * Filename: continuity_test.cpp + * Prepared By: James Dudley + * Date Prepared: March 5, 2018 + * Date Revised: March 5, 2018 + * Revision: 0.0.1 + ***************************************************************/ + +#include "BrainStem2/BrainStem-all.h" + +#define CYCLE_TIME 20 // Time to pause between readings, ms + +uint8_t continuity_pairs[][2] = {{0, 9}, {1, 10}, {2, 11}, {3, 12}, {4, 13}, {5, 14}}; +uint8_t n_cp = 6; + +int main(int argc, const char * argv[]) { + // Create BrainStem object + aMTMUSBStem stem; + + // Initialize error tracker + aErr err = aErrNone; + + // Discover and connect to MTM-USBStem object + // Connects to the first USB module discovered + err = stem.discoverAndConnect(USB); + if (err != aErrNone) { + printf("Error connecting to MTM-USBStem: %d\n", err); + return 0; + } + + // Set DIO configurations + uint8_t idx_cp = 0; + for (idx_cp = 0; idx_cp < n_cp; idx_cp++) { + uint8_t output_dio = continuity_pairs[idx_cp][0]; + uint8_t input_dio = continuity_pairs[idx_cp][1]; + + err = stem.digital[output_dio].setConfiguration(1); + if (err != aErrNone) { + printf("Error setting DIO%d configuration to output: %d\n", output_dio, err); + return 0; + } + + err = stem.digital[input_dio].setConfiguration(5); + if (err != aErrNone) { + printf("Error setting DIO%d configuration to input with pull-down: %d\n", input_dio, err); + return 0; + } + } + + // Test continuity between pairs + uint8_t continuity_array[n_cp][3]; + for (idx_cp = 0; idx_cp < n_cp; idx_cp++) { + uint8_t output_dio = continuity_pairs[idx_cp][0]; + uint8_t input_dio = continuity_pairs[idx_cp][1]; + + // Check continuity by raising the output HI (1) then LO (0) and verifying + // the corresponding input follows + uint8_t bContinuous = 1; + int8_t state = 1; + for (state = 1; state >= 0; state--) { + err = stem.digital[output_dio].setState(state); + if (err != aErrNone) { + printf("Error setting DIO%d to %d: %d\n", output_dio, state, err); + return 0; + } + + aTime_MSSleep(CYCLE_TIME); + + uint8_t read_state = 0; + err = stem.digital[input_dio].getState(&read_state); + if (err != aErrNone) { + printf("Error getting DIO%d state: %d\n", input_dio, err); + return 0; + } + + if (state != read_state) { + bContinuous = 0; + } + } + + continuity_array[idx_cp][0] = bContinuous; + continuity_array[idx_cp][1] = output_dio; + continuity_array[idx_cp][2] = input_dio; + } + + printf("* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n"); + for (idx_cp = 0; idx_cp < n_cp; idx_cp++) { + if (continuity_array[idx_cp][0] == 1) { + printf("DIO%d -- DIO%d: Continuous\n", continuity_array[idx_cp][1], continuity_array[idx_cp][2]); + } else { + printf("DIO%d -- DIO%d: Discontinuous\n", continuity_array[idx_cp][1], continuity_array[idx_cp][2]); + } + } + printf("* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n"); + + stem.disconnect(); + + return 0; +} diff --git a/api/examples/c_cpp/BrainStem2-Application-Notes/continuity_test.py b/api/examples/c_cpp/BrainStem2-Application-Notes/continuity_test.py new file mode 100755 index 0000000..1e43692 --- /dev/null +++ b/api/examples/c_cpp/BrainStem2-Application-Notes/continuity_test.py @@ -0,0 +1,88 @@ +############################################################################### +# Filename: continuity_test.py +# Prepared By: James Dudley +# Date Prepared: March 5, 2018 +# Date Revised: March 5, 2018 +# Revision: 0.0.1 +############################################################################### + +import brainstem # Import BrainStem API +from brainstem.result import Result # For easy access to error constants +from time import sleep, time + +CONTINUITY_PAIRS = [[0, 9], [1, 10], [2, 11], [3, 12], [4, 13], [5, 14]] # [output, input] +CYCLE_TIME = 0.2 # Time to pause between readings, seconds + +# Generic function to run BrainStem commands with error checking +def step(func, func_str, *args): + print '>> ' + func_str[0].upper() + func_str[1:] # Capitalize first letter of string + res = func(*args) + err = val = res + if isinstance(err, Result): + err = res.error + val = res.value + + if err is not Result.NO_ERROR: + raise Exception('Error %s: %d' % (func_str, err)) + + return val + + +def main(): + # Create MTM-USBSTEM object + stem = brainstem.stem.MTMUSBStem() # Uses default module address + + # Initialize error tracker + err = Result.NO_ERROR + + try: + # Discover and connect to MTM-PM-1 object + # Connects to the first USB module discovered + step(stem.discoverAndConnect, 'connecting to MTM-USBStem', brainstem.link.Spec.USB) + + # Set DIO configurations + for pair in CONTINUITY_PAIRS: + output_dio = pair[0] + input_dio = pair[1] + step(stem.digital[output_dio].setConfiguration, 'configuring DIO%d as output' % output_dio, 1) # Configuration value from datasheet + step(stem.digital[input_dio].setConfiguration, 'configuring DIO%d as input with pull-down' % input_dio, 5) # Configuration value from datasheet + + # Test continuity between pairs + continuity_array = [] + for pair in CONTINUITY_PAIRS: + output_dio = pair[0] + input_dio = pair[1] + + # Check continuity by raising the output HI (1), then LO (0) and verifying + # the corresponding input follows + bContinuous = True + for state in [1, 0]: + step(stem.digital[output_dio].setState, 'setting DIO%d to %d' % (output_dio, state), state) + + sleep(CYCLE_TIME) + + read_state = step(stem.digital[input_dio].getState, 'getting DIO%d state' % input_dio) + + if read_state != state: + bContinuous = False + + continuity_array.append([bContinuous, output_dio, input_dio]) + + print '* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *' + for idx in continuity_array: + if idx[0]: + print 'DIO%d -- DIO%d: Continuous' % (idx[1], idx[2]) + else: + print 'DIO%d -- DIO%d: Discontinuous' % (idx[1], idx[2]) + print '* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *' + + except Exception as exc: + print exc + + finally: + stem.disconnect() # Clean up possible remaining connections + del stem # Clean up MTM-USBSTEM object + + +if __name__ == '__main__': + main() diff --git a/api/examples/c_cpp/BrainStem2-Application-Notes/led_test.cpp b/api/examples/c_cpp/BrainStem2-Application-Notes/led_test.cpp new file mode 100755 index 0000000..f6cef20 --- /dev/null +++ b/api/examples/c_cpp/BrainStem2-Application-Notes/led_test.cpp @@ -0,0 +1,100 @@ +/**************************************************************** + * Filename: led_test.cpp + * Prepared By: James Dudley + * Date Prepared: February 26, 2018 + * Date Revised: February 26, 2018 + * Revision: 0.0.1 + ***************************************************************/ + +#include "BrainStem2/BrainStem-all.h" + +#define RESISTOR_VALUE 412 +#define POWER_VOLTAGE 5000000 +#define DAC 16 +#define CURRENT 14 +#define VOLTAGE 0 + +int main(int argc, const char * argv[]) { + // Create BrainStem object + aMTMDAQ1 daq; + + // Initialize error tracker + aErr err = aErrNone; + + // Discover and connect to MTM-DAQ-1 object + // Connects to the first USB module discovered + err = daq.discoverAndConnect(USB); + if (err != aErrNone) { + printf("Error connecting to MTM-DAQ-1: %d\n", err); + return 0; + } + + // Run the test twice, once with LED power enabled, once with it disabled + int8_t enable = 2; + for (enable = 1; enable >= 0; enable--) { + // Set MTM-DAQ-1 DAC0 (analog 16) to 5V and enable to power LED + err = daq.analog[DAC].setVoltage(POWER_VOLTAGE); + if (err != aErrNone) { + printf("Error setting DAC voltage: %d\n", err); + return 0; + } + err = daq.analog[DAC].setEnable(enable); + if (err != aErrNone) { + printf("Error setting DAC enable to %d: %d\n", enable, err); + return 0; + } + + // Set measurement ranges + err = daq.analog[VOLTAGE].setRange(12); + if (err != aErrNone) { + printf("Error setting Position B analog range to +/-10.24V: %d\n", err); + return 0; + } + err = daq.analog[CURRENT].setRange(9); + if (err != aErrNone) { + printf("Error setting Position A->B analog range to +/-5.12V: %d\n", err); + return 0; + } + + aTime_MSSleep(1000); // leave the LED on/off for a second + + // Read voltage measurements + int32_t v; + err = daq.analog[VOLTAGE].getVoltage(&v); + if (err != aErrNone) { + printf("Error reading Position B voltage: %d\n", err); + return 0; + } + int32_t v_current; + err = daq.analog[CURRENT].getVoltage(&v_current); + if (err != aErrNone) { + printf("Error reading Position A->B differential voltage: %d\n", err); + return 0; + } + + // Calculate current + int32_t i = v_current / RESISTOR_VALUE; // I = V / R + + printf("* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n"); + if (enable) { + printf("MTM-DAQ-1 DAC0 status: enabled\n"); + } else { + printf("MTM-DAQ-1 DAC0 status: disabled\n"); } + printf("Position B voltage (uV): %d\n", v); + printf("Position B voltage (V): %.3f\n", (float) v / 1e6); + printf("Position A->B voltage (uV): %d\n", v_current); + printf("Position A->B current (uA): %d\n", i); + printf("* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n"); + } + + err = daq.analog[DAC].setEnable(0); + if (err != aErrNone) { + printf("Error disabling DAC: %d\n", err); + return 0; + } + + daq.disconnect(); + + return 0; +} + diff --git a/api/examples/c_cpp/BrainStem2-Application-Notes/led_test.py b/api/examples/c_cpp/BrainStem2-Application-Notes/led_test.py new file mode 100755 index 0000000..2657091 --- /dev/null +++ b/api/examples/c_cpp/BrainStem2-Application-Notes/led_test.py @@ -0,0 +1,84 @@ +############################################################################### +# Filename: led_test.py +# Prepared By: James Dudley +# Date Prepared: February 26, 2018 +# Date Revised: February 26, 2018 +# Revision: 0.0.1 +############################################################################### + +import brainstem # import BrainStem API +from brainstem.result import Result # for easy access to error constants +from time import sleep + +RESISTOR_VALUE = 412 # Current-limiting resistor value, Ohms +POWER_VOLTAGE = 5000000 # LED power voltage setpoint, uV +DAC = 16 # Analog output index for LED power +CURRENT = 14 # Differential analog input index for current measurement +VOLTAGE = 0 # Single-ended analog input index for voltage measurement + +# Generic function to run BrainStem commands with error checking +def step(func, func_str, *args): + print '>> ' + func_str[0].upper() + func_str[1:] # Capitalize first letter of string + res = func(*args) + err = val = res + if isinstance(err, Result): + err = res.error + val = res.value + + if err is not Result.NO_ERROR: + raise Exception('Error %s: %d' % (func_str, err)) + + return val + + +def main(): + # Create MTM-DAQ-1 object + daq = brainstem.stem.MTMDAQ1() # Uses default module address + + # Initialize error tracker + err = Result.NO_ERROR + + try: + # Discover and connect to MTM-DAQ-1 object + # Connects to the first USB module discovered + step(daq.discoverAndConnect, 'connecting to MTM-DAQ-1', brainstem.link.Spec.USB) + + # Run the test twice, once with LED power enabled, once with it disabled + for enable, enable_str in zip([1, 0],['enabled', 'disabled']): + # Set MTM-DAQ-1 DAC0 (analog 16) to 5V and enable to power LED + step(daq.analog[DAC].setVoltage,'setting DAC voltage', POWER_VOLTAGE) # uV + step(daq.analog[DAC].setEnable,'setting DAC enable to %s' % enable_str, enable) # enable DAC0 + + # Set measurement ranges + step(daq.analog[VOLTAGE].setRange, 'setting Position B analog range to +/-10.24V', 12) # range value from datasheet + step(daq.analog[CURRENT].setRange, 'setting Position A->B analog range to +/-5.12V', 9) # range value from datasheet + + sleep(1) # Leave the LED on/off for a second + + # Read voltage measurements + v = step(daq.analog[VOLTAGE].getVoltage, 'reading Position B voltage') + v_current = step(daq.analog[CURRENT].getVoltage, 'reading Position A-B differential voltage') + + # Calculate current + i = v_current / RESISTOR_VALUE # I = V / R + + print '* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *' + print 'MTM-DAQ-1 DAC0 status: %s' % enable_str + print 'Position B voltage (uV): %d' % v + print 'Position B voltage (V): %.3f' % (v / 1e6) + print 'Position A->B voltage (uV): %d' % v_current + print 'Position A->B current (uA): %d' % i + print '* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *' + + step(daq.analog[DAC].setEnable, 'disabling DAC', 0) + + except Exception as exc: + print exc + + finally: + daq.disconnect() # Clean up possible remaining connections + del daq # Clean up MTM-DAQ-1 object + + +if __name__ == '__main__': + main() diff --git a/api/examples/c_cpp/BrainStem2-Application-Notes/short_test.cpp b/api/examples/c_cpp/BrainStem2-Application-Notes/short_test.cpp new file mode 100755 index 0000000..c0244a4 --- /dev/null +++ b/api/examples/c_cpp/BrainStem2-Application-Notes/short_test.cpp @@ -0,0 +1,88 @@ +/**************************************************************** + * Filename: led_test.cpp + * Prepared By: James Dudley + * Date Prepared: February 26, 2018 + * Date Revised: February 26, 2018 + * Revision: 0.0.1 + ***************************************************************/ + +#include "BrainStem2/BrainStem-all.h" + +#define RAIL 1 // Power rail to use for test +#define VOLTAGE 3300000 // Set voltage for Rail 0 +#define CYCLE_TIME 20 // Time to pause between readings, ms +#define TOTAL_TIME 5000 // Time to keep test running, seconds + +int main(int argc, const char * argv[]) { + // Create BrainStem object + aMTMPM1 pm; + + // Initialize error tracker + aErr err = aErrNone; + + // Discover and connect to MTM-PM-1 object + // Connects to the first USB module discovered + err = pm.discoverAndConnect(USB); + if (err != aErrNone) { + printf("Error connecting to MTM-PM-1: %d\n", err); + return 0; + } + + if (RAIL == 0) { + // Set Rail voltage + err = pm.rail[RAIL].setVoltage(VOLTAGE); + if (err != aErrNone) { + printf("Error setting Rail %d voltage to %d: %d\n", RAIL, VOLTAGE, err); + return 0; + } + } + + // Enable Rail + err = pm.rail[RAIL].setEnable(1); + if (err != aErrNone) { + printf("Error enabling Rail %d: %d\n", RAIL, err); + return 0; + } + + uint16_t time = 0; + while (time < TOTAL_TIME) { + time += CYCLE_TIME; + // Get MTM-PM-1 Rail enable state + uint8_t enable; + err = pm.rail[RAIL].getEnable(&enable); + if (err != aErrNone) { + printf("Error getting Rail %d enable state: %d\n", RAIL, err); + return 0; + } + + // Read MTM-PM-1 Rail voltage + int32_t v_rail; + err = pm.rail[RAIL].getVoltage(&v_rail); + if (err != aErrNone) { + printf("Error reading 'sensor' voltage: %d\n", err); + return 0; + } + + printf("* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n"); + if (enable == 0) { + printf("Enable State: OFF\n"); + } else { + printf("Enable State: ON\n"); + } + printf("Rail voltage (V): %.3f\n", (float) v_rail / 1e6); + printf("* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\n"); + + aTime_MSSleep(CYCLE_TIME); + } + + err = pm.rail[RAIL].setEnable(0); + if (err != aErrNone) { + printf("Error disabling Rail %d: %d\n", RAIL, err); + return 0; + } + + pm.disconnect(); + + return 0; +} + diff --git a/api/examples/c_cpp/BrainStem2-Application-Notes/short_test.py b/api/examples/c_cpp/BrainStem2-Application-Notes/short_test.py new file mode 100755 index 0000000..820e2c7 --- /dev/null +++ b/api/examples/c_cpp/BrainStem2-Application-Notes/short_test.py @@ -0,0 +1,80 @@ +############################################################################### +# Filename: short_test.py +# Prepared By: James Dudley +# Date Prepared: March 2, 2018 +# Date Revised: March 2, 2018 +# Revision: 0.0.1 +############################################################################### + +import brainstem # Import BrainStem API +from brainstem.result import Result # For easy access to error constants +from time import sleep, time + +RAIL = 1 # Power rail to use for test +VOLTAGE = 3300000 # Set voltage for Rail 0 +CYCLE_TIME = 0.2 # Time to pause between readings, seconds +TOTAL_TIME = 5 # Time to keep test running, seconds + +# Generic function to run BrainStem commands with error checking +def step(func, func_str, *args): + print '>> ' + func_str[0].upper() + func_str[1:] # Capitalize first letter of string + res = func(*args) + err = val = res + if isinstance(err, Result): + err = res.error + val = res.value + + if err is not Result.NO_ERROR: + raise Exception('Error %s: %d' % (func_str, err)) + + return val + + +def main(): + # Create MTM-PM-1 object + pm = brainstem.stem.MTMPM1() # Uses default module address + + # Initialize error tracker + err = Result.NO_ERROR + + try: + # Discover and connect to MTM-PM-1 object + # Connects to the first USB module discovered + step(pm.discoverAndConnect, 'connecting to MTM-PM-1', brainstem.link.Spec.USB) + + if RAIL is 0: + # Set Rail voltage + step(pm.rail[RAIL].setVoltage,'setting Rail %d voltage to %d' % (RAIL, VOLTAGE), 1) + + # Enable Rail + step(pm.rail[RAIL].setEnable,'enabling Rail %d' % RAIL, 1) + + enable_str = ['OFF', 'ON'] + tStart = tNow = time() + while tNow < tStart + TOTAL_TIME: + tNow = time() + # Get MTM-PM-1 Rail enable state + enable = step(pm.rail[RAIL].getEnable, 'reading Rail %d enable state' % RAIL) + + # Read MTM-PM-1 Rail voltage + v = step(pm.rail[RAIL].getVoltage, 'reading Rail %d voltage' % RAIL) + + print '* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *' + print 'Enable State: %s' % enable_str[enable] + print 'Rail voltage (V): %.3f' % (v / 1.e6) + print '* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *' + + sleep(CYCLE_TIME) + + step(pm.rail[RAIL].setEnable, 'disabling Rail %d' % RAIL, 0) + + except Exception as exc: + print exc + + finally: + pm.disconnect() # Clean up possible remaining connections + del pm # Clean up MTM-PM-1 object + + +if __name__ == '__main__': + main() diff --git a/api/examples/c_cpp/BrainStem2-C-Example/BrainStem2Example/main.c b/api/examples/c_cpp/BrainStem2-C-Example/BrainStem2Example/main.c new file mode 100755 index 0000000..ba5991d --- /dev/null +++ b/api/examples/c_cpp/BrainStem2-C-Example/BrainStem2Example/main.c @@ -0,0 +1,371 @@ +// +// main.c +// BrainStem2Example C +// +///////////////////////////////////////////////////////////////////// +// // +// Copyright (c) 2018 Acroname Inc. - All Rights Reserved // +// // +// This file is part of the BrainStem release. See the license.txt // +// file included with this package or go to // +// https://acroname.com/software/brainstem-development-kit // +// for full license details. // +///////////////////////////////////////////////////////////////////// + +#include +#include "BrainStem2/BrainStem-C.h" +#include "BrainStem2/aProtocoldefs.h" + +aErr getPacket32(aLinkRef stem, uint8_t command, uint8_t option, uint32_t *responseValue); +aErr getFirmwareVersion(aLinkRef stem); +aErr toggleUserLED(aLinkRef stem); +aErr getInputVoltage(aLinkRef stem); + +uint8_t moduleAddress = 0; + +int main(int argc, const char * argv[]) { + + linkSpec* spec = NULL; + aLinkRef stem = 0; + aErr err = aErrNone; + uint8_t count = 0; + uint32_t voltage = 0; + + //Set the global module address (device specific: i.e. 40pin = 2, MTMStem = 4) + //Pitfall: Software and Hardware offsets contribute to this value. + moduleAddress = 6; // USBHub3p + + printf("Finding the first BrainStem USB module.\n"); + + printf("\n"); + + spec = aDiscovery_FindFirstModule(USB, LOCALHOST_IP_ADDRESS); + + if (spec != NULL && spec->t.usb.usb_id != 0) { + printf("Connecting to BrainStem module %08X\n", spec->t.usb.usb_id); + + // If the link creation fails, a reference identifier of 0 is returned. + stem = aLink_CreateUSB(spec->t.usb.usb_id); + if (stem == 0) { + fprintf(stderr, "Error creating link.\n"); + return 1; + } + } + else{ + fprintf(stderr, "No BrainStem module was discovered.\n"); + return 1; + } + + aLinkSpec_Destroy(&spec); + + printf("BrainStem module connected.\n"); + + // Wait up to 300 milliseconds for the connection to be established. + // Start returns after a transport is established, but communications + // may not be ready. When using the C library layer it is up to the user + // to check that the connetion is ready and running. + + while ((aLink_GetStatus(stem) != RUNNING) && (count < 30)) { + count++; + aTime_MSSleep(10); + } + + if (count >= 30 && aLink_GetStatus(stem) != RUNNING) { + printf("BrainStem connection failed!\n"); + aLink_Destroy(&stem); + return 1; + } + + printf("Connected after %d milliseconds.\n", count * 10); + + printf("\n"); + + // Get and print the module firmware version + printf("Get the module firmware version.\n"); + err = getFirmwareVersion(stem); + if (err != aErrNone) { printf("Error in getFirmwareVersion(): %d\n", err); } + + printf("\n"); + + // Get and print the module input voltage + // use the generalized getUEI32 interface + printf("Get the module input voltage.\n"); + err = getInputVoltage(stem); + if (err != aErrNone) { printf("Error in getInputVoltage(): %d\n", err); } + + printf("\n"); + + printf("Get the module input voltage with generic interface.\n"); + err = getPacket32(stem, cmdSYSTEM, systemInputVoltage, &voltage); + if (err == aErrNone) { printf("System input voltage: %.3fV\n", (float)voltage/1.0e6); } + else { printf("Error in getPacket32(): %d\n", err); } + + printf("\n"); + + // Blink the User LED. + printf("Toggling the User LED.\n"); + err = toggleUserLED(stem); + if (err != aErrNone) { printf("Error in toggleUserLED(): %d\n", err); } + + printf("\n"); + + if (stem != 0) { + // Clean up our resources. + err = aLink_Destroy(&stem); + } + + if (err != aErrNone) { return 1; } + else { return 0; } + +} + +// Match for systemVersion +static uint8_t sSystemVersion(const aPacket* p, const void* vpRef) { + return (p->data[0] == cmdSYSTEM && (p->data[1] & ueiOPTION_MASK) == systemVersion); +} +aErr getFirmwareVersion(aLinkRef stem){ + // Set up some packet and data arrays + uint8_t pData[aBRAINSTEM_MAXPACKETBYTES]; + aPacket* packet = NULL; + aPacket* response = NULL; + aErr err = aErrNone; + uint32_t version = 0; + + // Get the module's firmware version + pData[0] = cmdSYSTEM; + pData[1] = ueiOPTION_GET | systemVersion; + pData[2] = ueiSPECIFIER_RETURN_HOST; + + // build a packet with the command + packet = aPacket_CreateWithData(moduleAddress, + 3, // pData length in bytes + pData); + if (packet != NULL) { + // send the command to the module via the link we created + err = aLink_PutPacket(stem, packet); + if (err != aErrNone) { printf("Error with aLink_PutPacket: %d\n", err); } + err = aPacket_Destroy(&packet); + if (err != aErrNone) { printf("Error with aPacket_Destroy: %d\n", err); } + + // We await a response here. We could exit or perform some corrective. + // action. + response = aLink_AwaitFirst(stem, sSystemVersion , NULL, 2000); + if (response == NULL) { + printf("Error awaiting packet\n"); + return aErrIO; + } + + // grab the version from the response packet + version = ((response->data[3])<<24) | ((response->data[4])<<16) | + ((response->data[5])<<8) | ((response->data[6])); + + //We can, and should, destroy the packet here to clean up. + err = aPacket_Destroy(&response); + if (err != aErrNone) { printf("Error with aPacket_Destroy: %d\n", err); } + } else { + // the creation of a packet failed + err = aErrMemory; + printf("Could not create packet\n"); + } + + // for pretty-printing, throw out the patch build-hash information; + // keep just the patch-version nibble + printf("Firmware version: %d.%d.%d\n", aVersion_ParseMajor(version), + aVersion_ParseMinor(version), aVersion_ParsePatch(version)); + + return err; +} + + +// Match packet proc. Here we match a systemLED set response. +static uint8_t sSystemLED(const aPacket* p, const void* vpRef) { + return (p->data[0] == cmdSYSTEM && (p->data[1] & ueiOPTION_MASK) == systemLED); +} +aErr toggleUserLED(aLinkRef stem){ + // Set up some packet and data arrays + uint8_t pData[4]; + aPacket* packet = NULL; + aPacket* response = NULL; + uint8_t i = 0; + aErr err = aErrNone; + + for( i = 0; i <= 10; i++) { + // create a command to turn the LED to bOn + pData[0] = cmdSYSTEM; + pData[1] = ueiOPTION_SET | systemLED; + pData[2] = ueiSPECIFIER_RETURN_HOST; + pData[3] = i%2; + + // build a packet with the command + packet = aPacket_CreateWithData(moduleAddress, + 4, // pData length in bytes + pData); + if (packet != NULL) { + // send the command to the module via the link we created + err = aLink_PutPacket(stem, packet); + if (err != aErrNone) { printf("Error with aLink_PutPacket: %d\n", err); } + err = aPacket_Destroy(&packet); + if (err != aErrNone) { printf("Error with aPacket_Destroy: %d\n", err); } + // We await a response here. We could exit or perform some corrective. + // action. + response = aLink_AwaitFirst(stem, sSystemLED , NULL, 2000); + if (response == NULL) { + printf("error awaiting packet\n"); + return aErrIO; + } + //We can, and should, destroy the packet here to clean up. + err = aPacket_Destroy(&response); + if (err != aErrNone) { printf("Error with aPacket_Destroy: %d\n", err); } + } else { + // the creation of a packet failed + err = aErrMemory; + } + + if (err != aErrNone) { + fprintf(stderr, "Error %d communicating with BrainStem module, exiting.\n", err); + break; + } + // We use the Acroname aTime utility here to avoid platform specific sleep issues. + aTime_MSSleep(250); + } // end for i < 10 + + return err; +} + + +// Match for systemInputVoltage +static uint8_t sSystemInputVoltage(const aPacket* p, const void* vpRef) { + return (p->data[0] == cmdSYSTEM && (p->data[1] & ueiOPTION_MASK) == systemInputVoltage); +} +aErr getInputVoltage(aLinkRef stem){ + // Set up some packet and data arrays + uint8_t pData[4]; + aPacket* packet = NULL; + aPacket* response = NULL; + aErr err = aErrNone; + uint32_t voltage = 0; + + // Get the module's firmware version + pData[0] = cmdSYSTEM; + pData[1] = ueiOPTION_GET | systemInputVoltage; + pData[2] = ueiSPECIFIER_RETURN_HOST; + + // build a packet with the command + packet = aPacket_CreateWithData(moduleAddress, + 3, // pData length in bytes + pData); + if (packet != NULL) { + // send the command to the module via the link we created + err = aLink_PutPacket(stem, packet); + if (err != aErrNone) { printf("Error with aLink_PutPacket: %d\n", err); } + err = aPacket_Destroy(&packet); + if (err != aErrNone) { printf("Error with aPacket_Destroy: %d\n", err); } + + // We await a response here. We could exit or perform some corrective. + // action. + response = aLink_AwaitFirst(stem, sSystemInputVoltage , NULL, 2000); + //response = aLink_AwaitPacket(stem, 2000); + if (response == NULL) { + printf("error awaiting packet\n"); + return aErrIO; + } + + // grab the voltage from the response packet + voltage = ((response->data[3])<<24) | ((response->data[4])<<16) | + ((response->data[5])<<8) | ((response->data[6])); + + //We can, and should, destroy the packet here to clean up. + err = aPacket_Destroy(&response); + if (err != aErrNone) { printf("Error with aPacket_Destroy: %d\n", err); } + } else { + // the creation of a packet failed + err = aErrMemory; + } + + // print out the voltage + printf("System input voltage: %.3f\n", (float)voltage/1.0e6); + + return err; +} + + +// The above functions are the brute force way to do BrainStem packet handling. +// Clearly these can be abstracted into a generic interface (a UEI). The +// following sets up a generic packet filter for a given command/option. One +// should also check for error packets with matching command/option. This is +// left as an exercise for the reader. (Hint: put it in the packet filter and +// handle the error packet after the filter). +static uint8_t sPacketFilter(const aPacket* packet, const void* vpRef) { + aPacket* query = (aPacket*)vpRef; + return (packet->address == query->address && + packet->data[0] == query->data[0] && + packet->data[1] == query->data[1]); +} +aErr getPacket32(aLinkRef stem, uint8_t command, uint8_t option, uint32_t *responseValue){ + uint8_t pData[4]; + aPacket* packet = NULL; + aPacket* response = NULL; + aErr err = aErrNone; + + if(!responseValue){ + return aErrMemory; + } + + // Get the module's firmware version + pData[0] = command; + pData[1] = ueiOPTION_GET | option; + pData[2] = ueiSPECIFIER_RETURN_HOST; + + // build a packet with the command + packet = aPacket_CreateWithData(moduleAddress, + 3, // pData length in bytes + pData); + if (packet == NULL) { + // the creation of a packet failed + return aErrMemory; + } + + // send the command to the module via the link we created + err = aLink_PutPacket(stem, packet); + if (err != aErrNone) { printf("Error with aLink_PutPacket: %d\n", err); } + err = aPacket_Destroy(&packet); + if (err != aErrNone) { printf("Error with aPacket_Destroy: %d\n", err); } + + // We await a response here. + // Change the packet to ba a val (response) type with the same cmd/option + pData[0] = command; + pData[1] = ueiOPTION_VAL | option; + pData[2] = ueiSPECIFIER_RETURN_HOST; + packet = aPacket_CreateWithData(moduleAddress, + 3, // pData length in bytes + pData); + if (packet == NULL) { + // the creation of a packet failed + return aErrMemory; + } + + response = aLink_AwaitFirst(stem, sPacketFilter, packet, 1000); + aPacket_Destroy(&packet); + if (response == NULL) { + printf("error awaiting packet\n"); + return aErrIO; + } + + + + // grab the version from the response packet + // data[0] = command + // data[1] = operation|option + // data[2] = reply|index + // data[3] = high data byte + // data[4..] = data bytes... + // https://acroname.com/reference/brainstem/appendix/uei.html + *responseValue = ((response->data[3])<<24) | ((response->data[4])<<16) | + ((response->data[5])<<8) | ((response->data[6])); + + //Destroy the response packet here to clean up + err = aPacket_Destroy(&response); + if (err != aErrNone) { printf("Error with aPacket_Destroy: %d\n", err); } + + return err; +} diff --git a/api/examples/c_cpp/BrainStem2-C-Example/How_to_Build.txt b/api/examples/c_cpp/BrainStem2-C-Example/How_to_Build.txt new file mode 100755 index 0000000..48e296e --- /dev/null +++ b/api/examples/c_cpp/BrainStem2-C-Example/How_to_Build.txt @@ -0,0 +1,23 @@ +=============================================================================== +BrainStem 2.0 C Example Readme +=============================================================================== + +This is a basic example of communication with a BrainStem USB module using the +BrainStem Universal Entity Interface (UEI) to read the firmware version, toggle +the user LED and measure the input voltage. + +Notes: +=============================================================================== + +# To build, copy the lib directory into this directory. The lib directory contains + the required header files, and the Brainstem2 shared object file. + +# The output directory is linux_BrainStem2Example/Debug. + +# A build step has been added to the project that copies the shared object into + the build output directory. In addition the runpath is updated to search in + the same directory as the executable. + +If you have questions, please see the reference, or check out our guides +at www.acroname.com. + diff --git a/api/examples/c_cpp/BrainStem2-C-Example/makefile b/api/examples/c_cpp/BrainStem2-C-Example/makefile new file mode 100755 index 0000000..ed2f6b8 --- /dev/null +++ b/api/examples/c_cpp/BrainStem2-C-Example/makefile @@ -0,0 +1,46 @@ +# Brainstem2Example C + +CC = gcc +ROOT = . +TARGET = BrainStem2Example +OUT := linux_$(TARGET) +DBG_DST := $(OUT)/Debug +REL_DST := $(OUT)/Release + + +# We are looking for the BrainStem2 library in +# a lib folder sibling to this makefile. Change +# these defines to point somewhere else if this +# is not the case. +LIBRARIES := -Llib/ -lBrainStem2 +INCLUDES := -Ilib + +# We add the current directory to the rpath expecting +# that libBrainStem2.so will be copied into the build +# folder. If this is not the case adjust the rpath +# do match your needs. +CFLAGS = -Wall -Werror -Wl,-rpath,. $(INCLUDES) + +all : dirs + make app + +app : debug release + +.PHONY : debug +debug: dirs + $(CC) $(CFLAGS) BrainStem2Example/main.c $(LIBRARIES) -o $(DBG_DST)/BrainStem2Example + cp lib/libBrainStem2.so $(DBG_DST) + +.PHONY : release +release: dirs + $(CC) $(CFLAGS) -DNDEBUG BrainStem2Example/main.c $(LIBRARIES) -o $(REL_DST)/BrainStem2Example + cp lib/libBrainStem2.so $(REL_DST) + +.PHONY : dirs +dirs: + mkdir -p $(DBG_DST) + mkdir -p $(REL_DST) + +clean: + rm -rf $(OUT) + diff --git a/api/examples/c_cpp/BrainStem2-C-Port-Mapping/BrainStem2Example/main.c b/api/examples/c_cpp/BrainStem2-C-Port-Mapping/BrainStem2Example/main.c new file mode 100755 index 0000000..cba909e --- /dev/null +++ b/api/examples/c_cpp/BrainStem2-C-Port-Mapping/BrainStem2Example/main.c @@ -0,0 +1,42 @@ +// +// main.cpp +// BrainStem2Example +// +// Created by Acroname Inc. on 1/16/15. +// Copyright (c) 2015 Acroname Inc. All rights reserved. +// + +#include "BrainStem2/BrainStem-C.h" +#include // standard input / output functions + +#define LIST_LENGTH (128U) + +int main(int argc, const char * argv[]) { + + DeviceNode_t list[LIST_LENGTH]; + uint32_t itemsCreated = 0; + aErr err = getDownstreamDevices(list, LIST_LENGTH, &itemsCreated); + printf("Items Created: %d\n", itemsCreated); + + if (err == aErrNone) { + for (uint32_t x = 0; x < itemsCreated; x++) { + printf("SN: %X\n", list[x].hubSerialNumber); + printf("Port: %X\n", list[x].hubPort); + printf(" -VendorID: 0x%04X\n", list[x].idVendor); + printf(" -ProductID: 0x%04X\n", list[x].idProduct); + printf(" -Serial Number: %s\n", list[x].serialNumber); + printf(" -Product: %s\n", list[x].productName); + printf(" -Manufacturer: %s\n", list[x].manufacturer); + printf(" -Speed: %d\n", list[x].speed); + printf("\n"); + } + } + else if (err == aErrParam) { printf("One of the parameters you passed in is not valid. \n"); } + else if (err == aErrMemory) { printf("Device list does not have enough room. \n"); } + else if (err == aErrNotFound) { printf("No Acroname devices were found. \n"); } + else { printf("Unknown error case: %d\n", err); } + + return 0; +} + + diff --git a/api/examples/c_cpp/BrainStem2-C-Port-Mapping/How_to_Build.txt b/api/examples/c_cpp/BrainStem2-C-Port-Mapping/How_to_Build.txt new file mode 100755 index 0000000..2520fbf --- /dev/null +++ b/api/examples/c_cpp/BrainStem2-C-Port-Mapping/How_to_Build.txt @@ -0,0 +1,22 @@ +=============================================================================== +BrainStem 2.0 C Port Mapping Example +=============================================================================== + +This examples shows how a user can query the downstream device information +of Acronames USB hubs. + +Notes: +=============================================================================== + +# To build, copy the lib directory into this directory. The lib directory contains + the required header files, and the Brainstem2 shared object file. + +# The output directory is linux_BrainStem2Example/Debug. + +# A build step has been added to the project that copies the shared object into + the build output directory. In addition the runpath is updated to search in + the same directory as the executable. + +If you have questions, please see the reference, or check out our guides +at www.acroname.com. + diff --git a/api/examples/c_cpp/BrainStem2-C-Port-Mapping/makefile b/api/examples/c_cpp/BrainStem2-C-Port-Mapping/makefile new file mode 100755 index 0000000..ed2f6b8 --- /dev/null +++ b/api/examples/c_cpp/BrainStem2-C-Port-Mapping/makefile @@ -0,0 +1,46 @@ +# Brainstem2Example C + +CC = gcc +ROOT = . +TARGET = BrainStem2Example +OUT := linux_$(TARGET) +DBG_DST := $(OUT)/Debug +REL_DST := $(OUT)/Release + + +# We are looking for the BrainStem2 library in +# a lib folder sibling to this makefile. Change +# these defines to point somewhere else if this +# is not the case. +LIBRARIES := -Llib/ -lBrainStem2 +INCLUDES := -Ilib + +# We add the current directory to the rpath expecting +# that libBrainStem2.so will be copied into the build +# folder. If this is not the case adjust the rpath +# do match your needs. +CFLAGS = -Wall -Werror -Wl,-rpath,. $(INCLUDES) + +all : dirs + make app + +app : debug release + +.PHONY : debug +debug: dirs + $(CC) $(CFLAGS) BrainStem2Example/main.c $(LIBRARIES) -o $(DBG_DST)/BrainStem2Example + cp lib/libBrainStem2.so $(DBG_DST) + +.PHONY : release +release: dirs + $(CC) $(CFLAGS) -DNDEBUG BrainStem2Example/main.c $(LIBRARIES) -o $(REL_DST)/BrainStem2Example + cp lib/libBrainStem2.so $(REL_DST) + +.PHONY : dirs +dirs: + mkdir -p $(DBG_DST) + mkdir -p $(REL_DST) + +clean: + rm -rf $(OUT) + diff --git a/api/examples/c_cpp/BrainStem2-CCA-Example/BrainStem2Example/main.c b/api/examples/c_cpp/BrainStem2-CCA-Example/BrainStem2Example/main.c new file mode 100755 index 0000000..1ef8f40 --- /dev/null +++ b/api/examples/c_cpp/BrainStem2-CCA-Example/BrainStem2Example/main.c @@ -0,0 +1,66 @@ +// +// main.c +// BrainStem2Example +// +// Created by Acroname Inc. on 1/16/15. +// Copyright (c) 2015 Acroname Inc. All rights reserved. +// + +#include "BrainStem2/BrainStem-C.h" //aTime_MSSleep +#include "BrainStem2_CCA/CCA_All.h" +#include // standard input / output functions + +#define SYSTEM_INDEX (0U) + +int main(int argc, const char * argv[]) { + + unsigned int id = 0; //Stem ID. Will be assigned by the module_createStem call. + struct Result result; + + //- If autoNetworking is True then moduleAddress has no meaning. Set it to 0 + //- If model is set and the serial number in discoverAndConnect is 0 then + // connection will only occur if the model matches the one provided. + // We use 0 here for simplicity. + module_createStem(&id, &result, 0, true, 0); + + //- linkType of 1 is used for USB. + //- If serialNumber = 0 a connection will be made to the first device that is + // found which has a matching model (unless model is 0). + //- Special care should be taken when working with multiple stems to ensure + // you are connected to the one you expect. + module_discoverAndConnect(&id, &result, 1, 0); + if(result.error) { + printf("Error trying to connect - Error: %d\n", result.error); + return 1; + } + + system_getSerialNumber(&id, &result, SYSTEM_INDEX); + if(aErrNone == result.error) { + printf("Serial Number: 0x%08X\n", result.value); + } + + printf("Toggling the user LED\n"); + static const uint8_t TOGGLES = 10; + for(uint8_t x = 0; x < TOGGLES; x++) { + system_getLED(&id, &result, 0); + if(aErrNone == result.error ) { + printf("Loop: %d/%d - Current LED State: %d - Changing to %d\n", x+1, TOGGLES, result.value, !result.value); + } + + system_setLED(&id, &result, SYSTEM_INDEX, !result.value); + + aTime_MSSleep(1000); + } + + system_getInputVoltage(&id, &result, 0); + if(aErrNone == result.error) { + printf("System Voltage: %.2fVDC\n", result.value/1000000.0); + } + + //Disconnect and cleanup memory. + module_disconnectAndDestroyStem(&id, &result); + + return 0; +} + + diff --git a/api/examples/c_cpp/BrainStem2-CCA-Example/How_to_Build.txt b/api/examples/c_cpp/BrainStem2-CCA-Example/How_to_Build.txt new file mode 100755 index 0000000..ad2b977 --- /dev/null +++ b/api/examples/c_cpp/BrainStem2-CCA-Example/How_to_Build.txt @@ -0,0 +1,23 @@ +=============================================================================== +BrainStem 2.0 CCA Example +=============================================================================== + +This example shows how to use the CCA API. +The CCA (C++ to C Abstraction) API provides a C interface while also +proving high level features of the C++ interface. + +Notes: +=============================================================================== + +# To build, copy the lib directory into this directory. The lib directory contains + the required header files, and the Brainstem2 shared object file. + +# The output directory is linux_BrainStem2Example/Debug. + +# A build step has been added to the project that copies the shared objects into + the build output directory. In addition the runpath is updated to search in + the same directory as the executable. + +If you have questions, please see the reference, or check out our guides +at www.acroname.com. + diff --git a/api/examples/c_cpp/BrainStem2-CCA-Example/makefile b/api/examples/c_cpp/BrainStem2-CCA-Example/makefile new file mode 100755 index 0000000..4959988 --- /dev/null +++ b/api/examples/c_cpp/BrainStem2-CCA-Example/makefile @@ -0,0 +1,48 @@ +# Brainstem2Example C + +CC = gcc +ROOT = . +TARGET = BrainStem2Example +OUT := linux_$(TARGET) +DBG_DST := $(OUT)/Debug +REL_DST := $(OUT)/Release + + +# We are looking for the BrainStem2 library in +# a lib folder sibling to this makefile. Change +# these defines to point somewhere else if this +# is not the case. +LIBRARIES := -Llib/ -lBrainStem2 -lBrainStem2_CCA +INCLUDES := -Ilib + +# We add the current directory to the rpath expecting +# that libBrainStem2.so will be copied into the build +# folder. If this is not the case adjust the rpath +# do match your needs. +CFLAGS = -Wall -Werror -Wl,-rpath,. $(INCLUDES) + +all : dirs + make app + +app : debug release + +.PHONY : debug +debug: dirs + $(CC) $(CFLAGS) BrainStem2Example/main.c $(LIBRARIES) -o $(DBG_DST)/BrainStem2Example + cp lib/libBrainStem2.so $(DBG_DST) + cp lib/libBrainStem2_CCA.so $(DBG_DST) + +.PHONY : release +release: dirs + $(CC) $(CFLAGS) -DNDEBUG BrainStem2Example/main.c $(LIBRARIES) -o $(REL_DST)/BrainStem2Example + cp lib/libBrainStem2.so $(REL_DST) + cp lib/libBrainStem2_CCA.so $(REL_DST) + +.PHONY : dirs +dirs: + mkdir -p $(DBG_DST) + mkdir -p $(REL_DST) + +clean: + rm -rf $(OUT) + diff --git a/api/examples/c_cpp/BrainStem2-Client-Cpp-Example/BrainStem2Example/main.cpp b/api/examples/c_cpp/BrainStem2-Client-Cpp-Example/BrainStem2Example/main.cpp new file mode 100755 index 0000000..9d4548f --- /dev/null +++ b/api/examples/c_cpp/BrainStem2-Client-Cpp-Example/BrainStem2Example/main.cpp @@ -0,0 +1,200 @@ +// +// main.cpp +// BrainStem2-Client-Cpp-Example +// +// Created by Acroname Inc. on 5/20/2023. +// Copyright (c) 2023 Acroname Inc. All rights reserved. +// + +//This example is intended to highlight the multi-process and +//network capabilities of BrainStem modules. This application +//is intended to be used in conjunction with BrainStem2-Server-Cpp-Example +//however, it will work with any application or even HubTool +//if configured properly. + +//Note 1: +// The actual server is created by the first process to connect to the device. +// This means if you run this application first it would create/own +// the server. This is intended to smooth over the user experience +// but is important to remember when closing applications. If +// The "Server" application is closed it will result in the "Clients" +// losing access to the device. + +//Note 2: +// This application was created with the aUSBHub3p object. If +// your devices differs (say a USBCSwitch) you will need to change +// all instances of aUSBHub3p to aUSBCSwitch in order to connect to +// the device. This is a result of discoveryAndConnect as it will +// only connect to a device that matches the object type. It is +// possible to use the generic "Module" object; however, this was avoided +// in order to present a simplified example. + +//Note 3: +// If you intended to connect to a device that is not connected +// to your local machine or on your local intranet (local network) +// you will need to define a linkSpec with the intended ip and port +// number of the device and then use "connectFromSpec". +// Discovery works through broadcast and multicast packets; +// neither of which work for the internet (global network). +// For more connection types see the "Discovery-and-Connection" + +//Note 4: +// Additional network details are described in _configure_aEther(). + +/////////////////////////////////////////////////////////////////////////////// +// Includes +/////////////////////////////////////////////////////////////////////////////// + +#include "BrainStem2/BrainStem-all.h" + + +/////////////////////////////////////////////////////////////////////////////// +// Private Macros +/////////////////////////////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////////////// +// Private Types +/////////////////////////////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////////////// +// Private Function Prototypes +/////////////////////////////////////////////////////////////////////////////// + +void _configure_aEther(Acroname::BrainStem::Module& m); +void _print_aEtherConfig(Acroname::BrainStem::Module& m); +void _printProgramInfo(void); +void _printFailedConnection(void); + +/////////////////////////////////////////////////////////////////////////////// +// Public Data +/////////////////////////////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////////////// +// Private Data +/////////////////////////////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////////////// +// Public Function Implementations +/////////////////////////////////////////////////////////////////////////////// + + +int main(int argc, const char * argv[]) { + aErr e = aErrNone; + + aUSBHub3p stem; + //If your module is different, replace it with the appropriate module + //Such as a USBCSwitch as shown below. + //aUSBCSwitch stem; + + _configure_aEther(stem); + e = stem.discoverAndConnect(USB); + + if(aErrNone == e) { + _printProgramInfo(); printf("\n"); + _print_aEtherConfig(stem); + + //Loop for a long time so that we can see the interactions + //of the client and server. + static const uint32_t NUM_LOOPS = 10000; + for(uint32_t x = 0; x < NUM_LOOPS; x++) { + if(x % 20 == 0) { printf("Loop: %d\n", x); } + + uint32_t voltage = 0; + e = stem.system.getInputVoltage(&voltage); + printf("System Input Voltage: %0.3f VDC - error: %d\n", + double(voltage)/1000000, e); + } + + stem.disconnect(); + } + else { _printFailedConnection(); } + + return 0; +} + + +/////////////////////////////////////////////////////////////////////////////// +// Private Function Implementations +/////////////////////////////////////////////////////////////////////////////// + + +void +_printProgramInfo(void) { + printf("The aUSBHub3p client has been started.\n"); +} + +void +_configure_aEther(Acroname::BrainStem::Module& m) { + //NOTE: Network configuration MUST be done before connecting. + Acroname::BrainStem::aEtherConfig config; + aErr err = m.getConfig(&config); + if(err == aErrNone) { + //Controls the exposure of the device. By default, + //the device is only exposed on the localhost. + //True = localhost(default); False = Public; + //config.localOnly = false; //uncomment to test non-default values + + //Controls how strictly we honor the linkType (USB, NETWORK). + //Fallback allows for a smoother user experience when getting + //familiar with the device; however, it might be helpful to disable + //this so that you can control who is the server and who is the client. + //For instance if stem.discoverAndConnect(USB) fails it will automatically + //try stem.discoverAndConnect(Network) and vise-versa. + //True = fallback (default); False = NO fallback + //config.fallback = false; //uncomment to test non-default values + + //Controls if the Client-Server model is used. If you prefer to restrict + //the device to a single process you can disable this capability. + //By default the stem is enabled for multi-process use. + //True = Client-Server (default); False = Direct connection (not multi-process) + //config.enabled = false; //uncomment to test non-default values + + //Allows the user to select what network interface the stem will be exposed to. + //Default = LOCALHOST_IP_ADDRESS; (0 is also accepted for LOCALHOST_IP_ADDRESS); + //Available interfaces can be found with aDiscovery_GetIPv4Interfaces + //NOTE 1: + // If config.localOnly == true; This value is ignored. + // If config.localOnly == false; The stem will automatically pick + // the highest priority network interface and will ignore 0 and + // LOCALHOST_IP_ADDRESS values. However, you may override this value. + //config.networkInterface = LOCALHOST_IP_ADDRESS; + + //Apply the configuration. + aErr err = m.setConfig(config); + if(err) { printf("setConfig Error: %d\n", err); } + } +} + +void +_print_aEtherConfig(Acroname::BrainStem::Module& m) { + Acroname::BrainStem::aEtherConfig config; + aErr err = m.getConfig(&config); + + char sInterface[INET_ADDRSTRLEN]; + aDiscovery_ConvertIPv4Interface(config.networkInterface, sInterface, INET_ADDRSTRLEN); + + printf("Current aEther Config (error: %d):\n", err); + printf("\t Local Only: %d\n" \ + "\t Fallback: %d\n" \ + "\t Server Enabled: %d\n" \ + "\t Assigned Port: %d\n" \ + "\t Network Interface: %d (%s)\n", \ + config.localOnly, + config.fallback, + config.enabled, + config.assignedPort, + config.networkInterface, + sInterface); +} + + +void +_printFailedConnection(void) { + printf("Failed to discover Module\n"); + printf(" - Confirm device is connected to your machine\n"); + printf(" - Confirm object type. This examples default is \"aUSBHub3p\"\n"); +} diff --git a/api/examples/c_cpp/BrainStem2-Client-Cpp-Example/How_To_Build.txt b/api/examples/c_cpp/BrainStem2-Client-Cpp-Example/How_To_Build.txt new file mode 100755 index 0000000..194bad3 --- /dev/null +++ b/api/examples/c_cpp/BrainStem2-Client-Cpp-Example/How_To_Build.txt @@ -0,0 +1,25 @@ +=============================================================================== +BrainStem2-Client-Cpp-Example Readme +=============================================================================== + +This example is intended to highlight the multi-process and +network capabilities of BrainStem modules. This application +is intended to be used in conjunction with BrainStem2-Server-Cpp-Example +however, it will work with any application or even HubTool +if configured properly. + +Notes: +=============================================================================== + +# To build, copy the lib directory into this directory. The lib directory contains + the required header files, and the Brainstem2 shared object file. + +# The output directory is linux_BrainStem2Example/Debug. + +# A build step has been added to the project that copies the shared object into + the build output directory. In addition the runpath is updated to search in + the same directory as the executable. + +If you have questions, please see the reference, or check out our guides +at www.acroname.com. + diff --git a/api/examples/c_cpp/BrainStem2-Client-Cpp-Example/makefile b/api/examples/c_cpp/BrainStem2-Client-Cpp-Example/makefile new file mode 100755 index 0000000..14f9e06 --- /dev/null +++ b/api/examples/c_cpp/BrainStem2-Client-Cpp-Example/makefile @@ -0,0 +1,44 @@ +# Brainstem2Example C + +CPP = g++ +ROOT = . +TARGET = BrainStem2Example +OUT := linux_$(TARGET) +DBG_DST := $(OUT)/Debug +REL_DST := $(OUT)/Release + +# We are looking for the BrainStem2 library in +# a lib folder sibling to this makefile. Change +# these defines to point somewhere else if this +# is not the case. +LIBRARIES := -L$(ROOT)/lib -lBrainStem2 +INCLUDES := -Ilib/ + +# We add the current directory to the rpath expecting +# that libBrainStem2.so will be copied into the build +# folder. If this is not the case adjust the rpath +# do match your needs. +CFLAGS = -std=c++11 -Wall -Werror -Wl,-rpath,. $(INCLUDES) + +all : dirs + make app + +app : debug release + +.PHONY : debug +debug: + $(CPP) $(CFLAGS) BrainStem2Example/main.cpp $(LIBRARIES) -o $(DBG_DST)/BrainStem2Example + cp lib/libBrainStem2.so $(DBG_DST) +.PHONY : release +release: + $(CPP) $(CFLAGS) -DNDEBUG BrainStem2Example/main.cpp $(LIBRARIES) -o $(REL_DST)/BrainStem2Example + cp lib/libBrainStem2.so $(REL_DST) + +.PHONY : dirs +dirs: + mkdir -p $(DBG_DST) + mkdir -p $(REL_DST) + +clean: + rm -rf $(OUT) + diff --git a/api/examples/c_cpp/BrainStem2-Cpp-BulkCapture/BrainStem2Example/main.cpp b/api/examples/c_cpp/BrainStem2-Cpp-BulkCapture/BrainStem2Example/main.cpp new file mode 100755 index 0000000..5cc7bb8 --- /dev/null +++ b/api/examples/c_cpp/BrainStem2-Cpp-BulkCapture/BrainStem2Example/main.cpp @@ -0,0 +1,97 @@ +// +// main.cpp +// BrainStem2A2DBulkCapture +// +///////////////////////////////////////////////////////////////////// +// // +// Copyright (c) 2018 Acroname Inc. - All Rights Reserved // +// // +// This file is part of the BrainStem release. See the license.txt // +// file included with this package or go to // +// https://acroname.com/software/brainstem-development-kit // +// for full license details. // +///////////////////////////////////////////////////////////////////// + +#include "BrainStem2/BrainStem-all.h" + +//Constants +static const int BULK_CAPTURE_CHANNEL = 0; +static const int NUM_SAMPLES = 8000; +static const int SAMPLE_RATE = 200000; + +int main(int argc, const char * argv[]) { + + aErr err = aErrNone; + uint8_t captureState = bulkCaptureIdle; + + printf("Creating MTMStem Object\n"); + aMTMUSBStem stem; + + // Connect to the hardware. + // The only difference for TCP/IP modules is to change 'USB' to 'TCP'; + printf("Attempting to connect\n"); + err = stem.discoverAndConnect(USB); + if (err == aErrNone) printf("Connected\n"); + else { printf("Error connecting to device\n"); return 1; } + + printf("\n"); + printf("Configuring Bulk capture\n"); + printf("Analog Channel: %d\n", BULK_CAPTURE_CHANNEL); + printf("Number of Samples: %d\n", NUM_SAMPLES); + printf("Sample Rate: %d\n", SAMPLE_RATE); + printf("\n"); + err = stem.analog[BULK_CAPTURE_CHANNEL].setBulkCaptureNumberOfSamples(NUM_SAMPLES); + err = stem.analog[BULK_CAPTURE_CHANNEL].setBulkCaptureSampleRate(SAMPLE_RATE); + + printf("\n"); + printf("Starting bulk capture\n"); + stem.analog[BULK_CAPTURE_CHANNEL].initiateBulkCapture(); + //Wait for Bulk Capture to finnish. + //You can go do other stuff if you would like... Including other BrainStem functions. + //but you will need to check that it is finnished before unloading the data + do { + err = stem.analog[BULK_CAPTURE_CHANNEL].getBulkCaptureState(&captureState); + if(captureState == bulkCaptureError) { + printf("There was an Error with Bulk Capture\n"); + break; + } + aTime_MSSleep(100); + } while(captureState != bulkCaptureFinished); + + //Find out how many samples are in the ram slot + size_t nSize = 0; + err = stem.store[storeRAMStore].getSlotSize(0, &nSize); + + if (nSize && (err == aErrNone)) { + + uint8_t *rawData = new uint8_t[nSize]; + uint16_t combinedValue = 0; + size_t nSizeUnloaded = 0; + printf("Unloading data from the device:\n"); + err = stem.store[storeRAMStore].unloadSlot(0, nSize, rawData, &nSizeUnloaded); + + // Process 8bit values 2 bytes at a time for a 16bit value (Little Endian) + // i.e. + // val[0] = XXXXXXXX = LSB's + // val[1] = YYYYYYYY = MSB's + // combinedVal = YYYYYYYY XXXXXXXX for a 16 bit value + // Repeat until all the data has been processed + // Note: ",2" increments loop counter "i" by 2 + for(unsigned int x = 0; x < nSize; x+=2) { + combinedValue = 0; + combinedValue = rawData[x] + (rawData[x+1] << 8); + printf("Sample: %d, \t\tVoltage: %.3f, \tRaw: %d\n", x/2, + (combinedValue/65535.0)*3.3, + combinedValue); + }//end for + delete[] rawData; + rawData = NULL; + }//end if + + printf("Disconnecting from device"); + err = stem.disconnect(); + + + + return 0; +} diff --git a/api/examples/c_cpp/BrainStem2-Cpp-BulkCapture/How_To_Build.txt b/api/examples/c_cpp/BrainStem2-Cpp-BulkCapture/How_To_Build.txt new file mode 100755 index 0000000..e3478f0 --- /dev/null +++ b/api/examples/c_cpp/BrainStem2-Cpp-BulkCapture/How_To_Build.txt @@ -0,0 +1,23 @@ +=============================================================================== +BrainStem2 A2D Bulk Capture C++ Example Readme +=============================================================================== + +This is a C++ example for the BrainStem 2.0 library to demonstrate bulk capturing +A2D readings. When run, the module triggers a bulk reading on analog input 0, +retrieves the values from the RAM store slot and pipes the readings to STDOUT. + +Notes: +=============================================================================== + +# To build, copy the lib directory into this directory. The lib directory contains + the required header files, and the Brainstem2 shared object file. + +# The output directory is linux_Brainstem2A2DBulkCapture/Debug. + +# A build step has been added to the project that copies the shared object into + the build output directory. In addition the runpath is updated to search in + the same directory as the executable. + +If you have questions, please see the reference, or check out our guides +at www.acroname.com. + diff --git a/api/examples/c_cpp/BrainStem2-Cpp-BulkCapture/makefile b/api/examples/c_cpp/BrainStem2-Cpp-BulkCapture/makefile new file mode 100755 index 0000000..6d887d7 --- /dev/null +++ b/api/examples/c_cpp/BrainStem2-Cpp-BulkCapture/makefile @@ -0,0 +1,44 @@ +# Brainstem2A2DBulkCapture Cpp + +CPP = g++ +ROOT = . +TARGET = BrainStem2Example +OUT := linux_$(TARGET) +DBG_DST := $(OUT)/Debug +REL_DST := $(OUT)/Release + +# We are looking for the BrainStem2 library in +# a lib folder sibling to this makefile. Change +# these defines to point somewhere else if this +# is not the case. +LIBRARIES := -L$(ROOT)/lib -lBrainStem2 +INCLUDES := -Ilib/ + +# We add the current directory to the rpath expecting +# that libBrainStem2.so will be copied into the build +# folder. If this is not the case adjust the rpath +# do match your needs. +CFLAGS = -std=c++11 -Wall -Werror -Wl,-rpath,. $(INCLUDES) + +all : dirs + make app + +app : debug release + +.PHONY : debug +debug: dirs + $(CPP) $(CFLAGS) BrainStem2Example/main.cpp $(LIBRARIES) -o $(DBG_DST)/BrainStem2Example + cp lib/libBrainStem2.so $(DBG_DST) + +.PHONY : release +release: dirs + $(CPP) $(CFLAGS) -DNDEBUG BrainStem2Example/main.cpp $(LIBRARIES) -o $(REL_DST)/BrainStem2Example + cp lib/libBrainStem2.so $(REL_DST) + +.PHONY : dirs +dirs: + mkdir -p $(DBG_DST) + mkdir -p $(REL_DST) + +clean: + rm -rf $(OUT) diff --git a/api/examples/c_cpp/BrainStem2-Cpp-Discovery-and-Connection/BrainStem2Example/main.cpp b/api/examples/c_cpp/BrainStem2-Cpp-Discovery-and-Connection/BrainStem2Example/main.cpp new file mode 100755 index 0000000..5162261 --- /dev/null +++ b/api/examples/c_cpp/BrainStem2-Cpp-Discovery-and-Connection/BrainStem2Example/main.cpp @@ -0,0 +1,387 @@ +// +// main.cpp +// BrainStemConnectionExample +// +///////////////////////////////////////////////////////////////////// +// // +// Copyright (c) 2019 Acroname Inc. - All Rights Reserved // +// // +// This file is part of the BrainStem release. See the license.txt // +// file included with this package or go to // +// https://acroname.com/software/brainstem-development-kit // +// for full license details. // +///////////////////////////////////////////////////////////////////// + + +#include "BrainStem2/BrainStem-all.h" +#include + +using std::string; +using std::cout; +using std::endl; + +//declarations +void discoverAndConnect_Example(); +void sDiscover_Example(); +void findFirstModule_Example(); +void findModule_Example(); +void connectFromSpec_Example(); +void connectThroughLinkModule_Example(); + +//Main: +/////////////////////////////////////////////////////////////////////// +//This example shows the various ways to discover and connect to BrainStem +//modules/devices. +//NOTE: Not all functions will be successful. Many of the examples will +// require slight modification in order to work with your device. +// Please refer to the individual notes/comments in and around +// each function. +/////////////////////////////////////////////////////////////////////// + +int main(int arc, const char* arg[]) { + + discoverAndConnect_Example(); + + sDiscover_Example(); + + findFirstModule_Example(); + + findModule_Example(); + + connectFromSpec_Example(); + + connectThroughLinkModule_Example(); + + cout << "Finished!" << endl; +} +/////////////////////////////////////////////////////////////////////// + +// discoverAndConnect_Example: +/////////////////////////////////////////////////////////////////////// +// This is the most common form of connection. The discovery and connection +// process is enveloped into a single function. +// +// PITFALL: This function requires that the object type matches the device +// you are attempting to connect to and will likely require modification +// in order to work properly. +/////////////////////////////////////////////////////////////////////// + +void discoverAndConnect_Example() { + + // Used to catch errors connecting + aErr err = aErrNone; + // declaring SN variable + uint32_t serial_number = 0; + + // TODO: + // Uncomment the object that matches your device. + + //a40PinModule stem; + //aEtherStem stem; + //aMTMStemModule stem; + //aMTMEtherStem stem; + //aMTMIOSerial stem; + //aMTMPM1 stem; + //aMTMRelay stem; + //aMTMUSBStem stem; + //aMTMDAQ1 stem; + //aMTMDAQ2 stem; + //aUSBHub2x4 stem; + aUSBHub3p stem; + //aUSBHub3c stem; + //aUSBCSwitch stem; + //aUSBStem stem; + + //When no serial number is provided discoverAndConnect will attempt to + //connect to the first module it finds. If multiple BrainStem devices + //are connected to your machine it is unknown which device will be + //discovered first. + //Under the hood this function uses findFirstModule() + + cout << "Example: discoverAndConnect(USB);" << endl; + err = stem.discoverAndConnect(USB); + // Connection failure + if (err != aErrNone) { + cout << "Unable to find BrainStem Module. Error: "<< err << "." << endl; + cout << "Are you using the correct Module/Object type?" << endl; + } + // successful connection + else { + cout << "Found and Connected to a BrainStem Module." << endl; + stem.system.getSerialNumber(&serial_number); + } + stem.disconnect(); + cout << endl; + + //discoverAndConnect has an overload which accepts a Serial Number. + //The example immediately above will attempt to fetch the serial number + //and use it in this example. Feel free to drop in the + //serial number of your device. + //Under the hood this function uses a combination of sDiscover() and + //connectFromSpec(). + + // Put the serial number of your device here. + uint32_t user_serial_number = serial_number; + + cout << "Example: discoverAndConnect(USB, Serial_Number);" << endl; + err = stem.discoverAndConnect(USB, user_serial_number); + // unsuccessful connection + if (err != aErrNone) { + cout << "Unable to find BrainStem Module, Serial Number: " << user_serial_number << ", Error: " << err << endl; + cout << "Are you using the Module/Object type?" << endl; + } + // successful connection + else { + cout << "Found and Connected to a BrainStem Module." << endl; + } + stem.disconnect(); + cout << "Finished with discoverAndConnect example." << endl << + "--------------------------------------------------------" << endl; +}// end example + +/////////////////////////////////////////////////////////////////////// + +// sDiscover_Example: +/////////////////////////////////////////////////////////////////////// +// Highlights how to discover and interrogate multiple BrainStem devices +// without connecting to them. +// This is especially helpful for device agnostic applications. +/////////////////////////////////////////////////////////////////////// +void sDiscover_Example(){ + + list specList; + + //USB + cout << "Example: Link::sDiscover(USB, specList);" << endl << endl; + specList.clear(); + Acroname::BrainStem::Link::sDiscover(linkType::USB, &specList); + for (auto it = specList.begin(); it != specList.end(); it++) { + cout << "Model: " << it->model << endl; + cout << "Module: " << it->module << endl; + cout << "Serial Number: " << it->serial_num << endl; + cout << "Router: " << it->router << endl; + cout << "Router Serial Number: " << it->router_serial_num << endl; + cout << "USB ID: " << it->t.usb.usb_id << endl << endl; + } + ///////////////////////////////////////////////// + + //TCPIP + cout << "Example: Link::sDiscover(TCPIP, specList);" << endl << endl; + specList.clear(); + Acroname::BrainStem::Link::sDiscover(linkType::TCPIP, &specList); + for (auto it = specList.begin(); it != specList.end(); it++) { + cout << "Model: " << it->model << endl; + cout << "Module: " << it->module << endl; + cout << "Serial Number: " << it->serial_num << endl; + cout << "Router: " << it->router << endl; + cout << "Router Serial Number: " << it->router_serial_num << endl; + cout << "USB ID: " << it->t.usb.usb_id << endl << endl; + } + cout << "Finished with sDiscover example." << endl << + "--------------------------------------------------------" << endl; +}// end example +/////////////////////////////////////////////////////////////////////// + +// findFirstModule_Example: +/////////////////////////////////////////////////////////////////////// +// This example is similar to Discover and Connect, except it connects +// the first BrainStem it finds, rather than connecting to a specific +// device type. +/////////////////////////////////////////////////////////////////////// +void findFirstModule_Example() { + + linkSpec *spec = nullptr; + + cout << "Example: findFirstModule(USB);" << endl << endl; + spec = aDiscovery_FindFirstModule(linkType::USB, LOCALHOST_IP_ADDRESS); + if (spec != nullptr) { + cout << "Model: " << spec->model << endl; + cout << "Module: " << spec->module << endl; + cout << "Serial Number: " << spec->serial_num << endl; + cout << "Router: " << spec->router << endl; + cout << "Router Serial Number: " << spec->router_serial_num << endl; + cout << "USB ID: " << spec->t.usb.usb_id << endl << endl; + aLinkSpec_Destroy(&spec); //The spec should be cleaned up when finished. + } + else { cout << "No USB BrainStem device was found." << endl << endl; } + + + cout << "Example: findFirstModule(TCPIP);" << endl << endl; + spec = nullptr; + spec = aDiscovery_FindFirstModule(linkType::TCPIP, LOCALHOST_IP_ADDRESS); + if (spec != nullptr) { + cout << "Model: " << spec->model << endl; + cout << "Module: " << spec->module << endl; + cout << "Serial Number: " << spec->serial_num << endl; + cout << "Router: " << spec->router << endl; + cout << "Router Serial Number: " << spec->router_serial_num << endl; + cout << "USB ID: " << spec->t.usb.usb_id << endl << endl; + aLinkSpec_Destroy(&spec); //The spec should be cleaned up when finished. + } + else { cout << "No TCPIP BrainStem device was found." << endl; } + + cout << "Finished with findFirstModule example." << endl << + "--------------------------------------------------------" << endl; +} +/////////////////////////////////////////////////////////////////////// + +// findModule_Example: +/////////////////////////////////////////////////////////////////////// +// This example will connect to any BrainStem device given its serial +// number. It will not connect without a SN. +/////////////////////////////////////////////////////////////////////// +void findModule_Example() { + + //TODO: + //Plug in the serial number of your device. + + uint32_t serial_number = 0xB971001E; //Replace with your devices Serial Number. + linkSpec *spec = nullptr; + + cout << "Example: findModule(USB, Serial_Number);" << endl << endl; + spec = aDiscovery_FindModule(linkType::USB, serial_number, LOCALHOST_IP_ADDRESS); + if(spec != nullptr) { + cout << "Model: " << spec->model << endl; + cout << "Module: " << spec->module << endl; + cout << "Serial Number: " << spec->serial_num << endl; + cout << "Router: " << spec->router << endl; + cout << "Router Serial Number: " << spec->router_serial_num << endl; + cout << "USB ID: " << spec->t.usb.usb_id << endl << endl; + aLinkSpec_Destroy(&spec); //The spec should be cleaned up when finished. + } + else { cout << "No USB BrainStem device with serial number " << serial_number << " was found." << endl; } + + + //For TCP/IP devices. Will not be successful with USB based devices. + cout << "Example: findModule(TCPIP, Serial_Number);" << endl << endl; + spec = nullptr; + spec = aDiscovery_FindModule(linkType::TCPIP, serial_number, LOCALHOST_IP_ADDRESS); + if (spec != nullptr) { + cout << "Model: " << spec->model << endl; + cout << "Module: " << spec->module << endl; + cout << "Serial Number: " << spec->serial_num << endl; + cout << "Router: " << spec->router << endl; + cout << "Router Serial Number: " << spec->router_serial_num << endl; + cout << "USB ID: " << spec->t.usb.usb_id << endl << endl; + aLinkSpec_Destroy(&spec); //The spec should be cleaned up when finished. + } + else { cout << "No TCPIP BrainStem device with serial number " << serial_number << " was found." << endl; } + + cout << "Finished with findModule example." << endl << + "--------------------------------------------------------" << endl; +} +/////////////////////////////////////////////////////////////////////// + +// connectFromSpec_Example: +/////////////////////////////////////////////////////////////////////// +// Many of the discovery functions will return a linkSpec object. +// This function shows how to use that object to connect to a BrainStem +// device. +// The benefit of this connection method is that it does not care +// about which BrainStem object/module you use. +// i.e. you can connect to a USBHub3p from a USBStem object. However, +// the USBStem object does not possess a USB Entity and therfor will not be +// able to control the USBHub3p correctly. This is typically not +// recommended. +/////////////////////////////////////////////////////////////////////// +void connectFromSpec_Example() { + + aErr err = aErrNone; + + aUSBHub3p stem; + + cout << "Example: connectFromSpec(linkSpec);" << endl << endl; + linkSpec* spec = aDiscovery_FindFirstModule(linkType::USB, LOCALHOST_IP_ADDRESS); + if (spec != nullptr) { + + err = stem.connectFromSpec(*spec); + if (err != aErrNone) { + cout << "Unable to connect to BrianStem Module. Error: " << err << endl; + } + else { + cout << "Found and Connected to BrainStem Module" << endl; + stem.disconnect(); + } + aLinkSpec_Destroy(&spec); //The spec should be cleaned up when finished. + } + else { cout << "No BrainStem devices were found." << endl; } + + cout << "Finished with connectFromSpec example." << endl << + "--------------------------------------------------------" << endl; +} +/////////////////////////////////////////////////////////////////////// + + +// connectThroughLinkModule_Example(): +/////////////////////////////////////////////////////////////////////// +// This function allows a device to share the connection of another device. +// This feature is only available for Acroname's MTM and 40pin devices. +// +// In this example we have a MTMUSBStem and a MTMDAQ2 connected to a BrainStem +// development board. The board is powered and ONLY the MTMUSBStem is connected +// to the computer via USB cable. The MTMDAQ2 will connect to the PC through the +// MTMUSBStem via the BrainStem Network (I2C) which is wired through the +// development board. +/////////////////////////////////////////////////////////////////////// +void connectThroughLinkModule_Example() { + + aErr err = aErrNone; + + aUSBHub3p stem; + + cout << "Example: connectThroughLinkModule;" << endl << endl; + + // Create the devices required for this example + aMTMUSBStem mtmstem; + aMTMDAQ2 mtmdaq2; + + err = mtmstem.discoverAndConnect(USB); + if (err != aErrNone) { + cout << "Unable to connect to MTMUSBStem Module. Error: " << err << endl; + } + else { + cout << "Found and Connected to MTMUSBStem Module" << endl; + + // Set the route functionality to route all BrainStem Network + // traffic to the MTMStem. + err = mtmstem.system.routeToMe(1); + if(err != aErrNone){ + cout << "Error routing Traffic to MTMUSBStem. Error: "<< err < +#include "BrainStem2/BrainStem-all.h" + +//Note: This example assumes you have a device connected to the rail 0 and is +// capable of allowing 5VDC @ 100mA. + +int main(int argc, const char * argv[]) { + std::cout << "Creating a MTMLoad1 module" << std::endl; + + // Create an instance of the MTMLoad1 module + aMTMLoad1 stem; + aErr err = aErrNone; + + // Connect to the hardware. + // The only difference for TCP/IP modules is to change "USB" to "TCP"; + // err = stem.discoverAndConnect(USB, 0x40F5849A); // for a known serial number + err = stem.discoverAndConnect(USB); + if (err != aErrNone) { + std::cout << "Error "<< err <<" encountered connecting to BrainStem module" << std::endl; + return 1; + + } + else { + uint32_t sn; + err = stem.system.getSerialNumber(&sn); + printf("Connected to BrainStem module. SN: 0x%08X. Error: %d\n", sn, err); + } + + //Operational modes are defined in aProtocoldefs.h (development/lib/BrainStem2/) + //Device specific configurations/capabilities can be found in the product datasheet. + //0x01 = (railOperationalModeConstantCurrent_Value(0x00) | railOperationalModeLinear_Value(0x01)) + stem.rail[0].setOperationalMode(railOperationalModeConstantCurrent_Value | railOperationalModeLinear_Value); + + printf("Setting load rail 0 to draw 0.1A\n"); + stem.rail[0].setCurrentSetpoint(100000); //Current is in microamps + + printf("Setting load rail 0 max voltage to 5.0V\n"); + stem.rail[0].setVoltageMaxLimit(5000000); + + printf("Enabling load rail 0\n"); + stem.rail[0].setEnable(true); + + printf("Allowing time for the rail to stabilize\n"); + aTime_MSSleep(1000); //Sleep for 1 second. + + int32_t voltage = 0; + err = stem.rail[0].getVoltage(&voltage); + printf("Voltage: %d microvolts, Error: %d\n", voltage, err); + + int32_t current = 0; + err = stem.rail[0].getCurrent(¤t); + printf("Current: %d microamps, Error: %d\n", current, err); + + printf("Disabling load rail 0\n"); + stem.rail[0].setEnable(false); + + // Disconnect + err = stem.disconnect(); + if (err == aErrNone) { + std::cout << "Disconnected from BrainStem module." << std::endl; + } + + return 0; +} diff --git a/api/examples/c_cpp/BrainStem2-MTMLoad1-Cpp-ConstantCurrent/How_To_Build.txt b/api/examples/c_cpp/BrainStem2-MTMLoad1-Cpp-ConstantCurrent/How_To_Build.txt new file mode 100755 index 0000000..8f6a8b8 --- /dev/null +++ b/api/examples/c_cpp/BrainStem2-MTMLoad1-Cpp-ConstantCurrent/How_To_Build.txt @@ -0,0 +1,23 @@ +=============================================================================== +MTM-Load-1 C++ Example Readme +=============================================================================== + +This is a basic C++ example for the MTM-Load-1. When executed, this example +programs the MTM-Load-1 to provide a constant 0.1 A load, enables the voltage rail +to 5 volts and measures the actual voltage and current draw of the load. + +Notes: +=============================================================================== + +# To build, copy the lib directory into this directory. The lib directory contains + the required header files, and the Brainstem2 shared object file. + +# The output directory is linux_BrainStem2Example/Debug. + +# A build step has been added to the project that copies the shared object into + the build output directory. In addition the runpath is updated to search in + the same directory as the executable. + +If you have questions, please see the reference, or check out our guides +at www.acroname.com. + diff --git a/api/examples/c_cpp/BrainStem2-MTMLoad1-Cpp-ConstantCurrent/makefile b/api/examples/c_cpp/BrainStem2-MTMLoad1-Cpp-ConstantCurrent/makefile new file mode 100755 index 0000000..936a6dc --- /dev/null +++ b/api/examples/c_cpp/BrainStem2-MTMLoad1-Cpp-ConstantCurrent/makefile @@ -0,0 +1,45 @@ +# Brainstem2Example C + +CPP = g++ +ROOT = . +TARGET = BrainStem2Example +OUT := linux_$(TARGET) +DBG_DST := $(OUT)/Debug +REL_DST := $(OUT)/Release + +# We are looking for the BrainStem2 library in +# a lib folder sibling to this makefile. Change +# these defines to point somewhere else if this +# is not the case. +LIBRARIES := -L$(ROOT)/lib -lBrainStem2 +INCLUDES := -Ilib/ + +# We add the current directory to the rpath expecting +# that libBrainStem2.so will be copied into the build +# folder. If this is not the case adjust the rpath +# do match your needs. +CFLAGS = -std=c++11 -Wall -Werror -Wl,-rpath,. $(INCLUDES) + +all : dirs + make app + +app : debug release + +.PHONY : debug +debug: dirs + $(CPP) $(CFLAGS) BrainStem2Example/main.cpp $(LIBRARIES) -o $(DBG_DST)/BrainStem2Example + cp lib/libBrainStem2.so $(DBG_DST) + +.PHONY : release +release: dirs + $(CPP) $(CFLAGS) -DNDEBUG BrainStem2Example/main.cpp $(LIBRARIES) -o $(REL_DST)/BrainStem2Example + cp lib/libBrainStem2.so $(REL_DST) + +.PHONY : dirs +dirs: + mkdir -p $(DBG_DST) + mkdir -p $(REL_DST) + +clean: + rm -rf $(OUT) + diff --git a/api/examples/c_cpp/BrainStem2-Server-Cpp-Example/BrainStem2Example/main.cpp b/api/examples/c_cpp/BrainStem2-Server-Cpp-Example/BrainStem2Example/main.cpp new file mode 100755 index 0000000..d6b8a06 --- /dev/null +++ b/api/examples/c_cpp/BrainStem2-Server-Cpp-Example/BrainStem2Example/main.cpp @@ -0,0 +1,273 @@ +// +// main.cpp +// BrainStem2-Server-Cpp-Example +// +// Created by Acroname Inc. on 5/20/2023. +// Copyright (c) 2023 Acroname Inc. All rights reserved. +// + +//This example is intended to highlight the multi-process and +//network capabilities of BrainStem modules. This application +//is intended to be used in conjunction with a "client" example (Any API) +//however, it will work with any application or even HubTool +//if configured properly. + +//Note 1: +// Although this is labeled as the "Server" application this +// is a bit misleading. The actual server is created by the +// first process to connect to the device. +// This means you could run the "Client" or even HubTool first in +// which it would create/own the server and this application would be +// a client. This is intended to smooth over the user experience +// but is important to remember when closing applications. If +// The "Server" application is closed it will result in the "Clients" +// losing access to the device. + +//Note 2: +// This application was created with the aUSBHub3p object. If +// your devices differs (say a USBCSwitch) you will need to change +// all instances of aUSBHub3p to aUSBCSwitch in order to connect to +// the device. This is a result of discoveryAndConnect as it will +// only connect to a device that matches the object type. It is +// possible to use the generic "Module" object; however, this was avoided +// in order to present a simplified example. For more connection types +// see the "Discovery-and-Connection" + +//Note 3: +// If you intended to connect to a device that is not connected +// to your local machine or on your local intranet (local network) +// you will need to define a linkSpec with the intended ip and port +// number of the device and then use "connectFromSpec". +// Discovery works through broadcast and multicast packets; +// neither of which work for the internet (global network). +// For more connection types see the "Discovery-and-Connection" + +//Note 4: +// Additional network details are described in _configure_aEther(). + + +/////////////////////////////////////////////////////////////////////////////// +// Includes +/////////////////////////////////////////////////////////////////////////////// + +#include "BrainStem2/BrainStem-all.h" + +#include +#include +#include +#include +#include + + + +/////////////////////////////////////////////////////////////////////////////// +// Private Macros +/////////////////////////////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////////////// +// Private Types +/////////////////////////////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////////////// +// Private Function Prototypes +/////////////////////////////////////////////////////////////////////////////// + +std::vector _parseArgs(const std::string &s, char delim); +bool _handleCLI(Acroname::BrainStem::Module& m); +void _configure_aEther(Acroname::BrainStem::Module& m); +void _printProgramInfo(void); +void _printCLIOutput(void); +void _printFailedConnection(void); +void _print_aEtherConfig(Acroname::BrainStem::Module& m); + +/////////////////////////////////////////////////////////////////////////////// +// Public Data +/////////////////////////////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////////////// +// Private Data +/////////////////////////////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////////////// +// Public Function Implementations +/////////////////////////////////////////////////////////////////////////////// + +int main(int argc, const char * argv[]) { + aErr e = aErrNone; + + aUSBHub3p stem; + //If your module is different, replace it with the appropriate module + //Such as a USBCSwitch as shown below. + //aUSBCSwitch stem; + + _configure_aEther(stem); + e = stem.discoverAndConnect(USB); + if(aErrNone == e) { + _printProgramInfo(); printf("\n"); + _print_aEtherConfig(stem); printf("\n"); + _printCLIOutput(); + + //Start thread for CLI stuff. + while(_handleCLI(stem)) { } + stem.disconnect(); + } + else { _printFailedConnection(); } + + return 0; +} + +/////////////////////////////////////////////////////////////////////////////// +// Private Function Implementations +/////////////////////////////////////////////////////////////////////////////// + +void _configure_aEther(Acroname::BrainStem::Module& m) { + //NOTE: Network configuration MUST be done before connecting. + Acroname::BrainStem::aEtherConfig config; + aErr err = m.getConfig(&config); + if(err == aErrNone) { + //Controls the exposure of the device. By default, + //the device is only exposed on the localhost. + //True = localhost(default); False = Public; + //config.localOnly = false; //uncomment to test non-default values + + //Controls how strictly we honor the linkType (USB, NETWORK). + //Fallback allows for a smoother user experience when getting + //familiar with the device; however, it might be helpful to disable + //this so that you can control who is the server and who is the client. + //For instance if stem.discoverAndConnect(USB) fails it will automatically + //try stem.discoverAndConnect(Network) and vise-versa. + //True = fallback (default); False = NO fallback + //config.fallback = false; //uncomment to test non-default values + + //Controls if the Client-Server model is used. If you prefer to restrict + //the device to a single process you can disable this capability. + //By default the stem is enabled for multi-process use. + //True = Client-Server (default); False = Direct connection (not multi-process) + //config.enabled = false; //uncomment to test non-default values + + //Allows the user to select what network interface the stem will be exposed to. + //Default = LOCALHOST_IP_ADDRESS; (0 is also accepted for LOCALHOST_IP_ADDRESS); + //Available interfaces can be found with aDiscovery_GetIPv4Interfaces + //NOTE: If config.localOnly == true; This value is ignored. + // If config.localOnly == false; The stem will automatically pick + // the highest priority network interface and will ignore 0 and + // LOCALHOST_IP_ADDRESS values. However, you may override this value. + //config.networkInterface = LOCALHOST_IP_ADDRESS; + + //Apply the configuration. + aErr err = m.setConfig(config); + if(err) { printf("setConfig Error: %d\n", err); } + } +} + +void _print_aEtherConfig(Acroname::BrainStem::Module& m) { + Acroname::BrainStem::aEtherConfig config; + aErr err = m.getConfig(&config); + + char sInterface[INET_ADDRSTRLEN]; + aDiscovery_ConvertIPv4Interface(config.networkInterface, sInterface, INET_ADDRSTRLEN); + + printf("Current aEther Config (error: %d):\n", err); + printf("\t Local Only: %d\n" \ + "\t Fallback: %d\n" \ + "\t Server Enabled: %d\n" \ + "\t Assigned Port: %d\n" \ + "\t Network Interface: %d (%s)\n", \ + config.localOnly, + config.fallback, + config.enabled, + config.assignedPort, + config.networkInterface, + sInterface); +} + + +std::vector +_parseArgs(const std::string &s, char delim) { + std::vector result; + std::stringstream ss (s); + std::string item; + + while (getline (ss, item, delim)) { + result.push_back (item); + } + + return result; +} + + +bool +_handleCLI(Acroname::BrainStem::Module& m) { + + std::string s; + getline(std::cin, s); + std::vector args = _parseArgs(s, 0x20); + aErr err = aErrNone; + + bool commandFound = true; + Acroname::BrainStem::SystemClass sys; + sys.init(&m, 0); + + if(args.size() == 1) { + if(args.at(0) == "exit") { return false; } + else if(args.at(0) == "led") { + uint8_t led = 0; + err = sys.getLED(&led); + printf("Get LED value: %d - error: %d\n", led, err); + } + else if(args.at(0) == "voltage") { + uint32_t voltage = 0; + err = sys.getInputVoltage(&voltage); + printf("System Input Voltage: %0.3f VDC - error: %d\n", + double(voltage)/1000000, err); + } + else { commandFound = false; } + } + else if(args.size() == 2) { + if(args.at(0) == "led") { + unsigned int led = atoi(args.at(1).c_str()); + sys.setLED(led); + printf("Set LED value: %d - error: %d\n", led, err); + } + else { commandFound = false; } + } + else { commandFound = false; } + + + if(! commandFound) { + printf("Unknown command with (%d) parameters\n", (uint32_t)args.size()); + _printCLIOutput(); + } + + s.clear(); + + return true; +} + +void +_printProgramInfo(void) { + printf("The aUSBHub3p server has been started.\n"); + printf("You can now access this device from another process.\n"); + printf("Build and run the \"client\" example to see it in action.\n"); + printf("Additionally you can still issue commands to this process.\n"); +} + +void +_printCLIOutput(void) { + printf("Commands: \n"); + printf("\t exit - Exits this application \n"); + printf("\t voltage - Gets the system input voltage\n"); + printf("\t led - Gets the current led value \n"); + printf("\t led - Sets the led to the defined value (0/1)\n"); +} + +void +_printFailedConnection(void) { + printf("Failed to discover Module\n"); + printf(" - Confirm device is connected to your machine\n"); + printf(" - Confirm object type. This examples default is \"aUSBHub3p\"\n"); +} diff --git a/api/examples/c_cpp/BrainStem2-Server-Cpp-Example/How_To_Build.txt b/api/examples/c_cpp/BrainStem2-Server-Cpp-Example/How_To_Build.txt new file mode 100755 index 0000000..9749b24 --- /dev/null +++ b/api/examples/c_cpp/BrainStem2-Server-Cpp-Example/How_To_Build.txt @@ -0,0 +1,25 @@ +=============================================================================== +BrainStem2-Server-Cpp-Example +=============================================================================== + +This example is intended to highlight the multi-process and +network capabilities of BrainStem modules. This application +is intended to be used in conjunction with BrainStem2-Client-Cpp-Example +however, it will work with any application or even HubTool +if configured properly. + +Notes: +=============================================================================== + +# To build, copy the lib directory into this directory. The lib directory contains + the required header files, and the Brainstem2 shared object file. + +# The output directory is linux_BrainStem2Example/Debug. + +# A build step has been added to the project that copies the shared object into + the build output directory. In addition the runpath is updated to search in + the same directory as the executable. + +If you have questions, please see the reference, or check out our guides +at www.acroname.com. + diff --git a/api/examples/c_cpp/BrainStem2-Server-Cpp-Example/makefile b/api/examples/c_cpp/BrainStem2-Server-Cpp-Example/makefile new file mode 100755 index 0000000..f939a65 --- /dev/null +++ b/api/examples/c_cpp/BrainStem2-Server-Cpp-Example/makefile @@ -0,0 +1,45 @@ +# Brainstem2Example C + +CPP = g++ +ROOT = . +TARGET = BrainStem2Example +OUT := linux_$(TARGET) +DBG_DST := $(OUT)/Debug +REL_DST := $(OUT)/Release + +# We are looking for the BrainStem2 library in +# a lib folder sibling to this makefile. Change +# these defines to point somewhere else if this +# is not the case. +LIBRARIES := -L$(ROOT)/lib -lBrainStem2 -pthread +INCLUDES := -Ilib/ + +# We add the current directory to the rpath expecting +# that libBrainStem2.so will be copied into the build +# folder. If this is not the case adjust the rpath +# do match your needs. +CFLAGS = -std=c++11 -Wall -Werror -Wl,-rpath,. $(INCLUDES) + +all : dirs + make app + +app : debug release + +.PHONY : debug +debug: dirs + $(CPP) $(CFLAGS) BrainStem2Example/main.cpp $(LIBRARIES) -o $(DBG_DST)/BrainStem2Example + cp lib/libBrainStem2.so $(DBG_DST) + +.PHONY : release +release: dirs + $(CPP) $(CFLAGS) -DNDEBUG BrainStem2Example/main.cpp $(LIBRARIES) -o $(REL_DST)/BrainStem2Example + cp lib/libBrainStem2.so $(REL_DST) + +.PHONY : dirs +dirs: + mkdir -p $(DBG_DST) + mkdir -p $(REL_DST) + +clean: + rm -rf $(OUT) + diff --git a/api/examples/c_cpp/BrainStem2-Signal-Example/BrainStem2Example/main.cpp b/api/examples/c_cpp/BrainStem2-Signal-Example/BrainStem2Example/main.cpp new file mode 100755 index 0000000..60f4b25 --- /dev/null +++ b/api/examples/c_cpp/BrainStem2-Signal-Example/BrainStem2Example/main.cpp @@ -0,0 +1,207 @@ +// +// main.cpp +// BrainStem2Example +// +///////////////////////////////////////////////////////////////////// +// // +// Copyright (c) 2019 Acroname Inc. - All Rights Reserved // +// // +// This file is part of the BrainStem release. See the license.txt // +// file included with this package or go to // +// https://acroname.com/software/brainstem-development-kit // +// for full license details. // +///////////////////////////////////////////////////////////////////// +// +// This Example shows basic interaction with the MTMUSBStem. Please see the +// the product datasheet and the reference material at: http://acroname.com/reference +// 1. Create a MTMUSBStem object and connect. +// 2. Configure the MTMUSBStem to output a square wave via digital pin 6. +// 3. Set the T3 Time for signal entity 2 to 100000000. +// 4. Get and display the T3 Time for signal entity 2. +// 5. Set the T2 Time for signal entity 2 to 50000000. +// 6. Get and display the T2 Time for signal entity 2. +// 7. Enable the signal output on signal entity 2. +// 8. Configure the MTMUSBStem to receive a square wave via digital pin 4. +// 9. Enable the signal input on signal entity 0. +// 10. Get and display the T3 Time for signal entity 0. +// 11. Get and display the T2 Time for signal entity 0. +// 12. Calculate the Duty Cycle with the read T3 and T2 values. +// 13. Disable the signal output on signal entity 2. +// 14. Disable the signal input on signal entity 0. +// 15. Disconnect from the MTMUSBStem object. + + +#include +#include "BrainStem2/BrainStem-all.h" +#include "BrainStem2/aMTMUSBStem.h" + +int main(int argc, const char * argv[]) { + std::cout << "Creating a signal loopback, between digital pins 6 and 4, with a MTMUSBStem module" << std::endl << std::endl << std::endl; + + // Lookup Table for Signal to Digital Mapping + // The indicies refer to the signal [0-4], while the values + // held in those indicies refer to the digital pins they + // are associated with. + // Note: This Lookup Table is for the MTMUSBStem only. + // Digital Entity to Signal Entity mapping varies per + // device. Please refer to the data sheet for the MTM + // Device you are using to see its unique mapping. + const int signalToDigitalMapping[] = {4, 5, 6, 7, 8}; + + // T Times to be set. Editable by user + const uint32_t T3_TIME = 100000000; + const uint32_t T2_TIME = 50000000; + + // Signal Entity indexs to be used for input and output. + const uint8_t SIGNAL_OUTPUT_IDX = 2; + const uint8_t SIGNAL_INPUT_IDX = 0; + + aMTMUSBStem usbstem; // Create an instance of a MTMUSBStem module + aErr err = aErrNone; // aErr variable which will hold the return value of the last command executed + + uint32_t readFromOutputT3Time = 0; // T3 Time read from signal entity 2 + uint32_t readFromOutputT2Time = 0; // T2 Time read from signal entity 2 + uint32_t readFromInputT3Time = 0; // T3 Time read from signal entity 0 + uint32_t readFromInputT2Time = 0; // T2 Time read from signal entity 0 + + // Connect to the hardware. + // The only difference for TCP/IP modules is to change 'USB' to 'TCP'; + err = usbstem.discoverAndConnect(USB); + if (err != aErrNone) { + std::cout << "Error "<< err <<" encountered connecting to BrainStem module. Aborting example!" << std::endl; + return 1; + + } else { + std::cout << "Connected to BrainStem module." << std::endl; + } + + std::cout << std::endl; + + /* + * Output + */ + + // Configure the MTMUSBStem to output a square wave via digital pin 6 + err = usbstem.digital[signalToDigitalMapping[SIGNAL_OUTPUT_IDX]].setConfiguration(digitalConfigurationSignalOutput); + if (err != aErrNone) { + std::cout << "Error "<< err <<" encountered attempting to set the configuration for digital pin 6 on the MTMUSBStem. Aborting example!" << std::endl << std::endl; + return 1; + } + + // Set the T3 Time for signal entity 2 to 100000000 + err = usbstem.signal[SIGNAL_OUTPUT_IDX].setT3Time(T3_TIME); + if (err != aErrNone) { + std::cout << "Error "<< err <<" encountered attempting to set the T3 Time for signal entity 2 on the MTMUSBStem. Aborting example!" << std::endl; + return 1; + } + + // Get and display the T3 Time from signal entity 2 + err = usbstem.signal[SIGNAL_OUTPUT_IDX].getT3Time(&readFromOutputT3Time); + if (err != aErrNone) { + std::cout << "Error "<< err <<" encountered attempting to get the T3 Time for signal entity 2 on the MTMUSBStem." << std::endl; + } + else if (readFromOutputT3Time == 0) { + std::cout << "T3 Time cannot be 0. Aborting example!" << std::endl; + return 1; + } + else { + std::cout << "T3 Time from Output Pin: " << readFromOutputT3Time << std::endl; + } + + // Set the T2 Time for signal entity 2 to 50000000 + err = usbstem.signal[SIGNAL_OUTPUT_IDX].setT2Time(T2_TIME); + if (err != aErrNone) { + std::cout << "Error "<< err <<" encountered attempting to set the T2 Time for signal entity 2 on the MTMUSBStem. Aborting example!" << std::endl; + return 1; + } + + // Get and display the T2 Time from signal entity 2 + err = usbstem.signal[SIGNAL_OUTPUT_IDX].getT2Time(&readFromOutputT2Time); + if (err != aErrNone) { + std::cout << "Error "<< err <<" encountered attempting to get the T2 Time for signal entity 2 on the MTMUSBStem" << std::endl; + } + else { + std::cout << "T2 Time from Output Pin: " << readFromOutputT2Time << std::endl; + } + + err = usbstem.signal[SIGNAL_OUTPUT_IDX].setEnable(true); + if (err != aErrNone) { + std::cout << "Error "<< err <<" encountered attempting to set the signal enabled state of signal entity 2 to true on the MTMUSBStem. Aborting example!" << std::endl; + return 1; + } + + std::cout << std::endl; + + /* + * Input + */ + + // Configure the MTMUSBStem to receive a square wave via digital pin 4 + err = usbstem.digital[signalToDigitalMapping[SIGNAL_INPUT_IDX]].setConfiguration(digitalConfigurationSignalInput); + if (err != aErrNone) { + std::cout << "Error "<< err <<" encountered attempting to set the configuration for digital pin 4 on the MTMUSBStem. Aborting example!" << std::endl << std::endl; + return 1; + } + + // Enable the signal input on signal entity 0 + err = usbstem.signal[SIGNAL_INPUT_IDX].setEnable(true); + if (err != aErrNone) { + std::cout << "Error "<< err <<" encountered attempting to set the signal enabled state of signal entity 0 to true on the MTMUSBStem. Aborting example!" << std::endl << std::endl; + return 1; + } + + /* + * Sleep for 500ms so the ouput can stabilize + * and the input can have time to calculate the + * time high/low + */ + aTime_MSSleep(500); + + // Get and display the T3 Time from signal entity 0 + err = usbstem.signal[SIGNAL_INPUT_IDX].getT3Time(&readFromInputT3Time); + if (err != aErrNone) { + std::cout << "Error "<< err <<" encountered attempting to get the T3 Time for signal entity 0 on the MTMUSBStem. Aborting example!" << std::endl; + return 1; + } + else if (readFromInputT3Time == 0) { + std::cout << "T3 Time cannot be 0. Aborting example!" << std::endl; + return 1; + } + else { + std::cout << "T3 Time from Input Pin: " << readFromInputT3Time << std::endl; + } + + // Get and display the T2 Time from signal entity 0 + err = usbstem.signal[SIGNAL_INPUT_IDX].getT2Time(&readFromInputT2Time); + if (err != aErrNone) { + std::cout << "Error "<< err <<" encountered attempting to get the T2 Time for signal entity 0 on the MTMUSBStem. Aborting example!" << std::endl; + return 1; + } + else { + std::cout << "T2 Time from Input Pin: " << readFromInputT2Time << std::endl; + } + + std::cout << std::endl; + + double dutyCycle = ((double)readFromInputT2Time / (double)readFromInputT3Time) * 100.0; // Calculate the Duty Cycle + + std::cout << "Duty Cycle: "<< dutyCycle << std::endl << std::endl; // Display the Duty Cycle + + // Disable the signal output on signal entity 2 + err = usbstem.signal[SIGNAL_OUTPUT_IDX].setEnable(false); + if (err != aErrNone) { + std::cout << "Error "<< err <<" encountered attempting to set the signal enabled state of signal entity 2 to false on the MTMUSBStem" << std::endl; + } + + // Disable the signal input on signal entity 0 + err = usbstem.signal[SIGNAL_INPUT_IDX].setEnable(false); + if (err != aErrNone) { + std::cout << "Error "<< err <<" encountered attempting to set the signal enabled state of signal entity 0 to false on the MTMUSBStem" << std::endl; + } + + std::cout << std::endl; + + usbstem.disconnect(); // Disconnect from the MTMUSBStem + + return 0; +} diff --git a/api/examples/c_cpp/BrainStem2-Signal-Example/How_To_Build.txt b/api/examples/c_cpp/BrainStem2-Signal-Example/How_To_Build.txt new file mode 100755 index 0000000..7ff7086 --- /dev/null +++ b/api/examples/c_cpp/BrainStem2-Signal-Example/How_To_Build.txt @@ -0,0 +1,22 @@ +=============================================================================== +MTM-USBStem C++ Example Readme +=============================================================================== + +This is a basic C++ example for the MTM-USBStem that demonstrates some of its +digital signal capabilities. + +Notes: +=============================================================================== + +# To build, copy the lib directory into this directory. The lib directory contains + the required header files, and the Brainstem2 shared object file. + +# The output directory is linux_BrainStem2Example/Debug. + +# A build step has been added to the project that copies the shared object into + the build output directory. In addition the runpath is updated to search in + the same directory as the executable. + +If you have questions, please see the reference, or check out our guides +at www.acroname.com. + diff --git a/api/examples/c_cpp/BrainStem2-Signal-Example/makefile b/api/examples/c_cpp/BrainStem2-Signal-Example/makefile new file mode 100755 index 0000000..0f0ebf8 --- /dev/null +++ b/api/examples/c_cpp/BrainStem2-Signal-Example/makefile @@ -0,0 +1,45 @@ +# Brainstem2Example C + +CPP = g++ +ROOT = . +TARGET = BrainStem2Example +OUT := linux_$(TARGET) +DBG_DST := $(OUT)/Debug +REL_DST := $(OUT)/Release + +# We are looking for the BrainStem2 library in +# a lib folder sibling to this makefile. Change +# these defines to point somewhere else if this +# is not the case. +LIBRARIES := -L$(ROOT)/lib -lBrainStem2 +INCLUDES := -Ilib/ + +# We add the current directory to the rpath expecting +# that libBrainStem2.so will be copied into the build +# folder. If this is not the case adjust the rpath +# do match your needs. +CFLAGS = -std=c++11 -Wall -Werror -Wl,-rpath,. $(INCLUDES) + +all : dirs + make app + +app : debug release + +.PHONY : debug +debug: dirs + $(CPP) $(CFLAGS) BrainStem2Example/main.cpp $(LIBRARIES) -o $(DBG_DST)/BrainStem2Example + cp lib/libBrainStem2.so $(DBG_DST) + +.PHONY : release +release: dirs + $(CPP) $(CFLAGS) -DNDEBUG BrainStem2Example/main.cpp $(LIBRARIES) -o $(REL_DST)/BrainStem2Example + cp lib/libBrainStem2.so $(REL_DST) + +.PHONY : dirs +dirs: + mkdir -p $(DBG_DST) + mkdir -p $(REL_DST) + +clean: + rm -rf $(OUT) + diff --git a/api/examples/c_cpp/BrainStem2-USBC-Switch-Cpp-Example/BrainStem2Example/main.cpp b/api/examples/c_cpp/BrainStem2-USBC-Switch-Cpp-Example/BrainStem2Example/main.cpp new file mode 100755 index 0000000..11af5a1 --- /dev/null +++ b/api/examples/c_cpp/BrainStem2-USBC-Switch-Cpp-Example/BrainStem2Example/main.cpp @@ -0,0 +1,137 @@ +// +// main.cpp +// BrainStem2Example +// +///////////////////////////////////////////////////////////////////// +// // +// Copyright (c) 2018 Acroname Inc. - All Rights Reserved // +// // +// This file is part of the BrainStem release. See the license.txt // +// file included with this package or go to // +// https://acroname.com/software/brainstem-development-kit // +// for full license details. // +///////////////////////////////////////////////////////////////////// +// +// This Example shows basic interaction with the USBC-Switch. Please see the +// the product datasheet and the reference material at: http://acroname.com/reference +// 1. Create a switch object and connect. +// 2. Set up the mux channel to channel 0, enable the common side +// via the USB entity, and enable the mux side. +// 3. Disable the connection on the common side via the USB entity. +// 4. Change the mux channel to channel 1. +// 5. Enable the connection on the common side via the USB entity. +// 6. Poll current and voltage once a second for MAX_LOOP seconds. +// 7. Disable the connection on the mux side via mux.setEnable. +// 8. Change the mux channel to channel 1. +// 9. Enable the connection on the mux side via mux.setEnable. + + +#include +#include "BrainStem2/BrainStem-all.h" + +// The common side USB is always channel 0 on the USBCSwitch. +#define USBC_COMMON 0 + +// Defines for enabling and disabling the mux channel. +#define ENABLE 1 +#define DISABLE 0 + +// Number of times current and voltage will be printed. +#define LOOP_MAX 5 + +#include "BrainStem2/aUSBCSwitch.h" + +int main(int argc, const char * argv[]) { + std::cout << "Creating a USBCSwitch module" << std::endl; + + // Create an instance of a USBCSwitch module. + aUSBCSwitch cswitch; + aErr err = aErrNone; + uint8_t count; + + // Connect to the hardware. + // The only difference for TCP/IP modules is to change 'USB' to 'TCP'; + // err = cswitch.discoverAndConnect(USB, 0x40F5849A); // for a known serial number + err = cswitch.discoverAndConnect(USB); + if (err != aErrNone) { + std::cout << "Error "<< err <<" encountered connecting to BrainStem module" << std::endl; + return 1; + + } else { + std::cout << "Connected to BrainStem module." << std::endl; + } + + // Initial port setup. + // Mux select channel 0, USB common side enabled, Mux side enabled. + cswitch.mux.setChannel(0); + cswitch.usb.setPortEnable(USBC_COMMON); + cswitch.mux.setEnable(ENABLE); + + // Using the USB channel disable the connection on the common side. + err = cswitch.usb.setPortDisable(USBC_COMMON); + if (err != aErrNone) { + std::cout << "Error "<< err <<" encountered disabling connection." << std::endl; + return 1; + } else { std::cout << "Disabled connection on the common (USB) side." << std::endl; } + + // Change the mux channel to channel 1. + err = cswitch.mux.setChannel(1); + if (err != aErrNone) { + std::cout << "Error "<< err <<" encountered changing the channel." << std::endl; + return 1; + } else { std::cout << "Switched to mux channel 1." << std::endl; } + + + // Using the usb entity enable the connection. + err = cswitch.usb.setPortEnable(USBC_COMMON); + if (err != aErrNone) { + std::cout << "Error "<< err <<" encountered enabling the connection." << std::endl; + return 1; + } else { std::cout << "Enabled the connection on the common (USB) side." << std::endl; } + + // Loop for LOOP_MAX seconds printing current and voltage. + for (count = 0; count < LOOP_MAX; count++) { + int32_t microVolts = 0; + int32_t microAmps = 0; + err = cswitch.usb.getPortVoltage(USBC_COMMON, µVolts); + if (err == aErrNone) { err = cswitch.usb.getPortCurrent(USBC_COMMON, µAmps); } + if (err != aErrNone) { + std::cout << "Error "<< err <<" encountered getting port voltage and current." << std::endl; + return 1; + } else { + std::cout << "Port Voltage: " << microVolts << " uV, " << "Port Current: " << microAmps << " uA " << std::endl; + } + aTime_MSSleep(1000); + } + + // Using the mux, disable the connection. + // Note : This has essentially the same effect as disabling the connection + // at the common side, except that it will not affect any of the USB + // port settings where the USB call directely affects these settings. + err = cswitch.mux.setEnable(DISABLE); + if (err != aErrNone) { + std::cout << "Error "<< err <<" encountered disabling the connection on the mux side." << std::endl; + return 1; + } else { std::cout << "Disabled the connection on the mux side." << std::endl; } + + // Change the mux channel to channel 0. + err = cswitch.mux.setChannel(0); + if (err != aErrNone) { + std::cout << "Error "<< err <<" encountered changing the channel." << std::endl; + return 1; + } else { std::cout << "Switched to mux channel 0." << std::endl; } + + // Using the mux, Enable the connection. + err = cswitch.mux.setEnable(ENABLE); + if (err != aErrNone) { + std::cout << "Error "<< err <<" encountered enabling the connection." << std::endl; + return 1; + } else { std::cout << "Enabled port via mux." << std::endl; } + + err = cswitch.disconnect(); + if (err == aErrNone) { + std::cout << "Disconnected from BrainStem module." << std::endl; + } + + return 0; +} diff --git a/api/examples/c_cpp/BrainStem2-USBC-Switch-Cpp-Example/How_To_Build.txt b/api/examples/c_cpp/BrainStem2-USBC-Switch-Cpp-Example/How_To_Build.txt new file mode 100755 index 0000000..0a084b6 --- /dev/null +++ b/api/examples/c_cpp/BrainStem2-USBC-Switch-Cpp-Example/How_To_Build.txt @@ -0,0 +1,23 @@ +=============================================================================== +USBC-Switch C++ Example Readme +=============================================================================== + +This is a basic C++ example for the USBC-Switch. It demonstrates enabling and +disabling the common port and the selection of mux channels. It also measures +voltage and current. + +Notes: +=============================================================================== + +# To build, copy the lib directory into this directory. The lib directory contains + the required header files, and the Brainstem2 shared object file. + +# The output directory is linux_BrainStem2Example/Debug. + +# A build step has been added to the project that copies the shared object into + the build output directory. In addition the runpath is updated to search in + the same directory as the executable. + +If you have questions, please see the reference, or check out our guides +at www.acroname.com. + diff --git a/api/examples/c_cpp/BrainStem2-USBC-Switch-Cpp-Example/makefile b/api/examples/c_cpp/BrainStem2-USBC-Switch-Cpp-Example/makefile new file mode 100755 index 0000000..936a6dc --- /dev/null +++ b/api/examples/c_cpp/BrainStem2-USBC-Switch-Cpp-Example/makefile @@ -0,0 +1,45 @@ +# Brainstem2Example C + +CPP = g++ +ROOT = . +TARGET = BrainStem2Example +OUT := linux_$(TARGET) +DBG_DST := $(OUT)/Debug +REL_DST := $(OUT)/Release + +# We are looking for the BrainStem2 library in +# a lib folder sibling to this makefile. Change +# these defines to point somewhere else if this +# is not the case. +LIBRARIES := -L$(ROOT)/lib -lBrainStem2 +INCLUDES := -Ilib/ + +# We add the current directory to the rpath expecting +# that libBrainStem2.so will be copied into the build +# folder. If this is not the case adjust the rpath +# do match your needs. +CFLAGS = -std=c++11 -Wall -Werror -Wl,-rpath,. $(INCLUDES) + +all : dirs + make app + +app : debug release + +.PHONY : debug +debug: dirs + $(CPP) $(CFLAGS) BrainStem2Example/main.cpp $(LIBRARIES) -o $(DBG_DST)/BrainStem2Example + cp lib/libBrainStem2.so $(DBG_DST) + +.PHONY : release +release: dirs + $(CPP) $(CFLAGS) -DNDEBUG BrainStem2Example/main.cpp $(LIBRARIES) -o $(REL_DST)/BrainStem2Example + cp lib/libBrainStem2.so $(REL_DST) + +.PHONY : dirs +dirs: + mkdir -p $(DBG_DST) + mkdir -p $(REL_DST) + +clean: + rm -rf $(OUT) + diff --git a/api/examples/c_cpp/BrainStem2-USBHub-CMD-Line-Example/AcronameHubCLI/cxxopts.hpp b/api/examples/c_cpp/BrainStem2-USBHub-CMD-Line-Example/AcronameHubCLI/cxxopts.hpp new file mode 100755 index 0000000..eee7ba0 --- /dev/null +++ b/api/examples/c_cpp/BrainStem2-USBHub-CMD-Line-Example/AcronameHubCLI/cxxopts.hpp @@ -0,0 +1,2383 @@ +/* + +Copyright (c) 2014, 2015, 2016, 2017 Jarryd Beck + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*/ + +#ifndef CXXOPTS_HPP_INCLUDED +#define CXXOPTS_HPP_INCLUDED + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __cpp_lib_optional +#include +#define CXXOPTS_HAS_OPTIONAL +#endif + +#if __cplusplus >= 201603L +#define CXXOPTS_NODISCARD [[nodiscard]] +#else +#define CXXOPTS_NODISCARD +#endif + +#ifndef CXXOPTS_VECTOR_DELIMITER +#define CXXOPTS_VECTOR_DELIMITER ',' +#endif + +#define CXXOPTS__VERSION_MAJOR 3 +#define CXXOPTS__VERSION_MINOR 0 +#define CXXOPTS__VERSION_PATCH 0 + +namespace cxxopts +{ + static constexpr struct { + uint8_t major, minor, patch; + } version = { + CXXOPTS__VERSION_MAJOR, + CXXOPTS__VERSION_MINOR, + CXXOPTS__VERSION_PATCH + }; +} // namespace cxxopts + +//when we ask cxxopts to use Unicode, help strings are processed using ICU, +//which results in the correct lengths being computed for strings when they +//are formatted for the help output +//it is necessary to make sure that can be found by the +//compiler, and that icu-uc is linked in to the binary. + +#ifdef CXXOPTS_USE_UNICODE +#include + +namespace cxxopts +{ + using String = icu::UnicodeString; + + inline + String + toLocalString(std::string s) + { + return icu::UnicodeString::fromUTF8(std::move(s)); + } + + class UnicodeStringIterator : public + std::iterator + { + public: + + UnicodeStringIterator(const icu::UnicodeString* string, int32_t pos) + : s(string) + , i(pos) + { + } + + value_type + operator*() const + { + return s->char32At(i); + } + + bool + operator==(const UnicodeStringIterator& rhs) const + { + return s == rhs.s && i == rhs.i; + } + + bool + operator!=(const UnicodeStringIterator& rhs) const + { + return !(*this == rhs); + } + + UnicodeStringIterator& + operator++() + { + ++i; + return *this; + } + + UnicodeStringIterator + operator+(int32_t v) + { + return UnicodeStringIterator(s, i + v); + } + + private: + const icu::UnicodeString* s; + int32_t i; + }; + + inline + String& + stringAppend(String&s, String a) + { + return s.append(std::move(a)); + } + + inline + String& + stringAppend(String& s, size_t n, UChar32 c) + { + for (size_t i = 0; i != n; ++i) + { + s.append(c); + } + + return s; + } + + template + String& + stringAppend(String& s, Iterator begin, Iterator end) + { + while (begin != end) + { + s.append(*begin); + ++begin; + } + + return s; + } + + inline + size_t + stringLength(const String& s) + { + return s.length(); + } + + inline + std::string + toUTF8String(const String& s) + { + std::string result; + s.toUTF8String(result); + + return result; + } + + inline + bool + empty(const String& s) + { + return s.isEmpty(); + } +} + +namespace std +{ + inline + cxxopts::UnicodeStringIterator + begin(const icu::UnicodeString& s) + { + return cxxopts::UnicodeStringIterator(&s, 0); + } + + inline + cxxopts::UnicodeStringIterator + end(const icu::UnicodeString& s) + { + return cxxopts::UnicodeStringIterator(&s, s.length()); + } +} + +//ifdef CXXOPTS_USE_UNICODE +#else + +namespace cxxopts +{ + using String = std::string; + + template + T + toLocalString(T&& t) + { + return std::forward(t); + } + + inline + size_t + stringLength(const String& s) + { + return s.length(); + } + + inline + String& + stringAppend(String&s, const String& a) + { + return s.append(a); + } + + inline + String& + stringAppend(String& s, size_t n, char c) + { + return s.append(n, c); + } + + template + String& + stringAppend(String& s, Iterator begin, Iterator end) + { + return s.append(begin, end); + } + + template + std::string + toUTF8String(T&& t) + { + return std::forward(t); + } + + inline + bool + empty(const std::string& s) + { + return s.empty(); + } +} // namespace cxxopts + +//ifdef CXXOPTS_USE_UNICODE +#endif + +namespace cxxopts +{ + namespace + { +#ifdef _WIN32 + const std::string LQUOTE("\'"); + const std::string RQUOTE("\'"); +#else + const std::string LQUOTE("‘"); + const std::string RQUOTE("’"); +#endif + } // namespace + +#if defined(__GNUC__) +// GNU GCC with -Weffc++ will issue a warning regarding the upcoming class, we want to silence it: +// warning: base class 'class std::enable_shared_from_this' has accessible non-virtual destructor +#pragma GCC diagnostic ignored "-Wnon-virtual-dtor" +#pragma GCC diagnostic push +// This will be ignored under other compilers like LLVM clang. +#endif + class Value : public std::enable_shared_from_this + { + public: + + virtual ~Value() = default; + + virtual + std::shared_ptr + clone() const = 0; + + virtual void + parse(const std::string& text) const = 0; + + virtual void + parse() const = 0; + + virtual bool + has_default() const = 0; + + virtual bool + is_container() const = 0; + + virtual bool + has_implicit() const = 0; + + virtual std::string + get_default_value() const = 0; + + virtual std::string + get_implicit_value() const = 0; + + virtual std::shared_ptr + default_value(const std::string& value) = 0; + + virtual std::shared_ptr + implicit_value(const std::string& value) = 0; + + virtual std::shared_ptr + no_implicit_value() = 0; + + virtual bool + is_boolean() const = 0; + }; +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif + class OptionException : public std::exception + { + public: + explicit OptionException(std::string message) + : m_message(std::move(message)) + { + } + + CXXOPTS_NODISCARD + const char* + what() const noexcept override + { + return m_message.c_str(); + } + + private: + std::string m_message; + }; + + class OptionSpecException : public OptionException + { + public: + + explicit OptionSpecException(const std::string& message) + : OptionException(message) + { + } + }; + + class OptionParseException : public OptionException + { + public: + explicit OptionParseException(const std::string& message) + : OptionException(message) + { + } + }; + + class option_exists_error : public OptionSpecException + { + public: + explicit option_exists_error(const std::string& option) + : OptionSpecException("Option " + LQUOTE + option + RQUOTE + " already exists") + { + } + }; + + class invalid_option_format_error : public OptionSpecException + { + public: + explicit invalid_option_format_error(const std::string& format) + : OptionSpecException("Invalid option format " + LQUOTE + format + RQUOTE) + { + } + }; + + class option_syntax_exception : public OptionParseException { + public: + explicit option_syntax_exception(const std::string& text) + : OptionParseException("Argument " + LQUOTE + text + RQUOTE + + " starts with a - but has incorrect syntax") + { + } + }; + + class option_not_exists_exception : public OptionParseException + { + public: + explicit option_not_exists_exception(const std::string& option) + : OptionParseException("Option " + LQUOTE + option + RQUOTE + " does not exist") + { + } + }; + + class missing_argument_exception : public OptionParseException + { + public: + explicit missing_argument_exception(const std::string& option) + : OptionParseException( + "Option " + LQUOTE + option + RQUOTE + " is missing an argument" + ) + { + } + }; + + class option_requires_argument_exception : public OptionParseException + { + public: + explicit option_requires_argument_exception(const std::string& option) + : OptionParseException( + "Option " + LQUOTE + option + RQUOTE + " requires an argument" + ) + { + } + }; + + class option_not_has_argument_exception : public OptionParseException + { + public: + option_not_has_argument_exception + ( + const std::string& option, + const std::string& arg + ) + : OptionParseException( + "Option " + LQUOTE + option + RQUOTE + + " does not take an argument, but argument " + + LQUOTE + arg + RQUOTE + " given" + ) + { + } + }; + + class option_not_present_exception : public OptionParseException + { + public: + explicit option_not_present_exception(const std::string& option) + : OptionParseException("Option " + LQUOTE + option + RQUOTE + " not present") + { + } + }; + + class option_has_no_value_exception : public OptionException + { + public: + explicit option_has_no_value_exception(const std::string& option) + : OptionException( + option.empty() ? + ("Option " + LQUOTE + option + RQUOTE + " has no value") : + "Option has no value") + { + } + }; + + class argument_incorrect_type : public OptionParseException + { + public: + explicit argument_incorrect_type + ( + const std::string& arg + ) + : OptionParseException( + "Argument " + LQUOTE + arg + RQUOTE + " failed to parse" + ) + { + } + }; + + class option_required_exception : public OptionParseException + { + public: + explicit option_required_exception(const std::string& option) + : OptionParseException( + "Option " + LQUOTE + option + RQUOTE + " is required but not present" + ) + { + } + }; + + template + void throw_or_mimic(const std::string& text) + { + static_assert(std::is_base_of::value, + "throw_or_mimic only works on std::exception and " + "deriving classes"); + +#ifndef CXXOPTS_NO_EXCEPTIONS + // If CXXOPTS_NO_EXCEPTIONS is not defined, just throw + throw T{text}; +#else + // Otherwise manually instantiate the exception, print what() to stderr, + // and exit + T exception{text}; + std::cerr << exception.what() << std::endl; + std::exit(EXIT_FAILURE); +#endif + } + + namespace values + { + namespace + { + std::basic_regex integer_pattern + ("(-)?(0x)?([0-9a-zA-Z]+)|((0x)?0)"); + std::basic_regex truthy_pattern + ("(t|T)(rue)?|1"); + std::basic_regex falsy_pattern + ("(f|F)(alse)?|0"); + } // namespace + + namespace detail + { + template + struct SignedCheck; + + template + struct SignedCheck + { + template + void + operator()(bool negative, U u, const std::string& text) + { + if (negative) + { + if (u > static_cast((std::numeric_limits::min)())) + { + throw_or_mimic(text); + } + } + else + { + if (u > static_cast((std::numeric_limits::max)())) + { + throw_or_mimic(text); + } + } + } + }; + + template + struct SignedCheck + { + template + void + operator()(bool, U, const std::string&) const {} + }; + + template + void + check_signed_range(bool negative, U value, const std::string& text) + { + SignedCheck::is_signed>()(negative, value, text); + } + } // namespace detail + + template + void + checked_negate(R& r, T&& t, const std::string&, std::true_type) + { + // if we got to here, then `t` is a positive number that fits into + // `R`. So to avoid MSVC C4146, we first cast it to `R`. + // See https://github.com/jarro2783/cxxopts/issues/62 for more details. + r = static_cast(-static_cast(t-1)-1); + } + + template + void + checked_negate(R&, T&&, const std::string& text, std::false_type) + { + throw_or_mimic(text); + } + + template + void + integer_parser(const std::string& text, T& value) + { + std::smatch match; + std::regex_match(text, match, integer_pattern); + + if (match.length() == 0) + { + throw_or_mimic(text); + } + + if (match.length(4) > 0) + { + value = 0; + return; + } + + using US = typename std::make_unsigned::type; + + constexpr bool is_signed = std::numeric_limits::is_signed; + const bool negative = match.length(1) > 0; + const uint8_t base = match.length(2) > 0 ? 16 : 10; + + auto value_match = match[3]; + + US result = 0; + + for (auto iter = value_match.first; iter != value_match.second; ++iter) + { + US digit = 0; + + if (*iter >= '0' && *iter <= '9') + { + digit = static_cast(*iter - '0'); + } + else if (base == 16 && *iter >= 'a' && *iter <= 'f') + { + digit = static_cast(*iter - 'a' + 10); + } + else if (base == 16 && *iter >= 'A' && *iter <= 'F') + { + digit = static_cast(*iter - 'A' + 10); + } + else + { + throw_or_mimic(text); + } + + const US next = static_cast(result * base + digit); + if (result > next) + { + throw_or_mimic(text); + } + + result = next; + } + + detail::check_signed_range(negative, result, text); + + if (negative) + { + checked_negate(value, result, text, std::integral_constant()); + } + else + { + value = static_cast(result); + } + } + + template + void stringstream_parser(const std::string& text, T& value) + { + std::stringstream in(text); + in >> value; + if (!in) { + throw_or_mimic(text); + } + } + + inline + void + parse_value(const std::string& text, uint8_t& value) + { + integer_parser(text, value); + } + + inline + void + parse_value(const std::string& text, int8_t& value) + { + integer_parser(text, value); + } + + inline + void + parse_value(const std::string& text, uint16_t& value) + { + integer_parser(text, value); + } + + inline + void + parse_value(const std::string& text, int16_t& value) + { + integer_parser(text, value); + } + + inline + void + parse_value(const std::string& text, uint32_t& value) + { + integer_parser(text, value); + } + + inline + void + parse_value(const std::string& text, int32_t& value) + { + integer_parser(text, value); + } + + inline + void + parse_value(const std::string& text, uint64_t& value) + { + integer_parser(text, value); + } + + inline + void + parse_value(const std::string& text, int64_t& value) + { + integer_parser(text, value); + } + + inline + void + parse_value(const std::string& text, bool& value) + { + std::smatch result; + std::regex_match(text, result, truthy_pattern); + + if (!result.empty()) + { + value = true; + return; + } + + std::regex_match(text, result, falsy_pattern); + if (!result.empty()) + { + value = false; + return; + } + + throw_or_mimic(text); + } + + inline + void + parse_value(const std::string& text, std::string& value) + { + value = text; + } + + // The fallback parser. It uses the stringstream parser to parse all types + // that have not been overloaded explicitly. It has to be placed in the + // source code before all other more specialized templates. + template + void + parse_value(const std::string& text, T& value) { + stringstream_parser(text, value); + } + + template + void + parse_value(const std::string& text, std::vector& value) + { + std::stringstream in(text); + std::string token; + while(!in.eof() && std::getline(in, token, CXXOPTS_VECTOR_DELIMITER)) { + T v; + parse_value(token, v); + value.emplace_back(std::move(v)); + } + } + +#ifdef CXXOPTS_HAS_OPTIONAL + template + void + parse_value(const std::string& text, std::optional& value) + { + T result; + parse_value(text, result); + value = std::move(result); + } +#endif + + inline + void parse_value(const std::string& text, char& c) + { + if (text.length() != 1) + { + throw_or_mimic(text); + } + + c = text[0]; + } + + template + struct type_is_container + { + static constexpr bool value = false; + }; + + template + struct type_is_container> + { + static constexpr bool value = true; + }; + + template + class abstract_value : public Value + { + using Self = abstract_value; + + public: + abstract_value() + : m_result(std::make_shared()) + , m_store(m_result.get()) + { + } + + explicit abstract_value(T* t) + : m_store(t) + { + } + + ~abstract_value() override = default; + + abstract_value& operator=(const abstract_value&) = default; + + abstract_value(const abstract_value& rhs) + { + if (rhs.m_result) + { + m_result = std::make_shared(); + m_store = m_result.get(); + } + else + { + m_store = rhs.m_store; + } + + m_default = rhs.m_default; + m_implicit = rhs.m_implicit; + m_default_value = rhs.m_default_value; + m_implicit_value = rhs.m_implicit_value; + } + + void + parse(const std::string& text) const override + { + parse_value(text, *m_store); + } + + bool + is_container() const override + { + return type_is_container::value; + } + + void + parse() const override + { + parse_value(m_default_value, *m_store); + } + + bool + has_default() const override + { + return m_default; + } + + bool + has_implicit() const override + { + return m_implicit; + } + + std::shared_ptr + default_value(const std::string& value) override + { + m_default = true; + m_default_value = value; + return shared_from_this(); + } + + std::shared_ptr + implicit_value(const std::string& value) override + { + m_implicit = true; + m_implicit_value = value; + return shared_from_this(); + } + + std::shared_ptr + no_implicit_value() override + { + m_implicit = false; + return shared_from_this(); + } + + std::string + get_default_value() const override + { + return m_default_value; + } + + std::string + get_implicit_value() const override + { + return m_implicit_value; + } + + bool + is_boolean() const override + { + return std::is_same::value; + } + + const T& + get() const + { + if (m_store == nullptr) + { + return *m_result; + } + return *m_store; + } + + protected: + std::shared_ptr m_result{}; + T* m_store{}; + + bool m_default = false; + bool m_implicit = false; + + std::string m_default_value{}; + std::string m_implicit_value{}; + }; + + template + class standard_value : public abstract_value + { + public: + using abstract_value::abstract_value; + + CXXOPTS_NODISCARD + std::shared_ptr + clone() const override + { + return std::make_shared>(*this); + } + }; + + template <> + class standard_value : public abstract_value + { + public: + ~standard_value() override = default; + + standard_value() + { + set_default_and_implicit(); + } + + explicit standard_value(bool* b) + : abstract_value(b) + { + set_default_and_implicit(); + } + + std::shared_ptr + clone() const override + { + return std::make_shared>(*this); + } + + private: + + void + set_default_and_implicit() + { + m_default = true; + m_default_value = "false"; + m_implicit = true; + m_implicit_value = "true"; + } + }; + } // namespace values + + template + std::shared_ptr + value() + { + return std::make_shared>(); + } + + template + std::shared_ptr + value(T& t) + { + return std::make_shared>(&t); + } + + class OptionAdder; + + class OptionDetails + { + public: + OptionDetails + ( + std::string short_, + std::string long_, + String desc, + std::shared_ptr val + ) + : m_short(std::move(short_)) + , m_long(std::move(long_)) + , m_desc(std::move(desc)) + , m_value(std::move(val)) + , m_count(0) + { + m_hash = std::hash{}(m_long + m_short); + } + + OptionDetails(const OptionDetails& rhs) + : m_desc(rhs.m_desc) + , m_value(rhs.m_value->clone()) + , m_count(rhs.m_count) + { + } + + OptionDetails(OptionDetails&& rhs) = default; + + CXXOPTS_NODISCARD + const String& + description() const + { + return m_desc; + } + + CXXOPTS_NODISCARD + const Value& + value() const { + return *m_value; + } + + CXXOPTS_NODISCARD + std::shared_ptr + make_storage() const + { + return m_value->clone(); + } + + CXXOPTS_NODISCARD + const std::string& + short_name() const + { + return m_short; + } + + CXXOPTS_NODISCARD + const std::string& + long_name() const + { + return m_long; + } + + size_t + hash() const + { + return m_hash; + } + + private: + std::string m_short{}; + std::string m_long{}; + String m_desc{}; + std::shared_ptr m_value{}; + int m_count; + + size_t m_hash{}; + }; + + struct HelpOptionDetails + { + std::string s; + std::string l; + String desc; + bool has_default; + std::string default_value; + bool has_implicit; + std::string implicit_value; + std::string arg_help; + bool is_container; + bool is_boolean; + }; + + struct HelpGroupDetails + { + std::string name{}; + std::string description{}; + std::vector options{}; + }; + + class OptionValue + { + public: + void + parse + ( + const std::shared_ptr& details, + const std::string& text + ) + { + ensure_value(details); + ++m_count; + m_value->parse(text); + m_long_name = &details->long_name(); + } + + void + parse_default(const std::shared_ptr& details) + { + ensure_value(details); + m_default = true; + m_long_name = &details->long_name(); + m_value->parse(); + } + +#if defined(__GNUC__) +#if __GNUC__ <= 10 && __GNUC_MINOR__ <= 1 +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Werror=null-dereference" +#endif +#endif + + CXXOPTS_NODISCARD + size_t + count() const noexcept + { + return m_count; + } + +#if defined(__GNUC__) +#if __GNUC__ <= 10 && __GNUC_MINOR__ <= 1 +#pragma GCC diagnostic pop +#endif +#endif + + // TODO: maybe default options should count towards the number of arguments + CXXOPTS_NODISCARD + bool + has_default() const noexcept + { + return m_default; + } + + template + const T& + as() const + { + if (m_value == nullptr) { + throw_or_mimic( + m_long_name == nullptr ? "" : *m_long_name); + } + +#ifdef CXXOPTS_NO_RTTI + return static_cast&>(*m_value).get(); +#else + return dynamic_cast&>(*m_value).get(); +#endif + } + + private: + void + ensure_value(const std::shared_ptr& details) + { + if (m_value == nullptr) + { + m_value = details->make_storage(); + } + } + + + const std::string* m_long_name = nullptr; + // Holding this pointer is safe, since OptionValue's only exist in key-value pairs, + // where the key has the string we point to. + std::shared_ptr m_value{}; + size_t m_count = 0; + bool m_default = false; + }; + + class KeyValue + { + public: + KeyValue(std::string key_, std::string value_) + : m_key(std::move(key_)) + , m_value(std::move(value_)) + { + } + + CXXOPTS_NODISCARD + const std::string& + key() const + { + return m_key; + } + + CXXOPTS_NODISCARD + const std::string& + value() const + { + return m_value; + } + + template + T + as() const + { + T result; + values::parse_value(m_value, result); + return result; + } + + private: + std::string m_key; + std::string m_value; + }; + + using ParsedHashMap = std::unordered_map; + using NameHashMap = std::unordered_map; + + class ParseResult + { + public: + + ParseResult() = default; + ParseResult(const ParseResult&) = default; + + ParseResult(NameHashMap&& keys, ParsedHashMap&& values, std::vector sequential, std::vector&& unmatched_args) + : m_keys(std::move(keys)) + , m_values(std::move(values)) + , m_sequential(std::move(sequential)) + , m_unmatched(std::move(unmatched_args)) + { + } + + ParseResult& operator=(ParseResult&&) = default; + ParseResult& operator=(const ParseResult&) = default; + + size_t + count(const std::string& o) const + { + auto iter = m_keys.find(o); + if (iter == m_keys.end()) + { + return 0; + } + + auto viter = m_values.find(iter->second); + + if (viter == m_values.end()) + { + return 0; + } + + return viter->second.count(); + } + + const OptionValue& + operator[](const std::string& option) const + { + auto iter = m_keys.find(option); + + if (iter == m_keys.end()) + { + throw_or_mimic(option); + } + + auto viter = m_values.find(iter->second); + + if (viter == m_values.end()) + { + throw_or_mimic(option); + } + + return viter->second; + } + + const std::vector& + arguments() const + { + return m_sequential; + } + + const std::vector& + unmatched() const + { + return m_unmatched; + } + + private: + NameHashMap m_keys{}; + ParsedHashMap m_values{}; + std::vector m_sequential{}; + std::vector m_unmatched{}; + }; + + struct Option + { + Option + ( + std::string opts, + std::string desc, + std::shared_ptr value = ::cxxopts::value(), + std::string arg_help = "" + ) + : opts_(std::move(opts)) + , desc_(std::move(desc)) + , value_(std::move(value)) + , arg_help_(std::move(arg_help)) + { + } + + std::string opts_; + std::string desc_; + std::shared_ptr value_; + std::string arg_help_; + }; + + using OptionMap = std::unordered_map>; + using PositionalList = std::vector; + using PositionalListIterator = PositionalList::const_iterator; + + class OptionParser + { + public: + OptionParser(const OptionMap& options, const PositionalList& positional, bool allow_unrecognised) + : m_options(options) + , m_positional(positional) + , m_allow_unrecognised(allow_unrecognised) + { + } + + ParseResult + parse(int argc, const char* const* argv); + + bool + consume_positional(const std::string& a, PositionalListIterator& next); + + void + checked_parse_arg + ( + int argc, + const char* const* argv, + int& current, + const std::shared_ptr& value, + const std::string& name + ); + + void + add_to_option(OptionMap::const_iterator iter, const std::string& option, const std::string& arg); + + void + parse_option + ( + const std::shared_ptr& value, + const std::string& name, + const std::string& arg = "" + ); + + void + parse_default(const std::shared_ptr& details); + + private: + + void finalise_aliases(); + + const OptionMap& m_options; + const PositionalList& m_positional; + + std::vector m_sequential{}; + bool m_allow_unrecognised; + + ParsedHashMap m_parsed{}; + NameHashMap m_keys{}; + }; + + class Options + { + public: + + explicit Options(std::string program, std::string help_string = "") + : m_program(std::move(program)) + , m_help_string(toLocalString(std::move(help_string))) + , m_custom_help("[OPTION...]") + , m_positional_help("positional parameters") + , m_show_positional(false) + , m_allow_unrecognised(false) + , m_width(76) + , m_tab_expansion(false) + , m_options(std::make_shared()) + { + } + + Options& + positional_help(std::string help_text) + { + m_positional_help = std::move(help_text); + return *this; + } + + Options& + custom_help(std::string help_text) + { + m_custom_help = std::move(help_text); + return *this; + } + + Options& + show_positional_help() + { + m_show_positional = true; + return *this; + } + + Options& + allow_unrecognised_options() + { + m_allow_unrecognised = true; + return *this; + } + + Options& + set_width(size_t width) + { + m_width = width; + return *this; + } + + Options& + set_tab_expansion(bool expansion=true) + { + m_tab_expansion = expansion; + return *this; + } + + ParseResult + parse(int argc, const char* const* argv); + + OptionAdder + add_options(std::string group = ""); + + void + add_options + ( + const std::string& group, + std::initializer_list