/// <summary> /// Stop the download process. /// This will close the binary writer and /// set the serial port back to ADCP mode. /// </summary> public void CancelDownload() { // Stop the trying to ask for a download _cancelDownload = true; // Stop the download watchdog //StopDownloadWatchDog(); // Close the file stream CloseBinaryWriter(); // The D command will cancel any pending downloads // Send it twice to first ignore the last packet sent, then // stop the download process SendData(string.Format("{0}", RTI.Commands.AdcpCommands.CMD_DS_CANCEL)); SendData(string.Format("{0}", RTI.Commands.AdcpCommands.CMD_DS_CANCEL)); // Set the mode of the ADCP // TODO: Should check if it was previously something else Mode = AdcpSerialModes.ADCP; // Set the interval back to default SetTimerInterval(); }
/// <summary> /// Parse the packet received from the serial port. /// The system is in Download mode, so the serial port /// is sending packets of data in XMODEM format. /// This will determine what type of packet is received /// and handle the packet. /// </summary> /// <param name="data">Data received from the serial port.</param> private void ParseDownloadData(byte[] data) { // Check for end of transfer // 20 is the length for the message // "<EOT> Transfer Complete" if (data.Length == 20 && data[0] == EOT) { // Close the file stream CloseBinaryWriter(); // Stop the Download process CompleteDownload(true); return; } // Set the buffer size based off in high speed mode or not int bufferSize = DEFAULT_DL_BUFF_SIZE; if (_isHighSpeedDownload) { bufferSize = DEFAULT_HSDL_BUFF_SIZE; } // Add the data to a buffer. // This is to wait until a complete packet has arrived _downloadDataBuffer.AddRange(data); // If there is not enough data in the buffer // wait for more data while (_downloadDataBuffer.Count >= bufferSize + 5) { int retry = XMODEM_RETRY_LIMIT; int slowdown = 0; // Find the type of packet switch (_downloadDataBuffer[0]) { default: SetReceiveBuffer("I"); _downloadDataBuffer.RemoveAt(0); break; case CAN: break; case SOH: break; case STX: // Stop the loop from requesting the // start of data _cancelWaitForDownload = true; byte[] Fbuff; if (VerifyPacketSTX(_downloadDataBuffer.ToArray(), _seqNum, out Fbuff)) { // Should be nothing else in the buffer // the buffer should have only contained the packet _downloadDataBuffer.Clear(); // Set how many bytes have been written _byteswritten += Fbuff.Length; // Show in the serial port console progress. //Debug.Write("."); // Add data to codec to parse and // add to the database if (_parseDownloadedData) { if (ReceiveAdcpSerialDataEvent != null) { // Parse and write the data to the database and file this.ReceiveAdcpSerialDataEvent(Fbuff); } } else { try { // Write the data to the file only _downloadDataBinWriter.Write(Fbuff); } catch (Exception e) { log.Error("Error trying to write serial port download data to file.", e); } } // Write ACK back to serial port // So the next packet will be sent if (!SendACK()) { // If command not sent properly // try again. If still not sent // properly, there may be an issue // with the serial port and stop // trying to download if (!SendACK()) { break; } } // Publish the event of the current // progress of the file download PublishDownloadProgressEvent(); // Used to slow down the reading // It may be to fast for the serial // port to handle if (slowdown > 0) { System.Threading.Thread.Sleep(slowdown); } // Reset retry retry = XMODEM_RETRY_LIMIT; // Set the sequence number _seqNum++; if (_seqNum > 255) _seqNum = 0; } else { // Packet in the buffer was bad // clear the buffer and request another packet _downloadDataBuffer.Clear(); // Send NAK that data was not received properly if (!SendNAK()) { // If command not sent properly // try again. If still not sent // properly, there may be an issue // with the serial port and stop // trying to download if (!SendNAK()) { break; } } System.Threading.Thread.Sleep(slowdown); // Maybe we are not waiting long enough // for the complete packet to arrive slowdown += 10; if (slowdown > 150) slowdown = 150; // Limit the number of times to get the // packet if it fails retry--; if (retry < 1) { break; } } break; case EOT: // Close the file stream CloseBinaryWriter(); // Set the mode of the ADCP // TODO: Should check if it was previously something else Mode = AdcpSerialModes.ADCP; break; } } }
/// <summary> /// Start the upload process. This will set all the /// settings in needed to do an upload. This includes /// pausing the read thread and setting the mode to Upload. /// </summary> private void StartUpload() { // Pause the read thread // This will make the read thread not read data from the serial port PauseReadThread(true); // Set the mode of the ADCP Mode = AdcpSerialModes.UPLOAD; // Set the interval to a large number // because we will not be using the read thread SetTimerInterval(2000); }
/// <summary> /// Reset all the settings back to standard ADCP mode. /// This includes resuming the read thread and setting /// the mode back to ADCP. /// </summary> private void CompleteUpload() { // Stop the upload loop XMODEM = false; // This will make the read thread resume reading data from the serial port PauseReadThread(false); // Set the mode of the ADCP Mode = AdcpSerialModes.ADCP; // Set the interval back to default SetTimerInterval(); }
/// <summary> /// Stop the download process. If the download process is complete /// or needs to be stopped, then return the ADCP to ADCP mode /// and starting reading at a normal interval rate again. /// </summary> /// <param name="goodDownload">Set flag that the download was good or bad when complete.</param> private void CompleteDownload(bool goodDownload) { // The D command will cancel any pending downloads // Send it twice to first ignore the last packet sent, then // stop the download process SendData(string.Format("{0}", RTI.Commands.AdcpCommands.CMD_DS_CANCEL)); SendData(string.Format("{0}", RTI.Commands.AdcpCommands.CMD_DS_CANCEL)); // Publish that download is complete for the file PublishDownloadCompleteEvent(goodDownload); // Stop the download watchdog //StopDownloadWatchDog(); // Set the mode of the ADCP // TODO: Should check if it was previously something else Mode = AdcpSerialModes.ADCP; // Set the interval back to default SetTimerInterval(); }
/// <summary> /// Download the file from the serial device using XMODE-CRC. /// Set parseData to determine what to do with the downloaded data. /// /// About 3.5mb per minute download speed at 921600 baud rate. /// /// If parseData is TRUE: /// The data will be published to the event: ReceiveAdcpSerialDataEvent. /// If parseData is FALSE: /// The data will be written to the file: dirName\fileName. /// </summary> /// <param name="dirName">Directory Name to store the files.</param> /// <param name="fileName">Filename to download.</param> /// <param name="parseData">Flag to parse and record data to the database. Default = FALSE.</param> /// <param name="isHighSpeed">Flag if we should download in high speed mode or not. Default = TRUE.</param> /// <returns>TRUE = file successful download / FALSE = File not downloaded.</returns> public bool XModemDownload(string dirName, string fileName, bool parseData = false, bool isHighSpeed = true) { // Set the mode of the ADCP Mode = AdcpSerialModes.DOWNLOAD; _parseDownloadedData = parseData; _isHighSpeedDownload = isHighSpeed; // Clear the input buffer of any previous commands // and clear the Receive Buffer ClearInputBuffer(); ReceiveBufferString = ""; // Increase the time to check the serial port SetTimerInterval(DOWNLOAD_SERIAL_INTERVAL); _seqNum = 1; _byteswritten = 0; _fileName = fileName; _downloadDataBuffer = new List<byte>(); bool C_ACK = false; _cancelWaitForDownload = false; _cancelDownload = false; bool xmodemCancel = false; byte[] buff = new byte[4]; //byte[] bBuff = new byte[140000]; //byte[] Dbuff = new byte[1024 + 5]; long elapsedTicks; DateTime currentDate = DateTime.Now; long lastTicks = currentDate.Ticks; int retry = XMODEM_RETRY_LIMIT; // Create the file path string path = dirName + "\\" + fileName; try { // If we are not parsing the data, then // we will record the data here. If we are // parsing the data, then the parser will also // record the data. if (!_parseDownloadedData) { // Create a binarywriter to write the data to the file _downloadDataBinWriter = CreateBinaryWriter(path); } // Ensure the serial port is open and accepting commands if (IsAvailable()) { { // Send the command to download the file // from the instrument // It will choose if we are downloading in high speed mode or not if (!SendCommandDSX(fileName)) { // Command could not be sent // so do not continue return false; } elapsedTicks = 0; currentDate = DateTime.Now; lastTicks = currentDate.Ticks; xmodemCancel = false; // The response from the command is: // "File Size = 0000000000" // "READY" // Wait for READY then begin // If we never receive a READY, // Complete the download for this file long filesize = 0; bool receivedREADY = CheckForREADY(out filesize); while (!xmodemCancel && !receivedREADY && elapsedTicks < 100000000) { receivedREADY = CheckForREADY(out filesize); currentDate = DateTime.Now; elapsedTicks = currentDate.Ticks - lastTicks; } // READY was received from the ADCP if (receivedREADY) { // Publish that a file size was found PublishFileSizeEvent(); _downloadDataBuffer.Clear(); // Start the watchdog to monitor for a hanging download //StartDownloadWatchDog(); xmodemCancel = false; // Set the timeout to wait for data to come in // 10000000 = 1 second long TO = 10000000; if (_isHighSpeedDownload) { switch (_serialOptions.BaudRate) { default: TO = 100000000; break; case 921600: TO = 20000000; break; case 115200: TO = 40000000; break; } } // _startTransfer is set set true when the incoming data is parsed // and an STX packet is valid in ParseDownloadData() // _cancelDownload is set true if the user tries to cancel the download // When the serial port receives data, it will call the event handler. // The event handler will then process the packets for file data in ParseDownloadData(). while (!_cancelWaitForDownload && !_cancelDownload) { try { currentDate = DateTime.Now; elapsedTicks = currentDate.Ticks - lastTicks; // Wait for data if (elapsedTicks > TO) { lastTicks = currentDate.Ticks; // Send a Capital C character instead of a NAK to start // the transfer using XMODEM-CRC (16-Bit CRC instead of 8-Bit CRC) // If the sender responds by sending a packet, it is assumed the // sender knows XMODEM-CRC. If no packet is sent, then assumed // the received does not know and fall back to traditional XMODEM. // Try at least 4 times to send C just in case one of the C was sent // bad. if (!C_ACK) { buff[0] = (byte)'C'; SendData(buff, 0, 1); } // If not going to use XMODEM-CRC, then send // a NAK to start the file transfer else { buff[0] = NAK; SendData(buff, 0, 1); } // Monitor number of retries // Did not receive a C // So stop trying to download retry--; if (retry < 1) { xmodemCancel = true; } } } catch(Exception e) { log.Error("Error downloading a file from the ADCP.", e); } // Canceled download if (xmodemCancel) { // Stop trying to download the file _cancelWaitForDownload = true; // Close the file stream //CloseBinaryWriter(); CancelDownload(); // File could not be downloaded return false; } } } else { // The file could not be started // So complete the download CompleteDownload(false); // Close the file stream CloseBinaryWriter(); return false; } } } } catch(Exception e) { //OK = false; //Debug.WriteLine("Exception: {0}", e.ToString()); log.Error("Error trying to download a file.", e); // Close the file stream CloseBinaryWriter(); return false; } return true; }
/// <summary> /// Stop the ADCP from being in Compass mode. /// This will set the compass to interval mode, /// then set the ADCP back to ADCP mode. /// </summary> public void StopCompassMode() { // Turn on compass interval outputing byte[] startIntervalCmd = PniPrimeCompassBinaryCodec.StartIntervalModeCommand(); SendData(startIntervalCmd, 0, startIntervalCmd.Length); // Stop ADCP from compass mode SendDataWaitReply(RTI.Commands.AdcpCommands.CMD_DIAGCPT_DISCONNECT, TIMEOUT); // Set the serial port to ADCP mode to decode ADCP data Mode = AdcpSerialPort.AdcpSerialModes.ADCP; }
/// <summary> /// Start Compass mode. This make the ADCP output /// compass data instead of ADCP data. /// </summary> /// <returns>TRUE if command sent properly.</returns> public bool StartCompassMode() { bool startResult = false; // Try to send the command, if it fails try again startResult = SendDataWaitReply(RTI.Commands.AdcpCommands.CMD_DIAGCPT, TIMEOUT); // If the command was not good, try it again if (!startResult) { startResult = SendDataWaitReply(RTI.Commands.AdcpCommands.CMD_DIAGCPT, TIMEOUT); } // If was capable of putting // into compass mode, change the mode if (startResult) { // Set the serial port to COMPASS mode to decode compass data Mode = AdcpSerialPort.AdcpSerialModes.COMPASS; } // Return if either failed return startResult; }