forked from wirenboard/wb-mqtt-serial
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathuniel_device.cpp
117 lines (103 loc) · 3.34 KB
/
uniel_device.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/select.h>
#include <fcntl.h>
#include <stdio.h>
#include <termios.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <iostream>
#include "uniel_device.h"
namespace {
enum {
READ_CMD = 0x05,
WRITE_CMD = 0x06,
SET_BRIGHTNESS_CMD = 0x0a
};
}
REGISTER_BASIC_INT_PROTOCOL("uniel", TUnielDevice, TRegisterTypes({
{ TUnielDevice::REG_RELAY, "relay", "switch", U8 },
{ TUnielDevice::REG_INPUT, "input", "text", U8, true },
{ TUnielDevice::REG_PARAM, "param", "value", U8 },
// "value", not "range" because 'max' cannot be specified here.
{ TUnielDevice::REG_BRIGHTNESS, "brightness", "value", U8 }
}));
TUnielDevice::TUnielDevice(PDeviceConfig config, PPort port, PProtocol protocol)
: TBasicProtocolSerialDevice<TBasicProtocol<TUnielDevice>>(config, port, protocol)
{}
void TUnielDevice::WriteCommand(uint8_t cmd, uint8_t mod, uint8_t b1, uint8_t b2, uint8_t b3)
{
Port()->CheckPortOpen();
uint8_t buf[8];
buf[0] = buf[1] = 0xff;
buf[2] = cmd;
buf[3] = mod;
buf[4] = b1;
buf[5] = b2;
buf[6] = b3;
buf[7] = (cmd + mod + b1 + b2 + b3) & 0xff;
Port()->WriteBytes(buf, 8);
}
void TUnielDevice::ReadResponse(uint8_t cmd, uint8_t* response)
{
uint8_t buf[5];
for (;;) {
uint8_t first = Port()->ReadByte();
if (first != 0xff) {
std::cerr << "uniel: warning: resync" << std::endl;
continue;
}
uint8_t second = Port()->ReadByte();
if (second == 0xff) {
second = Port()->ReadByte();
}
buf[0] = second;
uint8_t s = second;
for (int i = 1; i < 5; ++i) {
buf[i] = Port()->ReadByte();
s += buf[i];
}
if (Port()->ReadByte() != s)
throw TSerialDeviceTransientErrorException("uniel: warning: checksum failure");
break;
}
if (buf[0] != cmd)
throw TSerialDeviceTransientErrorException("bad command code in response");
if (buf[1] != 0)
throw TSerialDeviceTransientErrorException("bad module address in response");
for (int i = 2; i < 5; ++i)
*response++ = buf[i];
}
uint64_t TUnielDevice::ReadRegister(PRegister reg)
{
WriteCommand(READ_CMD, SlaveId, 0, uint8_t(reg->Address), 0);
uint8_t response[3];
ReadResponse(READ_CMD, response);
if (response[1] != uint8_t(reg->Address))
throw TSerialDeviceTransientErrorException("register index mismatch");
if (reg->Type == REG_RELAY)
return response[0] ? 1 : 0;
return response[0];
}
void TUnielDevice::WriteRegister(PRegister reg, uint64_t value)
{
uint8_t cmd, addr;
if (reg->Type == REG_BRIGHTNESS) {
cmd = SET_BRIGHTNESS_CMD;
addr = uint8_t(reg->Address >> 8);
} else {
cmd = WRITE_CMD;
addr = uint8_t(reg->Address);
}
if (reg->Type == REG_RELAY && value != 0)
value = 255;
WriteCommand(cmd, SlaveId, value, addr, 0);
uint8_t response[3];
ReadResponse(cmd, response);
if (response[1] != addr)
throw TSerialDeviceTransientErrorException("register index mismatch");
if (response[0] != value)
throw TSerialDeviceTransientErrorException("written register value mismatch");
}