package libcsp.csp.interfaces; import libcsp.csp.ImmortalEntry; import libcsp.csp.core.Node; import libcsp.csp.core.PacketCore; import com.jopdesign.io.I2Cport; public abstract class InterfaceI2C implements IMACProtocol { private static final byte INT_SIZE_IN_BYTES = 4; private static final byte BYTE_SHIFT_COUNTER = INT_SIZE_IN_BYTES - 1; private static final byte FRAME_SIZE_IN_BYTES = (INT_SIZE_IN_BYTES * 2); protected int frameByteIndex; protected I2Cport i2cPort; /* * The hardware object for I2C and the corresponding microcontroller * works by writing or reading single bytes at a time to the tx/rx register. * Transmitting a packet therefore needs to divide the whole 32bit header * and 32bit data into single bytes that are written to the tx register. * The result is the transmit buffer containing the first 7 bits with * the I2C address, the next 32 bits is the packet header * and the final 32 bits the data */ @Override public void transmitPacket(PacketCore packet) { int[] frame = new int[FRAME_SIZE_IN_BYTES]; Node packetDSTNode = ImmortalEntry.routeTable[packet.getDST()]; // This is not needed when using I2C. I2C's write method will insert the // destination address // insertNextHopAddressIntoFrame(frame, packetDSTNode.nextHopMacAddress); sliceDataIntoBytesAndInsertIntoFrame(frame, packet.header); sliceDataIntoBytesAndInsertIntoFrame(frame, packet.data); i2cPort.write(packetDSTNode.nextHopMacAddress, frame); /* Set the I2C interface to slave mode to be able to receive messages */ i2cPort.slaveMode(); frameByteIndex = 0; ImmortalEntry.resourcePool.putPacket(packet); } /* * The incoming I2C frame contains the whole packet, here we extract this * from the data register and assemble the packet to be delivered * * Context: ISR - invoked by the aperiodic event handler created during * initialization for the I2C interface */ @Override public void receiveFrame() { int header = mergeNextDataBytesReceivedAndInsertIntoInteger(); int data = mergeNextDataBytesReceivedAndInsertIntoInteger(); PacketCore packet = ImmortalEntry.resourcePool.getPacket(ImmortalEntry.TIMEOUT_SINGLE_ATTEMPT); packet.header = header; packet.data = data; ImmortalEntry.packetsToBeProcessed.enqueue(packet); } public int mergeNextDataBytesReceivedAndInsertIntoInteger() { int result = 0; for (byte b=0; b < 4; b++){ result |= i2cPort.rx_fifo_data << position(b); } return result; } public void insertNextHopAddressIntoFrame(int[] frame, byte nextHopAddress) { frame[frameByteIndex] = nextHopAddress << 1; frameByteIndex++; } public void sliceDataIntoBytesAndInsertIntoFrame(int[] frame, int data) { int dataMask; for(byte b = 0 ; b < INT_SIZE_IN_BYTES; b++) { dataMask = 0xFF000000 >>> b*8; frame[frameByteIndex] = (data & dataMask) >>> position(b); frameByteIndex++; } } public int position(int index) { return (BYTE_SHIFT_COUNTER - index)*8; } }