UART Communication
/* Note: This is apart of the vn-100 programming library example code, the following
code is the basic configuration of the vn-100 */
#include <stdio.h>
#include <inttypes.h>
/* Include files needed to use VnSensor. */
#include "vn/sensors.h"
/* The VnUartProtocol structure encapsulates the data used for buffering
* and handling incoming data. It is not associated with sending commands
* to the sensor. This will be illustrated further in the example. */
VnUartPacketFinder up;
/* First thing you should do is initialize the data structure. */
VnUartPacketFinder_initialize(&up);
/* Register our callback method for when the VnUartPacketFinder finds an
ASCII asynchronous packet. */
VnUartPacketFinder_registerPacketFoundHandler(&up, packetFoundHandler, NULL);
/* Initialize the UART port */
UserUart_initialize();
/* Continually checking for new UART data and then passing any received data to the
VnUartProtocol to build, parse and verify data packets. */
char buffer [256];
while (1) {
size_t numOfBytes;
if (UserUart_checkForReceivedData(buffer, 256, &numOfBytes)) {
VnUartPacketFinder_processReceivedData(buffer, numOfBytes);
}
}
UserUart_checkForReceivedData(buffer, sizeof(buffer), &numOfBytes);
VnUartPacketFinder_processData(&up,(uint8_t*) buffer, numOfBytes);
/* We will first illustrate querying the sensor's model number. First we
* generate a read register command. This is subject to change depending on the desired configuration */
VnUartPacket_genReadModelNumber(
genReadModelNumberBuffer,
sizeof(genReadModelNumberBuffer),
VNERRORDETECTIONMODE_CHECKSUM,
&readModelNumberSize);
/* Now send the data to the sensor. */
gIsCheckingForModelNumberResponse = true;
UserUart_sendData(genReadModelNumberBuffer, readModelNumberSize);
/* Now process the mock data that our fake UART port received and hand it
* over to our UART packet finder. */
UserUart_checkForReceivedData(buffer, sizeof(buffer), &numOfBytes);
VnUartPacketFinder_processData(&up, (uint8_t*)buffer, numOfBytes);
gIsCheckingForVpeBasicControlResponse = false;
/* This is our basic callback handler for notifications of new asynchronous
* data packets received. The userData parameter is a pointer to the data we
* supplied when we called registerAsyncPacketReceivedHandler. In this case
* we didn't need any user data so we just set this to NULL. Alternatively you
* can provide a pointer to user data which you can use in the callback method.
* One use for this is help in calling back to a member method instead of just
* a global or static method. The Packet p parameter is an encapsulation of
* the data packet. At this state, it has already been validated and identified
* as an asynchronous data message. However, some processing is required on the
* user side to make sure it is the right type of asynchronous message type so
* we can parse it correctly. The index parameter is an advanced usage item and
* can be safely ignored for now. */
void asciiAsyncMessageReceived(void *userData, VnUartPacket *packet, size_t runningIndex)
{
vec3f ypr;
char strConversions[50];
/* Silence 'unreferenced formal parameters' warning in Visual Studio. */
(userData);
(runningIndex);
/* Make sure we have an ASCII packet and not a binary packet. */
if (VnUartPacket_type(packet) != PACKETTYPE_ASCII)
return;
/* Make sure we have a VNYPR data packet. */
if (VnUartPacket_determineAsciiAsyncType(packet) != VNYPR)
return;
/* We now need to parse out the yaw, pitch, roll data. */
VnUartPacket_parseVNYPR(packet, &ypr);
/* Now print out the yaw, pitch, roll measurements. */
str_vec3f(strConversions, ypr);
printf("ASCII Async YPR: %s\\n", strConversions);
}
void asciiOrBinaryAsyncMessageReceived(void *userData, VnUartPacket *packet, size_t runningIndex)
{
vec3f ypr;
char strConversions[50];
/* Silence 'unreferenced formal parameters' warning in Visual Studio. */
(userData);
(runningIndex);
if (VnUartPacket_type(packet) == PACKETTYPE_ASCII && VnUartPacket_determineAsciiAsyncType(packet) == VNYPR)
{
VnUartPacket_parseVNYPR(packet, &ypr);
str_vec3f(strConversions, ypr);
printf("ASCII Async YPR: %s\\n", strConversions);
return;
}
if (VnUartPacket_type(packet) == PACKETTYPE_BINARY)
{
uint64_t timeStartup;
/* First make sure we have a binary packet type we expect since there
* are many types of binary output types that can be configured. */
if (!VnUartPacket_isCompatible(packet,
COMMONGROUP_TIMESTARTUP | COMMONGROUP_YAWPITCHROLL,
TIMEGROUP_NONE,
IMUGROUP_NONE,
GPSGROUP_NONE,
ATTITUDEGROUP_NONE,
INSGROUP_NONE,
GPSGROUP_NONE))
/* Not the type of binary packet we are expecting. */
return;
/* Ok, we have our expected binary output packet. Since there are many
* ways to configure the binary data output, the burden is on the user
* to correctly parse the binary packet. However, we can make use of
* the parsing convenience methods provided by the Packet structure.
* When using these convenience methods, you have to extract them in
* the order they are organized in the binary packet per the User Manual. */
timeStartup = VnUartPacket_extractUint64(packet);
ypr = VnUartPacket_extractVec3f(packet);
str_vec3f(strConversions, ypr);
printf("Binary Async TimeStartup: %" PRIu64 "\\n", timeStartup);
printf("Binary Async YPR: %s\\n", strConversions);
return;
}
}
int processErrorReceived(char* errorMessage, VnError errorCode)
{
char errorCodeStr[100];
strFromVnError(errorCodeStr, errorCode);
printf("%s\\nERROR: %s\\n", errorMessage, errorCodeStr);
return -1;
}
SPI Interface
#include <stdio.h>
#include <string.h>
/* Include to get access to the VectorNav SPI functions. */
#include "vn/protocol/spi.h"
#include "vn/protocol/common.h"
#include "vn/xplat/thread.h"
int display_error(const char* msg);
void mockspi_initialize(void);
void mockspi_writeread(const char* dataOut, size_t dataOutSize, char* dataIn);
int main(void)
{
/* This example walks through using the VectorNav C Library to connect to
* and interact with a mock VectorNav sensor through the Serial Peripheral
* Interaface (SPI). Once you work through and understand the example, you
* may want to try replacing the mock functions with ones that interface
* with your SPI subsystem. */
char txbuf[0x100];
char rxbuf[0x100];
size_t bufcmdsize;
size_t responseSize;
vec3f ypr;
char strConversions[50];
size_t i;
mockspi_initialize();
/* With SPI 'initialize', let's work through reading the current yaw, pitch,
* roll values from the sensor. */
/* First we must generate the command to query the sensor. */
bufcmdsize = sizeof(txbuf); /* First set this variable to the size of the buffer. */
if (VnSpi_genReadYawPitchRoll(
txbuf,
&bufcmdsize, /* Pass in the pointer since the function will set this with the length of the command generate. */
0,
&responseSize) !=E_NONE)
return display_error("Error generating read yaw, pitch, roll command.\\n");
/* Send out the command over SPI. */
mockspi_writeread(
txbuf,
responseSize,
rxbuf);
/* Now the sensor will have responded with data on this transaction but
* since the sensor only responds on following transaction, we will
* disregard this data. These double transactions can be mitigated by only
* requesting the same data each time or by staggering the the requested
* data in an appropriate order. */
/* Make sure enough time has passed for the sensor to format the previous response. */
VnThread_sleepMs(1); /* Actual sensor requirement is only 50 us. */
/* Retransmit so the sensor responds with the previous request. */
mockspi_writeread(
txbuf,
responseSize,
rxbuf);
/* Now parse the received response. */
if (VnSpi_parseYawPitchRoll(
rxbuf,
&ypr) !=E_NONE)
return display_error("Error parsing yaw, pitch, roll.\\n");
str_vec3f(strConversions, ypr);
printf("Current YPR: %s\\n", strConversions);
/* We have now shown how to process one full command transaction which
* requires two SPI transactions because the VectorNav sensor requires a
* short amount of time to ready the response. Now we can optimize this
* transaction squence to utilize this behavior when we are only requesting
* the same data each time. This is illustrated in the for loop below. */
for (i = 0; i < 25; i++)
{
/* For this loop, we want to display data at ~10 Hz. */
VnThread_sleepMs(100);
/* Perform a transaction for the same sensor register. */
mockspi_writeread(
txbuf,
responseSize,
rxbuf);
/* Now since the previous command was for the same register, we will
* have valid data and can print/use the results. */
if (VnSpi_parseYawPitchRoll(
rxbuf,
&ypr) !=E_NONE)
return display_error("Error parsing yaw, pitch, roll.\\n");
str_vec3f(strConversions, ypr);
printf("Current YPR: %s\\n", strConversions);
}
/* We illustrate how to write settings to the sensor by changing the
* asynchronous data output type. Note that this setting only affects the
* output on the UART ports and has no effect on the SPI ports. It is only
* used for illustration purposes. */
/* Remember to reset the bufcmdsize variable to let the function know how
* large the provided buffer is. */
bufcmdsize = sizeof(txbuf);
if (VnSpi_genWriteAsyncDataOutputType(
txbuf,
&bufcmdsize,
0,
&responseSize,
VNYPR) !=E_NONE)
return display_error("Error generating write async data output type command.\\n");
mockspi_writeread(
txbuf,
responseSize,
rxbuf);
return 0;
}
int display_error(const char* msg)
{
printf("%s\\n", msg);
return -1;
}
void mockspi_initialize(void)
{
/* Do nothing since we are faking the SPI interface. */
}
void mockspi_writeread(const char* dataOut, size_t dataOutSize, char* dataIn)
{
/* This function fakes a SPI subsystem for this example. */
char yprResponse[] = { 0x00, 0x01, 0x08, 0x00, 0xd8, 0x9c, 0xd4, 0x42, 0x44, 0xba, 0x9e, 0x40, 0x4e, 0xe4, 0x8b, 0x40 };
/* Silence 'unreferenced formal parameters' warning in Visual Studio. */
(dataOut);
(dataOutSize);
memcpy(dataIn, yprResponse, sizeof(yprResponse));
}
Easy Asynchronous readings using USB
#include <stdio.h>
/* Include files needed to use VnEzAsyncData. */
#include "vn/sensors/ezasyncdata.h"
int processErrorReceived(char* errorMessage, VnError errorCode);
int main(void)
{
VnEzAsyncData ez;
VnError error = E_NONE;
size_t i = 0;
char strConversions[50];
/* This example walks through using the VnEzAsyncData structure to easily access
* asynchronous data from a VectorNav sensor at a slight performance hit which is
* acceptable for many applications, especially simple data logging. */
/* First determine which COM port your sensor is attached to and update the
* constant below. Also, if you have changed your sensor from the factory
* default baudrate of 115200, you will need to update the baudrate
* constant below as well. */
const char SENSOR_PORT[] = "COM1"; /* Windows format for physical and virtual (USB) serial port. */
/*const char SENSOR_PORT[] = "/dev/ttyS1"; */ /* Linux format for physical serial port. */
/*const char SENSOR_PORT[] = "/dev/ttyUSB0"; */ /* Linux format for virtual (USB) serial port. */
/*const char SENSOR_PORT[] = "/dev/tty.usbserial-FTXXXXXX"; */ /* Mac OS X format for virtual (USB) serial port. */
/*const char SENSOR_PORT[] = "/dev/ttyS0"; */ /* CYGWIN format. Usually the Windows COM port number minus 1. This would connect to COM1. */
const uint32_t SENSOR_BAUDRATE = 115200;
/* We call the initialize and connect method to connect with our VectorNav sensor. */
if ((error = VnEzAsyncData_initializeAndConnect(&ez, SENSOR_PORT, SENSOR_BAUDRATE)) != E_NONE)
return processErrorReceived("Error connecting to sensor.", error);
/* Now let's display the latest yaw, pitch, roll data at 5 Hz for 5 seconds. */
printf("Displaying yaw, pitch, roll at 5 Hz for 5 seconds.\\n");
for (i = 0; i < 25; i++)
{
VnCompositeData cd;
VnThread_sleepMs(200);
cd = VnEzAsyncData_currentData(&ez);
str_vec3f(strConversions, cd.yawPitchRoll);
printf("Current YPR: %s\\n", strConversions);
}
/* Most of the asynchronous data handling is done by VnEzAsyncData but there are times
* when we wish to configure the sensor directly while still having VnEzAsyncData do
* most of the grunt work. This is easily accomplished and we show changing the ASCII
* asynchronous data output type here. */
if ((error = VnSensor_writeAsyncDataOutputType(VnEzAsyncData_sensor(&ez), VNYPR, true)) != E_NONE)
return processErrorReceived("Error setting async data output type.", error);
/* We can now display yaw, pitch, roll data from the new ASCII asynchronous data type. */
printf("Displaying yaw, pitch, roll from new ASCII async type.\\n");
for (i = 0; i < 25; i++)
{
VnCompositeData cd;
VnThread_sleepMs(200);
cd = VnEzAsyncData_currentData(&ez);
str_vec3f(strConversions, cd.yawPitchRoll);
printf("Current YPR: %s\\n", strConversions);
}
/* Now disconnect from the sensor since we are finished. */
if ((error = VnEzAsyncData_disconnectAndUninitialize(&ez)) != E_NONE)
return processErrorReceived("Error disconnecting from sensor.", error);
return 0;
}
int processErrorReceived(char* errorMessage, VnError errorCode)
{
char errorCodeStr[100];
strFromVnError(errorCodeStr, errorCode);
printf("%s\\nERROR: %s\\n", errorMessage, errorCodeStr);
return -1;
}