372 lines
13 KiB
C
Executable File
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;
|
|
}
|