Skip to content

Commit

Permalink
Merge pull request #31 from jhu-cisst/feature-eth-v9
Browse files Browse the repository at this point in the history
Feature eth v9
  • Loading branch information
pkazanzides authored Apr 16, 2024
2 parents 6da9639 + 00374b3 commit cb9b0c6
Show file tree
Hide file tree
Showing 18 changed files with 880 additions and 349 deletions.
71 changes: 58 additions & 13 deletions lib/BasePort.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ no warranty. The complete license can be found in license.txt and
*/

// Defined here for static methods ParseOptions and DefaultPort
#define ETH_UDP_DEFAULT_IP "169.254.0.100"
#define ETH_UDP_DEFAULT_IP "169.254.0.100"
#define ETH_UDP_MULTICAST_DEFAULT_IP "224.0.0.100"

// Some useful constants
const unsigned long BOARD_ID_MASK = 0x0f000000; /* Mask for board_id */
Expand All @@ -62,9 +63,9 @@ const unsigned int MAX_POSSIBLE_DATA_SIZE = 2048;
// The FireWire node number is represented by an unsigned char (8 bits), but only 6
// bits are used for the node number (0-63). The Ethernet/FireWire bridge protocol
// uses the upper two bits as flags to indicate whether the packet should be sent
// via Ethernet broadcast (0x80) and whether the Ethernet/FireWire bridge should
// via Ethernet broadcast/multicast (0x80) and whether the Ethernet/FireWire bridge should
// not forward (0x40) the received packet to other boards via FireWire.
const unsigned char FW_NODE_ETH_BROADCAST_MASK = 0x80; // Mask for Ethernet broadcast
const unsigned char FW_NODE_ETH_BROADCAST_MASK = 0x80; // Mask for Ethernet broadcast or multicast
const unsigned char FW_NODE_NOFORWARD_MASK = 0x40; // Mask to prevent forwarding by Ethernet/FireWire bridge
const unsigned char FW_NODE_FLAGS_MASK = 0xc0; // Mask for above flags
const unsigned char FW_NODE_MASK = 0x3f; // Mask for valid FireWire node numbers (0-63)
Expand All @@ -90,24 +91,41 @@ class BasePort
// With Firmware V7+, each FPGA starts a timer when it receives the broadcast query command
// sent by the host PC. The following times are relative to this timer.
struct BroadcastReadInfo {
unsigned int readSizeQuads; // Read size in quadlets
unsigned int readSequence; // The sequence number sent with the broadcast query command
double updateStartTime; // When the FPGA started updating the hub data
double updateFinishTime; // When the FPGA finished updating the hub data
bool updateOverflow; // Whether timer overflow was detected during data update
double readStartTime; // When the PC started reading the hub feedback data
double readFinishTime; // When the PC finished reading the hub feedback data
bool readOverflow; // Whether timer overflow was detected during gap or read
double gapTime; // Time between update finish and read start
double gapTimeMin; // Minimum gap time
double gapTimeMax; // Maximum gap time
struct BroadcastBoardInfo { // For each board:
bool inUse; // Whether board is participating in broadcast read
bool updated; // Whether successfully updated
unsigned int blockNum; // Block number that contained board data
unsigned int blockSize; // Number of quadlets from this board
unsigned int sequence; // The sequence number received (should be same as readSequence)
bool seq_error; // Sequence error mismatch on FPGA
double updateTime; // When the hub feedback data was updated

BroadcastBoardInfo() : inUse(false), blockSize(0), sequence(0), seq_error(false), updateTime(0.0) {}
BroadcastBoardInfo() : inUse(false), updated(false), blockNum(0), blockSize(0), sequence(0),
seq_error(false), updateTime(0.0) {}
~BroadcastBoardInfo() {}
};
BroadcastBoardInfo boardInfo[BoardIO::MAX_BOARDS];

BroadcastReadInfo() : readSequence(0), readStartTime(0.0), readFinishTime(0.0) {}
BroadcastReadInfo() : readSizeQuads(0), readSequence(0), updateStartTime(0.0), updateFinishTime(0.0),
updateOverflow(false), readStartTime(0.0), readFinishTime(0.0), readOverflow(false),
gapTime(0.0) { Clear(); }
~BroadcastReadInfo() {}
void PrintTiming(std::ostream &outStr, bool newLine = true) const;
unsigned int IncrementSequence();
void PrepareForRead();
void PrintTiming(std::ostream &outStr) const;
void Clear(void)
{ gapTimeMin = 1.0; gapTimeMax = 0.0; }
};

protected:
Expand Down Expand Up @@ -171,6 +189,11 @@ class BasePort
unsigned char Node2Board[MAX_NODES];
nodeid_t Board2Node[BoardIO::MAX_BOARDS];

// Returns true if Node2Board has a valid entry, which indicates that
// the node has been initialized.
bool isNodeValid(nodeid_t node) const
{ return (Node2Board[node] < BoardIO::MAX_BOARDS); }

// Initialize port (called by constructor and Reset)
virtual bool Init(void) = 0;

Expand All @@ -196,8 +219,8 @@ class BasePort
void SetReadBufferBroadcast(void);
void SetWriteBufferBroadcast(void);

// Return expected size for broadcast read, in bytes
unsigned int GetBroadcastReadSize(void) const;
// Return expected size for broadcast read, in quadlets
unsigned int GetBroadcastReadSizeQuads(void) const;

// Convenience function
void SetReadInvalid(void);
Expand Down Expand Up @@ -373,18 +396,24 @@ class BasePort
BroadcastReadInfo GetBroadcastReadInfo(void) const
{ return bcReadInfo; }

// Clear gapTime min/max
void ClearBroadcastReadInfo(void)
{ bcReadInfo.Clear(); }

// Return string version of PortType
static std::string PortTypeString(PortType portType);

// Helper function for parsing command line options.
// In particular, this is typically called after a certain option, such as -p, is
// recognized and it parses the rest of that option string:
// N for FireWire, where N is the port number (backward compatibility)
// fw:N for FireWire, where N is the port number
// eth:N for raw Ethernet (PCAP), where N is the port number
// udp:xx.xx.xx.xx for UDP, where xx.xx.xx.xx is the (optional) server IP address
// N for FireWire, where N is the port number (backward compatibility)
// fw:N for FireWire, where N is the port number
// eth:N for raw Ethernet (PCAP), where N is the port number
// ethfw:N as above, forcing bridge to FireWire if possible
// udp:xx.xx.xx.xx for UDP, where xx.xx.xx.xx is the (optional) server IP address
// udpfw:xx.xx.xx.xx as above, forcing bridge to FireWire if possible
static bool ParseOptions(const char *arg, PortType &portType, int &portNum, std::string &IPaddr,
std::ostream &ostr = std::cerr);
bool &fwBridge, std::ostream &ostr = std::cerr);

static PortType DefaultPortType(void);
static std::string DefaultPort(void);
Expand Down Expand Up @@ -453,6 +482,14 @@ class BasePort
// Read all boards broadcasting
virtual bool ReadAllBoardsBroadcast(void);

// Returns true if broadcast read packet contains boards in sequential order,
// starting with lowest numbered board
virtual bool isBroadcastReadOrdered(void) const { return true; }

// Return clock period used for broadcast read timing measurements
// 49.152 MHz, except 125 MHz when using FPGA V3 Ethernet-only
virtual double GetBroadcastReadClockPeriod(void) const;

// Write to all boards
virtual bool WriteAllBoards(void);

Expand Down Expand Up @@ -493,6 +530,14 @@ class BasePort
*/
virtual void WaitBroadcastRead(void) = 0;

/*!
\brief Receive the broadcast read response. This is usually a block read from
address 0x1000 (Hub memory); in the case of Ethernet-only, it receives
a response from an FPGA board some time after WriteBroadcastReadRequest
is issued.
*/
virtual bool ReceiveBroadcastReadResponse(quadlet_t *rdata, unsigned int nbytes);

/*!
\brief Add delay (if needed) for PROM I/O operations
The delay is 0 for FireWire, and non-zero for Ethernet.
Expand Down
59 changes: 49 additions & 10 deletions lib/EthBasePort.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,17 +59,22 @@ class EthBasePort : public BasePort
bool FwPacketDropped;
bool EthInternalError;
bool EthSummaryError;
bool noForwardFlag;
unsigned int srcPort;
unsigned int numStateInvalid; // Not used, except in debug builds of firmware
unsigned int numPacketError;
FPGA_Status() : FwBusReset(false), FwPacketDropped(false), EthInternalError(false), EthSummaryError(false),
numStateInvalid(0), numPacketError(0) {}
noForwardFlag(false), srcPort(0), numStateInvalid(0), numPacketError(0) {}
~FPGA_Status() {}
};

typedef bool (*EthCallbackType)(EthBasePort &port, unsigned char boardId, std::ostream &debugStream);

protected:

// Whether to use Ethernet/Firewire bridge (if false, use Ethernet only)
bool useFwBridge;

uint8_t fw_tl; // FireWire transaction label (6 bits)

EthCallbackType eth_read_callback;
Expand All @@ -79,7 +84,10 @@ class EthBasePort : public BasePort
FwBusReset = 0x01, // Firewire bus reset is active
FwPacketDropped = 0x02, // Firewire packet dropped
EthInternalError = 0x04, // Internal FPGA error (bus access or invalid state)
EthSummaryError = 0x08 // Summary of Ethernet protocol errors (see Status)
EthSummaryError = 0x08, // Summary of Ethernet protocol errors (see Status)
noForwardFlag = 0x10, // 1 -> Ethernet only (no forward to Firewire)
srcPortMask = 0x60, // Mask for srcPort bits
srcPortShift = 5 // Shift for srcPort bits
};

FPGA_Status FpgaStatus; // FPGA status from extra data returned
Expand All @@ -93,15 +101,18 @@ class EthBasePort : public BasePort
//! Write quadlet to node (internal method called by WriteQuadlet)
bool WriteQuadletNode(nodeid_t node, nodeaddr_t addr, quadlet_t data, unsigned char flags = 0);

// Write a block to the specified node. Internal method called by ReadBlock.
// Read a block from the specified node (also calls ReceiveResponseNode). Internal method called by ReadBlock.
bool ReadBlockNode(nodeid_t node, nodeaddr_t addr, quadlet_t *rdata, unsigned int nbytes, unsigned char flags = 0);

// Receive the block data. Internal method called by ReadBlockNode.
bool ReceiveResponseNode(nodeid_t node, quadlet_t *rdata, unsigned int nbytes, uint8_t fw_tl, nodeid_t *src_node = 0);

// Write a block to the specified node. Internal method called by WriteBlock and
// WriteAllBoardsBroadcast.
bool WriteBlockNode(nodeid_t node, nodeaddr_t addr, quadlet_t *wdata, unsigned int nbytes, unsigned char flags = 0);

// Send packet
virtual bool PacketSend(unsigned char *packet, size_t nbytes, bool useEthernetBroadcast) = 0;
virtual bool PacketSend(nodeid_t node, unsigned char *packet, size_t nbytes, bool useEthernetBroadcast) = 0;

// Receive packet
virtual int PacketReceive(unsigned char *packet, size_t nbytes) = 0;
Expand All @@ -119,7 +130,11 @@ class EthBasePort : public BasePort
// to be different than the one on the PC.
virtual void OnFwBusReset(unsigned int FwBusGeneration_FPGA);

virtual void make_write_header(unsigned char *packet, unsigned int nBytes, unsigned char flags);
// Make Ethernet header (only needed for raw Ethernet)
virtual void make_ethernet_header(unsigned char *packet, unsigned int numBytes, nodeid_t node, unsigned char flags);

// Make control word
void make_write_header(unsigned char *packet, unsigned int nBytes, unsigned char flags);

void make_1394_header(quadlet_t *packet, nodeid_t node, nodeaddr_t addr, unsigned int tcode, unsigned int tl);

Expand All @@ -130,7 +145,7 @@ class EthBasePort : public BasePort

public:

EthBasePort(int portNum, std::ostream &debugStream = std::cerr, EthCallbackType cb = 0);
EthBasePort(int portNum, bool forceFwBridge, std::ostream &debugStream = std::cerr, EthCallbackType cb = 0);

~EthBasePort();

Expand Down Expand Up @@ -163,6 +178,9 @@ class EthBasePort : public BasePort

void UpdateBusGeneration(unsigned int gen) { FwBusGeneration = gen; }

// virtual method in BasePort
bool CheckFwBusGeneration(const std::string &caller, bool doScan = false);

/*!
\brief Write the broadcast packet containing the DAC values and power control
*/
Expand All @@ -178,6 +196,20 @@ class EthBasePort : public BasePort
*/
void WaitBroadcastRead(void);

bool isBroadcastReadOrdered(void) const;

// Return clock period used for broadcast read timing measurements
// 125 MHz for FPGA V3 Ethernet-only; otherwise 49.152 MHz
double GetBroadcastReadClockPeriod(void) const;

/*!
\brief Receive the broadcast read response. This is usually a block read from
address 0x1000 (Hub memory); in the case of Ethernet-only, it receives
a response from an FPGA board some time after WriteBroadcastReadRequest
is issued.
*/
bool ReceiveBroadcastReadResponse(quadlet_t *rdata, unsigned int nbytes);

/*!
\brief Add delay (if needed) for PROM I/O operations
The delay is non-zero for Ethernet.
Expand Down Expand Up @@ -209,16 +241,23 @@ class EthBasePort : public BasePort
// Check Ethernet header (only for EthRawPort)
virtual bool CheckEthernetHeader(const unsigned char *packet, bool useEthernetBroadcast);

// Byteswap Firewire header of received packet (quadlet or block read response) to make it easier to work with,
// and to be consistent with CheckFirewirePacket and PrintFirewirePacket.
void ByteswapFirewireHeader(unsigned char *packet, unsigned int nbytes);
// Byteswap quadlets received packet (quadlet or block read response) to make it easier to work with,
// and to be consistent with CheckFirewirePacket and PrintFirewirePacket. This is typically used to
// byteswap the Firewire header quadlets.
void ByteswapQuadlets(unsigned char *packet, unsigned int nbytes);

// Get information from Firewire packet header
// Can specify 0 (null pointer) for fields to ignore
static void GetFirewireHeaderInfo(const unsigned char *packet, nodeid_t *src_node, unsigned int *tcode,
unsigned int *tl);

// Check if FireWire packet valid
// length: length of data section (for BRESPONSE)
// node: expected source node
// tcode: expected tcode (e.g., QRESPONSE or BRESPONSE)
// tl: transaction label
bool CheckFirewirePacket(const unsigned char *packet, size_t length, nodeid_t node, unsigned int tcode, unsigned int tl);
bool CheckFirewirePacket(const unsigned char *packet, size_t length, nodeid_t node, unsigned int tcode,
unsigned int tl);

// Process extra data received from FPGA
void ProcessExtraData(const unsigned char *packet);
Expand Down
12 changes: 6 additions & 6 deletions lib/EthRawPort.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
/*
Author(s): Zihan Chen, Peter Kazanzides
(C) Copyright 2014-2020 Johns Hopkins University (JHU), All Rights Reserved.
(C) Copyright 2014-2024 Johns Hopkins University (JHU), All Rights Reserved.
--- begin cisst license - do not edit ---
Expand Down Expand Up @@ -40,9 +40,8 @@ class EthRawPort : public EthBasePort

bool headercheck(const unsigned char *header, bool toPC) const;

void make_write_header(unsigned char *packet, unsigned int nBytes, unsigned char flags);

void make_ethernet_header(unsigned char *packet, unsigned int numBytes, unsigned char flags);
// Make Ethernet header
void make_ethernet_header(unsigned char *packet, unsigned int numBytes, nodeid_t node, unsigned char flags);

// Check Ethernet header
bool CheckEthernetHeader(const unsigned char *packet, bool useEthernetBroadcast);
Expand All @@ -58,7 +57,7 @@ class EthRawPort : public EthBasePort
nodeid_t InitNodes(void);

// Send packet via PCAP
bool PacketSend(unsigned char *packet, size_t nbytes, bool useEthernetBroadcast);
bool PacketSend(nodeid_t node, unsigned char *packet, size_t nbytes, bool useEthernetBroadcast);

// Receive packet via PCAP
int PacketReceive(unsigned char *packet, size_t nbytes);
Expand All @@ -67,7 +66,8 @@ class EthRawPort : public EthBasePort
int PacketFlushAll(void);

public:
EthRawPort(int portNum, std::ostream &debugStream = std::cerr, EthCallbackType cb = 0);
EthRawPort(int portNum, bool forceFwBridge = false,
std::ostream &debugStream = std::cerr, EthCallbackType cb = 0);

~EthRawPort();

Expand Down
10 changes: 7 additions & 3 deletions lib/EthUdpPort.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
/*
Author(s): Zihan Chen, Peter Kazanzides
(C) Copyright 2014-2021 Johns Hopkins University (JHU), All Rights Reserved.
(C) Copyright 2014-2024 Johns Hopkins University (JHU), All Rights Reserved.
--- begin cisst license - do not edit ---
Expand Down Expand Up @@ -34,7 +34,7 @@ class EthUdpPort : public EthBasePort
protected:
SocketInternals *sockPtr; // OS-specific internals
std::string ServerIP; // IP address of server (string)
unsigned long IP_addr; // IP address of server (32-bit number)
std::string MulticastIP; // IP address for multicast (string)
unsigned short UDP_port; // Port on server (FPGA)

//! Initialize EthUdp port
Expand All @@ -48,7 +48,7 @@ class EthUdpPort : public EthBasePort
nodeid_t InitNodes(void);

// Send packet via UDP
bool PacketSend(unsigned char *packet, size_t nbytes, bool useEthernetBroadcast);
bool PacketSend(nodeid_t node, unsigned char *packet, size_t nbytes, bool useEthernetBroadcast);

// Receive packet via UDP
int PacketReceive(unsigned char *packet, size_t nbytes);
Expand All @@ -59,10 +59,14 @@ class EthUdpPort : public EthBasePort
public:

EthUdpPort(int portNum, const std::string &serverIP = ETH_UDP_DEFAULT_IP,
bool forceFwBridge = false,
std::ostream &debugStream = std::cerr, EthCallbackType cb = 0);

~EthUdpPort();

std::string GetMultiCastIP() const { return MulticastIP; }
bool SetMulticastIP(const std::string &multicast);

//****************** BasePort virtual methods ***********************

PortType GetPortType(void) const { return PORT_ETH_UDP; }
Expand Down
Loading

0 comments on commit cb9b0c6

Please sign in to comment.