274 lines
9.8 KiB
C++
Executable File
274 lines
9.8 KiB
C++
Executable File
//
|
|
// 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 <iostream>
|
|
#include <sstream>
|
|
#include <iomanip>
|
|
#include <vector>
|
|
#include <future>
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Private Macros
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Private Types
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Private Function Prototypes
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
std::vector<std::string> _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<std::string>
|
|
_parseArgs(const std::string &s, char delim) {
|
|
std::vector<std::string> 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<std::string> 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 <value> - 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");
|
|
}
|