Added detection of im871a firmware and support c1+t1 mode.

pull/278/head
Fredrik Öhrström 2021-03-18 22:44:50 +01:00
rodzic 72fb4710ae
commit a26bac3932
9 zmienionych plików z 228 dodań i 105 usunięć

Wyświetl plik

@ -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

Wyświetl plik

@ -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

Wyświetl plik

@ -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);

Wyświetl plik

@ -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);

Wyświetl plik

@ -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

Wyświetl plik

@ -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

Wyświetl plik

@ -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();

Wyświetl plik

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

Wyświetl plik

@ -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)\