SELKIELogger  1.0.0
LPMSRead.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] datfile\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  FILE *nf = fopen(argv[optind], "r");
90 
91  if (nf == NULL) {
92  log_error(&state, "Unable to open input file \"%s\"", argv[optind]);
93  return -1;
94  }
95 
96  state.started = true;
97  bool processing = true;
98 
99  uint8_t buf[BUFSIZE] = {0};
100  size_t hw = 0;
101  int count = 0;
102  size_t end = 0;
103  while (processing || hw > 10) {
104  if (feof(nf) && processing) {
105  log_info(&state, 2, "End of file reached");
106  processing = false;
107  }
108  lpms_message *m = calloc(1, sizeof(lpms_message));
109  if (!m) {
110  perror("lpms_message calloc");
111  return EXIT_FAILURE;
112  }
113  bool r = lpms_readMessage_buf(fileno(nf), m, buf, &end, &hw);
114  if (r) {
115  uint16_t cs = 0;
116  bool csOK = (lpms_checksum(m, &cs) && cs == m->checksum);
117  if (m->command == LPMS_MSG_GET_IMUDATA) {
118  lpms_data d = {0};
119  // Guess based on observed data until detection implemented
120  d.present |= (1 << LPMS_IMU_ACCEL_RAW);
121  d.present |= (1 << LPMS_IMU_ACCEL_CAL);
122  d.present |= (1 << LPMS_IMU_MAG_RAW);
123  d.present |= (1 << LPMS_IMU_MAG_CAL);
124  d.present |= (1 << LPMS_IMU_GYRO_RAW);
125  d.present |= (1 << LPMS_IMU_GYRO_CAL);
126  d.present |= (1 << LPMS_IMU_GYRO_ALIGN);
127  d.present |= (1 << LPMS_IMU_OMEGA);
128  d.present |= (1 << LPMS_IMU_EULER);
129  d.present |= (1 << LPMS_IMU_ALTITUDE);
130  d.present |= (1 << LPMS_IMU_TEMPERATURE);
131  if (lpms_imu_set_timestamp(m, &d)) {
132  log_info(&state, 1, "%02x: Timestamp: %u", m->id,
133  d.timestamp);
134  } else {
135  log_warning(&state, "%02x: Timestamp invalid", m->id);
136  }
137  if (lpms_imu_set_accel_raw(m, &d)) {
138  log_info(&state, 1,
139  "%02x: Raw Acceleration: (%+.4f, %+.4f, %+4.f)",
140  m->id, d.accel_raw[0], d.accel_raw[1],
141  d.accel_raw[2]);
142  }
143  if (lpms_imu_set_accel_cal(m, &d)) {
144  log_info(
145  &state, 1,
146  "%02x: Calibrated Acceleration: (%+.4f, %+.4f, %+4.f)",
147  m->id, d.accel_cal[0], d.accel_cal[1],
148  d.accel_cal[2]);
149  }
150  if (lpms_imu_set_gyro_raw(m, &d)) {
151  log_info(&state, 1,
152  "%02x: Raw Gyro: (%+.4f, %+.4f, %+4.f)", m->id,
153  d.gyro_raw[0], d.gyro_raw[1], d.gyro_raw[2]);
154  }
155  if (lpms_imu_set_gyro_cal(m, &d)) {
156  log_info(&state, 1,
157  "%02x: Calibrated Gyro: (%+.4f, %+.4f, %+4.f)",
158  m->id, d.gyro_cal[0], d.gyro_cal[1],
159  d.gyro_cal[2]);
160  }
161  if (lpms_imu_set_gyro_aligned(m, &d)) {
162  log_info(&state, 1,
163  "%02x: Aligned Gyro: (%+.4f, %+.4f, %+4.f)",
164  m->id, d.gyro_aligned[0], d.gyro_aligned[1],
165  d.gyro_aligned[2]);
166  }
167  if (lpms_imu_set_mag_raw(m, &d)) {
168  log_info(&state, 1,
169  "%02x: Raw Magnetic Field: (%+.4f, %+.4f, %+4.f)",
170  m->id, d.mag_raw[0], d.mag_raw[1], d.mag_raw[2]);
171  }
172  if (lpms_imu_set_mag_cal(m, &d)) {
173  log_info(
174  &state, 1,
175  "%02x: Calibrated Magnetic Field: (%+.4f, %+.4f, %+4.f)",
176  m->id, d.mag_cal[0], d.mag_cal[1], d.mag_cal[2]);
177  }
178  if (lpms_imu_set_euler_angles(m, &d)) {
179  log_info(&state, 1,
180  "%02x: Euler roll angles: (%+.4f, %+.4f, %+.4f)",
181  m->id, d.euler_angles[0], d.euler_angles[1],
182  d.euler_angles[2]);
183  }
184  if (lpms_imu_set_pressure(m, &d)) {
185  log_info(&state, 1, "%02x: Pressure: %.2f", m->id,
186  d.pressure);
187  }
188  if (lpms_imu_set_altitude(m, &d)) {
189  log_info(&state, 1, "%02x: Altitude: %.2f", m->id,
190  d.altitude);
191  }
192  if (lpms_imu_set_temperature(m, &d)) {
193  log_info(&state, 1, "%02x: Temperature: %.2f", m->id,
194  d.temperature);
195  }
196  } else {
197  log_info(&state, 2, "%02x: Command %02x, %u bytes, checksum %s",
198  m->id, m->command, m->length, csOK ? "OK" : "not OK");
199  }
200  count++;
201  } else {
202  if (m->id == 0xAA || m->id == 0xEE) {
203  log_error(&state,
204  "Error reading messages from file (Code: 0x%02x)\n",
205  (uint8_t)m->id);
206  }
207 
208  if (m->id == 0xFD) {
209  processing = false;
210  if (end < hw) { end++; }
211  }
212  }
213 
214  if (m) {
215  if (m->data) { free(m->data); }
216  free(m);
217  m = NULL;
218  }
219  }
220  log_info(&state, 0, "%d messages successfully read from file", count);
221  fclose(nf);
222  return 0;
223 }
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_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: LPMSRead.c:52
#define BUFSIZE
Allocated read buffer size.
Definition: LPMSRead.c:40
#define LPMS_IMU_MAG_RAW
mag_raw[] will contain data
Definition: LPMSTypes.h:105
#define LPMS_IMU_EULER
euler[] will contain data
Definition: LPMSTypes.h:109
#define LPMS_IMU_OMEGA
omega[] will contain data
Definition: LPMSTypes.h:107
#define LPMS_IMU_ACCEL_CAL
accel_cal[] will contain data
Definition: LPMSTypes.h:101
#define LPMS_IMU_MAG_CAL
mag_cal[] will contain data
Definition: LPMSTypes.h:106
#define LPMS_IMU_GYRO_ALIGN
gyro_align[] will contain data
Definition: LPMSTypes.h:104
#define LPMS_IMU_TEMPERATURE
temperature will contain data
Definition: LPMSTypes.h:113
#define LPMS_IMU_ALTITUDE
altitude will contain data
Definition: LPMSTypes.h:112
#define LPMS_IMU_GYRO_CAL
gyro_cal[] will contain data
Definition: LPMSTypes.h:103
#define LPMS_IMU_GYRO_RAW
gyro_raw[] will contain data
Definition: LPMSTypes.h:102
#define LPMS_IMU_ACCEL_RAW
accel_raw[] will contain data
Definition: LPMSTypes.h:100
#define LPMS_MSG_GET_IMUDATA
IMU data, as configured by LPMS_MSG_SET_OUTPUTS.
Definition: LPMSMessages.h:58
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