unit NMRAnetDefines; // ****************************************************************************** // // * Copyright: // (c) Mustangpeak Software 2012. // // The contents of this file are subject to the GNU GPL v3 licence/ you maynot use // this file except in compliance with the License. You may obtain a copy of the // License at http://www.gnu.org/licenses/gpl.html // // * Revision History: // 2012-02-01: Created // 2012-10-07: Version 1.0 // // * Description: // // ***************************************************************************** {$I Options.inc} uses NMRAnetAppDefines; type Generic16BitPointer = Word; Generic32BitPointer = DWord; TBufferTag = Word; // ***************************************************************************** // Buffer Pool Defines // ***************************************************************************** const CBS_ALLOCATED = $01; // CommonBufferState is allocated but may be in Process, need to check for inprocess flags CBS_PROCESSING = $02; // CommonBufferState is Processing (what that means depends on the Buffer type, implys that the buffer is not ready for the main loop to use yet) CBS_OUTGOING = $04; // CommonBufferState is an outgoing Buffer (Transmitting to the CAN Bus) CBS_TRANSFER_COMPLETE = $08; // Multi Frame Message transfer is complete CBS_INHIBIT_AUTORELEASE = $10; // Typcially buffers are released when when the library sees fit. This allows that logic to be bypassed (So far only implemented on Datagrams) // These must be in Priority Order for transmit, higher = higher priority BMC_PROTOCOL_SUPPORT_QUERY = $01; // [IN] Buffer Message Code is a Protocol Support Query [BaseBuffer] BMC_PRODUCER_IDENTIFY = $02; // [IN] Buffer Message Code is Producer Identify [DataBuffer] BMC_CONSUMER_IDENTIFY = $03; // [IN] Buffer Message Code is Consumer Identify [DataBuffer] BMC_EVENT_LEARN = $04; // [IN] Buffer Message Code is Event Learn [BaseBuffer] BMC_SIMPLE_NODE_INFO_REQEUST = $05; // [IN] Buffer Message Code is ACDI Request [BaseBuffer] BMC_DATAGRAM = $07; BMC_DATAGRAM_MEMORY_CONFIG = $08; // [IN/OUT] Buffer Message Code is a Datagram [DatagramBuffer] BMC_TRACTION = $09; // {$IFDEF BOOTLOADER} BMC_DATAGRAM_BOOTLOADER = $10; // [IN/OUT] Buffer Message Code is a Datagram [DatagramBuffer] {$ENDIF} const CAN_DATA_LEN = 8; MAX_STREAM_TYPE_CONTENT = 8; type TCAN_DataBytes = array[CAN_DATA_LEN] of Byte; PCAN_DataBytes = ^TCAN_DataBytes; // ***************************************************************************** // Base buffer for dynamcally allocated structures // ***************************************************************************** type TBaseBuffer = record // Common Buffer layout that allow overlaying of bytes with TDatagramBuffer, etc State: Byte; // State of Buffer, see CBS_xxx constants Alias: Word; // Alias associated with the buffer (Destination or Source depending on if the buffer is a Rx or Tx buffer) Next: ^TBaseBuffer; // Pointer to the next Message Buffer mCode: Byte; // Buffer Message Code for what the message is StateMachine: Byte; // Local StateMachine Index for use Tag: TBufferTag; // General Purpose useage depending on the message type end; PBaseBuffer = ^TBaseBuffer; // ***************************************************************************** // Buffer to hold data for normal MTI message responses // ***************************************************************************** type TDataBuffer = record // Common Buffer layout that allow overlaying of bytes with TDatagramBuffer, etc State: Byte; // State of Buffer, see CBS_xxx flags Alias: Word; // Alias associated with the buffer (Destination or Source depending on if the buffer is a Rx or Tx buffer) Next: ^TDataBuffer; // Pointer to the next Message Buffer mCode: Byte; // Buffer Message Code for what the message is StateMachine: Byte; // Local StateMachine Index for use Tag: TBufferTag; // General Purpose useage depending on the message type ByteCount: Byte; // Number of CAN bytes Bytes: TCAN_DataBytes; // CAN bytes end; PDataBuffer = ^TDataBuffer; //***************************************************************************** // Stream Buffer //***************************************************************************** const SF_CONTENT_INCLUDED = 0; // Bit 0 of InitiateFlags; Stream includes content in the first 8 bytes SF_REJECTED = 1; // Bit 1 of InitiateFlags; The stream request was rejected, out of order or should not happen SF_PERMANENT_ERROR = 6; // Bit 6 of InitiateFlags; The error is permanent, don't try again SF_ACCEPT = 7; // Bit 7 of InitiateFlags; The stream request was accepted // Global Reject flags SAF_REJECT_INFO_LOGGED = 0; // If the request was rejected the info was logged // Bits 1..4 Reserved // Permanent specific Reject flags SAF_REJECT_PERMANENT_INVALID_STREAM = 5; SAF_REJECT_PERMANENT_SOURCE_NOT_PERMITTED = 6; SAF_REJECT_PERMANENT_STREAMS_NOT_ACCEPTED = 7; // Temporary specific Reject flags // None to date type TStream = array[0..MAX_STREAM_LEN-1] of Byte; PStream = ^TStream; TStreamContentType = array[MAX_STREAM_TYPE_CONTENT] of Byte; TStreamContent = record TypeIncluded: Boolean; // True if the stream contained defined content and the rest of this record will be filled in when the stream is returned ContentType: TStreamContentType; // Filled out with the Content Type marker if Type is Included in the stream end; TStreamBuffer = record // Overlays TBaseBuffer.......... State: Byte; // State of Buffer, see CBS_xxx flags Alias: Word; // Alias associated with the buffer (Destination or Source depending on if the buffer is a Rx or Tx buffer) Next: ^TStreamBuffer; // Pointer to the next Message Buffer mCode: Byte; // Buffer Message Code for what the message is StateMachine: Byte; // Local StateMachine Index for use Tag: TBufferTag; // Stream Only: TBD TotalTransferCount: DWord; // Total number of bytes to send or receive iByteCount: DWord; // The number of bytes recevied as they come in, or the number of bytes to transmit NegotiatedTransferSize: Word; // DataBytes: TStream; // The 1024 bytes sent in the stream InitiateFlags: Byte; // See Stream Flags (SF_xxx) for bit values InitiateAdditionalFlags: Byte; // Stream Additional Flags (SAF_xxx) for bit values Content: TStreamContent; // If the stream has well defined content then this will be filled out LocalStreamID, // Unique ID defined by the Local Node that identifies the Stream Conversation RemoteStreamID: Byte; // Unique ID defined by the Remote Node that identifies the Stream Conversation iWatchdog: Word; // Increments every 1ms or so to allow detecting a stream that was abandon and never sent the End message or during transmit the Target Node never responds iRetransmit: Byte; // Number of times the Stream was attempted to transmit use to test before not trying any more end; PStreamBuffer = ^TStreamBuffer; // ***************************************************************************** // Configuration Memory Buffer to hold data while configuration memory is // being accessed // **************************************************************************** type TConfigMemErrorCode = array[0..1] of Byte; PConfigMemErrorCode = ^TConfigMemErrorCode; const CBA_WRITE = $01; // ConfigmemBufferAction is a Write; CBA_WRITE_UNDER_MASK = $02; // ConfigmemBufferAction is a Write under Mask; CBA_READ = $03; // ConfigmemBufferAction is a Read; CBA_READ_STREAM = $04; CBA_WRITE_STREAM = $05; MAX_CONFIG_MEM_DATA = 64; MAX_CONFIG_MEM_ERROR_STR_LEN = 60; CONFIG_MEM_RESULT_OK : TConfigMemErrorCode = ($00, $00); CONFIG_MEM_RESULT_TERMINATE : TConfigMemErrorCode = ($10, $00); CONFIG_MEM_RESULT_REJECTED_STREAM_PERMANENT_ERROR : TConfigMemErrorCode = ($10, $10); // $10xx high bytes says don't try again CONFIG_MEM_RESULT_REJECTED_STREAM_BUFFER_FULL : TConfigMemErrorCode = ($20, $00); // $20xx high byte says to try again type TConfigMemData = array[0..MAX_CONFIG_MEM_DATA-1] of Byte; TConfigMemDataErrorStr = string[MAX_CONFIG_MEM_ERROR_STR_LEN]; PConfigMemDataErrorStr = ^TConfigMemDataErrorStr; TConfigMemBuffer = record // This subset of a Common Buffer to hold the information from a Configuration Memory request after it decodes the Datagram and stores the information here in clear clean way State: Byte; // State of Buffer, see CBS_xxx constants Alias: Word; // Alias associated with the buffer (Destination or Source depending on if the buffer is a Rx or Tx buffer) Next: ^TConfigMemBuffer; // Pointer to the next Message Buffer StateMachine: Byte; // Local StateMachine Index for use Action: Byte; // See CBA_xxx flags, One or more of the flags AddressSpace: Byte; // Address Space to access Address: DWord; // Configuration Memory Address into the Address Space DataCount: Integer; // Number of Bytes (only for non-Stream access) DataBytes: TConfigMemData; // Databytes for the ConfigMem access (only for non Stream access) DataOffset: Byte; // Allows Offsets to reads/writes in to the DataBytes array Stream: ^TStreamBuffer; // Holds the Stream if this is a stream request AckFlags: Byte; // Reply Flags to send back to the requesting node, allows telling the node the reply is pending and an estimated time ErrorCode: TConfigMemErrorCode; // Error Code to reply to the requestor with ErrorString: PConfigMemDataErrorStr; // Error Code String (2 byte for target Alias, 2 bytes for error code) end; PConfigMemBuffer = ^TConfigMemBuffer; // ***************************************************************************** // Datagram and Datagram Buffer Defines // ***************************************************************************** type TDatagramErrorCode = array[0..1] of Byte; PDatagramErrorCode = ^TDatagramErrorCode; const DATAGRAM_RESULT_OKAY : TDatagramErrorCode = ($00, $00); // Errors that will cause sender to not retry DATAGRAM_RESULT_REJECTED_PERMANENT_ERROR : TDatagramErrorCode = ($10, $00); DATAGRAM_RESULT_REJECTED_INFORMATION_LOGGED : TDatagramErrorCode = ($10, $10); DATAGRAM_RESULT_REJECTED_SOURCE_NOT_PERMITTED : TDatagramErrorCode = ($10, $20); DATAGRAM_RESULT_REJECTED_SOURCE_DATAGRAMS_NOT_ACCEPTED : TDatagramErrorCode = ($10, $40); // Error that should cause sender to retry DATAGRAM_RESULT_REJECTED_BUFFER_FULL : TDatagramErrorCode = ($20, $00); // Error that was a transport problem DATAGRAM_RESULT_REJECTED_OUT_OF_ORDER : TDatagramErrorCode = ($60, $00); DATAGRAM_RESULT_REJECTED_NO_RESENT_MASK = $1000; DATAGRAM_RESULT_REJECTED_RESEND_MASK = $2000; DATAGRAM_RESULT_REJECTED_TRANSPORT_ERROR_MASK = $4000; DATAGRAM_OK_ACK_REPLY_PENDING = $80; MAX_DATAGRAM_LEN = 72; // How many Bytes in the datagram // Datagram Buffer States DGS_EMPTY = $00; // [RX/TX] The Datagram Packet Buffer is empty DGS_ALLOCATED = $01; // Allocated DGS_IN_PROCESS = $02; // [RX/TX] The Datagram Packet Buffer is currently collecting/transmitting frames DGS_TRANSFER_COMPLETE = $04; // [RX/TX] The Datagram Packet has responded to the sender and ready for use (DATAGRAM_REJECTED_BUFFER_FULL response needed) // Datagram Receive Statemachine States STATE_DATAGRAM_RECEIVE_START = 0; // Receive Statemachine states STATE_DATAGRAM_RECEIVE_COMPLETE = 1; STATE_DATAGRAM_HANDLED_MESSASGE = 2; STATE_DATAGRAM_UNHANDLED_MESSAGE = 3; STATE_DATAGRAM_SENDING_RESPONSE = 4; STATE_DATAGRAM_ERROR_RESPONSES = 5; // Datagram Transmit Statemachine States STATE_DATAGRAM_TRANSMIT_START = 0; // Transmit Statemachine states STATE_DATAGRAM_TRANSMIT_SINGLE_FRAME = 1; STATE_DATAGRAM_TRANSMIT_WAIT_FOR_RESPONSE_SINGLE_FRAME = 2; STATE_DATAGRAM_TRANSMIT_MULTI_FRAME = 3; STATE_DATAGRAM_TRANSMIT_WAIT_FOR_RESPONSE_MULTI_FRAME = 4; DATAGRAM_WATCHDOG_MAX = 30; // 100ms counts before the buffer (base/datagram) is declared abandon, spec is must be greater than 3 seconds DATAGRAM_MAX_RETRY_COUNT = 3; // Number of try a datagram will try to be resent STREAM_WATCHDOG_MAX = 30; STREAM_MAX_RETRY_COUNT = 3; // The first byte in a datagram is a command byte that allows datagrams to be "tagged" as special through these codes // The first byte is always reserved for this special purpose DATAGRAM_TYPE_MEMORY_CONFIGURATION = $20; // Memory Configuration Protocol DATAGRAM_TYPE_TRAIN_CONTROL = $30; // Train Control Protocol {$IFDEF BOOTLOADER} DATAGRAM_TYPE_BOOTLOADER = $40; // MAKING A GUESS ON A NUMBER>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> {$ENDIF} DATAGRAM_TYPE_TWO_BYTE_CMD_MASK = $E0; // Next two bytes are command bytes and not data DATAGRAM_TYPE_SIX_BYTE_CMD_MASK = $F0; // Next six bytes are command bytes and not data type TDatagram = array[0..MAX_DATAGRAM_LEN-1] of Byte; PDatagram = ^TDatagram; TDatagramError = record SubType: TDatagramErrorCode; Count: Byte; // Number of Bytes to move into the CAN Databyte (MTI + SubType if needed) end; PDatagramError = ^TDatagramError; TDatagramBuffer = record // Overlays TBaseBuffer.......... State: Byte; // State of Buffer, see CBS_xxx flags Alias: Word; // Alias associated with the buffer (Destination or Source depending on if the buffer is a Rx or Tx buffer) Next: ^TDatagramBuffer; // Pointer to the next Message Buffer mCode: Byte; // Buffer Message Code for what the message is StateMachine: Byte; // Local StateMachine Index for use Tag: TBufferTag; // Datagram Only: Tracks the current index of the block of 8 bytes being sent iByteCount: Byte; // The number of bytes recevied as they come in, or the number of bytes to transmit DataBytes: TDatagram; // The 72 bytes sent in the datagram ErrorCode: TDatagramError; // Tracks any errors that occur through the MTI/Error Codes send as the first few bytes in the datagram iWatchdog: Word; // Increments every 1ms or so to allow detecting a datagram that was abandon and never sent the End message or during transmit the Target Node never responds iRetransmit: Byte; // Number of times the Datagram was attempted to transmit use to test before not trying any more end; PDatagramBuffer = ^TDatagramBuffer; // ***************************************************************************** // General NMRAnet Defines // ***************************************************************************** const MAX_BUS_LOGIN_TIMEOUT = 5; // Number of 100ms time tick to wait for a node to send a RID to signal a duplicate Alais CAN_TX_0 = 0; CAN_TX_1 = 1; CAN_TX_2 = 2; CAN_RX_0 = 0; CAN_RX_1 = 1; CAN_TX_PRIORITY_0 = 0; CAN_TX_PRIORITY_1 = 1; CAN_TX_PRIORITY_2 = 2; CAN_TX_PRIORITY_3 = 3; // ***************************************************************************** // Extended CAN Frames // 29 Bits Divided as follows: // - 1 Bit = Priority (1 = Low Priority typical) // - 4 Bits = Frame Type (FT_xxxx Constants) // - 12 Bits = Destination Node Address Alias or Message Type (MT_xxx Constants) // - 12 Bits = Source Node Address Alias // // Frame Types. These define what the Frame of the CAN message consists of. const MTI_OLCB_MSG = $08000000; // MTI_CAN = $00000000; // Frame Type CAN Control Message MTI_CID0 = $07000000; // First 12 Bits of 48 bit Node ID MTI_CID1 = $06000000; // 2rd 12 Bits of 48 bit Node ID MTI_CID2 = $05000000; // 3nd 12 Bits of 48 bit Node ID MTI_CID3 = $04000000; // Last 12 Bits of 48 bit Node ID MTI_CID4 = $03000000; // non-OpenLCB Protocol MTI_CID5 = $02000000; // non-OpenLCB Protocol MTI_CID6 = $01000000; // non-OpenLCB Protocol MTI_CID_MASK = $07000000; MTI_RID = $00700000; // Reserve ID MTI_AMD = $00701000; // Alias Map Definition MTI_AME = $00702000; // Alias Mapping Enquiry MTI_AMR = $00703000; // Alias Map Reset Frame MTI_MASK = $0FFFF000; MTI_FRAME_TYPE_MASK = $0F000000; MTI_FRAME_TYPE_GENERAL = $09000000; MTI_FRAME_TYPE_DATAGRAM_ONLY_FRAME = $0A000000; MTI_FRAME_TYPE_DATAGRAM_FRAME_START = $0B000000; MTI_FRAME_TYPE_DATAGRAM_FRAME = $0C000000; MTI_FRAME_TYPE_DATAGRAM_FRAME_END = $0D000000; MTI_FRAME_TYPE_STREAM_INIT_REQUEST = $09CC8000; MTI_FRAME_TYPE_STREAM_INIT_REPLY = $09868000; MTI_FRAME_TYPE_STREAM_SEND = $0F000000; MTI_FRAME_TYPE_STREAM_PROCEED = $09888000; MTI_FRAME_TYPE_STREAM_COMPLETE = $098A8000; MTI_ADDRESSED_MASK = $00008000; MTI_SIMPLE_PROTOCOL_MASK = $00010000; MTI_EVENT_PRESENT_MASK = $00002000; MTI_TRACTION_PROTOCOL = $095EA000; // Databytes = Protocol (Train Protocol, DCC, etc), Operation, control MTI_TRACTION_REPLY = $095E8000; // Databytes = Reply data/information MTI_INITIALIZATION_COMPLETE = $09100000; // Databytes = Full Node ID MTI_VERIFY_NODE_ID_NUMBER_DEST = $09488000; // Databytes = Destination Alias MTI_VERIFY_NODE_ID_NUMBER = $09490000; // MTI_VERIFIED_NODE_ID_NUMBER = $09170000; // {Optional Full Node ID} MTI_OPTIONAL_INTERACTION_REJECTED = $09068000; // Databytes = Destination Alias, Error, {Optional Info} MTI_TERMINATE_DUE_TO_ERROR = $090A8000; // Databytes = Destination Alias, Error, {Optional Info} MTI_PROTOCOL_SUPPORT_INQUIRY = $09828000; // Databytes = Destination Alias MTI_PROTOCOL_SUPPORT_REPLY = $09668000; // Databytes = Destination Alias, Protocol Flags MTI_CONSUMER_IDENTIFY = $098F4000; // Databytes = EventID MTI_CONSUMER_IDENTIFY_RANGE = $094A4000; // Databytes = EventID with Mask MTI_CONSUMER_IDENTIFIED_UNKNOWN = $094C7000; // Databytes = EventID MTI_CONSUMER_IDENTIFIED_SET = $094C4000; // Databytes = EventID MTI_CONSUMER_IDENTIFIED_CLEAR = $094C5000; // Databytes = EventID MTI_CONSUMER_IDENTIFIED_RESERVED = $094C6000; // Databytes = EventID MTI_PRODUCER_IDENDIFY = $09914000; // Databytes = EventID MTI_PRODUCER_IDENTIFY_RANGE = $09524000; // Databytes = EventID with Mask MTI_PRODUCER_IDENTIFIED_UNKNOWN = $09547000; // Databytes = EventID MTI_PRODUCER_IDENTIFIED_SET = $09544000; // Databytes = EventID MTI_PRODUCER_IDENTIFIED_CLEAR = $09545000; // Databytes = EventID MTI_PRODUCER_IDENTIFIED_RESERVED = $09546000; // Databytes = EventID MTI_EVENTS_IDENTIFY_DEST = $09968000; // Databytes = Destination Alias MTI_EVENTS_IDENTIFY = $09970000; // MTI_EVENT_LEARN = $09594000; // Databytes = EventID MTI_PC_EVENT_REPORT = $095B4000; // Databytes = EventID (Infamouse PCER) MTI_SIMPLE_NODE_INFO_REQUEST = $09DE8000; // Databytes = Destination Alias MTI_SIMPLE_NODE_INFO_REPLY = $09A08000; // Databytes = Destination Alias, ACDI Data MTI_DATAGRAM_OK_REPLY = $09A28000; // Databytes = Destination Alias MTI_DATAGRAM_REJECTED_REPLY = $09A48000; // Databytes = Destination Alias, Error Code MASK_SOURCE_ALIAS = $00000FFF; // Masks out just the Source Alias Address // These are Negavitve Logic so "xx01" = Start, "xx10" = End were the "0" is the bit of interest PIP_EXTENSION_START_BIT = $1000; // Flags in the Destination word for future extension of PIP PIP_EXTENSION_END_BIT = $2000; // Flags in the Destination word for future extension of PIP PIP_EXTENSION_START_BIT_MASK = $2000; // Confusing for sure.... PIP_EXTENSION_END_BIT_MASK = $1000; // Confusing for sure.... PIP_EXTENSION_START_END_BIT = $0000; // Both Start and End are "set" (active zero) TERMINATE_DUE_TO_ERROR_TEMPORARY = $1000; // Upper nibble of the Destination Alias in the DataBytes TERMINATE_DUE_TO_ERROR_PERMANENT = $2000; // Upper nibble of the Destination Alias in the DataBytes EVENT_STATE_CLEAR = $00; EVENT_STATE_VALID = $01; EVENT_STATE_INVALID = $02; EVENT_STATE_UNKOWN = $03; STATE_NMRABUS_START = 0; STATE_NMRABUS_GENERATE_NODE_ALIAS = 1; STATE_RANDOM_NUMBER_GENERATOR = 2; STATE_NMRABUS_TRANSMIT_CID = 3; STATE_NMRABUS_NEXT_CDI = 4; STATE_NMRABUS_WAITSTATE = 5; STATE_NMRABUS_SEND_LOGIN_RID = 6; STATE_NMRABUS_SEND_LOGIN_AMD = 8; STATE_NMRABUS_INITIALIZED = 9; STATE_NMRABUS_LOGIN_IDENTIFY_EVENTS = 10; STATE_NMRABUS_PERMITTED = 11; STATE_NMRABUS_INHIBITED = 12; STATE_NMRABUS_DUPLICATE_FULL_ID = 13; STATE_NMRABUS_TAKE_OFFLINE = 14; STATE_NMRABUS_OFFLINE = 15; STATE_ACDI_MFG_VERSION = 0; STATE_ACDI_MFG_INFO = 1; STATE_ACDI_USER_VERSION = 3; STATE_ACDI_USER_NAME = 4; STATE_ACDI_START_DESC = 5; STATE_ACDI_USER_DESC = 6; STATE_ACDI_DONE = 7; type TNodeID = array[0..1] of DWORD; // WARNING READ THIS::::: The Bottom 3 Bytes = [0] and the Top 3 Bytes = [1] The ID is not continious across the both DWords the upper nibble of the bottom DWord is not used TNodeIDs = record ID: TNodeID; AliasID: Word; end; TNodeInfo = record ID: TNodeID; // Unique 48 Bit ID for Node Seed: TNodeID; // Seed for Random Number Generator in case we have to reseed because of a duplicate ID AliasID: Word; // 12 Bit Alias ID end; const // NMRABus States NS_EMPTY = $00; NS_ALLOCATED = $01; NS_PERMITTED = $02; // NodeState CAN Frame Layer is permitted (Node ID's resolved with bus) NS_INITIALIZED = $04; // NodeState Message Layer has sent its first Initialize Complete Message NS_VIRTUAL = $08; // NodeState If is a virtual node NS_RELEASING = $10; // Node is tagged to send and AMD and be removed from the bus (while this is set what happens??) // MsgFlags in order of precidence (= 0 highest precidence) MF_DUPLICATE_NODE_ID = $01; // MsgFlag, a Duplicate Node ID was detected, critical fault MF_DUPLICATE_ALIAS = $02; // MsgFlag, a Duplicate Alias was Detected, critical fault MF_DUPLICATE_ALIAS_RID = $04; // MsgFlag, a Duplicate Alias was Detected during a CID message, not a fault just need to respond to claim the Alias MF_ALIAS_MAP_ENQUIRY = $08; // MsgFlag, an AMD message need to be responded to MF_VERIFY_NODE_ID = $10; // MsgFlag, a Verify Node ID message needs to be responded to type TNMRAnetNodeLoginInfo = record TimeCounter: Byte; // Number of timer ticks into the time waiting for a RID response from another node for our RID broadcasts iCID: Byte; // Which of the 4 CIDs we are broadcasting end; TNMRAnetNode = record iIndex: Byte; // Index in the main array State: Byte; // See the NS_xxxx flags; State of the Node Info: TNodeInfo; // Information about a Node Login: TNMRAnetNodeLoginInfo; // Login Information MsgFlags: Byte; // Message Flags for messages passed to the Node through a simple set bit (no complex reply data needed like destination Alias), see the MF_xxxx flags MsgFlagsUserDefined: Byte; // Message Flags for user apps to define AND handle in App Callbacks EventsProducedFlags: array[0..MAX_EVENTS_PRODUCED_BIT_BYTES-1] of Byte; // Events Produced that need to be broadcast, each event occupies 2 bits (unknown, valid, invalid) EventsConsumedFlags: array[0..MAX_EVENTS_CONSUMED_BIT_BYTES-1] of Byte; // Events Produced that need to be broadcast, each event occupies 2 bits (unknown, valid, invalid) PCER_Flags: array[0..MAX_PCER_BIT_BYTES-1] of Byte; // If bit is set then the index of the bit maps to the Produced Event and it requires a PCER sent for that event iStateMachine: Byte; // Statemachine index for the main bus login BaseBuffers: PBaseBuffer; // Head of a possible linked list of dataless Messages Replies to service DatagramBuffers: PDatagramBuffer; // Head of a possible linked list of Datagrams to service ConfigMemBuffers: PConfigMemBuffer; // Head of a possible linked list of Configuration Memory Accesses to service DataBuffers: PDataBuffer; // Head of a possible linked list of Message Replies that need sent Data Bytes to be serviced StreamBuffers: PStreamBuffer; // Head of a possible linked list of Streams to service ConfigurationAddress: Generic32BitPointer; // Pointer into the EEProm Memory, user assigned in the NMRAnetAppCallbacks file ParentAlias, // Definition depends on what kind of node. If a Throttle then Parent should never be set, If a Train then the will be the Owner Throttle ChildAlias, // Definition depends on what kind of node. If a Throttle then Child should the Train it is controlling, if a Train then should not be set LeftSibling, // Definition depends on what kind of node. If Train then may be the next in a Consist Chain RightSibling: ^TNMRAnetNode; // Definition depends on what kind of node. If Train then may be the previous in a Consist Chain RAMAddress: Generic32BitPointer; // Pointer to a DataStructure that is in Volatile RAM defined in the user defined NMRAnetAppCallbacks file, user assigned in the NMRAnetAppCallbacks file end; PNMRAnetNode = ^TNMRAnetNode; type TNodes = record RawList: array[0..MAX_NODE_COUNT-1] of TNMRAnetNode; // Node [0] is ALWAYS the physical node AllocatedList: array[0..MAX_NODE_COUNT-1] of PNMRAnetNode; // Node List sorted by Alias AllocatedCount: Integer; // Number of Nodes Allocated iActiveNode: Word; // The node that is "active" which means it is the one that the main statemachine is giving a time slice to execute end; PNodes = ^TNodes; type TDatagramTaskCallbackFunc = procedure(NodeBuffer: PNMRAnetNode; Datagram: PDatagramBuffer); PDatagramTaskCallbackFunc = ^TDatagramTaskCallbackFunc; // ***************************************************************************** // Memory Configuration Defines // ***************************************************************************** const MCP_COMMAND_MASK = $C0; // Upper 2 bits are the command type // Upper 2 bits 0 = Write Command MCP_COMMAND_WRITE = $00; // MemoryConfigurationProtocol - Write Memory Mask MCP_COMMAND_WRITE_STREAM = $20; // MemoryConfigurationProtocol - Write Memory Mask with Streams MCP_COMMAND_WRITE_UNDER_MASK = $08; // MemoryConfigurationProtocol - Write Memory under mask Mask MCP_COMMAND_WRITE_REPLY_OK = $10; MCP_COMMAND_WRITE_REPLY_FAIL = $18; // Upper 2 bits 1 = Read Command MCP_COMMAND_READ = $40; // MemoryConfigurationProtocol - Read Memory Mask MCP_COMMAND_READ_STREAM = $60; // MemoryConfigurationProtocol - Read Memory with Streams MCP_COMMAND_READ_REPLY_OK = $50; // MemoryConfigurationProtocol - Read Reply Mask [Does not include the Address Space Mask "or" it with the the Address space masks below] MCP_COMMAND_READ_REPLY_FAIL = $58; MCP_COMMAND_READ_SREAM_REPLY = $30; // Upper 2 bits 2 = Operation Command MCP_OPERATION = $80; // MemoryConfigurationProtocol - Operation Mask // Bit 0..2 are to define address space MCP_COMMAND_REPLY_FAIL = 3; // Bit 3 set mean the result is a failed result if it is a Command Reply MCP_COMMAND_WRITE_UNDER_MASK_BIT = 3; // Bit 3 set means write under mask for an in coming command MCP_REPLY_COMMAND_BIT = 4; // Bit 4 set means it is a reply to a Command MCP_STREAM_COMMAND_BIT = 5; // Bit 5 set means it is a Stream Command // Bit 6..7 define the Command MCP_CDI = $03; // Address space = CDI ($FF) access Mask MCP_ALL = $02; // Address space = All ($FE) access Mask MCP_CONFIGURATION = $01; // Address space = Basic Configuration ($FD) access Mask MCP_NONE = $00; // Use the optional {Space} byte in the datagram to defin the address space MCP_OP_GET_CONFIG = $80; // MemoryConfigurationProtocol Operation - Get Configuration MCP_OP_GET_CONFIG_REPLY = $82; // MemoryConfigurationProtocol Operation - Get Configuration Reply MCP_OP_GET_ADD_SPACE_INFO = $84; // MemoryConfigurationProtocol Operation - Get Add Space Info MCP_OP_GET_ADD_SPACE_INFO_REPLY = $86; // MemoryConfigurationProtocol Operation - Get Add Space Info Reply MCP_OP_LOCK = $88; // MemoryConfigurationProtocol Operation - Lock Node MCP_OP_LOCK_REPLY = $8A; // MemoryConfigurationProtocol Operation - Lock Node Reply MCP_OP_GET_UNIQUEID = $8C; // MemoryConfiguratio nProtocol Operation - Get Unique ID Key MCP_OP_GET_UNIQUEID_REPLY = $8E; // MemoryConfigurationProtocol Operation - Get Unique ID Key Reply MCP_OP_GET_ADD_SPACE_INFO_REPLY_PRESENT = $01; MCP_OP_FREEZE = $A0; // MemoryConfigurationProtocol Operation - Freeze Node MCP_OP_INDICATE = $A4; // MemoryConfigurationProtocol Operation - Indicate MCP_OP_UPDATE_COMPLETE = $A8; // MemoryConfigurationProtocol Operation - Update Complete MCP_OP_RESETS = $A9; // MemoryConfigurationProtocol Operation - Resets STATE_DATAGRAM_MEM_CONFIG_SEND_REPLY = $00; STATE_DATAGRAM_MEM_CONFIG_SEND_RESUSED_DATAGRAM = $01; STATE_DATAGRAM_MEM_CONFIG_WAITFOR_REPLY = $02; STATE_MEM_CONFIG_READWRITE_START = $00; STATE_MEM_CONFIG_READWRITE_READ = $01; STATE_MEM_CONFIG_READWRITE_WRITE = $02; STATE_MEM_CONFIG_READWRITE_WAIT_UNTIL_DONE_PROCESSING = $03; STATE_MEM_CONFIG_READWRITE_STREAM_REPLY_SETUP = $04; STATE_MEM_CONFIG_READWRITE_STREAM_READ = $05; STATE_MEM_CONFIG_READWRITE_STREAM_WRITE = $06; STATE_MEM_CONFIG_READWRITE_WRITE_UNDER_MASK = $07; STATE_MEM_CONFIG_RELEASE = $10; STATE_STREAM_IDLE = $00; STATE_STREAM_INITIATE_REQUEST = $01; STATE_STREAM_INITIATE_REQEUST_WAIT_FOR_REPLY = $02; STATE_STREAM_INITIATE_REPLY = $03; STATE_STREAM_SEND = $04; STATE_STREAM_PROCEED = $05; STATE_STREAM_COMPLETE = $06; var MaxTime_StateMachine: Word; MaxTime_RX: Word; implementation end.