Subversion Repositories group.electronics

Rev

Rev 172 | Blame | Compare with Previous | Last modification | View Log | RSS feed

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace nitdcscore {
    public class DcsBios {
        private UdpClient _udpReceiveClient = null;
        private UdpClient _udpSendClient = null;
        private Thread _listeningThread;

        private String _receiveFromIP = "239.255.50.10";
        private String _sendToIP = "127.0.0.1";
        private int _receivePort = 5010;
        private int _sendPort = 7778;
        private IPEndPoint _ipEndPointReceiver = null;
        private IPEndPoint _ipEndPointSender = null;

        private readonly DCSProtocolParser _parser;

        public DcsBios() {
            _parser = new DCSProtocolParser();
        }


        public void InitUDP() {
            try {
                _ipEndPointReceiver = new IPEndPoint(IPAddress.Any, _receivePort);
                _ipEndPointSender = new IPEndPoint(IPAddress.Parse(_sendToIP), _sendPort);

                _udpReceiveClient = new UdpClient();
                _udpReceiveClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
                _udpReceiveClient.Client.Bind(_ipEndPointReceiver);
                _udpReceiveClient.JoinMulticastGroup(IPAddress.Parse(_receiveFromIP));

                _udpSendClient = new UdpClient();
                _udpSendClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
                _udpSendClient.EnableBroadcast = true;

                if (_listeningThread != null) {
                    _listeningThread.Abort();
                }

                _listeningThread = new Thread(ReceiveData);
                _listeningThread.Start();
            } catch (Exception e) {
                if (_udpReceiveClient != null && _udpReceiveClient.Client.Connected) {
                    _udpReceiveClient.Close();
                    _udpReceiveClient = null;
                }
                if (_udpSendClient != null && _udpSendClient.Client.Connected) {
                    _udpSendClient.Close();
                    _udpSendClient = null;
                }
                Console.WriteLine(e.Message);
            }


        }

        public void ReceiveData() {
            try {
                while (true) {
                    var byteData = _udpReceiveClient.Receive(ref _ipEndPointReceiver);
                    for (int i=0; i<byteData.Length; i++) {
                        _parser.ProcessByte(byteData[i]);
                    }
                }
            } catch (Exception e) {
                Console.WriteLine(e.Message);
            }
        }

        public int SendData(string data) {
            var rslt = 0;
            try {
                var unicodeBytes = Encoding.Unicode.GetBytes(data);
                var asciiBytes = new List<byte>(data.Length);
                asciiBytes.AddRange(Encoding.Convert(Encoding.Unicode, Encoding.ASCII, unicodeBytes));
                rslt = _udpSendClient.Send(asciiBytes.ToArray(), asciiBytes.ToArray().Length, _ipEndPointSender);
            } catch (Exception e) {
                Console.WriteLine(e.Message);
            }

            return rslt;
        }

        public void Shutdown() {
            try {
                if (_listeningThread != null) {
                    _listeningThread.Abort();
                    _listeningThread = null;
                }
                _udpReceiveClient.Close();
                _udpSendClient.Close();
            } catch (Exception e) {
                Console.WriteLine(e.Message);
            }
        }

    }

    public enum DCSBiosStateEnum {
        WAIT_FOR_SYNC = 0,
        ADDRESS_LOW = 1,
        ADDRESS_HIGH = 2,
        COUNT_LOW = 3,
        COUNT_HIGH = 4,
        DATA_LOW = 5,
        DATA_HIGH = 6,
    }

    

    internal class DCSProtocolParser {
        private DCSBiosStateEnum _state;
        private uint _address;
        private uint _count;
        private uint _data;
        private byte _syncByteCount;

        internal DCSProtocolParser() {
            _state = DCSBiosStateEnum.WAIT_FOR_SYNC;
            _syncByteCount = 0;
        }

        internal void ProcessByte(byte b) {
            switch (_state) {
                case DCSBiosStateEnum.WAIT_FOR_SYNC:
                    break;
                case DCSBiosStateEnum.ADDRESS_LOW:
                    _address = b;
                    _state = DCSBiosStateEnum.ADDRESS_HIGH;
                    break;
                case DCSBiosStateEnum.ADDRESS_HIGH:
                    _address = (uint) (b << 8) | _address;
                    _state = _address != 0x5555 ? DCSBiosStateEnum.COUNT_LOW : DCSBiosStateEnum.WAIT_FOR_SYNC;
                    break;
                case DCSBiosStateEnum.COUNT_LOW:
                    _count = b;
                    _state = DCSBiosStateEnum.COUNT_HIGH;
                    break;
                case DCSBiosStateEnum.COUNT_HIGH:
                    _count = (uint)(b << 8) | _count;
                    _state = DCSBiosStateEnum.DATA_LOW;
                    break;
                case DCSBiosStateEnum.DATA_LOW:
                    _data = b;
                    _count--;
                    _state = DCSBiosStateEnum.DATA_HIGH;
                    break;
                case DCSBiosStateEnum.DATA_HIGH:
                    _data = (uint)(b << 8) | _data;
                    _count--;

                    UInt16 data;
                    if (Globals.BiosOutput.TryGetValue((UInt16)_address, out data)) {
                        Globals.BiosOutput[(UInt16)_address] = (UInt16)_data;
                    }
                        
                    _address += 2;
                    if (_count == 0)
                        _state = DCSBiosStateEnum.ADDRESS_LOW;
                    else
                        _state = DCSBiosStateEnum.DATA_LOW;
                    break;
            }
            if (b == 0x55)
                _syncByteCount++;
            else
                _syncByteCount = 0;
            if (_syncByteCount == 4) {
                _state = DCSBiosStateEnum.ADDRESS_LOW;
                _syncByteCount = 0;
            }
        }
    }

    
}