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