UmberHubManager/api/examples/c_cpp/BrainStem2-C-Example/BrainStem2Example/main.c

372 lines
13 KiB
C
Executable File

//
// 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 <stdio.h>
#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;
}