Skip to content
Merged
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
61 changes: 60 additions & 1 deletion drivers/europe/apator/apator.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

#include "../../engine/driver.h"

#include <stdio.h>

/* amiplus — smart electricity (relabelled by NES, DEV, APT). */
static const WmbusMVT k_mvt_amiplus[] = {
{"APA", 0x01, 0x02},
Expand Down Expand Up @@ -95,6 +97,63 @@ const WmbusDriver wmbus_drv_apator_elf = {
* in the wild: wmbusmeters' apatoreitn driver registers (mfr, 0x08,
* 0x04) which is version=0x08, medium=0x04, while older firmware uses
* the inverted (0x04, 0x08). Cover both. */
static uint16_t apator_hca_le16(const uint8_t* p) {
return (uint16_t)p[0] | ((uint16_t)p[1] << 8);
}

static size_t apator_hca_fallback(const uint8_t* a, size_t len, char* o, size_t cap) {
size_t pos = (size_t)snprintf(o, cap, "Apator HCA\n");
pos += (size_t)snprintf(o + pos, cap - pos,
"Bytes %u\n"
"Status bad length\n",
(unsigned)len);

size_t off = 0;
int rows = 0;
while(off < len && rows < 3 && pos + 24 < cap) {
size_t n = len - off;
if(n > 6) n = 6;
pos += (size_t)snprintf(o + pos, cap - pos, "Hex%02u ", (unsigned)off);
for(size_t i = 0; i < n && pos + 3 < cap; i++) {
pos += (size_t)snprintf(o + pos, cap - pos, "%02X", a[off + i]);
}
if(pos + 1 < cap) {
o[pos++] = '\n';
o[pos] = '\0';
}
off += n;
rows++;
}

return pos;
}

static size_t decode_apator_hca(uint16_t m, uint8_t v, uint8_t med,
const uint8_t* a, size_t len,
char* o, size_t cap) {
(void)m;
(void)v;
(void)med;

if(len != 15) return apator_hca_fallback(a, len, o, cap);

const uint16_t units = apator_hca_le16(a + 3);
const uint16_t ref_units = apator_hca_le16(a + 7);

return (size_t)snprintf(o, cap,
"Apator HCA\n"
"Units %u\n"
"RefUnits %u\n"
"TempC %u\n"
"Marker %02X%02X\n"
"Flags %02X%02X%02X%02X%02X\n",
units,
ref_units,
(unsigned)a[12],
a[9], a[10],
a[5], a[6], a[11], a[13], a[14]);
}

static const WmbusMVT k_mvt_apator_hca[] = {
{"APA", 0x04, 0x08},
{"APT", 0x04, 0x08},
Expand All @@ -104,7 +163,7 @@ static const WmbusMVT k_mvt_apator_hca[] = {
};
const WmbusDriver wmbus_drv_apator_hca = {
.id = "apator-hca", .title = "Apator HCA",
.mvt = k_mvt_apator_hca, .decode = NULL,
.mvt = k_mvt_apator_hca, .decode = decode_apator_hca,
};

/* Ultrimis water (cold) */
Expand Down
16 changes: 14 additions & 2 deletions tests/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,17 @@ IZAR_SRC = test_izar.c \
test_izar: $(IZAR_SRC)
$(CC) $(CFLAGS) $(IZAR_SRC) -o $@

APATOR_HCA_SRC = test_apator_hca.c \
../drivers/europe/apator/apator.c \
../drivers/engine/driver.c \
../protocol/wmbus_link.c \
../protocol/wmbus_manuf.c \
../protocol/wmbus_medium.c \
../protocol/wmbus_app_layer.c

test_apator_hca: $(APATOR_HCA_SRC)
$(CC) $(CFLAGS) $(APATOR_HCA_SRC) -o $@

PORTS_SRC = test_ports.c \
../drivers/europe/bmeters/hydrodigit.c \
../drivers/europe/engelmann/hydroclima.c \
Expand All @@ -36,12 +47,13 @@ PORTS_SRC = test_ports.c \
test_ports: $(PORTS_SRC)
$(CC) $(CFLAGS) $(PORTS_SRC) -o $@

check: test_link test_izar test_ports
check: test_link test_izar test_apator_hca test_ports
./test_link
./test_izar
./test_apator_hca
./test_ports

clean:
rm -f test_link test_izar test_ports
rm -f test_link test_izar test_apator_hca test_ports

.PHONY: check clean
68 changes: 68 additions & 0 deletions tests/test_apator_hca.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#include "../drivers/engine/driver.h"

#include <stdio.h>
#include <string.h>

extern const WmbusDriver wmbus_drv_apator_hca;

const WmbusDriver* const wmbus_engine_registry[] = { &wmbus_drv_apator_hca };
const size_t wmbus_engine_registry_len = 1;

#define MANUF(a, b, c) \
((uint16_t)((((uint16_t)((a) - '@')) << 10) | \
(((uint16_t)((b) - '@')) << 5) | \
((uint16_t)((c) - '@'))))

static int expect_contains(const char* name, const char* out, const char* expected) {
if(strstr(out, expected)) return 0;
fprintf(stderr, "%s: missing '%s' in:\n%s\n", name, expected, out);
return 1;
}

static int run_sample(void) {
const uint8_t apdu[] = {
0x21, 0x01, 0x00, 0x87, 0x19, 0x00, 0x00, 0x04,
0x20, 0xE7, 0x34, 0x88, 0x16, 0x08, 0x19,
};
char out[256];
int fails = 0;

wmbus_engine_decode(MANUF('A', 'P', 'A'), 0x04, 0x08,
apdu, sizeof(apdu), out, sizeof(out));

fails += expect_contains("sample", out, "Apator HCA\n");
fails += expect_contains("sample", out, "Units 6535\n");
fails += expect_contains("sample", out, "RefUnits 8196\n");
fails += expect_contains("sample", out, "TempC 22\n");
fails += expect_contains("sample", out, "Marker E734\n");
fails += expect_contains("sample", out, "Flags 0000880819\n");

return fails;
}

static int run_bad_length(void) {
const uint8_t apdu[] = {0x21, 0x01, 0x00};
char out[256];
int fails = 0;

wmbus_engine_decode(MANUF('A', 'P', 'A'), 0x04, 0x08,
apdu, sizeof(apdu), out, sizeof(out));

fails += expect_contains("bad_length", out, "Apator HCA\n");
fails += expect_contains("bad_length", out, "Bytes 3\n");
fails += expect_contains("bad_length", out, "Status bad length\n");
fails += expect_contains("bad_length", out, "Hex00 210100\n");

return fails;
}

int main(void) {
int fails = 0;

fails += run_sample();
fails += run_bad_length();

if(fails) return 1;
printf("All Apator HCA tests passed.\n");
return 0;
}
Binary file removed tests/test_link
Binary file not shown.
Loading