|
22 | 22 | #include <stdlib.h>
|
23 | 23 | #include <stdio.h>
|
24 | 24 | #include <string.h>
|
| 25 | +#include <stdbool.h> |
| 26 | +#include <limits.h> |
25 | 27 |
|
26 | 28 | #ifdef _MSC_VER
|
27 | 29 | #define snprintf _snprintf
|
|
88 | 90 | (((micro) & 0x1F) << 1) | \
|
89 | 91 | ((beta) & 0x01))
|
90 | 92 |
|
| 93 | +#define OSTC4_COMPASS_HEADING_CLEARED_FLAG 0x8000 |
| 94 | +#define OSTC4_COMPASS_HEADING_SET_FLAG 0x4000 |
| 95 | + |
| 96 | +#define OSTC4_SCRUBBER_STATE_ERROR_FLAG 0x4000 |
| 97 | +#define OSTC4_SCRUBBER_STATE_WARNING_FLAG 0x2000 |
| 98 | + |
91 | 99 | typedef struct hw_ostc_sample_info_t {
|
92 | 100 | unsigned int type;
|
93 | 101 | unsigned int divisor;
|
@@ -139,6 +147,10 @@ typedef struct hw_ostc_parser_t {
|
139 | 147 | unsigned int initial_setpoint;
|
140 | 148 | unsigned int initial_cns;
|
141 | 149 | hw_ostc_gasmix_t gasmix[NGASMIXES];
|
| 150 | + int first_scrubber_time_minutes; |
| 151 | + int last_scrubber_time_minutes; |
| 152 | + bool scrubber_error_reported; |
| 153 | + bool scrubber_warning_reported; |
142 | 154 | } hw_ostc_parser_t;
|
143 | 155 |
|
144 | 156 | static dc_status_t hw_ostc_parser_get_datetime (dc_parser_t *abstract, dc_datetime_t *datetime);
|
@@ -438,6 +450,10 @@ hw_ostc_parser_create_internal (dc_parser_t **out, dc_context_t *context, const
|
438 | 450 | parser->gasmix[i].active = 0;
|
439 | 451 | parser->gasmix[i].diluent = 0;
|
440 | 452 | }
|
| 453 | + parser->first_scrubber_time_minutes = INT_MAX; |
| 454 | + parser->last_scrubber_time_minutes = INT_MAX; |
| 455 | + parser->scrubber_error_reported = false; |
| 456 | + parser->scrubber_warning_reported = false; |
441 | 457 | parser->serial = serial;
|
442 | 458 |
|
443 | 459 | *out = (dc_parser_t *) parser;
|
@@ -800,6 +816,22 @@ hw_ostc_parser_get_field (dc_parser_t *abstract, dc_field_type_t type, unsigned
|
800 | 816 | else
|
801 | 817 | return DC_STATUS_DATAFORMAT;
|
802 | 818 | break;
|
| 819 | + case 6: |
| 820 | + if (parser->first_scrubber_time_minutes == INT_MAX) { |
| 821 | + return DC_STATUS_DATAFORMAT; |
| 822 | + } |
| 823 | + |
| 824 | + string->desc = "Remaining scrubber time at start [minutes]"; |
| 825 | + snprintf(buf, BUFLEN, "%d", parser->first_scrubber_time_minutes); |
| 826 | + break; |
| 827 | + case 7: |
| 828 | + if (parser->last_scrubber_time_minutes == INT_MAX) { |
| 829 | + return DC_STATUS_DATAFORMAT; |
| 830 | + } |
| 831 | + |
| 832 | + string->desc = "Remaining scrubber time at end [minutes]"; |
| 833 | + snprintf(buf, BUFLEN, "%d", parser->last_scrubber_time_minutes); |
| 834 | + break; |
803 | 835 | default:
|
804 | 836 | return DC_STATUS_UNSUPPORTED;
|
805 | 837 | }
|
@@ -928,6 +960,7 @@ hw_ostc_parser_internal_foreach (hw_ostc_parser_t *parser, dc_sample_callback_t
|
928 | 960 | unsigned int tank = parser->initial != UNDEFINED ? parser->initial - 1 : 0;
|
929 | 961 |
|
930 | 962 | unsigned int offset = header;
|
| 963 | + char buf[BUFLEN]; |
931 | 964 | if (version == 0x23 || version == 0x24)
|
932 | 965 | offset += 5 + 3 * nconfig;
|
933 | 966 | while (offset + 3 <= size) {
|
@@ -1135,30 +1168,83 @@ hw_ostc_parser_internal_foreach (hw_ostc_parser_t *parser, dc_sample_callback_t
|
1135 | 1168 | // Compass heading update
|
1136 | 1169 | if (events & 0x0200) {
|
1137 | 1170 | if (length < 2) {
|
1138 |
| - ERROR (abstract->context, "Buffer overflow detected!"); |
| 1171 | + ERROR (abstract->context, "Buffer underflow detected!"); |
1139 | 1172 | return DC_STATUS_DATAFORMAT;
|
1140 | 1173 | }
|
1141 | 1174 |
|
1142 | 1175 | if (callback) {
|
1143 |
| - unsigned int heading = array_uint16_le(data + offset); |
| 1176 | + unsigned int value = array_uint16_le(data + offset); |
1144 | 1177 | dc_sample_value_t sample = {
|
1145 | 1178 | .event.type = SAMPLE_EVENT_STRING,
|
1146 | 1179 | .event.flags = SAMPLE_FLAGS_SEVERITY_INFO,
|
1147 | 1180 | };
|
1148 | 1181 |
|
1149 |
| - if (heading & 0x8000) { |
1150 |
| - sample.event.name = "Cleared compass heading"; |
| 1182 | + unsigned int heading = value & 0x1FF; |
| 1183 | + if (value & OSTC4_COMPASS_HEADING_CLEARED_FLAG) { |
| 1184 | + snprintf(buf, BUFLEN, "Cleared compass heading"); |
1151 | 1185 | } else {
|
1152 |
| - if (heading & 0x4000) { |
| 1186 | + sample.event.value = heading; |
| 1187 | + |
| 1188 | + if (value & OSTC4_COMPASS_HEADING_SET_FLAG) { |
1153 | 1189 | sample.event.type = SAMPLE_EVENT_HEADING;
|
1154 |
| - sample.event.name = "Set compass heading"; |
| 1190 | + snprintf(buf, BUFLEN, "Set compass heading [degrees]%s", sample.event.value ? "" : ": 0"); |
1155 | 1191 | } else {
|
1156 |
| - sample.event.name = "Logged compass heading"; |
| 1192 | + snprintf(buf, BUFLEN, "Logged compass heading [degrees]%s", sample.event.value ? "" : ": 0"); |
1157 | 1193 | }
|
1158 | 1194 |
|
1159 |
| - sample.event.value = heading & 0x1FF; |
1160 | 1195 | }
|
1161 | 1196 |
|
| 1197 | + sample.event.name = buf; |
| 1198 | + |
| 1199 | + callback(DC_SAMPLE_EVENT, &sample, userdata); |
| 1200 | + } |
| 1201 | + |
| 1202 | + offset += 2; |
| 1203 | + length -= 2; |
| 1204 | + } |
| 1205 | + |
| 1206 | + // Scrubber state update |
| 1207 | + if (events & 0x0800) { |
| 1208 | + if (length < 2) { |
| 1209 | + ERROR (abstract->context, "Buffer underflow detected!"); |
| 1210 | + return DC_STATUS_DATAFORMAT; |
| 1211 | + } |
| 1212 | + |
| 1213 | + unsigned int scrubberState = array_uint16_le(data + offset); |
| 1214 | + int scrubberTimeMinutes = scrubberState & 0x0FFF; // Extract the 12-bit value |
| 1215 | + if (scrubberState & 0x0800) { // Check if the sign bit is set |
| 1216 | + scrubberTimeMinutes -= 0x1000; // Perform sign extension |
| 1217 | + } |
| 1218 | + if (parser->first_scrubber_time_minutes == INT_MAX) { |
| 1219 | + parser->first_scrubber_time_minutes = scrubberTimeMinutes; |
| 1220 | + } |
| 1221 | + parser->last_scrubber_time_minutes = scrubberTimeMinutes; |
| 1222 | + |
| 1223 | + if (callback) { |
| 1224 | + dc_sample_value_t sample = { |
| 1225 | + .event.type = SAMPLE_EVENT_STRING, |
| 1226 | + .event.flags = SAMPLE_FLAGS_SEVERITY_STATE, |
| 1227 | + .event.value = scrubberTimeMinutes, |
| 1228 | + }; |
| 1229 | + |
| 1230 | + if (scrubberState & OSTC4_SCRUBBER_STATE_ERROR_FLAG) { |
| 1231 | + if (!parser->scrubber_error_reported) { |
| 1232 | + sample.event.flags = SAMPLE_FLAGS_SEVERITY_ALARM; |
| 1233 | + parser->scrubber_error_reported = true; |
| 1234 | + } |
| 1235 | + snprintf(buf, BUFLEN, "Scrubber exhausted, time remaining [minutes]%s", sample.event.value ? "" : ": 0"); |
| 1236 | + } else if (scrubberState & OSTC4_SCRUBBER_STATE_WARNING_FLAG) { |
| 1237 | + if (!parser->scrubber_warning_reported) { |
| 1238 | + sample.event.flags = SAMPLE_FLAGS_SEVERITY_WARN; |
| 1239 | + parser->scrubber_warning_reported = true; |
| 1240 | + } |
| 1241 | + snprintf(buf, BUFLEN, "Scrubber warning, time remaining [minutes]%s", sample.event.value ? "" : ": 0"); |
| 1242 | + } else { |
| 1243 | + snprintf(buf, BUFLEN, "Scrubber time remaining [minutes]%s", sample.event.value ? "" : ": 0"); |
| 1244 | + } |
| 1245 | + |
| 1246 | + sample.event.name = buf; |
| 1247 | + |
1162 | 1248 | callback(DC_SAMPLE_EVENT, &sample, userdata);
|
1163 | 1249 | }
|
1164 | 1250 |
|
|
0 commit comments