OpenCores
URL https://opencores.org/ocsvn/etherlab/etherlab/trunk

Subversion Repositories etherlab

[/] [etherlab/] [trunk/] [net/] [EtherSocket/] [src/] [EtherSocket.cs] - Rev 2

Compare with Previous | Blame | View Log

/******************************************************************************
 * ETHERLAB - FPGA To C# To LABVIEW Bridge                                    *
 ******************************************************************************
 *                                                                            *
 * Copyright (C)2012  Mathias Hörtnagl <mathias.hoertnagl@gmail.com>          *
 *                                                                            *
 * 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 3 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, see <http://www.gnu.org/licenses/>.      *
 ******************************************************************************/
using System;
using System.Collections.Generic;
using System.Threading;

using PcapDotNet.Core;
using PcapDotNet.Packets;
using PcapDotNet.Packets.Ethernet;

namespace EtherLab
{
    /// <summary>
    /// A socket for EtherLab communication.
    /// 
    /// <para>
    /// Sending
    /// 
    /// To send data, first update any channel's data with <see cref="update()"/>.
    /// Subsequently call <see cref="send()"/> to send the updated EtherLab
    /// packet. If <see cref="update()"/> isn't invoked at least once, 
    /// <see cref="send()"/> will NOT send the packet, as there is no updated
    /// data available.
    /// <example>
    /// <code>
    ///     /** 
    ///      * Create a new instance of EtherSocket with default 
    ///      * destination MAC. The first parameter identifies the
    ///      * network device to select.
    ///      */
    ///     EtherSocket es = new EtherSocket(0, "00:1f:16:01:95:a5");
    ///     
    ///     // Update data for channel H and B.
    ///     es.update(EChannel.CHANNEL_H, 0x1234);
    ///     es.update(EChannel.CHANNEL_B, 0x4321);
    ///     
    ///     // Send the updated packet.
    ///     es.send();
    /// </code>
    /// </example>
    /// </para>
    /// 
    /// <para>
    /// Receiving
    /// 
    /// EtherSocket starts a new Thread automatically for the reception process.
    /// Data is read constatntly from the networ device. 
    /// To read a channel's current data chunk, invoke <see cref="read()"/>.
    /// 
    /// NOTE: There is no locking mechanism, to circumvent reading data while
    ///       new data is read from the network device.
    /// <example>
    /// <code>
    ///     /** 
    ///      * Create a new instance of EtherSocket with default 
    ///      * destination MAC. The first parameter identifies the
    ///      * network device to select.
    ///      */
    ///     EtherSocket es = new EtherSocket(0, "00:1f:16:01:95:a5");
    ///     
    ///     ushort data;
    ///     
    ///     // Read data of channel H;
    ///     data = es.read(EChannel.CHANNEL_H);
    /// </code>
    /// </example>
    /// </para>
    /// </summary>
    public sealed class EtherSocket
    {
        /// <summary>
        /// Packet receiver filter. Capture packages with EtherType = 0x0000
        /// and with a Version 2 field only.
        /// </summary>
        private const String RCV_FILTER 
            = "(ether[12:2] = 0x0000) and (ether[14] = 0x02)";

        private LivePacketDevice device;
        private PacketCommunicator com;
        private PacketBuilder builder;
        private EtherLabLayer sendLayer;
        private EtherLabLayer receiveLayer;
        private Thread receiverThread;

        /// <summary>
        /// Creates a new EtherSocket with "00:0a:35:00:00:00" as a default
        /// destination MAC.
        /// </summary>
        /// <param name="deviceId">The integer ID of the network device.</param>
        /// <param name="srcMAC">The source MAC address.</param>
        public EtherSocket(int deviceId, String srcMAC)
            : this(deviceId, srcMAC, "00:0a:35:00:00:00")
        {
        }

        /// <summary>
        /// Creates a new EtherSocket.
        /// </summary>
        /// <param name="deviceId">The integer ID of the network device.</param>
        /// <param name="srcMAC">The source MAC address.</param>
        /// <param name="dstMAC">The destination MAC address.</param>
        public EtherSocket(int deviceId, String srcMAC, String dstMAC)
        {
            IList<LivePacketDevice> allDevices = LivePacketDevice.AllLocalMachine;

            if ( (allDevices.Count == 0) || (allDevices.Count < deviceId) )
            {
                return;
            }

            device = allDevices[deviceId];
            com = device.Open(56, PacketDeviceOpenAttributes.Promiscuous, 1000);
            
            // Filter packages.
            using (BerkeleyPacketFilter filter = com.CreateFilter(RCV_FILTER)) 
            {
                com.SetFilter(filter);
            }

            EthernetLayer ethernetLayer = new EthernetLayer 
            {
                Source = new MacAddress(srcMAC),
                Destination = new MacAddress(dstMAC)
            };

            sendLayer = new EtherLabLayer();

            builder = new PacketBuilder(ethernetLayer, sendLayer);

            // Start receiver thread.
            receiverThread = new Thread(this.receive);
            receiverThread.Start();
        }

        /// <summary>
        /// Update channel data and set channel flag. Call send() to send
        /// the updated data in a new packet.
        /// </summary>
        /// <param name="channel">The channel to be updated.</param>
        /// <param name="channelData">The new data for that channel.</param>
        public void update(EChannel channel, ushort channelData)
        {
            sendLayer.update(channel, channelData);
        }

        /// <summary>
        /// Sends the current EtherLab packet and resets the channel
        /// flags to 0. A packet is sent only if at least one channel 
        /// flag is set.
        /// </summary>
        public void send()
        {
            if (sendLayer.pendingSendData())
            {
                com.SendPacket(builder.Build(DateTime.Now));
                sendLayer.reset();
            }
        }

        /// <summary>
        /// Receive a single packet. Packet data can be read with <see cref="read()"/>.
        /// </summary>
        private void receive()
        {
            com.ReceivePackets(0, PacketHandler);
        }

        /// <summary>
        /// Packet reception callback.
        /// </summary>
        /// <param name="packet">The received packet.</param>
        private void PacketHandler(Packet packet) 
        {
            EtherLabDatagram etherLabPacket 
                = new EtherLabDatagram(packet.Buffer, EthernetDatagram.HeaderLength, 18);

            receiveLayer = (EtherLabLayer) etherLabPacket.ExtractLayer();
        }

        /// <summary>
        /// Read data for a channel from current received packet. If no packet
        /// is available yet, this function returns 0.
        /// </summary>
        /// <param name="channel">The channel to be read from.</param>
        /// <returns>The current channel data.</returns>
        public ushort read(EChannel channel)
        {
            return (receiveLayer != null) ? receiveLayer.read(channel) : ushort.MinValue;
        }
    }
}

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.