Skip to content
This repository was archived by the owner on Feb 11, 2026. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ rebuilt properly. Normally CMake takes care of this for you).
* Available Modules:
* microstrain
* microstrain_extras (CPP only)
* microstrain_recording_connection (CPP only)
* microstrain_recording
* microstrain_serial
* microstrain_socket
* mip
Expand Down
109 changes: 48 additions & 61 deletions examples/c/5_series/ahrs/5_series_ahrs_example.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@
// Include the MicroStrain logging header for custom logging
#include <microstrain/logging.h>

// Include the MicroStrain timestamping header
#include <microstrain/embedded_time.h>

// Include all necessary MIP headers
// Note: The MIP SDK has headers for each module to include all headers associated with the module
// I.E., #include <mip/mip_all.h>
Expand All @@ -41,7 +44,6 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

////////////////////////////////////////////////////////////////////////////////
// NOTE: Setting these globally for example purposes
Expand All @@ -51,7 +53,7 @@
#ifdef _WIN32
static const char* PORT_NAME = "COM1";
#else // Unix
static const char* PORT_NAME = "/dev/ttyUSB0";
static const char* PORT_NAME = "/dev/ttyACM0";
#endif // _WIN32

// Set the baudrate for the connection (Serial/USB)
Expand Down Expand Up @@ -81,21 +83,20 @@ void initialize_filter(mip_interface* _device);
// Utility to display filter state changes
void display_filter_state(const mip_filter_mode _filter_state);

// Used for basic timestamping (since epoch in milliseconds)
// TODO: Update this to whatever timestamping method is desired
mip_timestamp get_current_timestamp();

// Device callbacks used for reading and writing packets
bool mip_interface_user_send_to_device(mip_interface* _device, const uint8_t* _data, size_t _length);
bool mip_interface_user_recv_from_device(mip_interface* _device, uint8_t* _buffer, size_t _max_length,
mip_timeout _wait_time, bool _from_cmd, size_t* _length_out, mip_timestamp* _timestamp_out);
bool mip_interface_user_send_to_device(const mip_interface* _device, const uint8_t* _data, const size_t _byte_count,
size_t* _bytes_written_out);
bool mip_interface_user_recv_from_device(const mip_interface* _device, uint8_t* _buffer, const size_t _buffer_size,
const uint32_t _wait_time, size_t* _bytes_read_out, microstrain_embedded_timestamp* _timestamp_out,
const bool _from_command);

// Common device initialization procedure
void initialize_device(mip_interface* _device, serial_port* _device_port, const uint32_t _baudrate);

// Utility functions the handle application closing and printing error messages
void terminate(serial_port* _device_port, const char* _message, const bool _successful);
void command_failure_terminate(const mip_interface* _device, const mip_cmd_result _cmd_result, const char* _format, ...);
void command_failure_terminate(const mip_interface* _device, const mip_cmd_result _cmd_result, const char* _format,
...);

int main(const int argc, const char* argv[])
{
Expand All @@ -107,14 +108,13 @@ int main(const int argc, const char* argv[])
MICROSTRAIN_LOG_INIT(&log_callback, MICROSTRAIN_LOG_LEVEL_INFO, NULL);

// Initialize the connection
MICROSTRAIN_LOG_INFO("Initializing the connection.\n");
MICROSTRAIN_LOG_INFO("Initializing the connection on port %s with %d baudrate.\n", PORT_NAME, BAUDRATE);
serial_port device_port;
serial_port_init(&device_port);

MICROSTRAIN_LOG_INFO("Connecting to the device on port %s with %d baudrate.\n", PORT_NAME, BAUDRATE);
serial_port_init(&device_port, PORT_NAME, BAUDRATE, NULL);

MICROSTRAIN_LOG_INFO("Connecting to the device.\n");
// Open the connection to the device
if (!serial_port_open(&device_port, PORT_NAME, BAUDRATE))
if (!serial_port_open(&device_port))
{
terminate(&device_port, "Could not open the connection!\n", false);
}
Expand Down Expand Up @@ -218,13 +218,13 @@ int main(const int argc, const char* argv[])
}

// Get the start time of the device update loop to handle exiting the application
const mip_timestamp loop_start_time = get_current_timestamp();
const microstrain_embedded_timestamp loop_start_time = microstrain_get_current_timestamp();

mip_timestamp previous_print_timestamp = 0;
microstrain_embedded_timestamp previous_print_timestamp = 0;

// Device loop
// Exit after predetermined time in seconds
while (get_current_timestamp() - loop_start_time <= RUN_TIME_SECONDS * 1000)
while (microstrain_get_current_timestamp() - loop_start_time <= RUN_TIME_SECONDS * 1000)
{
// Update the device state
// Note: This will update the device callbacks to trigger the filter state change
Expand All @@ -242,7 +242,7 @@ int main(const int argc, const char* argv[])
current_state = filter_status.filter_state;
}

const mip_timestamp current_timestamp = get_current_timestamp();
const microstrain_embedded_timestamp current_timestamp = microstrain_get_current_timestamp();

// Print out data based on the sample rate (1000 ms / SAMPLE_RATE_HZ)
if (current_timestamp - previous_print_timestamp >= 1000 / SAMPLE_RATE_HZ)
Expand Down Expand Up @@ -543,33 +543,6 @@ void display_filter_state(const mip_filter_mode _filter_state)
}
}

////////////////////////////////////////////////////////////////////////////////
/// @brief Gets the current system timestamp in milliseconds
///
/// @details Provides basic timestamping using system time:
/// - Returns milliseconds since Unix epoch
/// - Uses timespec_get() with UTC time base
/// - Returns 0 if time cannot be obtained
///
/// @note Update this function to use a different time source if needed for
/// your specific application requirements
///
/// @return Current system time in milliseconds since epoch
///
mip_timestamp get_current_timestamp()
{
struct timespec ts;

// Get system UTC time since epoch
if (timespec_get(&ts, TIME_UTC) != TIME_UTC)
{
return 0;
}

// Get the time in milliseconds
return (mip_timestamp)ts.tv_sec * 1000 + (mip_timestamp)ts.tv_nsec / 1000000;
}

////////////////////////////////////////////////////////////////////////////////
/// @brief Handles sending packets to the device
///
Expand All @@ -580,14 +553,16 @@ mip_timestamp get_current_timestamp()
///
/// @param _device MIP device interface containing the connection
/// @param _data Buffer containing packet data to send
/// @param _length Number of bytes to send
/// @param _byte_count Number of bytes to send
/// @param _bytes_written_out Number of actual bytes written
///
/// @return True if send was successful, false otherwise
///
bool mip_interface_user_send_to_device(mip_interface* _device, const uint8_t* _data, size_t _length)
bool mip_interface_user_send_to_device(const mip_interface* _device, const uint8_t* _data, const size_t _byte_count,
size_t* _bytes_written_out)
{
// Extract the serial port pointer that was used in the callback initialization
serial_port* device_port = (serial_port*)mip_interface_user_pointer(_device);
serial_port* device_port = (serial_port*)mip_interface_connection_pointer(_device);

if (device_port == NULL)
{
Expand All @@ -599,7 +574,17 @@ bool mip_interface_user_send_to_device(mip_interface* _device, const uint8_t* _d
size_t bytes_written;

// Send the packet to the device
return serial_port_write(device_port, _data, _length, &bytes_written);
if (!serial_port_write(device_port, _data, _byte_count, &bytes_written))
{
return false;
}

if (_bytes_written_out != NULL)
{
*_bytes_written_out = bytes_written;
}

return true;
}

////////////////////////////////////////////////////////////////////////////////
Expand All @@ -613,22 +598,23 @@ bool mip_interface_user_send_to_device(mip_interface* _device, const uint8_t* _d
///
/// @param _device MIP device interface containing the connection
/// @param _buffer Buffer to store received data
/// @param _max_length Maximum number of bytes to read
/// @param _buffer_size Maximum number of bytes to read
/// @param _wait_time How long to wait for data in milliseconds
/// @param _from_cmd Whether this read is from a command response (unused)
/// @param _length_out Number of bytes actually read
/// @param _bytes_read_out Number of bytes actually read
/// @param _timestamp_out Timestamp when data was received
/// @param _from_command Whether this read is from a command response (unused)
///
/// @return True if receive was successful, false otherwise
///
bool mip_interface_user_recv_from_device(mip_interface* _device, uint8_t* _buffer, size_t _max_length,
mip_timeout _wait_time, bool _from_cmd, size_t* _length_out, mip_timestamp* _timestamp_out)
bool mip_interface_user_recv_from_device(const mip_interface* _device, uint8_t* _buffer, const size_t _buffer_size,
const uint32_t _wait_time, size_t* _bytes_read_out, microstrain_embedded_timestamp* _timestamp_out,
const bool _from_command)
{
// Unused parameter
(void)_from_cmd;
(void)_from_command;

// Extract the serial port pointer that was used in the callback initialization
serial_port* device_port = (serial_port*)mip_interface_user_pointer(_device);
serial_port* device_port = (serial_port*)mip_interface_connection_pointer(_device);

if (device_port == NULL)
{
Expand All @@ -637,10 +623,10 @@ bool mip_interface_user_recv_from_device(mip_interface* _device, uint8_t* _buffe
}

// Get the time that the packet was received (system epoch UTC time in milliseconds)
*_timestamp_out = get_current_timestamp();
*_timestamp_out = microstrain_get_current_timestamp();

// Read the packet from the device
return serial_port_read(device_port, _buffer, _max_length, (int)_wait_time, _length_out);
return serial_port_read(device_port, _buffer, _buffer_size, _wait_time, _bytes_read_out, _timestamp_out);
}

////////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -669,7 +655,8 @@ void initialize_device(mip_interface* _device, serial_port* _device_port, const
&mip_interface_user_send_to_device, // User-defined send packet callback
&mip_interface_user_recv_from_device, // User-defined receive packet callback
&mip_interface_default_update, // Default update callback
(void*)_device_port // Cast the device port for use in the callbacks
(void*)_device_port, // Connection pointer
NULL // Optional user data
);

// Ping the device
Expand Down Expand Up @@ -817,7 +804,7 @@ void command_failure_terminate(const mip_interface* _device, const mip_cmd_resul
else
{
// Get the connection pointer that was set during device initialization
serial_port* device_port = (serial_port*)mip_interface_user_pointer(_device);
serial_port* device_port = (serial_port*)mip_interface_connection_pointer(_device);

terminate(device_port, "", false);
}
Expand Down
Loading
Loading