SELKIELogger  1.0.0
LPMSTest.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2023 Swansea University
3  *
4  * This file is part of the SELKIELogger suite of tools.
5  *
6  * SELKIELogger is free software: you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by the Free
8  * Software Foundation, either version 3 of the License, or (at your option)
9  * any later version.
10  *
11  * SELKIELogger is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14  * more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this SELKIELogger product.
18  * If not, see <http://www.gnu.org/licenses/>.
19 */
20 
21 #include <stdbool.h>
22 #include <stdint.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27 
28 #include "SELKIELoggerBase.h"
29 
30 #include "SELKIELoggerLPMS.h"
31 
32 #include "version.h"
40 #define BUFSIZE 1024
41 
52 int main(int argc, char *argv[]) {
53  program_state state = {0};
54  state.verbose = 1;
55 
56  char *usage = "Usage: %1$s [-v] [-q] port\n"
57  "\t-v\tIncrease verbosity\n"
58  "\t-q\tDecrease verbosity\n"
59  "\nVersion: " GIT_VERSION_STRING "\n";
60 
61  opterr = 0; // Handle errors ourselves
62  int go = 0;
63  bool doUsage = false;
64  while ((go = getopt(argc, argv, "vq")) != -1) {
65  switch (go) {
66  case 'v':
67  state.verbose++;
68  break;
69  case 'q':
70  state.verbose--;
71  break;
72  case '?':
73  log_error(&state, "Unknown option `-%c'", optopt);
74  doUsage = true;
75  }
76  }
77 
78  // Should be 1 spare arguments: The file to convert
79  if (argc - optind != 1) {
80  log_error(&state, "Invalid arguments");
81  doUsage = true;
82  }
83 
84  if (doUsage) {
85  fprintf(stderr, usage, argv[0]);
86  return -1;
87  }
88 
89  int hdl = lpms_openConnection(argv[optind], 921600);
90 
91  state.started = true;
92  bool processing = true;
93 
94  uint8_t buf[BUFSIZE] = {0};
95  size_t hw = 0;
96  int count = 0;
97  size_t end = 0;
99  usleep(10000);
100  lpms_message getModel = {.id = 0x01, .command = LPMS_MSG_GET_SENSORMODEL};
101  lpms_send_command(hdl, &getModel);
102  lpms_message getFW = {.id = 0x01, .command = LPMS_MSG_GET_FIRMWAREVER};
103  lpms_send_command(hdl, &getFW);
104  lpms_message getSerial = {.id = 0x01, .command = LPMS_MSG_GET_SERIALNUM};
105  lpms_send_command(hdl, &getSerial);
106  lpms_message getTransmitted = {.id = 0x01, .command = LPMS_MSG_GET_OUTPUTS};
107  lpms_send_command(hdl, &getTransmitted);
108  usleep(10000);
110  lpms_data d = {0};
111  while (processing || hw > 10) {
112  lpms_message *m = calloc(1, sizeof(lpms_message));
113  if (!m) {
114  perror("lpms_message calloc");
115  return EXIT_FAILURE;
116  }
117  bool r = lpms_readMessage_buf(hdl, m, buf, &end, &hw);
118  if (r) {
119  uint16_t cs = 0;
120  bool csOK = (lpms_checksum(m, &cs) && cs == m->checksum);
121  if (m->command == LPMS_MSG_GET_OUTPUTS) {
122  d.present = (uint32_t)m->data[0] + ((uint32_t)m->data[1] << 8) +
123  ((uint32_t)m->data[2] << 16) +
124  ((uint32_t)m->data[3] << 24);
125  log_info(&state, 2, "%02x: Output configuration received", m->id);
126  } else if (m->command == LPMS_MSG_GET_SENSORMODEL) {
127  log_info(&state, 2, "%02x: Sensor model: %-24s", m->id,
128  (char *)m->data);
129  } else if (m->command == LPMS_MSG_GET_SERIALNUM) {
130  log_info(&state, 2, "%02x: Serial number: %-24s", m->id,
131  (char *)m->data);
132  } else if (m->command == LPMS_MSG_GET_FIRMWAREVER) {
133  log_info(&state, 2, "%02x: Firmware version: %-24s", m->id,
134  (char *)m->data);
135  } else if (m->command == LPMS_MSG_GET_IMUDATA) {
136  if (lpms_imu_set_timestamp(m, &d)) {
137  log_info(&state, 1, "%02x: Timestamp: %u", m->id,
138  d.timestamp);
139  } else {
140  log_warning(&state, "%02x: Timestamp invalid", m->id);
141  }
142  if (lpms_imu_set_accel_raw(m, &d)) {
143  log_info(&state, 1,
144  "%02x: Raw Acceleration: (%+.4f, %+.4f, %+4.f)",
145  m->id, d.accel_raw[0], d.accel_raw[1],
146  d.accel_raw[2]);
147  }
148  if (lpms_imu_set_accel_cal(m, &d)) {
149  log_info(
150  &state, 1,
151  "%02x: Calibrated Acceleration: (%+.4f, %+.4f, %+4.f)",
152  m->id, d.accel_cal[0], d.accel_cal[1],
153  d.accel_cal[2]);
154  }
155  if (lpms_imu_set_gyro_raw(m, &d)) {
156  log_info(&state, 1,
157  "%02x: Raw Gyro: (%+.4f, %+.4f, %+4.f)", m->id,
158  d.gyro_raw[0], d.gyro_raw[1], d.gyro_raw[2]);
159  }
160  if (lpms_imu_set_gyro_cal(m, &d)) {
161  log_info(&state, 1,
162  "%02x: Calibrated Gyro: (%+.4f, %+.4f, %+4.f)",
163  m->id, d.gyro_cal[0], d.gyro_cal[1],
164  d.gyro_cal[2]);
165  }
166  if (lpms_imu_set_gyro_aligned(m, &d)) {
167  log_info(&state, 1,
168  "%02x: Aligned Gyro: (%+.4f, %+.4f, %+4.f)",
169  m->id, d.gyro_aligned[0], d.gyro_aligned[1],
170  d.gyro_aligned[2]);
171  }
172  if (lpms_imu_set_mag_raw(m, &d)) {
173  log_info(&state, 1,
174  "%02x: Raw Magnetic Field: (%+.4f, %+.4f, %+4.f)",
175  m->id, d.mag_raw[0], d.mag_raw[1], d.mag_raw[2]);
176  }
177  if (lpms_imu_set_mag_cal(m, &d)) {
178  log_info(
179  &state, 1,
180  "%02x: Calibrated Magnetic Field: (%+.4f, %+.4f, %+4.f)",
181  m->id, d.mag_cal[0], d.mag_cal[1], d.mag_cal[2]);
182  }
183  if (lpms_imu_set_euler_angles(m, &d)) {
184  log_info(&state, 1,
185  "%02x: Euler roll angles: (%+.4f, %+.4f, %+.4f)",
186  m->id, d.euler_angles[0], d.euler_angles[1],
187  d.euler_angles[2]);
188  }
189  if (lpms_imu_set_pressure(m, &d)) {
190  log_info(&state, 1, "%02x: Pressure: %.2f", m->id,
191  d.pressure);
192  }
193  if (lpms_imu_set_altitude(m, &d)) {
194  log_info(&state, 1, "%02x: Altitude: %.2f", m->id,
195  d.altitude);
196  }
197  if (lpms_imu_set_temperature(m, &d)) {
198  log_info(&state, 1, "%02x: Temperature: %.2f", m->id,
199  d.temperature);
200  }
201  } else {
202  log_info(&state, 1, "%02x: Command %02x, %u bytes, checksum %s",
203  m->id, m->command, m->length, csOK ? "OK" : "not OK");
204  }
205  count++;
206  } else {
207  if (m->command > 0 || m->id > 0 || m->length > 0) {
208  log_info(&state, 1, "%02x: [Error] - Command %02x, %u bytes",
209  m->id, m->command, m->length);
210  }
211  if (m->id == 0xAA || m->id == 0xEE) {
212  log_error(&state,
213  "Error reading messages from file (Code: 0x%02x)\n",
214  (uint8_t)m->id);
215  }
216 
217  if (m->id == 0xFD) {
218  processing = false;
219  if (end < hw) { end++; }
220  }
221  }
222 
223  if (m) {
224  if (m->data) { free(m->data); }
225  free(m);
226  m = NULL;
227  }
228  }
229  log_info(&state, 0, "%d messages successfully read from file", count);
230  return 0;
231 }
bool lpms_readMessage_buf(int handle, lpms_message *out, uint8_t buf[LPMS_BUFF], size_t *index, size_t *hw)
Read data from handle, and parse message if able.
bool lpms_send_command(const int handle, lpms_message *m)
Write command defined by structure to handle.
int lpms_openConnection(const char *device, const int baud)
Open connection to an LPMS serial device.
bool lpms_send_stream_mode(const int handle)
Shortcut: Send LPMS_MSG_MODE_STREAM.
bool lpms_send_command_mode(const int handle)
Shortcut: Send LPMS_MSG_MODE_CMD.
bool lpms_imu_set_temperature(const lpms_message *msg, lpms_data *d)
Extract temperature from lpms_message into lpms_data, if available.
Definition: LPMSMessages.c:501
bool lpms_checksum(const lpms_message *msg, uint16_t *csum)
Calculate checksum for LPMS message packet.
Definition: LPMSMessages.c:135
bool lpms_imu_set_gyro_aligned(const lpms_message *msg, lpms_data *d)
Extract gyro_aligned from lpms_message into lpms_data, if available.
Definition: LPMSMessages.c:258
bool lpms_imu_set_mag_cal(const lpms_message *msg, lpms_data *d)
Extract mag_cal from lpms_message into lpms_data, if available.
Definition: LPMSMessages.c:305
bool lpms_imu_set_altitude(const lpms_message *msg, lpms_data *d)
Extract altitude from lpms_message into lpms_data, if available.
Definition: LPMSMessages.c:470
bool lpms_imu_set_euler_angles(const lpms_message *msg, lpms_data *d)
Extract euler_angles from lpms_message into lpms_data, if available.
Definition: LPMSMessages.c:383
bool lpms_imu_set_gyro_raw(const lpms_message *msg, lpms_data *d)
Extract gyro_raw from lpms_message into lpms_data, if available.
Definition: LPMSMessages.c:214
bool lpms_imu_set_accel_raw(const lpms_message *msg, lpms_data *d)
Extract accel_raw from lpms_message into lpms_data, if available.
Definition: LPMSMessages.c:178
bool lpms_imu_set_timestamp(const lpms_message *msg, lpms_data *d)
Extract timestamp from lpms_message into lpms_data, if available.
Definition: LPMSMessages.c:161
bool lpms_imu_set_accel_cal(const lpms_message *msg, lpms_data *d)
Extract accel_cal from lpms_message into lpms_data, if available.
Definition: LPMSMessages.c:194
bool lpms_imu_set_pressure(const lpms_message *msg, lpms_data *d)
Extract pressure from lpms_message into lpms_data, if available.
Definition: LPMSMessages.c:440
bool lpms_imu_set_mag_raw(const lpms_message *msg, lpms_data *d)
Extract mag_raw from lpms_message into lpms_data, if available.
Definition: LPMSMessages.c:281
bool lpms_imu_set_gyro_cal(const lpms_message *msg, lpms_data *d)
Extract gyro_cal from lpms_message into lpms_data, if available.
Definition: LPMSMessages.c:235
int main(int argc, char *argv[])
Definition: LPMSTest.c:52
#define BUFSIZE
Allocated read buffer size.
Definition: LPMSTest.c:40
#define LPMS_MSG_GET_OUTPUTS
Get fields configured for IMUDATA messages.
Definition: LPMSMessages.h:64
#define LPMS_MSG_GET_SERIALNUM
Get serial number as 24 character string.
Definition: LPMSMessages.h:61
#define LPMS_MSG_GET_IMUDATA
IMU data, as configured by LPMS_MSG_SET_OUTPUTS.
Definition: LPMSMessages.h:58
#define LPMS_MSG_GET_FIRMWAREVER
Get firmware version as 24 character string.
Definition: LPMSMessages.h:60
#define LPMS_MSG_GET_SENSORMODEL
Get hardware model as 24 character string.
Definition: LPMSMessages.h:59
void log_info(const program_state *s, const int level, const char *format,...)
Output formatted information message at a given level.
Definition: logging.c:125
void log_warning(const program_state *s, const char *format,...)
Output formatted warning message.
Definition: logging.c:86
void log_error(const program_state *s, const char *format,...)
Output formatted error message.
Definition: logging.c:47
LPMS IMU data packet.
Definition: LPMSTypes.h:72
float euler_angles[3]
Orientation as Euler roll angles [X].
Definition: LPMSTypes.h:83
float altitude
Altitude [m].
Definition: LPMSTypes.h:86
float temperature
Temperature [Celsius].
Definition: LPMSTypes.h:87
float gyro_aligned[3]
Calibrated and aligned gyroscope values [X/s].
Definition: LPMSTypes.h:78
float mag_cal[3]
Calibrated magnetometer values [uT].
Definition: LPMSTypes.h:80
float gyro_raw[3]
Raw gyroscope values [X/s].
Definition: LPMSTypes.h:76
uint32_t timestamp
Counted in 0.002s increments.
Definition: LPMSTypes.h:73
float accel_cal[3]
Calibrated accelerometer values [g].
Definition: LPMSTypes.h:75
float gyro_cal[3]
Calibrated gyroscope values [X/s].
Definition: LPMSTypes.h:77
float mag_raw[3]
Raw magnetometer values [uT].
Definition: LPMSTypes.h:79
float accel_raw[3]
Raw accelerometer values [g].
Definition: LPMSTypes.h:74
uint32_t present
Bitmask indicating set/valid members.
Definition: LPMSTypes.h:88
float pressure
Atmospheric pressure [kPa].
Definition: LPMSTypes.h:85
Represent LPMS message.
Definition: LPMSTypes.h:48
uint16_t length
Length of data, in bytes.
Definition: LPMSTypes.h:51
uint16_t checksum
Sum of all preceding message bytes.
Definition: LPMSTypes.h:52
uint8_t * data
Pointer to data array.
Definition: LPMSTypes.h:53
uint16_t id
Source/Destination Sensor ID.
Definition: LPMSTypes.h:49
uint16_t command
Message type.
Definition: LPMSTypes.h:50
Program state and logging information.
Definition: logging.h:40
int verbose
Current log verbosity (console output)
Definition: logging.h:43
bool started
Indicates startup completed.
Definition: logging.h:41
#define GIT_VERSION_STRING
Git version description.
Definition: version.h.in:13