diff --git a/src/dcc/Packet.cxx b/src/dcc/Packet.cxx index 84d953669..b35922024 100644 --- a/src/dcc/Packet.cxx +++ b/src/dcc/Packet.cxx @@ -69,6 +69,10 @@ enum DCC_FUNCTION2_F9 = 0b10100000, DCC_FEATURE_EXP_F13 = 0b11011110, DCC_FEATURE_EXP_F21 = 0b11011111, + DCC_FEATURE_EXP_FNHI = 0b11011000, + DCC_BINARY_SHORT = 0b11011101, + DCC_BINARY_LONG = 0b11000000, + DCC_ANALOG_FN = 0b00111101, DCC_PROG_READ1 = 0b11100100, DCC_PROG_WRITE1 = 0b11101100, @@ -234,17 +238,39 @@ void Packet::add_dcc_function9_12(unsigned values) add_dcc_checksum(); } -void Packet::add_dcc_function13_20(unsigned values) +void Packet::add_dcc_function_hi(uint8_t base, uint8_t values) { - payload[dlc++] = DCC_FEATURE_EXP_F13; - payload[dlc++] = values & 0xff; + base -= 13; + HASSERT((base & 0b111) == 0); + HASSERT(base <= (61 - 13)); + base >>= 3; + base -= 2; + payload[dlc++] = DCC_FEATURE_EXP_FNHI | (base & 0b111); + payload[dlc++] = values; add_dcc_checksum(); } -void Packet::add_dcc_function21_28(unsigned values) +void Packet::add_dcc_binary_state(uint16_t fn, bool value) { - payload[dlc++] = DCC_FEATURE_EXP_F21; - payload[dlc++] = values & 0xff; + if (fn <= 127) + { + payload[dlc++] = DCC_BINARY_SHORT; + payload[dlc++] = fn | (value ? 0x80 : 0); + } + else + { + payload[dlc++] = DCC_BINARY_LONG; + payload[dlc++] = (fn & 0x7F) | (value ? 0x80 : 0); + payload[dlc++] = (fn >> 8) & 0xFF; + } + add_dcc_checksum(); +} + +void Packet::add_dcc_analog_function(uint8_t fn, uint8_t value) +{ + payload[dlc++] = DCC_ANALOG_FN; + payload[dlc++] = fn; + payload[dlc++] = value; add_dcc_checksum(); } diff --git a/src/dcc/Packet.cxxtest b/src/dcc/Packet.cxxtest index 06b4c23ce..afd6e878b 100644 --- a/src/dcc/Packet.cxxtest +++ b/src/dcc/Packet.cxxtest @@ -172,6 +172,75 @@ TEST_F(PacketTest, Fn20) EXPECT_THAT(get_packet(), ElementsAre(55, 0b11011111, 0xAA, _)); } +TEST_F(PacketTest, Fn29) +{ + pkt_.add_dcc_address(DccShortAddress(55)); + pkt_.add_dcc_function_hi(29, 0x5A); + EXPECT_THAT(get_packet(), ElementsAre(55, 0b11011000, 0x5A, _)); +} + +TEST_F(PacketTest, Fn37) +{ + pkt_.add_dcc_address(DccShortAddress(55)); + pkt_.add_dcc_function_hi(37, 0x11); + EXPECT_THAT(get_packet(), ElementsAre(55, 0b11011001, 0x11, _)); +} + +TEST_F(PacketTest, Fn45) +{ + pkt_.add_dcc_address(DccShortAddress(55)); + pkt_.add_dcc_function_hi(45, 0x11); + EXPECT_THAT(get_packet(), ElementsAre(55, 0b11011010, 0x11, _)); +} + +TEST_F(PacketTest, Fn53) +{ + pkt_.add_dcc_address(DccShortAddress(55)); + pkt_.add_dcc_function_hi(53, 0x11); + EXPECT_THAT(get_packet(), ElementsAre(55, 0b11011011, 0x11, _)); +} + +TEST_F(PacketTest, Fn61) +{ + pkt_.add_dcc_address(DccShortAddress(55)); + pkt_.add_dcc_function_hi(61, 0x11); + EXPECT_THAT(get_packet(), ElementsAre(55, 0b11011100, 0x11, _)); +} + +TEST_F(PacketTest, BinaryStateShort) +{ + pkt_.add_dcc_address(DccShortAddress(55)); + pkt_.add_dcc_binary_state(61, true); + EXPECT_THAT(get_packet(), ElementsAre(55, 0b11011101, 61 | 0x80, _)); +} + +TEST_F(PacketTest, BinaryStateShortOff) +{ + pkt_.add_dcc_address(DccShortAddress(55)); + pkt_.add_dcc_binary_state(127, false); + EXPECT_THAT(get_packet(), ElementsAre(55, 0b11011101, 127, _)); +} + +TEST_F(PacketTest, BinaryStateLongOn) +{ + pkt_.add_dcc_address(DccShortAddress(55)); + pkt_.add_dcc_binary_state(16 * 256 + 61, true); + EXPECT_THAT(get_packet(), ElementsAre(55, 0b11000000, 61 + 0x80, 16, _)); +} + +TEST_F(PacketTest, BinaryStateLongOff) +{ + pkt_.add_dcc_address(DccShortAddress(55)); + pkt_.add_dcc_binary_state(16 * 256 + 61, false); + EXPECT_THAT(get_packet(), ElementsAre(55, 0b11000000, 61, 16, _)); +} + +TEST_F(PacketTest, AnalogFunction) +{ + pkt_.add_dcc_address(DccShortAddress(55)); + pkt_.add_dcc_analog_function(17, 99); + EXPECT_THAT(get_packet(), ElementsAre(55, 0b00111101, 17, 99, _)); +} TEST_F(PacketTest, DccBasicAccyOn) { diff --git a/src/dcc/Packet.hxx b/src/dcc/Packet.hxx index 276bd75e6..ff6460145 100644 --- a/src/dcc/Packet.hxx +++ b/src/dcc/Packet.hxx @@ -182,11 +182,34 @@ struct Packet : public DCCPacket /** Adds a DCC function group command to the packet. The lowest numbered * function is always at bit zero. @param values are bitmask of functions * to send to the loco. */ - void add_dcc_function13_20(unsigned values); + void add_dcc_function13_20(unsigned values) + { + add_dcc_function_hi(13, values); + } /** Adds a DCC function group command to the packet. The lowest numbered * function is always at bit zero. @param values are bitmask of functions * to send to the loco. */ - void add_dcc_function21_28(unsigned values); + void add_dcc_function21_28(unsigned values) + { + add_dcc_function_hi(21, values); + } + /** Adds a DCC function group command to the packet. The lowest numbered + * function is always at bit zero. + * @param base is a valid function number base, 13, 21, 29, 37, 45, 53 + * or 61. + * @param values are bitmask of functions to send to the loco. */ + void add_dcc_function_hi(uint8_t base, uint8_t values); + + /** Adds a DCC binary state control command to the packet. Automatically + * picks the short or long form, depending on the range of the argument. + * @param fn is a binary function variable, 0 to 32767. + * @param value true/false, what to set to. */ + void add_dcc_binary_state(uint16_t fn, bool value); + + /** Adds a DCC analog function control command to the packet. + * @param fn is an analog function variable, 0 to 255. + * @param value to set it to, 0 to 255. */ + void add_dcc_analog_function(uint8_t fn, uint8_t value); /** Helper function for adding programming mode packets. */ void add_dcc_prog_command(