Skip to content

Commit

Permalink
Adds print features for service mode packets to DccDebug. (#631)
Browse files Browse the repository at this point in the history
Adds debug hooks to the programming track backend.
  • Loading branch information
balazsracz authored Jun 25, 2022
1 parent c835af7 commit 333056f
Show file tree
Hide file tree
Showing 4 changed files with 148 additions and 5 deletions.
91 changes: 88 additions & 3 deletions src/dcc/DccDebug.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@
*/

#include "dcc/DccDebug.hxx"
#include "dcc/Defs.hxx"
#include "utils/StringPrintf.hxx"
#include "utils/logging.h"

namespace dcc
{
Expand Down Expand Up @@ -81,15 +83,94 @@ string packet_to_string(const DCCPacket &pkt, bool bin_payload)
options.pop_back();
options += "]";
}
if (pkt.packet_header.is_marklin) {
if (pkt.packet_header.is_marklin)
{
return options;
}
unsigned ofs = 0;
bool is_idle_packet = false;
bool is_basic_accy_packet = false;
bool is_unknown_packet = false;
bool is_svc_packet = false;
unsigned accy_address = 0;
if (pkt.payload[ofs] == 0xff)
if (pkt.packet_header.send_long_preamble)
{
// Checks for service mode packets.

// WARNING: This code is only guaranteed to correctly decide between
// service mode packets and basic decoder packets if the packets were
// generated by OpenMRN. Otherwise it is not guaranteed that
// long_preamble is equivalent to service mode.
using namespace dcc::Defs;
is_svc_packet = true;
uint8_t cmd = pkt.payload[ofs];
int cv = (((pkt.payload[ofs] & 0x3) << 8) | pkt.payload[ofs + 1]) + 1;
int reg = (pkt.payload[ofs] & 0x7) + 1;
// How many bytes does the command have (cmd and arguments), usually 2
// for paged mode and 3 for direct mode commands.
int num_bytes =
pkt.packet_header.skip_ec ? pkt.dlc - ofs - 1 : pkt.dlc - ofs;
if (num_bytes == 3 && (cmd & DCC_SVC_MASK) == DCC_SVC_WRITE)
{
options += StringPrintf(
"[svc] Direct Write Byte CV %d = %d", cv, pkt.payload[ofs + 2]);
ofs += 2;
}
else if (num_bytes == 3 && (cmd & DCC_SVC_MASK) == DCC_SVC_VERIFY)
{
options += StringPrintf("[svc] Direct Verify Byte CV %d =?= %d", cv,
pkt.payload[ofs + 2]);
ofs += 2;
}
else if (num_bytes == 3 &&
((cmd & DCC_SVC_MASK) == DCC_SVC_BIT_MANIPULATE) &&
((pkt.payload[ofs + 2] & DCC_SVC_BITVAL_MASK) ==
DCC_SVC_BITVAL_WRITE))
{
int bitnum = pkt.payload[ofs + 2] & 7;
int bitval = pkt.payload[ofs + 2] & DCC_SVC_BITVAL_VALUE ? 1 : 0;
options += StringPrintf(
"[svc] Direct Write Bit CV %d bit %d = %d", cv, bitnum, bitval);
ofs += 2;
}
else if (num_bytes == 3 &&
((cmd & DCC_SVC_MASK) == DCC_SVC_BIT_MANIPULATE) &&
((pkt.payload[ofs + 2] & DCC_SVC_BITVAL_MASK) ==
DCC_SVC_BITVAL_VERIFY))
{
int bitnum = pkt.payload[ofs + 2] & 7;
int bitval = pkt.payload[ofs + 2] & DCC_SVC_BITVAL_VALUE ? 1 : 0;
options +=
StringPrintf("[svc] Direct Verify Bit CV %d bit %d =?= %d", cv,
bitnum, bitval);
ofs += 2;
}
else if (num_bytes == 2 &&
(cmd & DCC_SVC_PAGED_MASK) == DCC_SVC_PAGED_WRITE)
{
options += StringPrintf("[svc] Paged Write Byte Reg %d = %d", reg,
pkt.payload[ofs + 1]);
ofs++;
}
else if (num_bytes == 2 &&
(cmd & DCC_SVC_PAGED_MASK) == DCC_SVC_PAGED_VERIFY)
{
options += StringPrintf("[svc] Paged Verify Byte Reg %d =?= %d",
reg, pkt.payload[ofs + 1]);
ofs++;
}
else
{
// Not recognized.
is_svc_packet = false;
}
}

if (is_svc_packet)
{
// Do not use the regular address partition logic here.
}
else if (pkt.payload[ofs] == 0xff)
{
options += " Idle packet";
ofs++;
Expand All @@ -103,6 +184,10 @@ string packet_to_string(const DCCPacket &pkt, bool bin_payload)
{
options += " Broadcast";
ofs++;
if (pkt.payload[ofs] == 0)
{
options += " reset";
}
}
else if ((pkt.payload[ofs] & 0x80) == 0)
{
Expand Down Expand Up @@ -155,7 +240,7 @@ string packet_to_string(const DCCPacket &pkt, bool bin_payload)
options += StringPrintf(" Accy %u %s", accy_address,
is_activate ? "activate" : "deactivate");
}
else if (is_unknown_packet)
else if (is_unknown_packet || is_svc_packet)
{
}
else if ((cmd & 0xC0) == 0x40)
Expand Down
40 changes: 40 additions & 0 deletions src/dcc/DccDebug.cxxtest
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,46 @@ TEST(DccDebug, POMRead)
"[dcc] Short Address 3 POM CV14 read/verify 0", packet_to_string(pkt));
}

TEST(DccDebug, BroadcastReset)
{
Packet pkt;
pkt.set_dcc_reset_all_decoders();
EXPECT_EQ("[dcc] Broadcast reset", packet_to_string(pkt));
}

TEST(DccDebug, SvcMode)
{
Packet pkt;
pkt.set_dcc_svc_verify_byte(567, 133);
EXPECT_EQ("[dcc][long_preamble][svc] Direct Verify Byte CV 568 =?= 133",
packet_to_string(pkt));
pkt.set_dcc_svc_write_byte(567, 133);
EXPECT_EQ("[dcc][long_preamble][svc] Direct Write Byte CV 568 = 133",
packet_to_string(pkt));
pkt.set_dcc_svc_verify_bit(567, 3, true);
EXPECT_EQ("[dcc][long_preamble][svc] Direct Verify Bit CV 568 bit 3 =?= 1",
packet_to_string(pkt));
pkt.set_dcc_svc_verify_bit(567, 7, false);
EXPECT_EQ("[dcc][long_preamble][svc] Direct Verify Bit CV 568 bit 7 =?= 0",
packet_to_string(pkt));
pkt.set_dcc_svc_write_bit(567, 3, true);
EXPECT_EQ("[dcc][long_preamble][svc] Direct Write Bit CV 568 bit 3 = 1",
packet_to_string(pkt));
pkt.set_dcc_svc_write_bit(567, 7, false);
EXPECT_EQ("[dcc][long_preamble][svc] Direct Write Bit CV 568 bit 7 = 0",
packet_to_string(pkt));

pkt.set_dcc_svc_paged_write_reg(3, 133);
EXPECT_EQ("[dcc][long_preamble][svc] Paged Write Byte Reg 4 = 133",
packet_to_string(pkt));
pkt.set_dcc_svc_paged_verify_reg(4, 133);
EXPECT_EQ("[dcc][long_preamble][svc] Paged Verify Byte Reg 5 =?= 133",
packet_to_string(pkt));
pkt.set_dcc_svc_paged_set_page(27);
EXPECT_EQ("[dcc][long_preamble][svc] Paged Write Byte Reg 6 = 27",
packet_to_string(pkt));
}

TEST(DccDebug, Accy)
{
Packet pkt;
Expand Down
7 changes: 5 additions & 2 deletions src/dcc/Defs.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -97,13 +97,16 @@ enum
DCC_SVC_BIT_MANIPULATE = 0b01111000,
DCC_SVC_WRITE = 0b01111100,
DCC_SVC_VERIFY = 0b01110100,
DCC_SVC_MASK = 0b11111100,

DCC_SVC_BITVAL_WRITE = 0b11110000,
DCC_SVC_BITVAL_VERIFY = 0b11100000,
DCC_SVC_BITVAL_VALUE = 0b00001000,
DCC_SVC_BITVAL_MASK = 0b11110000,

DCC_SVC_PAGED_WRITE = 0b01111000,
DCC_SVC_PAGED_VERIFY = 0b01110000,
DCC_SVC_PAGED_MASK = 0b11111000,

DCC_BASIC_ACCESSORY_B1 = 0b10000000,
DCC_BASIC_ACCESSORY_B2 = 0b10000000,
Expand Down Expand Up @@ -138,7 +141,7 @@ enum
DCC_DID_MAX = DCC_LOGON_ASSIGN + 0xF,
/// Mask used for the DCC_DID packets primary command byte.
DCC_DID_MASK = 0xF0,

// Commands in 254 Select and 253 addressed.
CMD_READ_SHORT_INFO = 0b11111111,
CMD_READ_BLOCK = 0b11111110,
Expand All @@ -150,7 +153,7 @@ enum

/// Mask for the address partition bits.
ADR_MASK = 0b111111,

/// 7-bit mobile decoders
ADR_MOBILE_SHORT = 0b00111000,
/// Mask for 7-bit mobile decoders
Expand Down
15 changes: 15 additions & 0 deletions src/dcc/ProgrammingTrackBackend.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ extern "C" {
void enable_dcc();
}

// If defined, adds instrumentation calls to a logging function.
// #define DEBUG_PROGRAMTRACK_BACKEND

struct ProgrammingTrackRequest : public CallableFlowRequestBase
{
enum EnterServiceMode
Expand Down Expand Up @@ -161,6 +164,9 @@ private:
}
};

extern void progdebug_log_packet(dcc::Packet *pkt);
extern void progdebug_log_string(const char *s);

class ProgrammingTrackBackend : public CallableFlow<ProgrammingTrackRequest>,
private dcc::NonTrainPacketSource,
public Singleton<ProgrammingTrackBackend>
Expand Down Expand Up @@ -346,10 +352,16 @@ private:
if (request() == nullptr)
{
packet->set_dcc_reset_all_decoders();
#ifdef DEBUG_PROGRAMTRACK_BACKEND
progdebug_log_packet(packet);
#endif
return;
}

*packet = request()->packetToSend_;
#ifdef DEBUG_PROGRAMTRACK_BACKEND
progdebug_log_packet(packet);
#endif
if (request()->repeatCount_ > 0)
{
--request()->repeatCount_;
Expand All @@ -358,6 +370,9 @@ private:
{
if (isWaitingForPackets_)
{
#ifdef DEBUG_PROGRAMTRACK_BACKEND
progdebug_log_string("done flush");
#endif
isWaitingForPackets_ = 0;
/// @todo: wait for flushing the packets to the track.
// resume flow
Expand Down

0 comments on commit 333056f

Please sign in to comment.