using System; using System.IO; using System.Text; using System.IO.Ports; using System.Threading; using Microsoft.SPOT; namespace CPF { class BTConsole { private static SerialPort consolePort = new SerialPort("COM1", 115200, Parity.None, 8, StopBits.One); public static XModem Modem = new XModem(consolePort, XModem.Variants.XModem1K); private static StructQueue.qStruct qS = new StructQueue.qStruct(); public static bool BTSend = true; public static void OpenConsolePort() { if (!consolePort.IsOpen) { consolePort.Open(); } consolePort.DiscardInBuffer(); consolePort.DiscardOutBuffer(); consolePort.DataReceived += new SerialDataReceivedEventHandler(consolePortDataReceived); qS.byteArray = new byte[StructQueue.qRecordWidth]; } private static StringBuilder uploadStartComment = new StringBuilder(128); private static StringBuilder sbFUS = new StringBuilder("File Upload Successful"); private static StringBuilder sbFUF = new StringBuilder("File Upload Failed"); private static StringBuilder uploadStartPrefix = new StringBuilder(128); private static StringBuilder uploadPrefix2 = new StringBuilder(128); public static MemoryStream DataMemoryStream = new MemoryStream(); // Grows dynamically public static byte[] DataArray = new byte[0]; private static FileStream uploadFile; private static int uploadFileLength = 0; private static Object BTLock = new Object(); public static void detachEventHandler() { //Detach the "regular" console port event handler so the XModem class attach its event handler consolePort.DataReceived -= consolePortDataReceived; } private static StringBuilder sbWaiting = new StringBuilder("Waiting 30 seconds. Setup your PC to receive a file using XModem-1K protocol"); private static StringBuilder sbDoneWaiting = new StringBuilder("Starting XMODEM upload"); public static void uploadDataFileWhole(StringBuilder uploadFileName) { //The XModem SendFileWhole method expects the whole file to be in a byte array in memory //There is a SendFilePieces for really big files uploadFile = new FileStream(uploadFileName.ToString(), FileMode.Open, FileAccess.Read); uploadFileLength = (int)uploadFile.Length; DataArray = new byte[uploadFileLength]; uploadFile.Read(DataArray, 0, uploadFileLength); //Detach the "regular" console port event handler so the XModem class attach its event handler consolePort.DataReceived -= consolePortDataReceived; SendLine(sbWaiting); qS.timeStamp = DateTime.Now; qS.state = Program.CPFState; qS.qRecordType = StructQueue.QRecordType.BTConsole; Array.Copy(UTF8Encoding.UTF8.GetBytes(sbWaiting.ToString()), qS.byteArray, sbWaiting.Length); lock (BTLock) { Program.sQueue.Enqueue(qS); } Thread.Sleep(30000); SendLine(sbDoneWaiting); qS.timeStamp = DateTime.Now; qS.state = Program.CPFState; qS.qRecordType = StructQueue.QRecordType.BTConsole; Array.Copy(UTF8Encoding.UTF8.GetBytes(sbDoneWaiting.ToString()), qS.byteArray, sbDoneWaiting.Length); lock (BTLock) { Program.sQueue.Enqueue(qS); } SendFileWhole(); //Re-attach "regular" console port event handler consolePort.DataReceived += consolePortDataReceived; } private static StringBuilder sbTemp = new StringBuilder(512); private static byte[] byteTemp = new byte[1024]; public static void SendLine(StringBuilder sbLineToSend) { if (BTSend) { sbTemp.Clear(); sbTemp.Append(sbLineToSend); Array.Clear(byteTemp, 0, byteTemp.Length); Array.Copy(UTF8Encoding.UTF8.GetBytes(sbTemp.ToString()), byteTemp, sbTemp.Length); consolePort.Write(byteTemp, 0, byteTemp.Length); } } public static void CloseConsolePort() { consolePort.Close(); } private static byte[] consolePortReadBytes = new byte[64]; private static byte[] consolePortInBytes = new byte[16]; private static byte[] header = UTF8Encoding.UTF8.GetBytes("CON"); private static byte[] message = new byte[256]; private static byte STX = 36; //Start of text = "$" private static byte ETX = 10; //End of text = LF private static int messageNum = 0; private static int consolePortBytesToRead = 0; private static int consolePortInBytesIndex = 0; private static object consoleLock = new object(); private static void consolePortDataReceived(object sender, SerialDataReceivedEventArgs e) { consolePortBytesToRead = consolePort.BytesToRead; try { consolePort.Read(consolePortReadBytes, 0, consolePortBytesToRead); } catch { Debug.Print("Console Read Exception"); //TODO do something smarter here } for (int i = 0; i < consolePortBytesToRead; i++) { consolePortInBytes[consolePortInBytesIndex] = consolePortReadBytes[i]; if (consolePortInBytesIndex == 0) //Check to make sure first character is = LF { if (consolePortInBytes[0] == STX) //only move on to byte index 1 after we get a LF { consolePortInBytesIndex = consolePortInBytesIndex + 1; } } else { if (consolePortInBytes[consolePortInBytesIndex] == ETX) { //Array.Clear(message, 0, message.Length); //Array.Copy(header, message, header.Length); //Array.Copy(consolePortInBytes, 1, message, header.Length, consolePortInBytesIndex); //lock (consoleLock) { Program.MessageQueue.Enqueue(message); } Array.Clear(qS.byteArray, 0, qS.byteArray.Length); Array.Copy(consolePortInBytes, qS.byteArray, consolePortInBytesIndex); qS.timeStamp = DateTime.Now; qS.state = Program.CPFState; qS.qRecordType = StructQueue.QRecordType.BTConsole; lock (consoleLock) { Program.sQueue.Enqueue(qS); } consolePortInBytesIndex = 0; messageNum = messageNum + 1; Array.Clear(consolePortInBytes, 0, consolePortInBytes.Length); Array.Clear(consolePortReadBytes, 0, consolePortReadBytes.Length); } else { consolePortInBytesIndex = consolePortInBytesIndex + 1; } } } } public static void ReceiveFileWhole() { // Passing an empty MemoryStream object to the XModem.Receive() method indicates that the user wishes to receive the entire // file in one big lump. NOTE: If using this technique, your device must have enough contiguous RAM to support the expected // file size. Contiguous RAM is the largest memory that can be allocated to a single object. It is usually much smaller // than a device's "total" RAM. // Start the XModem receive process. This method blocks until the transfer has terminated (either through successful // end-of-file, or due to errors such as timeouts, excessive retries, etc). You can examine the termination reason to // determine under what conditions the transfer has stopped. XModem.TerminationReasonEnum terminationReason = Modem.Receive(DataMemoryStream); if (terminationReason == XModem.TerminationReasonEnum.EndOfFile) { Debug.Print("LUMP FILE RECEIVE SUCCESSFUL!"); // Transfer successful, so convert MemoryStream to byte array DataArray = DataMemoryStream.ToArray(); // Because XModem packets are a fixed size, if the original transmitted file does not fill a packet completely, // padding bytes are added until the packet is the required size. The padding byte is usually the SUB symbol // (byte value 26). You may strip away these padding bytes if desired. This may be a problem, however, // if one or more SUB bytes dangling at the end is actually a legitimate part of the file (rare, but theoretically // possible). // In this example, we will assume that consecutive dangling SUB bytes are never a legitimate part of the file, // and we can strip them away so that the received file will match its original size. DataArray = Modem.TrimPaddingBytesFromEnd(DataArray); } else { // Something went wrong during the transfer. You may examine the termination reason and respond accordingly. Debug.Print("LUMP FILE RECEIVE FAILED!"); } } public static bool SendFileWhole() { int numBytesSuccessfullySent = 0; bool success = false; numBytesSuccessfullySent = Modem.Send(DataArray); if (numBytesSuccessfullySent == DataArray.Length && Modem.TerminationReason == XModem.TerminationReasonEnum.EndOfFile) { SendLine(sbFUS); qS.timeStamp = DateTime.Now; qS.state = Program.CPFState; qS.qRecordType = StructQueue.QRecordType.BTConsole; Array.Copy(UTF8Encoding.UTF8.GetBytes(sbFUS.ToString()), qS.byteArray, sbFUS.Length); lock (BTLock) { Program.sQueue.Enqueue(qS); } success = true; } else { SendLine(sbFUF); qS.timeStamp = DateTime.Now; qS.state = Program.CPFState; qS.qRecordType = StructQueue.QRecordType.BTConsole; Array.Copy(UTF8Encoding.UTF8.GetBytes(sbFUF.ToString()), qS.byteArray, sbFUF.Length); lock (BTLock) { Program.sQueue.Enqueue(qS); } success = false; } return (success); } } }