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