2020-08-02 13:01:34 +02:00

1283 Zeilen
23 KiB
C++

/**
* server/src/hardware/protocol/loconet/messages.hpp
*
* This file is part of the traintastic source code.
*
* Copyright (C) 2019-2020 Reinder Feenstra
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/**
* Portions Copyright (C) Digitrax Inc.
*
* LocoNet is a registered trademark of DigiTrax, Inc.
*/
#ifndef TRAINTASTIC_SERVER_HARDWARE_PROTOCOL_LOCONET_MESSAGES_HPP
#define TRAINTASTIC_SERVER_HARDWARE_PROTOCOL_LOCONET_MESSAGES_HPP
#include <string>
#include <traintastic/enum/direction.hpp>
#include "opcode.hpp"
namespace LocoNet {
struct Message;
uint8_t calcChecksum(const Message& msmessageg);
void updateChecksum(Message& message);
bool isChecksumValid(const Message& message);
bool isValid(const Message& message);
std::string to_string(const Message& message, bool raw = false);
constexpr uint8_t SLOT_LOCO_MIN = 1;
constexpr uint8_t SLOT_LOCO_MAX = 119;
constexpr uint8_t SLOT_FAST_CLOCK = 123;
constexpr uint8_t SLOT_PROGRAMMING_TRACK = 124;
constexpr uint8_t SLOT_UNKNOWN = 255; //!< placeholder to indicate invalid slot
constexpr uint8_t SPEED_STOP = 0;
constexpr uint8_t SPEED_ESTOP = 1;
constexpr uint8_t SPEED_MAX = 127;
constexpr uint8_t SL_CONUP = 0x40;
constexpr uint8_t SL_BUSY = 0x20;
constexpr uint8_t SL_ACTIVE = 0x10;
constexpr uint8_t SL_CONDN = 0x08;
constexpr uint8_t SL_DIR = 0x20;
constexpr uint8_t SL_F0 = 0x10;
constexpr uint8_t SL_F4 = 0x08;
constexpr uint8_t SL_F3 = 0x04;
constexpr uint8_t SL_F2 = 0x02;
constexpr uint8_t SL_F1 = 0x01;
constexpr uint8_t SL_F5 = 0x01;
constexpr uint8_t SL_F6 = 0x02;
constexpr uint8_t SL_F7 = 0x04;
constexpr uint8_t SL_F8 = 0x08;
constexpr uint8_t SL_F9 = 0x01;
constexpr uint8_t SL_F10 = 0x02;
constexpr uint8_t SL_F11 = 0x04;
constexpr uint8_t SL_F12 = 0x08;
constexpr uint8_t SL_F13 = 0x01;
constexpr uint8_t SL_F14 = 0x02;
constexpr uint8_t SL_F15 = 0x04;
constexpr uint8_t SL_F16 = 0x08;
constexpr uint8_t SL_F17 = 0x10;
constexpr uint8_t SL_F18 = 0x20;
constexpr uint8_t SL_F19 = 0x40;
constexpr uint8_t SL_F20 = 0x20;
constexpr uint8_t SL_F28 = 0x40;
constexpr uint8_t SL_F21 = 0x01;
constexpr uint8_t SL_F22 = 0x02;
constexpr uint8_t SL_F23 = 0x04;
constexpr uint8_t SL_F24 = 0x08;
constexpr uint8_t SL_F25 = 0x10;
constexpr uint8_t SL_F26 = 0x20;
constexpr uint8_t SL_F27 = 0x40;
constexpr uint8_t MULTI_SENSE_TYPE_MASK = 0xE0;
constexpr uint8_t MULTI_SENSE_TYPE_TRANSPONDER_GONE = 0x00;
constexpr uint8_t MULTI_SENSE_TYPE_TRANSPONDER_PRESENT = 0x20;
constexpr uint8_t MULTI_SENSE_TRANSPONDER_ADDRESS_SHORT = 0xFD;
struct Message
{
OpCode opCode;
Message()
{
}
Message(OpCode _opCode) :
opCode{_opCode}
{
}
uint8_t size() const
{
switch(opCode & 0xE0)
{
case 0x80: // 1 0 0 F D C B A
return 2;
case 0xA0: // 1 0 1 F D C B A
return 4;
case 0xC0: // 1 1 0 F D C B A
return 6;
case 0xE0: // 1 1 1 F D C B A => length in next byte
return reinterpret_cast<const uint8_t*>(this)[1];
default:
return 0; // not an op opcode, bit 7 not 1
}
}
};
struct SlotMessage : Message
{
uint8_t slot;
SlotMessage(OpCode _opCode, uint8_t _slot) :
Message{_opCode},
slot{_slot}
{
}
};
struct Idle : Message
{
uint8_t checksum;
Idle() :
Message{OPC_IDLE},
checksum{0x7A}
{
}
};
static_assert(sizeof(Idle) == 2);
struct GlobalPowerOn : Message
{
uint8_t checksum;
GlobalPowerOn() :
Message{OPC_GPON},
checksum{0x7C}
{
}
};
static_assert(sizeof(GlobalPowerOn) == 2);
struct GlobalPowerOff : Message
{
uint8_t checksum;
GlobalPowerOff() :
Message{OPC_GPOFF},
checksum{0x7D}
{
}
};
static_assert(sizeof(GlobalPowerOff) == 2);
struct Busy : Message
{
uint8_t checksum;
Busy() :
Message{OPC_BUSY},
checksum{0x7E}
{
}
};
static_assert(sizeof(Busy) == 2);
struct LocoAdr : Message
{
uint8_t addressHigh;
uint8_t addressLow;
uint8_t checksum;
LocoAdr(uint16_t address) :
Message{OPC_LOCO_ADR},
addressHigh{static_cast<uint8_t>(address >> 7)},
addressLow{static_cast<uint8_t>(address & 0x7F)}
{
checksum = calcChecksum(*this);
}
};
static_assert(sizeof(LocoAdr) == 4);
struct LocoSpd : SlotMessage
{
uint8_t speed;
uint8_t checksum;
LocoSpd(uint8_t _speed) :
SlotMessage{OPC_LOCO_SPD, SLOT_UNKNOWN},
speed{_speed}
{
checksum = calcChecksum(*this);
}
};
static_assert(sizeof(LocoSpd) == 4);
struct LocoDirF : SlotMessage
{
uint8_t dirf;
uint8_t checksum;
LocoDirF(Direction direction, bool f0, bool f1, bool f2, bool f3, bool f4) :
SlotMessage{OPC_LOCO_DIRF, SLOT_UNKNOWN},
dirf{0}
{
if(direction == Direction::Forward)
dirf |= SL_DIR;
if(f0)
dirf |= SL_F0;
if(f1)
dirf |= SL_F1;
if(f2)
dirf |= SL_F2;
if(f3)
dirf |= SL_F3;
if(f4)
dirf |= SL_F4;
}
inline Direction direction() const
{
return (dirf & SL_DIR) ? Direction::Forward : Direction::Reverse;
}
inline void setDirection(Direction value)
{
if(value == Direction::Forward)
dirf |= SL_DIR;
else
dirf &= ~SL_DIR;
}
inline bool f0() const
{
return dirf & SL_F0;
}
inline void setF0(bool value)
{
if(value)
dirf |= SL_F0;
else
dirf &= ~SL_F0;
}
inline bool f1() const
{
return dirf & SL_F1;
}
inline void setF1(bool value)
{
if(value)
dirf |= SL_F1;
else
dirf &= ~SL_F1;
}
inline bool f2() const
{
return dirf & SL_F2;
}
inline void setF2(bool value)
{
if(value)
dirf |= SL_F2;
else
dirf &= ~SL_F2;
}
inline bool f3() const
{
return dirf & SL_F3;
}
inline void setF3(bool value)
{
if(value)
dirf |= SL_F3;
else
dirf &= ~SL_F3;
}
inline bool f4() const
{
return dirf & SL_F4;
}
inline void setF4(bool value)
{
if(value)
dirf |= SL_F4;
else
dirf &= ~SL_F4;
}
};
static_assert(sizeof(LocoDirF) == 4);
struct LocoSnd : SlotMessage
{
uint8_t snd;
uint8_t checksum;
LocoSnd(bool f5, bool f6, bool f7, bool f8) :
SlotMessage{OPC_LOCO_SND, SLOT_UNKNOWN},
snd{0}
{
if(f5)
snd |= SL_F5;
if(f6)
snd |= SL_F6;
if(f7)
snd |= SL_F7;
if(f8)
snd |= SL_F8;
checksum = calcChecksum(*this);
}
inline bool f5() const
{
return snd & SL_F5;
}
inline void setF5(bool value)
{
if(value)
snd |= SL_F5;
else
snd &= ~SL_F5;
}
inline bool f6() const
{
return snd & SL_F6;
}
inline void setF6(bool value)
{
if(value)
snd |= SL_F6;
else
snd &= ~SL_F6;
}
inline bool f7() const
{
return snd & SL_F7;
}
inline void setF7(bool value)
{
if(value)
snd |= SL_F7;
else
snd &= ~SL_F7;
}
inline bool f8() const
{
return snd & SL_F8;
}
inline void setF8(bool value)
{
if(value)
snd |= SL_F8;
else
snd &= ~SL_F8;
}
};
static_assert(sizeof(LocoSnd) == 4);
struct LocoF9F12 : SlotMessage
{
uint8_t function;
uint8_t checksum;
LocoF9F12(bool f9, bool f10, bool f11, bool f12) :
SlotMessage{OPC_LOCO_F9F12, SLOT_UNKNOWN},
function{0}
{
if(f9)
function |= SL_F9;
if(f10)
function |= SL_F10;
if(f11)
function |= SL_F11;
if(f12)
function |= SL_F12;
checksum = calcChecksum(*this);
}
inline bool f9() const
{
return function & SL_F9;
}
inline void setF9(bool value)
{
if(value)
function |= SL_F9;
else
function &= ~SL_F9;
}
inline bool f10() const
{
return function & SL_F10;
}
inline void setF10(bool value)
{
if(value)
function |= SL_F10;
else
function &= ~SL_F10;
}
inline bool f11() const
{
return function & SL_F7;
}
inline void setF11(bool value)
{
if(value)
function |= SL_F11;
else
function &= ~SL_F11;
}
inline bool f12() const
{
return function & SL_F8;
}
inline void setF12(bool value)
{
if(value)
function |= SL_F12;
else
function &= ~SL_F12;
}
};
static_assert(sizeof(LocoF9F12) == 4);
/*
2020-02-04 21:27:59.123954 [debug] cs1: unknown message: dataLen=0x0008, header=0x00a0, data=b2 11 70 2c
2020-02-04 21:27:59.413558 [debug] cs1: unknown message: dataLen=0x0008, header=0x00a0, data=b2 19 40 14
2020-02-04 21:28:00.046282 [debug] cs1: unknown message: dataLen=0x0008, header=0x00a0, data=b2 11 50 0c
2020-02-04 21:28:00.433662 [debug] cs1: unknown message: dataLen=0x0008, header=0x00a0, data=b2 11 60 3c
2020-02-04 21:28:02.502012 [debug] cs1: unknown message: dataLen=0x0008, header=0x00a0, data=b2 09 70 34
2020-02-04 21:28:02.913595 [debug] cs1: unknown message: dataLen=0x0008, header=0x00a0, data=b2 11 40 1c
2020-02-04 21:28:03.629638 [debug] cs1: unknown message: dataLen=0x0008, header=0x00a0, data=b2 09 50 14
2020-02-04 21:28:03.937476 [debug] cs1: unknown message: dataLen=0x0008, header=0x00a0, data=b2 09 60 24
*/
struct InputRep : Message
{
uint8_t in1;
uint8_t in2;
uint8_t checksum;
InputRep() :
Message{OPC_INPUT_REP}
{
}
inline uint16_t address() const
{
return (in1 & 0x7F) | (static_cast<uint16_t>(in2 & 0x0F) << 7);
}
inline bool isSwitchInput() const
{
return in2 & 0x20;
}
inline bool isAuxInput() const
{
return !isSwitchInput();
}
inline bool value() const
{
return in2 & 0x10;
}
};
static_assert(sizeof(InputRep) == 4);
struct RequestSlotData : Message
{
uint8_t slot;
uint8_t data2;
uint8_t checksum;
RequestSlotData(uint8_t _slot) :
Message(OPC_RQ_SL_DATA),
slot{_slot},
data2{0}
{
checksum = calcChecksum(*this);
}
};
static_assert(sizeof(RequestSlotData) == 4);
// d0 00 42 20 13 5e
struct MultiSense : Message
{
uint8_t data1;
uint8_t data2;
uint8_t data3;
uint8_t data4;
uint8_t checksum;
MultiSense() :
Message(OPC_MULTI_SENSE)
{
}
bool isTransponder() const
{
return
((data1 & MULTI_SENSE_TYPE_MASK) == MULTI_SENSE_TYPE_TRANSPONDER_GONE) ||
((data1 & MULTI_SENSE_TYPE_MASK) == MULTI_SENSE_TYPE_TRANSPONDER_PRESENT);
}
};
static_assert(sizeof(MultiSense) == 6);
struct LocoF13F19 : Message
{
uint8_t data1;
uint8_t slot;
uint8_t data3;
uint8_t function;
uint8_t checksum;
LocoF13F19(bool f13, bool f14, bool f15, bool f16, bool f17, bool f18, bool f19) :
Message(OPC_D4),
data1{0x20},
slot{SLOT_UNKNOWN},
data3{0x08},
function{0}
{
if(f13)
function |= SL_F13;
if(f14)
function |= SL_F14;
if(f15)
function |= SL_F15;
if(f16)
function |= SL_F16;
if(f17)
function |= SL_F17;
if(f18)
function |= SL_F18;
if(f19)
function |= SL_F19;
}
inline bool f13() const
{
return function & SL_F13;
}
inline void setF13(bool value)
{
if(value)
function |= SL_F13;
else
function &= ~SL_F13;
}
inline bool f14() const
{
return function & SL_F14;
}
inline void setF14(bool value)
{
if(value)
function |= SL_F14;
else
function &= ~SL_F14;
}
inline bool f15() const
{
return function & SL_F15;
}
inline void setF15(bool value)
{
if(value)
function |= SL_F15;
else
function &= ~SL_F15;
}
inline bool f16() const
{
return function & SL_F16;
}
inline void setF16(bool value)
{
if(value)
function |= SL_F16;
else
function &= ~SL_F16;
}
inline bool f17() const
{
return function & SL_F17;
}
inline void setF17(bool value)
{
if(value)
function |= SL_F17;
else
function &= ~SL_F17;
}
inline bool f18() const
{
return function & SL_F18;
}
inline void setF18(bool value)
{
if(value)
function |= SL_F18;
else
function &= ~SL_F18;
}
inline bool f19() const
{
return function & SL_F19;
}
inline void setF19(bool value)
{
if(value)
function |= SL_F19;
else
function &= ~SL_F19;
}
};
static_assert(sizeof(LocoF13F19) == 6);
struct LocoF20F28 : Message
{
uint8_t data1;
uint8_t slot;
uint8_t data3;
uint8_t function;
uint8_t checksum;
LocoF20F28(bool f20, bool f28) :
Message(OPC_D4),
data1{0x20},
slot{SLOT_UNKNOWN},
data3{0x05},
function{0}
{
if(f20)
function |= SL_F20;
if(f28)
function |= SL_F28;
}
inline bool f20() const
{
return function & SL_F20;
}
inline void setF20(bool value)
{
if(value)
function |= SL_F20;
else
function &= ~SL_F20;
}
inline bool f28() const
{
return function & SL_F28;
}
inline void setF28(bool value)
{
if(value)
function |= SL_F28;
else
function &= ~SL_F28;
}
};
static_assert(sizeof(LocoF20F28) == 6);
struct LocoF21F27 : Message
{
uint8_t data1;
uint8_t slot;
uint8_t data3;
uint8_t function;
uint8_t checksum;
LocoF21F27(bool f21, bool f22, bool f23, bool f24, bool f25, bool f26, bool f27) :
Message(OPC_D4),
data1{0x20},
slot{SLOT_UNKNOWN},
data3{0x09},
function{0}
{
if(f21)
function |= SL_F21;
if(f22)
function |= SL_F22;
if(f23)
function |= SL_F23;
if(f24)
function |= SL_F24;
if(f25)
function |= SL_F25;
if(f26)
function |= SL_F26;
if(f27)
function |= SL_F27;
}
inline bool f21() const
{
return function & SL_F21;
}
inline void setF21(bool value)
{
if(value)
function |= SL_F21;
else
function &= ~SL_F21;
}
inline bool f22() const
{
return function & SL_F22;
}
inline void setF22(bool value)
{
if(value)
function |= SL_F22;
else
function &= ~SL_F22;
}
inline bool f23() const
{
return function & SL_F23;
}
inline void setF23(bool value)
{
if(value)
function |= SL_F23;
else
function &= ~SL_F23;
}
inline bool f24() const
{
return function & SL_F24;
}
inline void setF24(bool value)
{
if(value)
function |= SL_F24;
else
function &= ~SL_F24;
}
inline bool f25() const
{
return function & SL_F25;
}
inline void setF25(bool value)
{
if(value)
function |= SL_F25;
else
function &= ~SL_F25;
}
inline bool f26() const
{
return function & SL_F26;
}
inline void setF26(bool value)
{
if(value)
function |= SL_F26;
else
function &= ~SL_F26;
}
inline bool f27() const
{
return function & SL_F27;
}
inline void setF27(bool value)
{
if(value)
function |= SL_F27;
else
function &= ~SL_F27;
}
};
static_assert(sizeof(LocoF21F27) == 6);
struct MultiSenseTransponder : MultiSense
{
bool isPresent() const
{
return (data1 & MULTI_SENSE_TYPE_MASK) == MULTI_SENSE_TYPE_TRANSPONDER_PRESENT;
}
uint16_t sensorAddress() const
{
return (static_cast<uint16_t>(data1 & 0x1F) << 7) | (data2 & 0x7F);
}
uint16_t transponderAddress() const
{
if(isTransponderAddressLong())
return (static_cast<uint16_t>(data3 & 0x7F) << 7) | (data4 & 0x7F);
else
return (data4 & 0x7F);
}
bool isTransponderAddressLong() const
{
return data3 != MULTI_SENSE_TRANSPONDER_ADDRESS_SHORT;
}
};
static_assert(sizeof(MultiSenseTransponder) == 6);
struct MultiSenseLong : Message
{
uint8_t len;
uint8_t data1;
uint8_t data2;
uint8_t data3;
uint8_t data4;
uint8_t data5;
uint8_t data6;
uint8_t checksum;
MultiSenseLong() :
Message(OPC_MULTI_SENSE_LONG),
len{9}
{
}
bool isTransponder() const
{
return
((data1 & MULTI_SENSE_TYPE_MASK) == MULTI_SENSE_TYPE_TRANSPONDER_GONE) ||
((data1 & MULTI_SENSE_TYPE_MASK) == MULTI_SENSE_TYPE_TRANSPONDER_PRESENT);
}
};
static_assert(sizeof(MultiSenseLong) == 9);
struct MultiSenseLongTransponder : MultiSenseLong
{
bool isPresent() const
{
return (data1 & MULTI_SENSE_TYPE_MASK) == MULTI_SENSE_TYPE_TRANSPONDER_PRESENT;
}
uint16_t sensorAddress() const
{
return (static_cast<uint16_t>(data1 & 0x1F) << 7) | (data2 & 0x7F);
}
uint16_t transponderAddress() const
{
if(isTransponderAddressLong())
return (static_cast<uint16_t>(data3 & 0x7F) << 7) | (data4 & 0x7F);
else
return (data4 & 0x7F);
}
bool isTransponderAddressLong() const
{
return data3 != MULTI_SENSE_TRANSPONDER_ADDRESS_SHORT;
}
Direction transponderDirection() const
{
return (data5 & 0x40) ? Direction::Forward : Direction::Reverse;
}
};
static_assert(sizeof(MultiSenseLongTransponder) == 9);
// OPC_SL_RD_DATA [E7 0E 1F 13 6F 01 30 07 08 19 00 00 00 52]
struct SlotReadData : Message
{
uint8_t len;
uint8_t slot;
uint8_t stat;
uint8_t adr;
uint8_t spd;
uint8_t dirf;
uint8_t trk;
uint8_t ss2;
uint8_t adr2;
uint8_t snd;
uint8_t id1;
uint8_t id2;
uint8_t checksum;
SlotReadData() :
Message(OPC_SL_RD_DATA),
len{14}
{
}
bool isBusy() const
{
return stat & SL_BUSY;
}
bool isActive() const
{
return stat & SL_ACTIVE;
}
uint16_t address() const
{
return (static_cast<uint16_t>(adr2) << 7) | adr;
}
bool isEmergencyStop() const
{
return spd == 0x01;
}
uint8_t speed() const
{
return spd > 1 ? spd - 1 : 0;
}
inline Direction direction() const
{
return (dirf & SL_DIR) ? Direction::Forward : Direction::Reverse;
}
inline void setDirection(Direction value)
{
if(value == Direction::Forward)
dirf |= SL_DIR;
else
dirf &= ~SL_DIR;
}
inline bool f0() const
{
return dirf & SL_F0;
}
inline void setF0(bool value)
{
if(value)
dirf |= SL_F0;
else
dirf &= ~SL_F0;
}
inline bool f1() const
{
return dirf & SL_F1;
}
inline void setF1(bool value)
{
if(value)
dirf |= SL_F1;
else
dirf &= ~SL_F1;
}
inline bool f2() const
{
return dirf & SL_F2;
}
inline void setF2(bool value)
{
if(value)
dirf |= SL_F2;
else
dirf &= ~SL_F2;
}
inline bool f3() const
{
return dirf & SL_F3;
}
inline void setF3(bool value)
{
if(value)
dirf |= SL_F3;
else
dirf &= ~SL_F3;
}
inline bool f4() const
{
return dirf & SL_F4;
}
inline void setF4(bool value)
{
if(value)
dirf |= SL_F4;
else
dirf &= ~SL_F4;
}
inline bool f5() const
{
return snd & SL_F5;
}
inline void setF5(bool value)
{
if(value)
snd |= SL_F5;
else
snd &= ~SL_F5;
}
inline bool f6() const
{
return snd & SL_F6;
}
inline void setF6(bool value)
{
if(value)
snd |= SL_F6;
else
snd &= ~SL_F6;
}
inline bool f7() const
{
return snd & SL_F7;
}
inline void setF7(bool value)
{
if(value)
snd |= SL_F7;
else
snd &= ~SL_F7;
}
inline bool f8() const
{
return snd & SL_F8;
}
inline void setF8(bool value)
{
if(value)
snd |= SL_F8;
else
snd &= ~SL_F8;
}
};
static_assert(sizeof(SlotReadData) == 14);
/*
struct ImmediatePacket : Message
{
uint8_t len;
uint8_t header;
uint8_t reps;
uint8_t dhi;
uint8_t im[5];
uint8_t checksum;
ImmediatePacket() :
Message(OPC_IMM_PACKET),
len{11},
header{0x7F},
reps{0},
dhi{0},
im{0, 0, 0, 0, 0}
{
}
void setIMCount(uint8_t value)
{
assert(value <= 5);
reps = (reps & 0x8F) | ((value & 0x07) << 4);
}
void updateDHI()
{
dhi = 0x20 |
(im[0] & 0x40) >> 7 |
(im[1] & 0x40) >> 6 |
(im[2] & 0x40) >> 5 |
(im[3] & 0x40) >> 4 |
(im[4] & 0x40) >> 3;
}
};
static_assert(sizeof(ImmediatePacket) == 11);
struct ImmediatePacketLoco : ImmediatePacket
{
ImmediatePacketLoco(uint16_t address, uint8_t repeatCount) :
ImmediatePacket()
{
assert(repeatCount <= 7);
reps = repeatCount & 0x07;
if(isLongAddress(address))
{
im[0] = 0xC0 | ((address >> 8) & 0x3F);
im[1] = address & 0xFF;
}
else
im[0] = address & 0x7F;
}
};
static_assert(sizeof(ImmediatePacketLoco) == sizeof(ImmediatePacket));
struct ImmediatePacketF9F12 : ImmediatePacketLoco
{
ImmediatePacketF9F12(uint16_t address, bool f9, bool f10, bool f11, bool f12, uint8_t repeatCount = 2) :
ImmediatePacketLoco(address, repeatCount)
{
const uint8_t offset = (im[0] & 0x80) ? 2 : 1;
im[offset] = 0xB0; // Function group two instruction: F9-F12
if(f9)
im[offset] |= 0x01;
if(f10)
im[offset] |= 0x02;
if(f11)
im[offset] |= 0x04;
if(f12)
im[offset] |= 0x08;
setIMCount(offset + 1);
updateDHI();
checksum = calcChecksum(*this);
}
};
static_assert(sizeof(ImmediatePacketF9F12) == sizeof(ImmediatePacketLoco));
struct ImmediatePacketF13F20 : ImmediatePacketLoco
{
ImmediatePacketF13F20(uint16_t address, bool f13, bool f14, bool f15, bool f16, bool f17, bool f18, bool f19, bool f20, uint8_t repeatCount = 2) :
ImmediatePacketLoco(address, repeatCount)
{
uint8_t offset = (im[0] & 0x80) ? 2 : 1;
im[offset++] = 0xDE; // Feature Expansion Instruction: F13-F20 function control
if(f13)
im[offset] |= 0x01;
if(f14)
im[offset] |= 0x02;
if(f15)
im[offset] |= 0x04;
if(f16)
im[offset] |= 0x08;
if(f17)
im[offset] |= 0x10;
if(f18)
im[offset] |= 0x20;
if(f19)
im[offset] |= 0x40;
if(f20)
im[offset] |= 0x80;
setIMCount(offset + 1);
updateDHI();
checksum = calcChecksum(*this);
}
};
static_assert(sizeof(ImmediatePacketF13F20) == sizeof(ImmediatePacketLoco));
struct ImmediatePacketF21F28 : ImmediatePacketLoco
{
ImmediatePacketF21F28(uint16_t address, bool f21, bool f22, bool f23, bool f24, bool f25, bool f26, bool f27, bool f28, uint8_t repeatCount = 2) :
ImmediatePacketLoco(address, repeatCount)
{
uint8_t offset = (im[0] & 0x80) ? 2 : 1;
im[offset++] = 0xDF; // Feature Expansion Instruction: F20-F28 function control
if(f21)
im[offset] |= 0x01;
if(f22)
im[offset] |= 0x02;
if(f23)
im[offset] |= 0x04;
if(f24)
im[offset] |= 0x08;
if(f25)
im[offset] |= 0x10;
if(f26)
im[offset] |= 0x20;
if(f27)
im[offset] |= 0x40;
if(f28)
im[offset] |= 0x80;
setIMCount(offset + 1);
updateDHI();
checksum = calcChecksum(*this);
}
};
static_assert(sizeof(ImmediatePacketF21F28) == sizeof(ImmediatePacketLoco));
*/
}
#endif