Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'bracz-stat-max' into bracz-select-race-condition
Browse files Browse the repository at this point in the history
* bracz-stat-max:
  Latency test with maximum stats and custom process evaluation (#773)
  Fixes data type of max.
  Fix comment.
  Adds documentation comment to latency test consumer.
  Fix compiler warnings in openmrn when using new GCC's. (#772)
  Fix comment.
  Upintegrate changes from the OpenMRNIDF repository (#771)
  Fix comments.
  Adds support for DCC extended accessories  (#769)
  Fix incorrect consumer identified message being emitted by dcc accy producer. (#768)
  Avoids rendering hidden segments. (#767)
  Adds trailing zero to the cdi XML file written to the filesystem. (#777)
  Fix target subdirectory name (#775)
balazsracz committed Feb 5, 2024
2 parents 1999aef + 8259060 commit 89ca807
Showing 15 changed files with 337 additions and 22 deletions.
2 changes: 1 addition & 1 deletion applications/hub_test/targets/Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
SUBDIRS = \
linux.86 \
linux.x86 \

include $(OPENMRNPATH)/etc/recurse.mk
8 changes: 8 additions & 0 deletions src/dcc/Packet.cxx
Original file line number Diff line number Diff line change
@@ -346,6 +346,14 @@ void Packet::add_dcc_basic_accessory(unsigned address, bool is_activate)
add_dcc_checksum();
}

void Packet::add_dcc_ext_accessory(unsigned address, uint8_t aspect)
{
add_dcc_accy_address(false, address);
payload[dlc++] = aspect;
add_dcc_checksum();
}


void Packet::set_dcc_logon_enable(
Defs::LogonEnableParam param, uint16_t cid, uint8_t session_id)
{
15 changes: 15 additions & 0 deletions src/dcc/Packet.cxxtest
Original file line number Diff line number Diff line change
@@ -373,6 +373,21 @@ TEST_F(PacketTest, DccBasicAccyPom)
0b10011100));
}

TEST_F(PacketTest, DccExtAccySet)
{
pkt_.add_dcc_ext_accessory(1733, 0x5a);
// 1733 = 0x6c5 = 0b 110 1100 0101
uint8_t b1 = 0b10110001;
uint8_t b2 = 0b00010011;
uint8_t b3 = 0x5a;
EXPECT_THAT(get_packet(), ElementsAre(b1, b2, b3, b1 ^ b2 ^ b3));

pkt_.clear();
pkt_.add_dcc_ext_accessory(1733, 0x80);
b3 = 0x80;
EXPECT_THAT(get_packet(), ElementsAre(b1, b2, b3, b1 ^ b2 ^ b3));
}


TEST_F(PacketTest, SvcProgDirectByte)
{
11 changes: 11 additions & 0 deletions src/dcc/Packet.hxx
Original file line number Diff line number Diff line change
@@ -310,6 +310,17 @@ struct Packet : public DCCPacket
/// @param is_normal true for normal, false for reverse
/// @param is_activate true for activate, false for deactivate
void set_dcc_basic_accy_params(bool is_normal, bool is_activate);

/// Adds a DCC extended accessory decoder command packet and the checksum
/// byte.
/// @param address is the 11-bit binary address, 0..2047. No bits have to be
/// inverted. This will be A10..A0 on the track. (To convert from a user
/// address, see accy_address_user_to_binary in dcc::Defs.)
/// @param aspect is the argument byte to the extended
/// accessory. Traditionally this was used as an aspect for a signal
/// decoder, but different accessories might have different interpretation
/// of it.
void add_dcc_ext_accessory(unsigned address, uint8_t aspect);

/// Sets the packet to a logon enable packet.
/// @param param defines which decoders should be requested to logon.
4 changes: 2 additions & 2 deletions src/freertos_drivers/esp32/Esp32Gpio.hxx
Original file line number Diff line number Diff line change
@@ -43,7 +43,6 @@

#include <driver/gpio.h>
#include <esp_rom_gpio.h>
#include <soc/adc_channel.h>

#include <soc/gpio_struct.h>

@@ -553,8 +552,9 @@ template <class Defs> struct GpioInputPUPD : public GpioInputPin<Defs, true, tru
struct NAME##Defs \
{ \
static const gpio_num_t PIN_NUM = (gpio_num_t)NUM; \
\
public: \
static gpio_num_t pin() \
static gpio_num_t pin() \
{ \
return PIN_NUM; \
} \
5 changes: 2 additions & 3 deletions src/freertos_drivers/esp32/Esp32HardwareTwai.cxx
Original file line number Diff line number Diff line change
@@ -35,8 +35,7 @@
* @date 1 May 2021
*/

// Ensure we only compile this code for the ESP32 family of MCUs and that the
// ESP-IDF version is supported for this code.
// Ensure we only compile this code for the ESP32 family of MCUs.
#if defined(ESP_PLATFORM)

#include "sdkconfig.h"
@@ -714,7 +713,7 @@ static void twai_isr(void *arg)
{
BaseType_t wakeup = pdFALSE;
uint32_t events = twai_hal_get_events(&twai.context);
ESP_EARLY_LOGV(TWAI_LOG_TAG, "events: %04x", events);
ESP_EARLY_LOGV(TWAI_LOG_TAG, "events: %04" PRIx32, events);

#if defined(CONFIG_TWAI_ERRATA_FIX_RX_FRAME_INVALID) || \
defined(CONFIG_TWAI_ERRATA_FIX_RX_FIFO_CORRUPT)
2 changes: 1 addition & 1 deletion src/freertos_drivers/esp32/Esp32Ledc.cxx
Original file line number Diff line number Diff line change
@@ -33,7 +33,7 @@
*/

// Ensure we only compile this code for the ESP32 family of MCUs.
#if defined(ESP32)
#if defined(ESP_PLATFORM)

#include "Esp32Ledc.hxx"

3 changes: 3 additions & 0 deletions src/openlcb/CompileCdiMain.cxx
Original file line number Diff line number Diff line change
@@ -27,6 +27,9 @@ void render_cdi_helper(const CdiType &t, string ns, string name)
t.config_renderer().render_cdi(&payload);
if (raw_render)
{
// Adds trailing zero to the file written.
payload.push_back(0);
// Writes the file.
string filename = name + ".xmlout";
printf("Writing %d bytes to %s\n", (int)payload.size(),
filename.c_str());
21 changes: 21 additions & 0 deletions src/openlcb/ConfigRenderer.cxxtest
Original file line number Diff line number Diff line change
@@ -351,5 +351,26 @@ TEST(CdiRender, RenderIdent)
EXPECT_EQ(34u, cfg.testseg().e2().offset());
}


CDI_GROUP(TestCdi3, MainCdi());
CDI_GROUP_ENTRY(acdi, Acdi);
CDI_GROUP_ENTRY(testseg, OtherSegment, Hidden(true));
CDI_GROUP_END();

TEST(CdiRender, NoRenderHiddenSegment)
{
string s;
TestCdi3 cfg(0);
cfg.config_renderer().render_cdi(&s);
const char kExpectedTestNodeCdi[] = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" R"data(
<cdi xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://openlcb.org/schema/cdi/1/1/cdi.xsd">
<acdi/>
</cdi>
)data";
EXPECT_EQ(kExpectedTestNodeCdi, s);
EXPECT_EQ(34u, cfg.testseg().e2().offset());
}


} // namespace
} // namespace openlcb
6 changes: 5 additions & 1 deletion src/openlcb/ConfigRenderer.hxx
Original file line number Diff line number Diff line change
@@ -406,7 +406,11 @@ public:
GroupConfigOptions opts(args..., Body::group_opts());
if (opts.hidden())
{
EmptyGroupConfigRenderer(Body::size() * replication_).render_cdi(s);
if (!opts.is_segment())
{
EmptyGroupConfigRenderer(Body::size() * replication_)
.render_cdi(s);
}
return;
}
const char *tag = nullptr;
80 changes: 80 additions & 0 deletions src/openlcb/DccAccyConsumer.cxxtest
Original file line number Diff line number Diff line change
@@ -58,6 +58,11 @@ public:
class DccAccyTest : public AsyncNodeTest
{
protected:
DccAccyTest()
{
wait();
}

StrictMock<MockPacketQueue> trackSendQueue_;
DccAccyConsumer consumer_{node_, &trackSendQueue_};
};
@@ -72,6 +77,19 @@ TEST_F(DccAccyTest, identify_boot_invalid)
":X198F4111N0101020000FF01F0;", ":X194C722AN0101020000FF01F0;");
}

TEST_F(DccAccyTest, global_identify)
{
clear_expect(true);
// Consumer range for two 4096 long ranges.
expect_packet(":X194A422AN0101020000FF0FFF;");
expect_packet(":X194A422AN0101020000FE0FFF;");

// identify events addressed.
send_packet(":X19968111N022A;");
wait();
}


TEST_F(DccAccyTest, identify_throw_identify)
{
EXPECT_CALL(trackSendQueue_, arrived(_, _)).Times(2);
@@ -122,4 +140,66 @@ TEST_F(DccAccyTest, packet_throw)
wait();
}


class DccExtAccyTest : public AsyncNodeTest
{
protected:
DccExtAccyTest()
{
wait();
}

StrictMock<MockPacketQueue> trackSendQueue_;
DccExtAccyConsumer consumer_{node_, &trackSendQueue_};
};

TEST_F(DccExtAccyTest, create)
{
}

TEST_F(DccExtAccyTest, global_identify)
{
clear_expect(true);
// Consumer range for one very long range (11 bit plus 8 bit).
expect_packet(":X194A422AN010102000107FFFF;");

// identify events addressed.
send_packet(":X19968111N022A;");
wait();
}


TEST_F(DccExtAccyTest, identify_unknown)
{
// unknown identify
send_packet_and_expect_response(
":X198F4111N0101020001035a77;", ":X194C722AN0101020001035a77;");
}

TEST_F(DccExtAccyTest, packet_throw)
{
uint8_t hdr = 0b01100100;
EXPECT_CALL(trackSendQueue_,
arrived(hdr, ElementsAre(0b10110001, 0b00010011, 0xa5, _)));

// set to 0xa5
send_packet(":X195B4111N010102000106c5a5;");


EXPECT_CALL(trackSendQueue_,
arrived(hdr, ElementsAre(0b10110001, 0b00010011, 0x00, _)));

// set to 0x00
send_packet(":X195B4111N010102000106c500;");

EXPECT_CALL(trackSendQueue_,
arrived(hdr, ElementsAre(0b10110001, 0b00010011, 0xff, _)));

// set to 0xff
send_packet(":X195B4111N010102000106c5ff;");

wait();
}


} // namespace openlcb
178 changes: 166 additions & 12 deletions src/openlcb/DccAccyConsumer.hxx
Original file line number Diff line number Diff line change
@@ -74,21 +74,31 @@ protected:
void handle_identify_global(const EventRegistryEntry &registry_entry,
EventReport *event, BarrierNotifiable *done) OVERRIDE
{
AutoNotify an(done);
if (event->dst_node && event->dst_node != node_)
{
return done->notify();
return;
}
if (registry_entry.event ==
TractionDefs::ACTIVATE_BASIC_DCC_ACCESSORY_EVENT_BASE)
{
event->event_write_helper<1>()->WriteAsync(node_,
Defs::MTI_CONSUMER_IDENTIFIED_RANGE, WriteHelper::global(),
eventid_to_buffer(EncodeRange(
TractionDefs::ACTIVATE_BASIC_DCC_ACCESSORY_EVENT_BASE,
4095)),
done->new_child());
}
if (registry_entry.event ==
TractionDefs::INACTIVATE_BASIC_DCC_ACCESSORY_EVENT_BASE)
{
event->event_write_helper<2>()->WriteAsync(node_,
Defs::MTI_CONSUMER_IDENTIFIED_RANGE, WriteHelper::global(),
eventid_to_buffer(EncodeRange(
TractionDefs::INACTIVATE_BASIC_DCC_ACCESSORY_EVENT_BASE,
4095)),
done->new_child());
}
event->event_write_helper<1>()->WriteAsync(node_,
Defs::MTI_CONSUMER_IDENTIFIED_RANGE, WriteHelper::global(),
eventid_to_buffer(EncodeRange(
TractionDefs::ACTIVATE_BASIC_DCC_ACCESSORY_EVENT_BASE, 2044)),
done->new_child());
event->event_write_helper<2>()->WriteAsync(node_,
Defs::MTI_CONSUMER_IDENTIFIED_RANGE, WriteHelper::global(),
eventid_to_buffer(EncodeRange(
TractionDefs::INACTIVATE_BASIC_DCC_ACCESSORY_EVENT_BASE, 2044)),
done->new_child());
done->notify();
}

void handle_event_report(const EventRegistryEntry &registry_entry,
@@ -250,6 +260,150 @@ private:
dcc::TrackIf *track_;
};

/// Base (generic protocol) implementation of the DCC extended accessory
/// consumer. Unlike the basic accessory version, this one does not remember
/// the last set state.
class DccExtAccyConsumerBase : public SimpleEventHandler
{
protected:
/// How may addresses are there for extended accessories.
static constexpr unsigned NUM_ADDRESS = 2048;
/// How may aspects are supported per accessory.
static constexpr unsigned NUM_ASPECT = 256;
/// Total number of events we are listening for.
static constexpr unsigned NUM_EVENT = NUM_ASPECT * NUM_ADDRESS;

/// Constructs a listener for DCC extended accessory control.
/// @param node is the virtual node that will be listening for events and
/// responding to Identify messages.
DccExtAccyConsumerBase(Node *node)
: node_(node)
{
EventRegistry::instance()->register_handler(
EventRegistryEntry(
this, TractionDefs::EXT_DCC_ACCESSORY_EVENT_BASE),
11+8 /*number of bits*/);
}

/// Destructor.
~DccExtAccyConsumerBase()
{
EventRegistry::instance()->unregister_handler(this);
}

void handle_identify_global(const EventRegistryEntry &registry_entry,
EventReport *event, BarrierNotifiable *done) OVERRIDE
{
AutoNotify an(done);
if (event->dst_node && event->dst_node != node_)
{
return;
}
event->event_write_helper<1>()->WriteAsync(node_,
Defs::MTI_CONSUMER_IDENTIFIED_RANGE, WriteHelper::global(),
eventid_to_buffer(EncodeRange(
TractionDefs::EXT_DCC_ACCESSORY_EVENT_BASE, NUM_EVENT - 1)),
done->new_child());
}

void handle_event_report(const EventRegistryEntry &registry_entry,
EventReport *event, BarrierNotifiable *done) override
{
AutoNotify an(done);
if (!parse_event(event->event))
{
return;
}
send_accy_command();
}

void handle_identify_consumer(const EventRegistryEntry &entry,
EventReport *event, BarrierNotifiable *done) override
{
AutoNotify an(done);
if (!parse_event(event->event))
{
return;
}
event->event_write_helper<1>()->WriteAsync(node_,
Defs::MTI_CONSUMER_IDENTIFIED_UNKNOWN, WriteHelper::global(),
eventid_to_buffer(event->event), done->new_child());
}

/// Send the actual accessory command.
virtual void send_accy_command() = 0;

/// Parses an event into an openlcb accessory offset.
/// @return true if the event is in the accessory range, false if this
/// event can be ignored.
/// @param on_off will be set to true if this is an activate event, false
/// if it is an inactivate event.
/// @param ofs will be set to the offset in the state_ arrays.
/// @param mask will be set to a single bit value that marks the location
/// in the state_ arrays.
bool parse_event(EventId event)
{
if (event >= TractionDefs::EXT_DCC_ACCESSORY_EVENT_BASE &&
event <
TractionDefs::EXT_DCC_ACCESSORY_EVENT_BASE + NUM_EVENT)
{
aspect_ = event & 0xff;
dccAddress_ = (event >> 8) & (NUM_ADDRESS - 1);
return true;
}
else
{
return false;
}
}


/// Parsed event state: dcc address (0..2047) without inverting or encoding.
unsigned dccAddress_ : 11;
/// Parsed event state: the aspect commanded.
unsigned aspect_ : 8;

/// OpenLCB node to export the consumer on.
Node *node_;
};

/// Specialized (DCC protocol) implementation of a DCC extended accessory
/// consumer.
class DccExtAccyConsumer : public DccExtAccyConsumerBase
{
public:
/// Constructs a listener for DCC accessory control.
/// @param node is the virtual node that will be listening for events and
/// responding to Identify messages.
/// @param track is the interface through which we will be writing DCC
/// accessory packets.
DccExtAccyConsumer(Node *node, dcc::TrackIf *track)
: DccExtAccyConsumerBase(node)
, track_(track)
{
}

/// Destructor.
~DccExtAccyConsumer()
{
}

private:
/// Send the actual accessory command.
void send_accy_command() override
{
dcc::TrackIf::message_type *pkt;
mainBufferPool->alloc(&pkt);
pkt->data()->add_dcc_ext_accessory(dccAddress_, aspect_);
pkt->data()->packet_header.rept_count = 3;
track_->send(pkt);
}

/// Track to send DCC packets to.
dcc::TrackIf *track_;
};


} // namespace openlcb

#endif // _OPENLCB_DCCACCYCONSUMER_HXX_
18 changes: 18 additions & 0 deletions src/openlcb/LatencyTestConsumer.hxx
Original file line number Diff line number Diff line change
@@ -40,6 +40,24 @@
namespace openlcb
{

/// This event consumer works together with the hub_test application in order
/// to detect the response latency of a node. The theory of operation is that
/// hub_test sends out an identify consumer message with a given event ID, and
/// this consumer is going to respond. The hub_test then measures the response
/// latency. There is a big event range being advertised (32 bits), and
/// hub_test will send events with different IDs to be able to match request to
/// response.
///
/// Here in the consumer the only thing we need to do is respond to identify
/// consumer messages with consumer identified.
///
/// An additional feature is to be able to measure an arbitrary processing step
/// inside the node. For this purpose we have a hook function. When the
/// identify producer message comes in, we call the hook. When the measured
/// process completes, it should notify the given notifiable. Only thereafter
/// the consumer will reply on the bus. Requests' handling is not
/// parallelized. If the hook process cannot complete the requests fast enough,
/// the node will run out of memory and crash.
class LatencyTestConsumer : public SimpleEventHandler
{
public:
2 changes: 2 additions & 0 deletions src/openlcb/TractionDefs.hxx
Original file line number Diff line number Diff line change
@@ -73,6 +73,8 @@ struct TractionDefs {
static constexpr uint64_t ACTIVATE_BASIC_DCC_ACCESSORY_EVENT_BASE = 0x0101020000FF0000ULL;
/// Base address of DCC accessory decoder well-known event range (inactive)
static constexpr uint64_t INACTIVATE_BASIC_DCC_ACCESSORY_EVENT_BASE = 0x0101020000FE0000ULL;
/// Base address of DCC extended accessory decoder well-known event range
static constexpr uint64_t EXT_DCC_ACCESSORY_EVENT_BASE = 0x0101020001000000ULL;
/// Node ID space allocated for DC blocks.
static const uint64_t NODE_ID_DC_BLOCK = 0x060000000000ULL;
/// Node ID space allocated for DCC locomotives.
4 changes: 2 additions & 2 deletions src/utils/Stats.hxx
Original file line number Diff line number Diff line change
@@ -94,14 +94,14 @@ public:
return sqrt(qsum_ * count_ - sum * sum) / count_;
}

/// Creates a half-a-line prinout of this stats object for debug purposes.
/// Creates a half-a-line printout of this stats object for debug purposes.
std::string debug_string();

private:
/// Number of samples added.
uint32_t count_;
/// Maximum value found since the last clear.
int32_t max_;
ValueType max_;
/// Sum of sample values added.
int64_t sum_;
/// Sum of squares of sample values added.

0 comments on commit 89ca807

Please sign in to comment.