package libcsp.csp; import javax.safetycritical.annotate.Level; import javax.safetycritical.annotate.SCJAllowed; import libcsp.csp.core.ConnectionCore; import libcsp.csp.core.Port; import libcsp.csp.core.SocketCore; import libcsp.csp.interfaces.IMACProtocol; import libcsp.csp.interfaces.InterfaceI2C_A; import libcsp.csp.interfaces.InterfaceI2C_B; import libcsp.csp.interfaces.InterfaceLoopback; import libcsp.csp.util.Const; /** * This class creates the shared data structures and the router handler. It also * provides service functions. * * @author Mikkel Todberg, Jeppe Lund Andersen * */ public class CSPManager { /* MAC-layer Protocols */ public static final byte INTERFACE_I2C_A = 1; public static final byte INTERFACE_I2C_B = 2; public static final byte INTERFACE_LOOPBACK = 3; /* Local node address */ public static byte nodeAddress; /** * Specifies a route in the routing table for outgoing packets. init() must * be invoked before setting routes. * * @param nodeAddress * Destination address (must be in the range 0-30) * @param protocol * Outgoing interface protocol used for the next hop * @param nextHopMacAddress * Next hop mac address for the interface protocol */ @SCJAllowed(Level.LEVEL_1) public void routeSet(int nodeAddress, IMACProtocol protocol, int nextHopMacAddress) { ImmortalEntry.routeTable[nodeAddress].nextHopMacAddress = (byte) nextHopMacAddress; ImmortalEntry.routeTable[nodeAddress].protocolInterface = protocol; } /** * Retrieves the object implementing a specific MAC-layer protocol. * * @param Identifier * Protocol identifier * @return A singleton object implementing the protocol */ @SCJAllowed(Level.LEVEL_1) public IMACProtocol getIMACProtocol(int type) { switch (type) { case INTERFACE_I2C_A: return InterfaceI2C_A.getInterface(); case INTERFACE_I2C_B: return InterfaceI2C_B.getInterface(); case INTERFACE_LOOPBACK: return InterfaceLoopback.getInterface(); } return null; } /** * Creates and binds a socket to a specific port. * * @param port * Port number to use * @param options * Socket options * @return Socket object bound to the port or null if none available */ @SCJAllowed(Level.LEVEL_1) public synchronized Socket createSocket(int port, Object options) { Port p = ImmortalEntry.portTable[port]; if (!p.isOpen) { Socket socket = ImmortalEntry.resourcePool .getSocket(ImmortalEntry.TIMEOUT_SINGLE_ATTEMPT); if (socket != null) { p.isOpen = true; p.socket = (SocketCore) socket; p.socket.port = (byte) port; return socket; } } return null; } /** * Creates a connection to another network node. This only prepares the * connection - i.e no data is actually sent to the node. A successive call * to this method e.g. from the next release in a periodic handler may not * get the same <code>Connection</code> object from the pool as in the * previous release. * * This method also iterates over the currently free ports in order to set * the source port for the future communication. * * When a <code>Connection</code> object is successfully returned, its * identifier is set according to the passed parameters and on the free port * that was previously found by iterating over the currently free ports. * * @param address * Destination address (must in range 0-32) * @param port * Destination port (must be in range 0-47) * @param timeout * Maximum time in milliseconds to wait for an unused connection * from the connection pool * @param options * Connection options * @return Newly created connection */ @SCJAllowed(Level.LEVEL_1) public Connection createConnection(int address, int port, int timeout, Object options) { ConnectionCore connection = ImmortalEntry.resourcePool.getConnection(timeout); if (connection != null) { byte nodePort = findUnusedOutgoingPort(); if (nodePort != -1) { nodePort += (Const.MAX_INCOMING_PORTS + 1); connection.setId(nodeAddress, nodePort, (byte) address, (byte) port); connection.isOpen = true; return connection; } } return null; } private synchronized byte findUnusedOutgoingPort() { short mask; for (short index = 0; index < 15; index++) { mask = (short) (1 << index); if ((ImmortalEntry.outgoingPorts & mask) == 0) { ImmortalEntry.outgoingPorts |= mask; return (byte) index; } } return -1; } /** * Provides a new empty packet that can be transmitted over an open * connection. * * @return Empty packet */ @SCJAllowed(Level.LEVEL_1) public Packet createPacket() { return ImmortalEntry.resourcePool .getPacket(ImmortalEntry.TIMEOUT_SINGLE_ATTEMPT); } }