Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using CanTransceiverInterfaces;
namespace CanTransceiver
{
public class CanTransceiver : ICanTransceiver, IDisposable
{
private IntPtr m_hCan = IntPtr.Zero;
private readonly object m_syncRoot = new object();
private readonly AutoResetEvent m_incomingMessageAvailableEvent = new AutoResetEvent(false);
private readonly AutoResetEvent m_outgoingMessageAvailableEvent = new AutoResetEvent(false);
private readonly Queue<can.tCanMsg> m_incomingMessageQueue = new Queue<can.tCanMsg>();
private readonly Queue<can.tCanMsg> m_outgoingMessageQueue = new Queue<can.tCanMsg>();
private bool m_isRunning = false;
private Thread m_receivedMessageDispatcherThread;
private bool m_isReceivedMessageDispatcherRunning;
private Thread m_messagePollingThread;
private bool m_isMessagePollingRunning;
private Thread m_messageSendingThread;
private bool m_isMessageSendingRunning;
private IntPtr receivingMessageIntPtr;
private can.tCanMsg message;
public event Action<ICanMessage> MessageReceived;
public CanTransceiver()
{
Init();
}
~CanTransceiver()
{
if (IntPtr.Zero != m_hCan)
{
can_teg.TegCan_Deinit(m_hCan);
}
}
private void Init()
{
message.data = new char[8];
message.dataLen = 8;
var messageSize = Marshal.SizeOf(message);
receivingMessageIntPtr = Marshal.AllocHGlobal(messageSize);
m_hCan = can_teg.TegCan_Init("SPI1");
can_teg.TegCan_SetConfigString(m_hCan, "FilterFrameFormat", "extended", TdxCommon.ParamStorageType.StoreVolatile);
can_teg.TegCan_SetConfigString(m_hCan, "FilterRemote", "Data", TdxCommon.ParamStorageType.StoreVolatile);
can_teg.TegCan_SetConfigInt(m_hCan, "FilterID", 0x00, TdxCommon.ParamStorageType.StoreVolatile);
can_teg.TegCan_SetConfigInt(m_hCan, "FilterMask", 0x00, TdxCommon.ParamStorageType.StoreVolatile);
can_teg.TegCan_SetConfigInt(m_hCan, "BitRateHz", 500000, TdxCommon.ParamStorageType.StoreVolatile);
can_teg.TegCan_SetConfigInt(m_hCan, "ioInterrupt", 127, TdxCommon.ParamStorageType.StoreVolatile);
can_teg.TegCan_SetConfigInt(m_hCan, "Timeout", 1000, TdxCommon.ParamStorageType.StoreVolatile);
}
private void ResetBus()
{
can_teg.TegCan_Close(m_hCan);
can_teg.TegCan_Deinit(m_hCan);
//we have to reinit the controller to trigger the can reset function.
Init();
}
public bool Running
{
get { return this.m_isRunning; }
}
public bool Connect()
{
return Connect(false);
}
private bool Connect(bool isRetry)
{
var result = false;
lock (this.m_syncRoot)
{
if (!m_isRunning)
{
m_isRunning = true;
result = can_teg.TegCan_Open(m_hCan);
if (result)
{
uint status = 0;
can_teg.TegCan_GetConfigInt(m_hCan, "BusStatus", ref status);
if (status == 0)
{
StartReceivedMessageDispatcherThread();
StartMessagePollingThread();
StartMessageSendingThread();
}
else
{
if (isRetry)
{
return false;
}
ResetBus();
Connect(true);
}
}
}
}
return result;
}
public void CleanUp()
{
lock (this.m_syncRoot)
{
if (this.m_isRunning)
{
this.m_isRunning = false;
StopMessageSendingThread();
StopMessagePollingThread();
StopReceivedMessageDispatcherThread();
can_teg.TegCan_Close(m_hCan);
}
}
}
public void TransmitData(ICanMessage canMessage)
{
var message = new can.tCanMsg
{
id = canMessage.Identifier,
dataLen = 4, //should be 2, but the lib need 4 because of UTF-16 / UTF-8 problems.
data = new char[8],
canMsgFlags = can.CanMsgFlags.CanMsgFlags_IDE
};
//test message. should 01 01 on CAN bus
message.data[0] = '1';
message.data[1] = '1';
lock (m_syncRoot)
{
m_outgoingMessageQueue.Enqueue(message);
m_outgoingMessageAvailableEvent.Set();
}
}
public void SetCanAcceptanceFrameType(AcceptanceFrameType frameType)
{
throw new NotSupportedException();
}
private void StartReceivedMessageDispatcherThread()
{
m_isReceivedMessageDispatcherRunning = true;
m_receivedMessageDispatcherThread = new Thread(this.ReceivedMessageDispatcherLoop)
{
IsBackground = true,
Name = "CanTransceiver.MessageDispatcher",
Priority = ThreadPriority.Normal
};
m_receivedMessageDispatcherThread.Start();
}
private void StopReceivedMessageDispatcherThread()
{
if (m_isReceivedMessageDispatcherRunning)
{
m_isReceivedMessageDispatcherRunning = false;
this.m_incomingMessageAvailableEvent.Set();
m_receivedMessageDispatcherThread = null;
}
}
private void ReceivedMessageDispatcherLoop()
{
while (this.m_isReceivedMessageDispatcherRunning)
{
this.m_incomingMessageAvailableEvent.WaitOne();
if (this.m_isReceivedMessageDispatcherRunning)
{
while (this.m_incomingMessageQueue.Count > 0)
{
can.tCanMsg message;
lock (m_syncRoot)
{
message = this.m_incomingMessageQueue.Dequeue();
}
var handler = MessageReceived;
if (handler != null)
{
ICanMessage canMessage = new MessageWrapper(message);
handler(canMessage);
}
}
}
}
}
private void StartMessagePollingThread()
{
m_isMessagePollingRunning = true;
m_messagePollingThread = new Thread(this.MessagePollingLoop)
{
IsBackground = true,
Name = "CanTransceiver.MessagePolling",
Priority = ThreadPriority.Normal
};
m_messagePollingThread.Start();
}
private void StopMessagePollingThread()
{
if (this.m_isMessagePollingRunning)
{
this.m_isMessagePollingRunning = false;
//m_messagePollingThread.Join();
m_messagePollingThread = null;
}
}
private void MessagePollingLoop()
{
while (this.m_isMessagePollingRunning)
{
var receivedMessage = this.WaitForIncomingMessage();
if (m_isMessagePollingRunning && receivedMessage.HasValue)
{
this.m_incomingMessageQueue.Enqueue(receivedMessage.Value);
this.m_incomingMessageAvailableEvent.Set();
}
}
}
private can.tCanMsg? WaitForIncomingMessage()
{
var result = new can.tCanMsg?();
Marshal.StructureToPtr(message, receivingMessageIntPtr, true);
var canResult = can_teg.TegCan_Read(m_hCan, receivingMessageIntPtr, 1);
if (canResult > 0)
{
result = (can.tCanMsg)Marshal.PtrToStructure(receivingMessageIntPtr, typeof(can.tCanMsg));
}
return result;
}
private void StartMessageSendingThread()
{
m_isMessageSendingRunning = true;
m_messageSendingThread = new Thread(this.SendMessageLoop)
{
IsBackground = true,
Name = "CanTransceiver.SendMessage",
Priority = ThreadPriority.Normal
};
m_messageSendingThread.Start();
}
private void StopMessageSendingThread()
{
if (this.m_isMessageSendingRunning)
{
this.m_isMessageSendingRunning = false;
m_outgoingMessageAvailableEvent.Set();
//m_messageSendingThread.Join();
m_messageSendingThread = null;
}
}
private void SendMessageLoop()
{
while (m_isMessageSendingRunning)
{
m_outgoingMessageAvailableEvent.WaitOne();
if (m_isMessageSendingRunning)
{
while (this.m_outgoingMessageQueue.Count > 0)
{
can.tCanMsg message;
lock (m_syncRoot)
{
message = this.m_outgoingMessageQueue.Dequeue();
}
this.SendOutgoingMessage(message);
}
}
}
}
private bool SendOutgoingMessage(can.tCanMsg message)
{
var result = false;
var messageIntPtr = IntPtr.Zero;
try
{
var messageSize = Marshal.SizeOf(message);
messageIntPtr = Marshal.AllocHGlobal(messageSize);
Marshal.StructureToPtr(message, messageIntPtr, true);
result = can_teg.TegCan_Write(m_hCan, messageIntPtr, 1) == 1;
}
finally
{
if (IntPtr.Zero != messageIntPtr)
{
Marshal.FreeHGlobal(messageIntPtr);
}
}
return result;
}
#region IDisposable Members
public void Dispose()
{
if (IntPtr.Zero != receivingMessageIntPtr)
{
Marshal.FreeHGlobal(receivingMessageIntPtr);
}
}
#endregion
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment