Skip to content

Commit

Permalink
Fixed AnyTone DTMF contact encoding (#425) (#434)
Browse files Browse the repository at this point in the history
* Fixed encoding of DMTF number length for AnyTone devices. Addresses #425.
* Fix codeplug verification to allow for 128 DTMF contacts in AnyTone radios.
  • Loading branch information
hmatuschek authored May 14, 2024
1 parent 8715d77 commit 6f72aa5
Show file tree
Hide file tree
Showing 9 changed files with 67 additions and 9 deletions.
2 changes: 1 addition & 1 deletion lib/anytone_codeplug.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1124,7 +1124,7 @@ AnytoneCodeplug::DTMFContactElement::setNumber(const QString &number) {
return;
memset(_data+Offset::digits(), 0, Limit::digitCount()/2);
unsigned int n = std::min((unsigned int)number.length(), Limit::digitCount());
setUInt8(Offset::digits(), n);
setUInt8(Offset::numDigits(), n);
for (unsigned int i=0; i<n; i++) {
if (0 == (i%2))
_data[Offset::digits() + i/2] |= (_anytone_bin_dtmf_tab.indexOf(number[i].toLatin1())<<4);
Expand Down
5 changes: 4 additions & 1 deletion lib/d578uv_limits.cc
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,10 @@ D578UVLimits::D578UVLimits(const std::initializer_list<std::pair<Frequency, Freq
}},
{ "number", new RadioLimitUInt(0, 16777215) }
} },
{ DTMFContact::staticMetaObject, -1, -1, new RadioLimitIgnored() }
{ DTMFContact::staticMetaObject, 0, 128, new RadioLimitObject {
{ "name", new RadioLimitString(1, 15, RadioLimitString::ASCII) },
{ "number", new RadioLimitString(1, 14, RadioLimitString::DTMF) }
} }
});

/* Define limits for group lists. */
Expand Down
11 changes: 7 additions & 4 deletions lib/d868uv_limits.cc
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,17 @@ D868UVLimits::D868UVLimits(const std::initializer_list<std::pair<Frequency, Freq
{ DMRContact::staticMetaObject, 1, 10000, new RadioLimitObject {
{ "name", new RadioLimitString(1, 16, RadioLimitString::ASCII) },
{ "ring", new RadioLimitBool() },
{ "type", new RadioLimitEnum{
{ "type", new RadioLimitEnum {
(unsigned)DMRContact::PrivateCall,
(unsigned)DMRContact::GroupCall,
(unsigned)DMRContact::AllCall
(unsigned)DMRContact::GroupCall,
(unsigned)DMRContact::AllCall
}},
{ "number", new RadioLimitUInt(0, 16777215) }
} },
{ DTMFContact::staticMetaObject, -1, -1, new RadioLimitIgnored() }
{ DTMFContact::staticMetaObject, 0, 128, new RadioLimitObject {
{ "name", new RadioLimitString(1, 15, RadioLimitString::ASCII) },
{ "number", new RadioLimitString(1, 14, RadioLimitString::DTMF) }
} }
});

/* Define limits for group lists. */
Expand Down
5 changes: 4 additions & 1 deletion lib/d878uv2_limits.cc
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,10 @@ D878UV2Limits::D878UV2Limits(const std::initializer_list<std::pair<Frequency, Fr
}},
{ "number", new RadioLimitUInt(0, 16777215) }
} },
{ DTMFContact::staticMetaObject, -1, -1, new RadioLimitIgnored() }
{ DTMFContact::staticMetaObject, 0, 128, new RadioLimitObject {
{ "name", new RadioLimitString(1, 15, RadioLimitString::ASCII) },
{ "number", new RadioLimitString(1, 14, RadioLimitString::DTMF) }
} }
});

/* Define limits for group lists. */
Expand Down
5 changes: 4 additions & 1 deletion lib/d878uv_limits.cc
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,10 @@ D878UVLimits::D878UVLimits(const std::initializer_list<std::pair<Frequency, Freq
}},
{ "number", new RadioLimitUInt(0, 16777215) }
} },
{ DTMFContact::staticMetaObject, -1, -1, new RadioLimitIgnored() }
{ DTMFContact::staticMetaObject, 0, 128, new RadioLimitObject {
{ "name", new RadioLimitString(1, 15, RadioLimitString::ASCII) },
{ "number", new RadioLimitString(1, 14, RadioLimitString::DTMF) }
} }
});

/* Define limits for group lists. */
Expand Down
10 changes: 10 additions & 0 deletions lib/radiolimits.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "logger.hh"
#include "config.hh"
#include <QMetaProperty>
#include <QRegularExpression>
#include <ctype.h>

// Utility function to check string content for ASCII encoding
Expand All @@ -14,6 +15,12 @@ inline bool qstring_is_ascii(const QString &text) {
return true;
}

// Utility function to check string content for DTMF encoding
inline bool qstring_is_dtmf(const QString &text) {
return QRegularExpression("^[0-9A-Da-d*#]*$").match(text).isValid();
}



/* ********************************************************************************************* *
* Implementation of RadioLimitIssue
Expand Down Expand Up @@ -209,6 +216,9 @@ RadioLimitString::verify(const ConfigItem *item, const QMetaProperty &prop, Radi
if ((ASCII == _encoding) && (! qstring_is_ascii(value))) {
auto &msg = context.newMessage();
msg << "Cannot encode string '" << value << "' in ASCII.";
} else if ((DTMF == _encoding) && (! qstring_is_dtmf(value))) {
auto &msg = context.newMessage();
msg << "Cannot encode string '" << value << "' in DTMF.";
}

return true;
Expand Down
1 change: 1 addition & 0 deletions lib/radiolimits.hh
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ class RadioLimitString: public RadioLimitValue
public:
/** Possible encoding of strings. */
enum Encoding {
DTMF, ///< Just DTMF symbols are allowed (0-9, A-D, *, #).
ASCII, ///< Just ASCII is allowed.
Unicode ///< Any Unicode character is allowed.
};
Expand Down
36 changes: 35 additions & 1 deletion test/d868uve_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ D868UVETest::testAutoRepeaterOffset() {
// Decode
Config comp_config;
if (! codeplug.decode(&comp_config, err)) {
QFAIL(QString("Cannot decode codeplug for AnyTone AT-D878UVII: %1")
QFAIL(QString("Cannot decode codeplug for AnyTone AT-D868UVE: %1")
.arg(err.format()).toStdString().c_str());
}

Expand All @@ -117,5 +117,39 @@ D868UVETest::testAutoRepeaterOffset() {
QCOMPARE(ext->uhfRef()->as<AnytoneAutoRepeaterOffset>(), ext->offsets()->get(1)->as<AnytoneAutoRepeaterOffset>());
}

void
D868UVETest::testDTMFContacts() {
// Assemble config
Config base;

DTMFContact *contact0 = new DTMFContact();
contact0->setName("Contact 0"); contact0->setNumber("0123456789ABCD#*");
base.contacts()->add(contact0);

// Encode
D868UVCodeplug codeplug; ErrorStack err;
Codeplug::Flags flags; flags.updateCodePlug=false;
if (! codeplug.encode(&base, flags, err)) {
QFAIL(QString("Cannot encode codeplug for AnyTone AT-D868UVE: %1")
.arg(err.format()).toStdString().c_str());
}


// Decode
Config comp_config;
if (! codeplug.decode(&comp_config, err)) {
QFAIL(QString("Cannot decode codeplug for AnyTone AT-D868UVE: %1")
.arg(err.format()).toStdString().c_str());
}

// Check contacts
QCOMPARE(comp_config.contacts()->count(), 1);
QVERIFY(comp_config.contacts()->get(0)->is<DTMFContact>());
QCOMPARE(comp_config.contacts()->get(0)->as<DTMFContact>()->name(), "Contact 0");
// Contacts are limited to 14 digit numbers.
QCOMPARE(comp_config.contacts()->get(0)->as<DTMFContact>()->number(), "0123456789ABCD");
}


QTEST_GUILESS_MAIN(D868UVETest)

1 change: 1 addition & 0 deletions test/d868uve_test.hh
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ private slots:
void testBasicConfigDecoding();
void testChannelFrequency();
void testAutoRepeaterOffset();
void testDTMFContacts();
};

#endif // D878UV2TEST_HH

0 comments on commit 6f72aa5

Please sign in to comment.