Created
October 8, 2018 14:15
-
-
Save chrome050/6f54c1cc219ea00e0bbbb965e7a61658 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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