//-----------------------------------------------------------------------
//
// Copyright © 2012 Nils Hammar. All rights reserved.
//
//-----------------------------------------------------------------------
/*
* Software to access vehicle information via the OBD-II connector.
*
* Copyright © 2012 Nils Hammar
*
* 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 .
*
* Alternative licensing is possible, see the licensing document.
*
* The above text may not be removed or modified.
*/
namespace SharedObjects.UdpServer
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using SharedObjects.Protocol;
///
/// CAN bus simulation using UDP socket communication.
///
/// This is intended to be useful when no CAN hardware is present.
///
///
public class UdpCanSimulation : IObdCommunicator
{
///
/// Gets or sets time in milliseconds between sent frames.
///
public long frameSpacing { get; set; }
///
/// IP endpoint address.
///
private IPEndPoint ipep;
///
/// UDP Socket.
///
private UdpClient newsock;
///
/// Thread for receiving of data.
///
private Thread rxDataThread;
///
/// Flag for thread.
///
private bool doRun = false;
///
/// Port number to communicate on.
///
private int port;
///
/// List of data receivers.
///
private IList iDataReceiverList = new List();
///
/// Initializes a new instance of the class.
///
/// Port number to communicate on.
public UdpCanSimulation(int port)
{
this.port = port;
this.ipep = new IPEndPoint(IPAddress.Any, port);
this.newsock = new UdpClient();
this.newsock.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
this.newsock.Client.Bind(this.ipep);
}
///
/// Clean up.
///
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
///
/// Unregister as a data receiver instance
///
/// Data receiver instance.
public void removeDataReceiver(ISessionLayer iDataReceiver)
{
if (this.iDataReceiverList.Contains(iDataReceiver))
{
this.iDataReceiverList.Remove(iDataReceiver);
}
}
///
/// Register as a data receiver instance
///
/// Data receiver instance.
public void addDataReceiver(ISessionLayer iDataReceiver)
{
if (!this.iDataReceiverList.Contains(iDataReceiver))
{
this.iDataReceiverList.Add(iDataReceiver);
}
}
///
/// Send data.
///
/// Target address.
/// Data to send.
public void send(uint id, byte[] payload)
{
if (payload != null)
{
byte[] data = new byte[payload.Length + 4];
data[0] = (byte)((id >> 24) & 0xff);
data[1] = (byte)((id >> 16) & 0xff);
data[2] = (byte)((id >> 8) & 0xff);
data[3] = (byte)(id & 0xff);
Array.Copy(payload, 0, data, 4, payload.Length);
IPEndPoint sender = new IPEndPoint(IPAddress.Broadcast, this.port);
this.newsock.Send(data, data.Length, sender);
}
}
///
/// Start CAN communication.
///
public void startConnection()
{
this.doRun = true;
this.rxDataThread = new Thread(this.rxDataThreadImpl);
this.rxDataThread.Start();
}
///
/// Stop CAN communication.
///
public void stopConnection()
{
this.doRun = false;
this.newsock.Close();
this.rxDataThread.Abort();
}
///
/// Clean up.
///
/// 'true' if disposing.
protected virtual void Dispose(bool disposing)
{
this.doRun = false;
this.stopConnection();
}
///
/// Implementation of thread to receive data.
///
private void rxDataThreadImpl()
{
byte[] data = new byte[4096];
IPEndPoint sender = new IPEndPoint(IPAddress.Any, this.port);
while (this.doRun)
{
data = this.newsock.Receive(ref sender);
if (data.Length > 4)
{
uint addr = 0;
for (int i = 0; i < 4; i++)
{
addr = addr << 8;
addr |= data[i];
}
byte[] ba = new byte[data.Length - 4];
Array.Copy(data, 4, ba, 0, ba.Length);
foreach (ISessionLayer iDataReceiver in this.iDataReceiverList)
{
iDataReceiver.receiveData(addr, ba, 0x00, 0x00, 0x00);
}
}
}
}
}
}