Breadcrumbs


Subscribe RSS




Here you go a class for Serial Communication with Texas Instruments eZ430-TMS37157 RFID written on C#. I had some lot of troubles by creating this class mainly due to the lack of documentation from TI side. Nevertheless, I found a lot of sources online that I've combined and wrote some stuff by myself so I hope this code will help you too! :)

Note that the code might be a little bit inconsistent in terms of variable naming and also the communication protocol is only partially implemented, because I've needed only the message part.

 





//
// Serial Class with all stuff for communication with eZ430-TMS37157 written on C# // // by svilen.info :) // using System; using System.Collections.Generic; using System.Diagnostics; using System.IO.Ports; using System.Linq; using System.Management; using System.Runtime.Remoting.Metadata.W3cXsd2001; namespace tudos { /// <summary> /// The Type of the Serial Error /// </summary> enum SerialErrorType { OK, SEND_TIMEOUT, SEND_INVALID_OPERATION, READ_OVERLOAD, READ_TIMEOUT, NO_ANSWER } /// <summary> /// Whole Serial Message used to determine errors when class is deployed /// </summary> class SerialMessage { public string message = "OK :)"; public SerialErrorType type = SerialErrorType.OK; public object exceptionObject = null; } /// <summary> /// Serial class to deal with eZ430-TMS37157 /// </summary> class Serial { /// <summary> /// No Answer Standard /// </summary> const string NOANSWER = "010B00000000000000000000000B"; /// <summary> /// Serial Port instance /// </summary> private static SerialPort _serialPort; /// <summary> /// Last Serial Message /// </summary> public SerialMessage LastMessage { get; private set; } /// <summary> /// All received Buffers stored when debugging /// </summary> public List<byte[]> ReceivedBuffers { get; private set; } /// <summary> /// All sent buffers stored when debugging /// </summary> public List<byte[]> SentBuffers { get; private set; } /// <summary> /// Save the available comports to enable switching /// </summary> public List<COMPortInfo> AvailableComports { get; private set; } /// <summary> /// Standard Constructor to connect to eZ430-TMS37157 /// </summary> public Serial() { OpenSerial(RefreshAvailablePorts()); #if DEBUG { ReceivedBuffers = new List<byte[]>(); SentBuffers = new List<byte[]>(); } #endif LastMessage = new SerialMessage { message = "Serial Class Initialized" + DateTime.Now }; } ~Serial() { _serialPort.Close(); } /// <summary> /// Open serial port /// </summary> /// <param name="name">the unfriendly name</param> private void OpenSerial(string name) { // taking the standard settnigs of eZ430-TMS37157 _serialPort = new SerialPort { PortName = name, BaudRate = 9600, Parity = Parity.None, DataBits = 8, StopBits = StopBits.One, Handshake = Handshake.None, ReadTimeout = 500, WriteTimeout = 500 }; _serialPort.Open(); _serialPort.ErrorReceived += ErrorEvent; } /// <summary> /// Refreshes the serial ports /// </summary> /// <returns>gives back the probable unfriendly comport name of some eZ430-TMS37157</returns> private string RefreshAvailablePorts() { string portName = String.Empty; AvailableComports = COMPortInfo.GetCOMPortsInfo(); foreach (COMPortInfo comPort in AvailableComports) { Debug.WriteLine(string.Format("{0} – {1}", comPort.Name, comPort.Description)); // query the friendly name if (comPort.Description.Contains("USB Serial Port")) { portName = comPort.Name; } } return portName; } /// <summary> /// Catching the errors out of the Serial Class /// </summary> /// The Serial Class is pretty strange, as the functions don't return success parameter /// <param name="sender">Serial Class</param> /// <param name="e">System.IO.Ports.SerialError</param> private void ErrorEvent(object sender, EventArgs e) { SerialError errorOccured = ((SerialErrorReceivedEventArgs)e).EventType; switch (errorOccured) { case SerialError.TXFull: break; case SerialError.RXOver: break; case SerialError.Overrun: break; case SerialError.RXParity: break; case SerialError.Frame: break; default: throw new ArgumentOutOfRangeException(); } } /// <summary> /// Read One Buffer /// </summary> /// <param name="receivedBuffer"></param> /// <returns></returns> public SerialMessage ReadBuffer(out byte[] receivedBuffer) { try { if (!_serialPort.IsOpen) { _serialPort.Open(); } string buffer = _serialPort.ReadTo("\r\n "); buffer = _serialPort.ReadTo("\r\n"); if ("" != _serialPort.ReadExisting()) { receivedBuffer = null; return new SerialMessage { message = "Serial Receive Overload", type = SerialErrorType.READ_OVERLOAD }; } if (buffer == NOANSWER) { receivedBuffer = null; return new SerialMessage { message = "Serial Received No Answer", type = SerialErrorType.NO_ANSWER }; } byte[] framedBuffer = BufferConverter.GetStringToBytes(buffer); receivedBuffer = RemoveFrames(framedBuffer); #if DEBUG { ReceivedBuffers.Add(receivedBuffer); } #endif return new SerialMessage(); } catch (TimeoutException e) { receivedBuffer = null; return new SerialMessage { message = "Serial", exceptionObject = e, type = SerialErrorType.READ_TIMEOUT }; } } /// <summary> /// Writes buffer to the comport /// </summary> /// <param name="buffer">buffer to write</param> /// <returns>success status</returns> public SerialMessage WriteBuffer(byte[] buffer) { try { if (!_serialPort.IsOpen) { _serialPort.Open(); } byte[] fullBuffer = AddFrames(buffer); _serialPort.Write(BufferConverter.GetBytesToString(fullBuffer)); #if DEBUG { SentBuffers.Add(fullBuffer); } #endif //_serialPort.Close(); } catch(TimeoutException e) { LastMessage = new SerialMessage { message = "Command Send Time Out: " + e.Message, type = SerialErrorType.SEND_TIMEOUT, exceptionObject = e }; return LastMessage; } catch (InvalidOperationException e) { LastMessage = new SerialMessage { message = "Command Send Invalid Operation: " + e.Message, type = SerialErrorType.SEND_INVALID_OPERATION, exceptionObject = e }; return LastMessage; } LastMessage = new SerialMessage { message = "Command Sent", }; return LastMessage; } /// <summary> /// Add the headers to the raw buffer /// </summary> /// <param name="rawBuffer">buffer body</param> /// <returns>framed buffer</returns> byte[] AddFrames(byte[] rawBuffer) { const int HEADERS_LENGHT = 6; const int FOOTERS_LENGHT = 5; const int FRAMES_LENGTH = HEADERS_LENGHT + FOOTERS_LENGHT; byte[] buffer = new byte[rawBuffer.Length + FRAMES_LENGTH]; buffer[0] = 0x01; // fixed buffer[1] = (byte)(rawBuffer.Length + FRAMES_LENGTH - 3); // size of buffer buffer[2] = 0x06; // CMD1 buffer[3] = 0x32; // PB1 buffer[4] = 0x48; // #TX Bits buffer[5] = 0x7d; // MSP ACCESS Write Address Array.Copy(rawBuffer, 0, buffer, 6, rawBuffer.Length); // Actual Data byte[] CRCData = buffer.Skip(5).Take(7).ToArray(); // Data for the CRC byte[] CRC = Crc16Ccitt.GetCRC(CRCData); // The Actual CRC buffer[HEADERS_LENGHT + rawBuffer.Length] = CRC[0]; // CRC MSB buffer[HEADERS_LENGHT + rawBuffer.Length + 1] = CRC[1]; // CRC LSB buffer[HEADERS_LENGHT + rawBuffer.Length + 2] = 0x0F; // PB2 buffer[HEADERS_LENGHT + rawBuffer.Length + 3] = 0x0A; // Size of awaited Answer (add this to variable some day to check...) byte[] LRCData = buffer.Skip(1).Take(buffer.Length - 2).ToArray(); byte lrc = LRC.calculateLRC(LRCData); buffer[buffer.Length - 1] = lrc; // LRC return buffer; } /// <summary> /// Remove frames from the buffer /// </summary> /// <param name="rawBuffer">framed buffer</param> /// <returns>body buffer</returns> byte[] RemoveFrames(byte[] rawBuffer) { const int HEADERS_LENGHT = 6; const int BODY_LENGTH = 6; byte[] CRCData = rawBuffer.Skip(5).Take(7).ToArray(); // Data for the CRC byte[] CRC = Crc16Ccitt.GetCRC(CRCData); // The Actual CRC if (CRC[0] != rawBuffer[HEADERS_LENGHT + BODY_LENGTH] && CRC[1] != rawBuffer[HEADERS_LENGHT + BODY_LENGTH + 1]) { // throw CRC error } byte[] LRCData = rawBuffer.Skip(1).Take(rawBuffer.Length - 2).ToArray(); byte lrc = LRC.calculateLRC(LRCData); if (rawBuffer[rawBuffer.Length - 1] != lrc) { // throw LRC error } return rawBuffer.Skip(4).Take(6).ToArray(); } } /// <summary> /// Convert byte buffers back and forth /// </summary> static class BufferConverter { static public byte[] GetStringToBytes(string value) { SoapHexBinary shb = SoapHexBinary.Parse(value); return shb.Value; } static public string GetBytesToString(byte[] value) { SoapHexBinary shb = new SoapHexBinary(value); return shb.ToString(); } } /// <summary> /// Cyclic Redundancy Check (CRC) /// </summary> /// CCITT (x^16 + x^12 + x^5 + 1) public static class Crc16Ccitt { public static byte[] GetCRC(byte[] data) { ushort crc = 0x3791; // eZ430-TMS37157 initial value for (byte i = 0; i < data.Length; i++) { byte bits = 8; byte current = data[i]; // Next byte while (bits-- > 0) { bool lsb = (crc & 1) > 0; // Store LSB crc >>= 1; // Shift right 1 bit bool rxdt = (current & 1) > 0; if (rxdt) { crc |= 0x8000; // Shift in next bit } if (lsb) // Check stored LSB { crc ^= 0x8000; // Invert MSB } if (0x8000 == (crc & 0x8000)) // Check MSB { crc ^= 0x0408; // Invert bits 3 and 10 (have in mind those are x^12 and x^5) } current >>= 1; // Next bit } } return BitConverter.GetBytes(crc); } } /// <summary> /// Longitudinal Redundancy Check (LRC) /// </summary> public static class LRC { public static byte calculateLRC(byte[] bytes) { byte LRC = 0; for (int i = 0; i < bytes.Length; i++) { LRC ^= bytes[i]; } return LRC; } } /// <summary> /// Get Friendly Comport Names :) /// </summary> /// based on http://dariosantarelli.wordpress.com/2010/10/18/c-how-to-programmatically-find-a-com-port-by-friendly-name/ public class COMPortInfo { public string Name; public string Description; public static List<COMPortInfo> GetCOMPortsInfo() { List<COMPortInfo> comPortInfoList = new List<COMPortInfo>(); ManagementScope connectionScope = new ManagementScope { Path = new ManagementPath(@"\\" + Environment.MachineName + @"\root\CIMV2"), Options = new ConnectionOptions { Impersonation = ImpersonationLevel.Impersonate, Authentication = AuthenticationLevel.Default, EnablePrivileges = true } }; connectionScope.Connect(); ObjectQuery objectQuery = new ObjectQuery("SELECT * FROM Win32_PnPEntity WHERE ConfigManagerErrorCode = 0"); ManagementObjectSearcher comPortSearcher = new ManagementObjectSearcher(connectionScope, objectQuery); using (comPortSearcher) { string caption; foreach (ManagementObject obj in comPortSearcher.Get()) { if (obj != null) { object captionObj = obj["Caption"]; if (captionObj != null) { caption = captionObj.ToString(); if (caption.Contains("(COM")) { COMPortInfo comPortInfo = new COMPortInfo { Name = caption.Substring(caption.LastIndexOf("(COM")).Replace("(", string.Empty).Replace(")", string.Empty), Description = caption }; comPortInfoList.Add(comPortInfo); } } } } } return comPortInfoList; } } }