// // 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"); }