+
+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;
+}