kopia lustrzana https://github.com/weetmuts/wmbusmeters
Added detection of im871a firmware and support c1+t1 mode.
rodzic
72fb4710ae
commit
a26bac3932
5
CHANGES
5
CHANGES
|
@ -12,6 +12,11 @@ a logged line in the log file or stderr output with a timestamp.
|
|||
Important means timestamp warnings and device changes.
|
||||
Daemon mode defaults to important.
|
||||
|
||||
Added support for firmware version 0x14 for im871a dongle.
|
||||
(The old version is 0x13 and you can see the firmware version if
|
||||
you run with --verbose.) The new version of the im871a firmware
|
||||
supports listening to c1 and t1 at the same time.
|
||||
|
||||
Version 1.2.0: 2021-03-07
|
||||
|
||||
IMPORTANT CHANGES THAT MIGHT AFFECT YOU!vvvvvvvvvvvvvvvvvvvvvv
|
||||
|
|
18
README.md
18
README.md
|
@ -329,13 +329,19 @@ Gransystems 301 and 303 (gransystems)
|
|||
Kamstrup Omnipower (omnipower)
|
||||
```
|
||||
|
||||
The wmbus dongles imst871a can listen to one type of wmbus telegrams
|
||||
at a time, ie either C1 or T1 telegrams. Thus you can listen to
|
||||
multiple meters as long as they all require the same radio mode C1 or
|
||||
T1.
|
||||
The wmbus dongle im871a can listen to either s1, c1 or t1.
|
||||
However with the latest firmware version (0x14) im871a can
|
||||
also listen to c1 and t1 telegrams at the same time.
|
||||
(Use --verbose to see your dongles firmware version.)
|
||||
|
||||
However if you use amb8465 or rtlwmbus, then you can listen to both C1
|
||||
and T1 telegrams at the same time.
|
||||
The amb8465 dongle can listen to either s1, c1 or t1. However it
|
||||
can also listen to c1 and t1 at the same time.
|
||||
|
||||
With the latest rtlwmbus you can listen to s1, c1 and t1 at
|
||||
the same time.
|
||||
|
||||
The cul dongle can listen to either s1, c1 or t1, but only
|
||||
one at a time.
|
||||
|
||||
# Usage examples
|
||||
|
||||
|
|
|
@ -237,7 +237,7 @@ void detectWMBUSReceiver()
|
|||
probeFor("cul", detectCUL);
|
||||
break;
|
||||
case ReceiversType::IM871A:
|
||||
probeFor("im871a", detectIM871A);
|
||||
probeFor("im871a/im170a", detectIM871AIM170A);
|
||||
break;
|
||||
case ReceiversType::RC1180:
|
||||
probeFor("rc1180", detectRC1180);
|
||||
|
|
|
@ -196,6 +196,10 @@ shared_ptr<WMBus> BusManager::createWmbusObject(Detected *detected, Configuratio
|
|||
verbose("(im871a) on %s\n", detected->found_file.c_str());
|
||||
wmbus = openIM871A(*detected, serial_manager_, serial_override);
|
||||
break;
|
||||
case DEVICE_IM170A:
|
||||
verbose("(im170a) on %s\n", detected->found_file.c_str());
|
||||
wmbus = openIM170A(*detected, serial_manager_, serial_override);
|
||||
break;
|
||||
case DEVICE_AMB8465:
|
||||
verbose("(amb8465) on %s\n", detected->found_file.c_str());
|
||||
wmbus = openAMB8465(*detected, serial_manager_, serial_override);
|
||||
|
|
43
src/wmbus.cc
43
src/wmbus.cc
|
@ -791,22 +791,16 @@ bool Telegram::parseMBusDLL(vector<uchar>::iterator &pos)
|
|||
int remaining = distance(pos, frame.end());
|
||||
if (remaining == 0) return expectedMore(__LINE__);
|
||||
|
||||
debug("(wmbus) parseDLL @%d %d\n", distance(frame.begin(), pos), remaining);
|
||||
debug("(wmbus) parse MBUS DLL @%d %d\n", distance(frame.begin(), pos), remaining);
|
||||
dll_len = *pos;
|
||||
if (remaining < dll_len) return expectedMore(__LINE__);
|
||||
addExplanationAndIncrementPos(pos, 1, "%02x length (%d bytes)", dll_len, dll_len);
|
||||
|
||||
dll_c = *pos;
|
||||
addExplanationAndIncrementPos(pos, 1, "%02x dll-c (%s)", dll_c, cType(dll_c).c_str());
|
||||
addExplanationAndIncrementPos(pos, 1, "%02x dll-c (%s)", dll_c, mbusCField(dll_c).c_str());
|
||||
|
||||
dll_a.resize(6);
|
||||
for (int i=0; i<6; ++i) dll_a[i] = 0;
|
||||
dll_id.resize(4);
|
||||
for (int i=0; i<4; ++i) dll_id[i] = 0;
|
||||
dll_a[0] = *pos;
|
||||
dll_id[0] = *pos;
|
||||
|
||||
addExplanationAndIncrementPos(pos, 1, "%02x dll-a (%d)", dll_a[0], dll_a[0]);
|
||||
mbus_primary_address = *pos;
|
||||
addExplanationAndIncrementPos(pos, 1, "%02x dll-a primary (%d)", mbus_primary_address, mbus_primary_address);
|
||||
|
||||
// Add dll_id to ids.
|
||||
string id = tostrprintf("%02x", dll_a[0]);
|
||||
|
@ -1880,6 +1874,16 @@ string Telegram::autoDetectPossibleDrivers()
|
|||
return possibles;
|
||||
}
|
||||
|
||||
string mbusCField(uchar c_field)
|
||||
{
|
||||
string s;
|
||||
switch (c_field)
|
||||
{
|
||||
case 0x08: return "RSP_UD2";
|
||||
}
|
||||
return "?";
|
||||
}
|
||||
|
||||
string cType(int c_field)
|
||||
{
|
||||
string s;
|
||||
|
@ -4342,7 +4346,7 @@ const char *toString(WMBusDeviceType t)
|
|||
{
|
||||
switch (t)
|
||||
{
|
||||
#define X(name,text,tty,rtlsdr) case DEVICE_ ## name: return #text;
|
||||
#define X(name,text,tty,rtlsdr,detector) case DEVICE_ ## name: return #text;
|
||||
LIST_OF_MBUS_DEVICES
|
||||
#undef X
|
||||
|
||||
|
@ -4354,7 +4358,7 @@ const char *toLowerCaseString(WMBusDeviceType t)
|
|||
{
|
||||
switch (t)
|
||||
{
|
||||
#define X(name,text,tty,rtlsdr) case DEVICE_ ## name: return #text;
|
||||
#define X(name,text,tty,rtlsdr,detector) case DEVICE_ ## name: return #text;
|
||||
LIST_OF_MBUS_DEVICES
|
||||
#undef X
|
||||
|
||||
|
@ -4364,7 +4368,7 @@ LIST_OF_MBUS_DEVICES
|
|||
|
||||
WMBusDeviceType toWMBusDeviceType(string &t)
|
||||
{
|
||||
#define X(name,text,tty,rtlsdr) if (t == #text) return DEVICE_ ## name;
|
||||
#define X(name,text,tty,rtlsdr,detector) if (t == #text) return DEVICE_ ## name;
|
||||
LIST_OF_MBUS_DEVICES
|
||||
#undef X
|
||||
return DEVICE_UNKNOWN;
|
||||
|
@ -4669,7 +4673,7 @@ Detected detectWMBusDeviceOnTTY(string tty,
|
|||
|
||||
// Talk im871a with it...
|
||||
// assumes this device is configured for 57600 bps, which seems to be the default.
|
||||
if (detectIM871A(&detected, handler) == AccessCheck::AccessOK)
|
||||
if (detectIM871AIM170A(&detected, handler) == AccessCheck::AccessOK)
|
||||
{
|
||||
return detected;
|
||||
}
|
||||
|
@ -4802,6 +4806,11 @@ AccessCheck detectUNKNOWN(Detected *detected, shared_ptr<SerialCommunicationMana
|
|||
return AccessCheck::NotThere;
|
||||
}
|
||||
|
||||
AccessCheck detectSKIP(Detected *detected, shared_ptr<SerialCommunicationManager> handler)
|
||||
{
|
||||
return AccessCheck::NotThere;
|
||||
}
|
||||
|
||||
AccessCheck detectSIMULATION(Detected *detected, shared_ptr<SerialCommunicationManager> handler)
|
||||
{
|
||||
return AccessCheck::NotThere;
|
||||
|
@ -4817,7 +4826,7 @@ AccessCheck reDetectDevice(Detected *detected, shared_ptr<SerialCommunicationMan
|
|||
{
|
||||
WMBusDeviceType type = detected->specified_device.type;
|
||||
|
||||
#define X(name,text,tty,rtlsdr) if (type == WMBusDeviceType::DEVICE_ ## name) return detect ## name(detected,handler);
|
||||
#define X(name,text,tty,rtlsdr,detector) if (type == WMBusDeviceType::DEVICE_ ## name) return detector(detected,handler);
|
||||
LIST_OF_MBUS_DEVICES
|
||||
#undef X
|
||||
|
||||
|
@ -4827,7 +4836,7 @@ LIST_OF_MBUS_DEVICES
|
|||
|
||||
bool usesRTLSDR(WMBusDeviceType t)
|
||||
{
|
||||
#define X(name,text,tty,rtlsdr) if (t == WMBusDeviceType::DEVICE_ ## name) return rtlsdr;
|
||||
#define X(name,text,tty,rtlsdr,detector) if (t == WMBusDeviceType::DEVICE_ ## name) return rtlsdr;
|
||||
LIST_OF_MBUS_DEVICES
|
||||
#undef X
|
||||
|
||||
|
@ -4837,7 +4846,7 @@ LIST_OF_MBUS_DEVICES
|
|||
|
||||
bool usesTTY(WMBusDeviceType t)
|
||||
{
|
||||
#define X(name,text,tty,rtlsdr) if (t == WMBusDeviceType::DEVICE_ ## name) return tty;
|
||||
#define X(name,text,tty,rtlsdr,detector) if (t == WMBusDeviceType::DEVICE_ ## name) return tty;
|
||||
LIST_OF_MBUS_DEVICES
|
||||
#undef X
|
||||
|
||||
|
|
38
src/wmbus.h
38
src/wmbus.h
|
@ -31,20 +31,21 @@ bool trimCRCsFrameFormatA(std::vector<uchar> &payload);
|
|||
bool trimCRCsFrameFormatB(std::vector<uchar> &payload);
|
||||
|
||||
#define LIST_OF_MBUS_DEVICES \
|
||||
X(UNKNOWN,unknown,false,false) \
|
||||
X(MBUS,mbus,true,false) \
|
||||
X(AUTO,auto,false,false) \
|
||||
X(AMB8465,amb8465,true,false) \
|
||||
X(CUL,cul,true,false) \
|
||||
X(IM871A,im871a,true,false) \
|
||||
X(RAWTTY,rawtty,true,false) \
|
||||
X(RC1180,rc1180,true,false) \
|
||||
X(RTL433,rtl433,false,true) \
|
||||
X(RTLWMBUS,rtlwmbus,false,true)\
|
||||
X(SIMULATION,simulation,false,false)
|
||||
X(UNKNOWN,unknown,false,false,detectUNKNOWN) \
|
||||
X(MBUS,mbus,true,false,detectMBUS) \
|
||||
X(AUTO,auto,false,false,detectAUTO) \
|
||||
X(AMB8465,amb8465,true,false,detectAMB8465) \
|
||||
X(CUL,cul,true,false,detectCUL) \
|
||||
X(IM871A,im871a,true,false,detectIM871AIM170A) \
|
||||
X(IM170A,im170a,true,false,detectSKIP) \
|
||||
X(RAWTTY,rawtty,true,false,detectRAWTTY) \
|
||||
X(RC1180,rc1180,true,false,detectRC1180) \
|
||||
X(RTL433,rtl433,false,true,detectRTL433) \
|
||||
X(RTLWMBUS,rtlwmbus,false,true,detectRTLWMBUS) \
|
||||
X(SIMULATION,simulation,false,false,detectSIMULATION)
|
||||
|
||||
enum WMBusDeviceType {
|
||||
#define X(name,text,tty,rtlsdr) DEVICE_ ## name,
|
||||
#define X(name,text,tty,rtlsdr,detector) DEVICE_ ## name,
|
||||
LIST_OF_MBUS_DEVICES
|
||||
#undef X
|
||||
};
|
||||
|
@ -367,6 +368,8 @@ struct Telegram
|
|||
uchar dll_mfct_b[2]; // 2 bytes
|
||||
int dll_mfct {};
|
||||
|
||||
uchar mbus_primary_address; // Single byte address 0-250 for mbus devices.
|
||||
|
||||
vector<uchar> dll_a; // A field 6 bytes
|
||||
// The 6 a field bytes are composed of 4 id bytes, version and type.
|
||||
uchar dll_id_b[4] {}; // 4 bytes, address in BCD = 8 decimal 00000000...99999999 digits.
|
||||
|
@ -604,6 +607,9 @@ Detected detectWMBusDeviceWithCommand(SpecifiedDevice &specified_device,
|
|||
shared_ptr<WMBus> openIM871A(Detected detected,
|
||||
shared_ptr<SerialCommunicationManager> manager,
|
||||
shared_ptr<SerialDevice> serial_override);
|
||||
shared_ptr<WMBus> openIM170A(Detected detected,
|
||||
shared_ptr<SerialCommunicationManager> manager,
|
||||
shared_ptr<SerialDevice> serial_override);
|
||||
shared_ptr<WMBus> openAMB8465(Detected detected,
|
||||
shared_ptr<SerialCommunicationManager> manager,
|
||||
shared_ptr<SerialDevice> serial_override);
|
||||
|
@ -690,13 +696,13 @@ AccessCheck detectAUTO(Detected *detected, shared_ptr<SerialCommunicationManager
|
|||
AccessCheck detectAMB8465(Detected *detected, shared_ptr<SerialCommunicationManager> handler);
|
||||
AccessCheck detectCUL(Detected *detected, shared_ptr<SerialCommunicationManager> handler);
|
||||
AccessCheck detectD1TC(Detected *detected, shared_ptr<SerialCommunicationManager> manager);
|
||||
AccessCheck detectIM871A(Detected *detected, shared_ptr<SerialCommunicationManager> handler);
|
||||
AccessCheck detectIM871AIM170A(Detected *detected, shared_ptr<SerialCommunicationManager> handler);
|
||||
AccessCheck detectRAWTTY(Detected *detected, shared_ptr<SerialCommunicationManager> handler);
|
||||
AccessCheck detectMBUS(Detected *detected, shared_ptr<SerialCommunicationManager> handler);
|
||||
AccessCheck detectRC1180(Detected *detected, shared_ptr<SerialCommunicationManager> handler);
|
||||
AccessCheck detectRTL433(Detected *detected, shared_ptr<SerialCommunicationManager> handler);
|
||||
AccessCheck detectRTLWMBUS(Detected *detected, shared_ptr<SerialCommunicationManager> handler);
|
||||
AccessCheck detectWMB13U(Detected *detected, shared_ptr<SerialCommunicationManager> handler);
|
||||
AccessCheck detectSKIP(Detected *detected, shared_ptr<SerialCommunicationManager> handler);
|
||||
|
||||
// Try to factory reset an AMB8465 by trying all possible serial speeds and
|
||||
// restore to factory settings.
|
||||
|
@ -709,4 +715,8 @@ Detected detectWMBusDeviceOnTTY(string tty,
|
|||
// Remember meters id/mfct/ver/type combos that we should only warn once for.
|
||||
bool warned_for_telegram_before(Telegram *t, vector<uchar> &dll_a);
|
||||
|
||||
////////////////// MBUS
|
||||
|
||||
string mbusCField(uchar c_field);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -57,7 +57,7 @@ struct WMBusCUL : public virtual WMBusCommonImplementation
|
|||
if (lms.empty()) return false;
|
||||
if (!supportedLinkModes().supports(lms)) return false;
|
||||
// Ok, the supplied link modes are compatible,
|
||||
// but im871a can only listen to one at a time.
|
||||
// but cul can only listen to one at a time.
|
||||
return 1 == countSetBits(lms.asBits());
|
||||
}
|
||||
void processSerialData();
|
||||
|
|
|
@ -31,11 +31,14 @@
|
|||
|
||||
using namespace std;
|
||||
|
||||
#define FIRMWARE_14_C_AND_T 0x14
|
||||
#define FIRMWARE_13_C_OR_T 0x13
|
||||
|
||||
struct DeviceInfo
|
||||
{
|
||||
uchar module_type; // 0x33 = im871a 0x36 = im170a
|
||||
uchar device_mode; // 0 = other 1 = meter
|
||||
uchar firmware_version;
|
||||
uchar firmware_version; // 13 hci 1.6 and 14 hci 1.7
|
||||
uchar hci_version; // serial protocol?
|
||||
uint32_t uid;
|
||||
|
||||
|
@ -152,41 +155,66 @@ LIST_OF_IM871A_LINK_MODES
|
|||
return "unknown";
|
||||
}
|
||||
|
||||
struct WMBusIM871A : public virtual WMBusCommonImplementation
|
||||
struct WMBusIM871aIM170A : public virtual WMBusCommonImplementation
|
||||
{
|
||||
bool ping();
|
||||
string getDeviceId();
|
||||
string getDeviceUniqueId();
|
||||
uchar getFirmwareVersion();
|
||||
LinkModeSet getLinkModes();
|
||||
void deviceReset();
|
||||
void deviceSetLinkModes(LinkModeSet lms);
|
||||
LinkModeSet supportedLinkModes() {
|
||||
return
|
||||
C1_bit |
|
||||
S1_bit |
|
||||
S1m_bit |
|
||||
T1_bit |
|
||||
N1a_bit |
|
||||
N1b_bit |
|
||||
N1c_bit |
|
||||
N1d_bit |
|
||||
N1e_bit |
|
||||
N1f_bit;
|
||||
LinkModeSet supportedLinkModes()
|
||||
{
|
||||
if (type() == WMBusDeviceType::DEVICE_IM871A)
|
||||
{
|
||||
return
|
||||
C1_bit |
|
||||
S1_bit |
|
||||
S1m_bit |
|
||||
T1_bit;
|
||||
}
|
||||
else
|
||||
{
|
||||
return N1a_bit |
|
||||
N1b_bit |
|
||||
N1c_bit |
|
||||
N1d_bit |
|
||||
N1e_bit |
|
||||
N1f_bit;
|
||||
}
|
||||
}
|
||||
int numConcurrentLinkModes() {
|
||||
return 2;
|
||||
}
|
||||
int numConcurrentLinkModes() { return 1; }
|
||||
bool canSetLinkModes(LinkModeSet lms)
|
||||
{
|
||||
if (lms.empty()) return false;
|
||||
if (!supportedLinkModes().supports(lms)) return false;
|
||||
// Ok, the supplied link modes are compatible,
|
||||
// but im871a can only listen to one at a time.
|
||||
// Ok, the supplied link modes are compatible.
|
||||
if (type() == DEVICE_IM170A)
|
||||
{
|
||||
// Simple test.
|
||||
return 1 == countSetBits(lms.asBits());
|
||||
}
|
||||
// For im871a and latest firmware.
|
||||
if (getFirmwareVersion() == FIRMWARE_14_C_AND_T)
|
||||
{
|
||||
if (2 == countSetBits(lms.asBits()) &&
|
||||
lms.has(LinkMode::C1) &&
|
||||
lms.has(LinkMode::T1))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// Otherwise its a single link mode.
|
||||
return 1 == countSetBits(lms.asBits());
|
||||
}
|
||||
void processSerialData();
|
||||
void simulate() { }
|
||||
|
||||
WMBusIM871A(string alias, shared_ptr<SerialDevice> serial, shared_ptr<SerialCommunicationManager> manager);
|
||||
~WMBusIM871A() {
|
||||
WMBusIM871aIM170A(WMBusDeviceType type, string alias, shared_ptr<SerialDevice> serial, shared_ptr<SerialCommunicationManager> manager);
|
||||
~WMBusIM871aIM170A() {
|
||||
}
|
||||
|
||||
static FrameStatus checkIM871AFrame(vector<uchar> &data,
|
||||
|
@ -204,9 +232,11 @@ private:
|
|||
vector<uchar> response_;
|
||||
|
||||
bool getDeviceInfo();
|
||||
bool loaded_device_info_ {};
|
||||
|
||||
bool getConfig();
|
||||
|
||||
friend AccessCheck detectIM871A(Detected *detected, shared_ptr<SerialCommunicationManager> manager);
|
||||
friend AccessCheck detectIM871AIM170A(Detected *detected, shared_ptr<SerialCommunicationManager> manager);
|
||||
void handleDevMgmt(int msgid, vector<uchar> &payload);
|
||||
void handleRadioLink(int msgid, vector<uchar> &payload, int rssi_dbm);
|
||||
void handleRadioLinkTest(int msgid, vector<uchar> &payload);
|
||||
|
@ -228,30 +258,40 @@ int toDBM(int rssi)
|
|||
return dbm;
|
||||
}
|
||||
|
||||
shared_ptr<WMBus> openIM871A(Detected detected, shared_ptr<SerialCommunicationManager> manager, shared_ptr<SerialDevice> serial_override)
|
||||
shared_ptr<WMBus> openIM871AIM170A(WMBusDeviceType type, Detected detected, shared_ptr<SerialCommunicationManager> manager, shared_ptr<SerialDevice> serial_override)
|
||||
{
|
||||
string alias = detected.specified_device.alias;
|
||||
string device_file = detected.found_file;
|
||||
assert(device_file != "");
|
||||
if (serial_override)
|
||||
{
|
||||
WMBusIM871A *imp = new WMBusIM871A(alias, serial_override, manager);
|
||||
WMBusIM871aIM170A *imp = new WMBusIM871aIM170A(type, alias, serial_override, manager);
|
||||
imp->markAsNoLongerSerial();
|
||||
return shared_ptr<WMBus>(imp);
|
||||
}
|
||||
|
||||
auto serial = manager->createSerialDeviceTTY(device_file.c_str(), 57600, PARITY::NONE, "im871a");
|
||||
WMBusIM871A *imp = new WMBusIM871A(alias, serial, manager);
|
||||
WMBusIM871aIM170A *imp = new WMBusIM871aIM170A(type, alias, serial, manager);
|
||||
return shared_ptr<WMBus>(imp);
|
||||
}
|
||||
|
||||
WMBusIM871A::WMBusIM871A(string alias, shared_ptr<SerialDevice> serial, shared_ptr<SerialCommunicationManager> manager) :
|
||||
WMBusCommonImplementation(alias, DEVICE_IM871A, manager, serial, true)
|
||||
shared_ptr<WMBus> openIM871A(Detected detected, shared_ptr<SerialCommunicationManager> manager, shared_ptr<SerialDevice> serial_override)
|
||||
{
|
||||
return openIM871AIM170A(WMBusDeviceType::DEVICE_IM871A, detected, manager, serial_override);
|
||||
}
|
||||
|
||||
shared_ptr<WMBus> openIM170A(Detected detected, shared_ptr<SerialCommunicationManager> manager, shared_ptr<SerialDevice> serial_override)
|
||||
{
|
||||
return openIM871AIM170A(WMBusDeviceType::DEVICE_IM170A, detected, manager, serial_override);
|
||||
}
|
||||
|
||||
WMBusIM871aIM170A::WMBusIM871aIM170A(WMBusDeviceType type, string alias, shared_ptr<SerialDevice> serial, shared_ptr<SerialCommunicationManager> manager) :
|
||||
WMBusCommonImplementation(alias, type, manager, serial, true)
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
bool WMBusIM871A::ping()
|
||||
bool WMBusIM871aIM170A::ping()
|
||||
{
|
||||
if (serial()->readonly()) return true; // Feeding from stdin or file.
|
||||
|
||||
|
@ -271,7 +311,7 @@ bool WMBusIM871A::ping()
|
|||
return true;
|
||||
}
|
||||
|
||||
string WMBusIM871A::getDeviceId()
|
||||
string WMBusIM871aIM170A::getDeviceId()
|
||||
{
|
||||
if (serial()->readonly()) return "?"; // Feeding from stdin or file.
|
||||
if (cached_device_id_ != "") return cached_device_id_;
|
||||
|
@ -286,7 +326,7 @@ string WMBusIM871A::getDeviceId()
|
|||
return cached_device_id_;
|
||||
}
|
||||
|
||||
string WMBusIM871A::getDeviceUniqueId()
|
||||
string WMBusIM871aIM170A::getDeviceUniqueId()
|
||||
{
|
||||
if (serial()->readonly()) return "?"; // Feeding from stdin or file.
|
||||
if (cached_device_unique_id_ != "") return cached_device_unique_id_;
|
||||
|
@ -301,7 +341,17 @@ string WMBusIM871A::getDeviceUniqueId()
|
|||
return cached_device_unique_id_;
|
||||
}
|
||||
|
||||
LinkModeSet WMBusIM871A::getLinkModes()
|
||||
uchar WMBusIM871aIM170A::getFirmwareVersion()
|
||||
{
|
||||
if (serial()->readonly()) return 0x14; // Feeding from stdin or file.
|
||||
|
||||
bool ok = getDeviceInfo();
|
||||
if (!ok) return 255;
|
||||
|
||||
return device_info_.firmware_version;
|
||||
}
|
||||
|
||||
LinkModeSet WMBusIM871aIM170A::getLinkModes()
|
||||
{
|
||||
if (serial()->readonly()) { return Any_bit; } // Feeding from stdin or file.
|
||||
|
||||
|
@ -366,7 +416,7 @@ LinkModeSet WMBusIM871A::getLinkModes()
|
|||
if (response_[offset] == (int)LinkModeIM871A::T1) {
|
||||
lm = LinkMode::T1;
|
||||
}
|
||||
if (response_[offset] == (int)LinkModeIM871A::N1A) {
|
||||
if (response_[offset] == (int)LinkModeIM871A::CT_N1A) {
|
||||
lm = LinkMode::N1a;
|
||||
}
|
||||
if (response_[offset] == (int)LinkModeIM871A::N1B) {
|
||||
|
@ -463,7 +513,7 @@ LinkModeSet WMBusIM871A::getLinkModes()
|
|||
return lms;
|
||||
}
|
||||
|
||||
void WMBusIM871A::deviceReset()
|
||||
void WMBusIM871aIM170A::deviceReset()
|
||||
{
|
||||
// No device specific settings needed right now.
|
||||
// The common code in wmbus.cc reset()
|
||||
|
@ -471,7 +521,7 @@ void WMBusIM871A::deviceReset()
|
|||
// set the link modes properly.
|
||||
}
|
||||
|
||||
void WMBusIM871A::deviceSetLinkModes(LinkModeSet lms)
|
||||
void WMBusIM871aIM170A::deviceSetLinkModes(LinkModeSet lms)
|
||||
{
|
||||
if (serial()->readonly()) return; // Feeding from stdin or file.
|
||||
|
||||
|
@ -490,7 +540,10 @@ void WMBusIM871A::deviceSetLinkModes(LinkModeSet lms)
|
|||
request_[3] = 6; // Len
|
||||
request_[4] = 0; // Temporary
|
||||
request_[5] = 2; // iff1 bits: Set Radio Mode
|
||||
if (lms.has(LinkMode::C1)) {
|
||||
if (lms.has(LinkMode::C1) && lms.has(LinkMode::T1)) {
|
||||
assert(getFirmwareVersion() == FIRMWARE_14_C_AND_T);
|
||||
request_[6] = (int)LinkModeIM871A::CT_N1A;
|
||||
} else if (lms.has(LinkMode::C1)) {
|
||||
request_[6] = (int)LinkModeIM871A::C1a;
|
||||
} else if (lms.has(LinkMode::S1)) {
|
||||
request_[6] = (int)LinkModeIM871A::S1;
|
||||
|
@ -499,7 +552,7 @@ void WMBusIM871A::deviceSetLinkModes(LinkModeSet lms)
|
|||
} else if (lms.has(LinkMode::T1)) {
|
||||
request_[6] = (int)LinkModeIM871A::T1;
|
||||
} else if (lms.has(LinkMode::N1a)) {
|
||||
request_[6] = (int)LinkModeIM871A::N1A;
|
||||
request_[6] = (int)LinkModeIM871A::CT_N1A;
|
||||
} else if (lms.has(LinkMode::N1b)) {
|
||||
request_[6] = (int)LinkModeIM871A::N1B;
|
||||
} else if (lms.has(LinkMode::N1c)) {
|
||||
|
@ -531,7 +584,7 @@ void WMBusIM871A::deviceSetLinkModes(LinkModeSet lms)
|
|||
}
|
||||
}
|
||||
|
||||
FrameStatus WMBusIM871A::checkIM871AFrame(vector<uchar> &data,
|
||||
FrameStatus WMBusIM871aIM170A::checkIM871AFrame(vector<uchar> &data,
|
||||
size_t *frame_length, int *endpoint_out, int *msgid_out,
|
||||
int *payload_len_out, int *payload_offset,
|
||||
int *rssi_dbm)
|
||||
|
@ -657,7 +710,7 @@ FrameStatus WMBusIM871A::checkIM871AFrame(vector<uchar> &data,
|
|||
return FullFrame;
|
||||
}
|
||||
|
||||
void WMBusIM871A::processSerialData()
|
||||
void WMBusIM871aIM170A::processSerialData()
|
||||
{
|
||||
vector<uchar> data;
|
||||
|
||||
|
@ -720,7 +773,7 @@ void WMBusIM871A::processSerialData()
|
|||
}
|
||||
}
|
||||
|
||||
void WMBusIM871A::handleDevMgmt(int msgid, vector<uchar> &payload)
|
||||
void WMBusIM871aIM170A::handleDevMgmt(int msgid, vector<uchar> &payload)
|
||||
{
|
||||
switch (msgid) {
|
||||
case DEVMGMT_MSG_PING_RSP: // 0x02
|
||||
|
@ -750,7 +803,7 @@ void WMBusIM871A::handleDevMgmt(int msgid, vector<uchar> &payload)
|
|||
}
|
||||
}
|
||||
|
||||
void WMBusIM871A::handleRadioLink(int msgid, vector<uchar> &frame, int rssi_dbm)
|
||||
void WMBusIM871aIM170A::handleRadioLink(int msgid, vector<uchar> &frame, int rssi_dbm)
|
||||
{
|
||||
switch (msgid) {
|
||||
case RADIOLINK_MSG_WMBUSMSG_IND: // 0x03
|
||||
|
@ -765,7 +818,7 @@ void WMBusIM871A::handleRadioLink(int msgid, vector<uchar> &frame, int rssi_dbm)
|
|||
}
|
||||
}
|
||||
|
||||
void WMBusIM871A::handleRadioLinkTest(int msgid, vector<uchar> &payload)
|
||||
void WMBusIM871aIM170A::handleRadioLinkTest(int msgid, vector<uchar> &payload)
|
||||
{
|
||||
switch (msgid) {
|
||||
default:
|
||||
|
@ -773,7 +826,7 @@ void WMBusIM871A::handleRadioLinkTest(int msgid, vector<uchar> &payload)
|
|||
}
|
||||
}
|
||||
|
||||
void WMBusIM871A::handleHWTest(int msgid, vector<uchar> &payload)
|
||||
void WMBusIM871aIM170A::handleHWTest(int msgid, vector<uchar> &payload)
|
||||
{
|
||||
switch (msgid) {
|
||||
default:
|
||||
|
@ -785,7 +838,7 @@ bool extract_response(vector<uchar> &data, vector<uchar> &response, int expected
|
|||
{
|
||||
size_t frame_length;
|
||||
int endpoint, msgid, payload_len, payload_offset, rssi_dbm;
|
||||
FrameStatus status = WMBusIM871A::checkIM871AFrame(data,
|
||||
FrameStatus status = WMBusIM871aIM170A::checkIM871AFrame(data,
|
||||
&frame_length, &endpoint, &msgid,
|
||||
&payload_len, &payload_offset, &rssi_dbm);
|
||||
if (status != FullFrame ||
|
||||
|
@ -800,8 +853,10 @@ bool extract_response(vector<uchar> &data, vector<uchar> &response, int expected
|
|||
return true;
|
||||
}
|
||||
|
||||
bool WMBusIM871A::getDeviceInfo()
|
||||
bool WMBusIM871aIM170A::getDeviceInfo()
|
||||
{
|
||||
if (loaded_device_info_) return true;
|
||||
|
||||
LOCK_WMBUS_EXECUTING_COMMAND(get_device_info);
|
||||
|
||||
request_.resize(4);
|
||||
|
@ -813,33 +868,21 @@ bool WMBusIM871A::getDeviceInfo()
|
|||
verbose("(im871a) get device info\n");
|
||||
|
||||
bool sent = serial()->send(request_);
|
||||
|
||||
if (!sent) return false; // tty overridden with stdin/file
|
||||
|
||||
/*
|
||||
if (!use_manager)
|
||||
{
|
||||
// Wait for 100ms so that the USB stick have time to prepare a response.
|
||||
usleep(1000*100);
|
||||
vector<uchar> data;
|
||||
serial->receive(&data);
|
||||
|
||||
bool ok = extract_response(data, response_, 1, 16);
|
||||
if (!ok) return false;
|
||||
}*/
|
||||
bool ok = waitForResponse(DEVMGMT_MSG_GET_DEVICEINFO_RSP);
|
||||
if (!ok) return false; // timeout
|
||||
|
||||
// Now device info response is in response_ vector.
|
||||
|
||||
device_info_.decode(response_);
|
||||
|
||||
loaded_device_info_ = true;
|
||||
verbose("(im871a) device info: %s\n", device_info_.str().c_str());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WMBusIM871A::getConfig()
|
||||
bool WMBusIM871aIM170A::getConfig()
|
||||
{
|
||||
if (serial()->readonly()) return true;
|
||||
|
||||
|
@ -862,7 +905,7 @@ bool WMBusIM871A::getConfig()
|
|||
return device_config_.decode(response_);
|
||||
}
|
||||
|
||||
AccessCheck detectIM871A(Detected *detected, shared_ptr<SerialCommunicationManager> manager)
|
||||
AccessCheck detectIM871AIM170A(Detected *detected, shared_ptr<SerialCommunicationManager> manager)
|
||||
{
|
||||
// Talk to the device and expect a very specific answer.
|
||||
auto serial = manager->createSerialDeviceTTY(detected->found_file.c_str(), 57600, PARITY::NONE, "detect im871a");
|
||||
|
@ -879,7 +922,7 @@ AccessCheck detectIM871A(Detected *detected, shared_ptr<SerialCommunicationManag
|
|||
request.resize(4);
|
||||
request[0] = IM871A_SERIAL_SOF;
|
||||
request[1] = DEVMGMT_ID;
|
||||
request[2] = DEVMGMT_MSG_GET_CONFIG_REQ;
|
||||
request[2] = DEVMGMT_MSG_GET_DEVICEINFO_REQ;
|
||||
request[3] = 0;
|
||||
|
||||
serial->send(request);
|
||||
|
@ -889,21 +932,68 @@ AccessCheck detectIM871A(Detected *detected, shared_ptr<SerialCommunicationManag
|
|||
|
||||
size_t frame_length;
|
||||
int endpoint, msgid, payload_len, payload_offset, rssi_dbm;
|
||||
FrameStatus status = WMBusIM871A::checkIM871AFrame(response,
|
||||
FrameStatus status = WMBusIM871aIM170A::checkIM871AFrame(response,
|
||||
&frame_length, &endpoint, &msgid,
|
||||
&payload_len, &payload_offset, &rssi_dbm);
|
||||
if (status != FullFrame ||
|
||||
endpoint != 1 ||
|
||||
msgid != DEVMGMT_MSG_GET_DEVICEINFO_RSP)
|
||||
{
|
||||
verbose("(im871a/im170a) are you there? no.\n");
|
||||
serial->close();
|
||||
return AccessCheck::NotThere;
|
||||
}
|
||||
|
||||
vector<uchar> payload;
|
||||
payload.insert(payload.end(), response.begin()+payload_offset, response.begin()+payload_offset+payload_len);
|
||||
|
||||
debugPayload("(device info bytes)", payload);
|
||||
|
||||
DeviceInfo di;
|
||||
di.decode(payload);
|
||||
|
||||
debug("(im871a/im170a) info: %s\n", di.str().c_str());
|
||||
|
||||
WMBusDeviceType type;
|
||||
|
||||
string types;
|
||||
if (di.module_type == 0x33)
|
||||
{
|
||||
type = WMBusDeviceType::DEVICE_IM871A;
|
||||
types = "im871a";
|
||||
}
|
||||
else
|
||||
{
|
||||
type = WMBusDeviceType::DEVICE_IM170A;
|
||||
types = "im170a";
|
||||
}
|
||||
|
||||
request.resize(4);
|
||||
request[0] = IM871A_SERIAL_SOF;
|
||||
request[1] = DEVMGMT_ID;
|
||||
request[2] = DEVMGMT_MSG_GET_CONFIG_REQ;
|
||||
request[3] = 0;
|
||||
|
||||
serial->send(request);
|
||||
// Wait for 100ms so that the USB stick have time to prepare a response.
|
||||
usleep(1000*100);
|
||||
serial->receive(&response);
|
||||
|
||||
status = WMBusIM871aIM170A::checkIM871AFrame(response,
|
||||
&frame_length, &endpoint, &msgid,
|
||||
&payload_len, &payload_offset, &rssi_dbm);
|
||||
if (status != FullFrame ||
|
||||
endpoint != 1 ||
|
||||
msgid != DEVMGMT_MSG_GET_CONFIG_RSP)
|
||||
{
|
||||
verbose("(im871a) are you there? no.\n");
|
||||
verbose("(im871a/im170a) are you there? no.\n");
|
||||
serial->close();
|
||||
return AccessCheck::NotThere;
|
||||
}
|
||||
|
||||
serial->close();
|
||||
|
||||
vector<uchar> payload;
|
||||
payload.clear();
|
||||
payload.insert(payload.end(), response.begin()+payload_offset, response.begin()+payload_offset+payload_len);
|
||||
|
||||
debugPayload("(device config bytes)", payload);
|
||||
|
@ -911,12 +1001,11 @@ AccessCheck detectIM871A(Detected *detected, shared_ptr<SerialCommunicationManag
|
|||
Config co;
|
||||
co.decode(payload);
|
||||
|
||||
debug("(im871a) config: %s\n", co.str().c_str());
|
||||
debug("(im871a/im170a) config: %s\n", co.str().c_str());
|
||||
|
||||
detected->setAsFound(co.dongleId(), WMBusDeviceType::DEVICE_IM871A, 57600, false,
|
||||
detected->specified_device.linkmodes);
|
||||
detected->setAsFound(co.dongleId(), type, 57600, false, detected->specified_device.linkmodes);
|
||||
|
||||
verbose("(im871a) are you there? yes %s\n", co.dongleId().c_str());
|
||||
verbose("(im871a/im170a) are you there? yes %s %s firmware: %02x\n", co.dongleId().c_str(), types.c_str(), di.firmware_version);
|
||||
|
||||
return AccessCheck::AccessOK;
|
||||
}
|
||||
|
|
|
@ -69,7 +69,7 @@
|
|||
X(C1b,cab)\
|
||||
X(C2a,c2a)\
|
||||
X(C2b,c2b)\
|
||||
X(N1A,n1a)\
|
||||
X(CT_N1A,ct_n1a)\
|
||||
X(N2A,n2a)\
|
||||
X(N1B,n1b)\
|
||||
X(N2B,n2b)\
|
||||
|
|
Ładowanie…
Reference in New Issue