0

I'm currently developing a WIn IoT app for the Raspberry Pi and I have a significant problem there...I could really need some help solving that...

The problem I'm having is that I have different commands I send over the serial port and every command recieves different responses.

After sending a few commands (can be just one or it can be 15...it's basically random -.-) my app just stops accepting the commands to send or completely crashes when I invoke one of the commands. It happens rather randomly and when I restart the app it's working again. At least most of the time... Sometimes the first restart doesn't do anything and I have to restart again...

Since the app will probably be used in a bigger project I want to guarantee flawless execution. I don't want to have a customer (or the tool we use to communicate with the Pi) to restart the whole app. It should just abort it's non-working operation, log an error and then be back up running.

I think it may be a possibility that the buffer overflows for whatever reason... But I don't know of any way to clear the buffer from code in UWP. And I can't seem to find anything regarding that.

If you can help me I would be really happy. I'm trying to get this to work for almost a week but I can't find the problem...

My colleague rewrote some of my code last week. I originally passed every info I needed through tuples but he told me it's not good. So he wrote the class containing the info for me. But since then I run into a lot of problems. But I really don't know why it doesn't...

If you want to know more about my code feel free to ask. I really need this to work :/

Some of the code I'm using:

This is the block containing my data:

public class InfoBlock
{
    public List<InfoBlockValue> Names { get; set; }

    public byte[] ReceivedCrcSum { get; set; }

    public byte[] CalculatedCrcSum { get; set; }

    public bool IsChecksumEqual { get; set; } = false;
}

public class InfoBlockValue
{
    public string InfoString { get; set; }

    public InfoBlockValue(string info)
    {
        this.InfoString = info;
    }

    public override string ToString()
    {
        return InfoString;
    }
}

This is the class for my Read and Write operations:

public class GetInfoBlock
{
    public string SendCommand { get; set; } = "##getnames";

    public async Task<uint> Write()
    {
        byte CarriageReturn = 0x0D;

        byte[] WriteArray = StringToByteArray(SendCommand);

        byte[] WriteArrayCR = new byte[WriteArray.Length + 1];
        WriteArray.CopyTo(WriteArrayCR, 0);
        WriteArrayCR[WriteArray.Length] = CarriageReturn;

        return await ReadWriteAdapter.Current.WriteAsync(WriteArrayCR);
    }

    public async Task<InfoBlock> Read()
    {
        InfoBlock block = new InfoBlock();

        byte[] ListenOut = await ReadWriteAdapter.Current.Listen(5802);

        byte[] NameCrcSource = new byte[5800];
        byte[] NameCrc16 = new byte[2];

        Array.Copy(ListenOut, 0, NameCrcSource, 0, 5800);

        block.Names = ConvertFromBytes(NameCrcSource);
        block.ReceivedCrcSum = new byte[] { ListenOut[5801], ListenOut[5800] };

        block.CalculatedCrcSum = Crc16Ccitt.ComputeChecksumBytes(NameCrcSource);
        block.IsChecksumEqual = ValidateDataCRC.ValidateData(NameCrcSource, block.ReceivedCrcSum);

        return block;
    }

    public List<InfoBlockValue> ConvertFromBytes(byte[] dataFromDrive)
    {
        List<InfoBlockValue> InfoValue = new List<InfoBlockValue>();

        string[] allConvertedIntegers = new String[100];

        int lastReadByte = 0;
        int parameterIndex = 0;
        int parameterByteIndex = 0;

        for (parameterIndex = 0; parameterIndex < 99; parameterIndex++)
        {
            byte[] allBytesOfOneParameter = new byte[28];                                

            Array.Copy(dataFromDrive, lastReadByte + 1, allBytesOfOneParameter, 0, 28);

            InfoValue.Add(new InfoBlockValue(System.Text.Encoding.UTF8.GetString(allBytesOfOneParameter)));

            parameterByteIndex = 0;
            lastReadByte += 29;
        }

        return InfoValue;
    }

    public byte[] StringToByteArray(string str)
    {
        System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
        return enc.GetBytes(str);
    }
}

This is the code where I use the operations:

public class ReadInfo
{
    private GetInfoBlock InfoBlock = null;

    public async Task<Tuple<string, InfoBlock>> ReadNamesBlock()
    {
        if (InfoBlock == null)
        {
            InfoBlock = new GetInfoBlock();
        }

        await ReadWriteAdapter.semaphore.WaitAsync();

        string returnString = string.Empty;

        uint writeTuple = await InfoBlock.Write();

        try
        {
            InfoBlock readTuple = await NamesBlock.Read();

            bool validationResult = readTuple.IsChecksumEqual;

            if (validationResult)
            {
                returnString += $"Checksum {BitConverter.ToString(readTuple.CalculatedCrcSum)} ReceivedCrcSum: {BitConverter.ToString(readTuple.ReceivedCrcSum)}";

                //await ValidateDataCRC.SendAck();

            }
            else
            {
                returnString += "Checksum error";

                await ValidateDataCRC.SendNack();
            }

            return new Tuple<string, InfoBlock>(returnString, readTuple);
        }
        catch (Exception ex)
        {
            string exception = $"Error while reading the parameternames from the device: {ex.Message}";

            return new Tuple<string, InfoBlock>(exception, null);
        }
        finally
        {
            NamesBlock = null;
            ReadWriteAdapter.semaphore.Release();
        }
    }
}

And the last one is my ReadWriteAdapter:

public class ReadWriteAdapter
{
    public static SemaphoreSlim semaphore = new SemaphoreSlim(1);

    private static readonly Object lockObject = new object();
    private static ReadWriteAdapter instance;

    public static ReadWriteAdapter Current
    {
        get
        {
            if (instance == null)
            {
                lock (lockObject)
                {
                    if (instance == null)
                    {
                        instance = new ReadWriteAdapter();
                    }
                }
            }
            return instance;
        }
    }


    private DataWriter dataWriter = null;
    private DataReader dataReader = null;

    private CancellationTokenSource ReadCancellationTokenSource;
    private SerialDevice serialPort = null;

    public bool IsDeviceInitialized()
    {
        return serialPort != null;
    }


    public async Task<string> Init()
    {
        try
        {
            string aqs = SerialDevice.GetDeviceSelector();

            DeviceInformationCollection devices = await DeviceInformation.FindAllAsync(aqs, null);

            if (devices.Any())
            {
                if (devices[0].Id.Contains("FTDI"))
                {
                    string deviceId = devices[0].Id;
                    await OpenPort(deviceId);
                }
                else
                {
                    string deviceId = devices[1].Id;
                    await OpenPort(deviceId);
                }

                ReadCancellationTokenSource = new CancellationTokenSource();

                dataWriter = new DataWriter(serialPort.OutputStream);
                dataReader = new DataReader(serialPort.InputStream);
                return "found port";
            }
            return "nodevices";
        }
        catch (Exception ex)
        {
            return ex.Message;
        }
    }

    private async Task OpenPort(string deviceId)
    {
        serialPort = await SerialDevice.FromIdAsync(deviceId);

        if (serialPort != null)
        {
            serialPort.WriteTimeout = TimeSpan.FromMilliseconds(500);
            serialPort.ReadTimeout = TimeSpan.FromMilliseconds(500);
            serialPort.BaudRate = 19200;
            serialPort.Parity = SerialParity.None;
            serialPort.StopBits = SerialStopBitCount.One;
            serialPort.DataBits = 8;
            serialPort.Handshake = SerialHandshake.None;
        }
    }


    private async Task<byte[]> ReadAsync(CancellationToken cancellationToken, uint ReadBufferLength)
    {
        Task<uint> loadAsyncTask;
        byte[] returnArray = new byte[ReadBufferLength];

        dataReader.InputStreamOptions = InputStreamOptions.Partial;

        loadAsyncTask = dataReader.LoadAsync(ReadBufferLength).AsTask(cancellationToken);   // Create a task object

        uint bytesRead = await loadAsyncTask;    // Launch the task and wait until buffer would be full

        if (bytesRead > 0)
        {
            dataReader.ReadBytes(returnArray);
        }

        return returnArray;
    }

    public async Task<uint> WriteAsync(byte[] data)
    {
        if (serialPort == null)
        {
            throw new ArgumentNullException("device");
        }
        if (dataWriter == null)
        {
            throw new ArgumentNullException("device");
        }

        if (data.Length != 0)
        {                
            dataWriter.WriteBytes(data);

            // Launch an async task to complete the write operation
            Task<uint> storeAsyncTask = dataWriter.StoreAsync().AsTask();

            return await storeAsyncTask;
        }
        else
        {
            return 0;
        }
    }

    public async Task<byte[]> Listen(uint BufferLength)
    {
        byte[] listen = new byte[BufferLength];

        try
        {
            if (serialPort != null)
            {
                dataReader = new DataReader(serialPort.InputStream);

                listen = await ReadAsync(ReadCancellationTokenSource.Token, BufferLength);
            }
        }
        catch (Exception ex)
        {
            throw ex;
        }
        finally
        {
            if (dataReader != null)    // Cleanup once complete
            {
                dataReader.DetachStream();
                dataReader = null;
            }
        }

        return listen;
    }
}
Daniel
  • 242
  • 2
  • 12
  • 1
    I am so sorry but: "*So he wrote the class containing the info for me. But since then I run into a lot of problems.*". Then revert it or ask him to help you troubleshoot. This is off topic for SO since we cannot reproduce this and question about "why is this not working" are off-topic in that case. – Peter Bons Jan 31 '18 at 14:56

1 Answers1

1

Found the answer myself...

I had to dispose the dataReader after I used it. I guess the amount of streams I had on the reader just overflowed or whatever.

Changed this in ReadWriteAdapter:

finally
    {
        if (dataReader != null)    // Cleanup once complete
        {
            dataReader.DetachStream();
            dataReader = null;
        }
    }

To this:

finally
    {
        if (dataReader != null)    // Cleanup once complete
        {
            dataReader.DetachStream();
            dataReader.Dispose();  //Added this part
            dataReader = null;
        }
    }
Daniel
  • 242
  • 2
  • 12