add trinketSetAlarmLevel
[trinked.git] / trinket.c
index 82822b3..002687c 100644 (file)
--- a/trinket.c
+++ b/trinket.c
@@ -7,10 +7,10 @@
  * modification, are permitted provided that the following conditions
  * are met:
  * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
+ *       notice, this list of conditions and the following disclaimer.
  * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
  *
  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  *-------------------------------------------------------------------------
  */
 
-#include <assert.h>
 #include <stdint.h>
 #include <stdio.h>
+#include <string.h>
+
 #include <hidapi/hidapi.h>
+
+#include <tlog.h>
 #include <trinket.h>
 
 #define         packed_struct __attribute__((packed))
@@ -75,7 +78,8 @@ typedef struct {
        uint32_t                respLen; /* 0 means variable, > 0 fixed */
 } TrinketProtoDesc;
 
-static const TrinketProtoDesc protoDesc[] = { 
+/* hardcoded knowledge from  docs/geyger.pdf */
+static const TrinketProtoDesc protoDesc[] = {
        {CMD_PING,                      4,              5                               },
        {CMD_VCC_VALUE,         4,              8                               },
        {CMD_VCC_ALARM,         8,              8                               },
@@ -104,21 +108,22 @@ dumpBuf(char *msg, uint8_t *buf, int len) {
 
 TrinketErrorCode
 trinketOpen() {
-#ifndef NDEBUG
+       TrinketErrorCode        r;
        int i;
 
        for(i = 0; i < sizeof(protoDesc) / sizeof(*protoDesc); i++)
-               assert(i == protoDesc[i].cmdId);
-#endif
+               tassert(i == protoDesc[i].cmdId);
 
        trinketDev = hid_open(0x2047, 0x0301, NULL);
 
        if (trinketDev == NULL) {
-               fprintf(stderr, "hid_open fails\n");
+               tlog(TL_WARN, "hid_open fails");
                return ERR_ERROR;
        }
 
-       return trinketPing();
+       if ((r = trinketPing()) != ERR_OK)
+               trinketClose();
+       return r;
 }
 
 void
@@ -153,14 +158,14 @@ trinketPing() {
        } resp;
        int     r;
 
-       assert(proto->cmdId == CMD_PING);
-       assert(sizeof(cmd) == cmd.len + sizeof(ProtoHeader));
-       assert(sizeof(resp) == proto->respLen + sizeof(ProtoHeader));
+       tassert(proto->cmdId == CMD_PING);
+       tassert(sizeof(cmd) == cmd.len + sizeof(ProtoHeader));
+       tassert(sizeof(resp) == proto->respLen + sizeof(ProtoHeader));
 
        r = hid_write(trinketDev, (unsigned char*)&cmd, sizeof(cmd));
 
        if (r < 0 || r != sizeof(cmd)) {
-               fprintf(stderr, "hid_write  returns %d instead of %u\n", r, cmd.len);
+               tlog(TL_WARN, "hid_write  returns %d instead of %u", r, cmd.len);
                return ERR_ERROR;
        }
 
@@ -169,32 +174,32 @@ trinketPing() {
 
        r = hid_read_timeout(trinketDev, (unsigned char*)&resp, sizeof(resp), DEV_TIMEOUT);
        if (r < 0) {
-               fprintf(stderr, "hid_read_timeout fails\n");
+               tlog(TL_WARN, "hid_read_timeout fails");
                return  ERR_NO_ANSWER;
        }
 
        if (r != sizeof(resp)) {
-               fprintf(stderr, "hid_read_timeout  returns %d instead of %u\n", r, (unsigned int)sizeof(resp));
+               tlog(TL_WARN, "hid_read_timeout  returns %d instead of %u", r, (unsigned int)sizeof(resp));
                return ERR_ERROR;
        }
 
        if (resp.header.reportId != REPORT_ID) {
-               fprintf(stderr, "hid_read_timeout  returns report id %02x instead of %02x\n", resp.header.reportId, REPORT_ID);
+               tlog(TL_WARN, "hid_read_timeout  returns report id %02x instead of %02x", resp.header.reportId, REPORT_ID);
                return ERR_ERROR;
        }
 
        if (resp.header.size != proto->respLen) {
-               fprintf(stderr, "hid_read_timeout returns length %u intsead if %u\n", resp.header.size, proto->respLen);
+               tlog(TL_WARN, "hid_read_timeout returns length %u intsead if %u", resp.header.size, proto->respLen);
                return ERR_PROTO;
        }
 
        if (resp.len != proto->respLen) {
-               fprintf(stderr, "hid_read_timeout response length %u instead of %u\n", resp.len, proto->respLen);
+               tlog(TL_WARN, "hid_read_timeout response length %u instead of %u", resp.len, proto->respLen);
                return ERR_PROTO;
        }
 
        if (!(resp.begin == ACK_ANSWER_OK && resp.payload == 0 && resp.end == END_ANSWER)) {
-               fprintf(stderr, "hid_read_timeout  ACK %02x with payload %u and ETB %02x\n", resp.begin, resp.payload, resp.end);
+               tlog(TL_WARN, "hid_read_timeout  ACK %02x with payload %u and ETB %02x", resp.begin, resp.payload, resp.end);
                return ERR_PROTO;
        }
 
@@ -226,14 +231,14 @@ trinketGetCumDose(double *value) {
        } resp;
        int     r;
 
-       assert(proto->cmdId == CMD_CUM_DOSE);
-       assert(sizeof(cmd) == cmd.len + sizeof(ProtoHeader));
-       assert(sizeof(resp) == proto->respLen + sizeof(ProtoHeader));
+       tassert(proto->cmdId == CMD_CUM_DOSE);
+       tassert(sizeof(cmd) == cmd.len + sizeof(ProtoHeader));
+       tassert(sizeof(resp) == proto->respLen + sizeof(ProtoHeader));
 
        r = hid_write(trinketDev, (unsigned char*)&cmd, sizeof(cmd));
 
        if (r < 0 || r != sizeof(cmd)) {
-               fprintf(stderr, "hid_send_feature_report  returns %d instead of %u\n", r, cmd.len);
+               tlog(TL_WARN, "hid_send_feature_report  returns %d instead of %u", r, cmd.len);
                return ERR_ERROR;
        }
 
@@ -242,32 +247,32 @@ trinketGetCumDose(double *value) {
 
        r = hid_read_timeout(trinketDev, (unsigned char*)&resp, sizeof(resp), DEV_TIMEOUT);
        if (r < 0) {
-               fprintf(stderr, "hid_read_timeout fails\n");
+               tlog(TL_WARN, "hid_read_timeout fails");
                return  ERR_NO_ANSWER;
        }
 
        if (r != sizeof(resp)) {
-               fprintf(stderr, "hid_read_timeout  returns %d instead of %u\n", r, (unsigned int)sizeof(resp));
+               tlog(TL_WARN, "hid_read_timeout  returns %d instead of %u", r, (unsigned int)sizeof(resp));
                return ERR_ERROR;
        }
 
        if (resp.header.reportId != REPORT_ID) {
-               fprintf(stderr, "hid_read_timeout  returns report id %02x instead of %02x\n", resp.header.reportId, REPORT_ID);
+               tlog(TL_WARN, "hid_read_timeout  returns report id %02x instead of %02x", resp.header.reportId, REPORT_ID);
                return ERR_ERROR;
        }
 
        if (resp.header.size != proto->respLen) {
-               fprintf(stderr, "hid_read_timeout returns length %u intsead if %u\n", resp.header.size, proto->respLen);
+               tlog(TL_WARN, "hid_read_timeout returns length %u intsead if %u", resp.header.size, proto->respLen);
                return ERR_PROTO;
        }
 
        if (resp.len != proto->respLen) {
-               fprintf(stderr, "hid_read_timeout response length %u instead of %u\n", resp.len, proto->respLen);
+               tlog(TL_WARN, "hid_read_timeout response length %u instead of %u", resp.len, proto->respLen);
                return ERR_PROTO;
        }
 
        if (!(resp.begin == ACK_ANSWER_OK && resp.end == END_ANSWER)) {
-               fprintf(stderr, "hid_read_timeout  ACK %02x and ETB %02x\n", resp.begin, resp.end);
+               tlog(TL_WARN, "hid_read_timeout  ACK %02x and ETB %02x", resp.begin, resp.end);
                return ERR_PROTO;
        }
 
@@ -275,3 +280,82 @@ trinketGetCumDose(double *value) {
 
        return ERR_OK;
 }
+
+TrinketErrorCode
+trinketSetAlarmLevel(double value[N_ALARM_LEVELS]) {
+       const TrinketProtoDesc  *proto = &protoDesc[CMD_ALARM_LEVELS];
+       struct {
+               ProtoHeader header;
+               uint8_t         begin;
+               uint8_t         len;
+               uint8_t         cmd;
+               float           levels[N_ALARM_LEVELS];
+               uint8_t         end;
+       } cmd = {
+                                       {REPORT_ID, proto->cmdLen},
+                                       BEGIN_COMMAND,
+                                       proto->cmdLen,
+                                       proto->cmdId,
+                                       {0,0,0,0,0},
+                                       END_COMMAND
+       };
+       struct packed_struct {
+               ProtoHeader header;
+               uint8_t         begin;
+               uint16_t        len;
+               float           payload[N_ALARM_LEVELS];
+               uint8_t         end;
+       } resp;
+       int     r;
+
+       tassert(proto->cmdId == CMD_ALARM_LEVELS);
+       tassert(sizeof(cmd) == cmd.len + sizeof(ProtoHeader));
+       tassert(sizeof(resp) == proto->respLen + sizeof(ProtoHeader));
+
+       memcpy(cmd.levels, value, sizeof(value[0]) * N_ALARM_LEVELS);
+
+       r = hid_write(trinketDev, (unsigned char*)&cmd, sizeof(cmd));
+
+       if (r < 0 || r != sizeof(cmd)) {
+               tlog(TL_WARN, "hid_send_feature_report  returns %d instead of %u", r, cmd.len);
+               return ERR_ERROR;
+       }
+
+       /* must be assigned to 0x3F by the host */
+       resp.header.reportId = REPORT_ID;
+
+       r = hid_read_timeout(trinketDev, (unsigned char*)&resp, sizeof(resp), DEV_TIMEOUT);
+       if (r < 0) {
+               tlog(TL_WARN, "hid_read_timeout fails");
+               return  ERR_NO_ANSWER;
+       }
+
+       if (r != sizeof(resp)) {
+               tlog(TL_WARN, "hid_read_timeout  returns %d instead of %u", r, (unsigned int)sizeof(resp));
+               return ERR_ERROR;
+       }
+
+       if (resp.header.reportId != REPORT_ID) {
+               tlog(TL_WARN, "hid_read_timeout  returns report id %02x instead of %02x", resp.header.reportId, REPORT_ID);
+               return ERR_ERROR;
+       }
+
+       if (resp.header.size != proto->respLen) {
+               tlog(TL_WARN, "hid_read_timeout returns length %u intsead if %u", resp.header.size, proto->respLen);
+               return ERR_PROTO;
+       }
+
+       if (resp.len != proto->respLen) {
+               tlog(TL_WARN, "hid_read_timeout response length %u instead of %u", resp.len, proto->respLen);
+               return ERR_PROTO;
+       }
+
+       if (!(resp.begin == ACK_ANSWER_OK && resp.end == END_ANSWER)) {
+               tlog(TL_WARN, "hid_read_timeout  ACK %02x and ETB %02x", resp.begin, resp.end);
+               return ERR_PROTO;
+       }
+
+       memcpy(value, resp.payload, sizeof(value[0]) * N_ALARM_LEVELS);
+
+       return ERR_OK;
+}