Why my program sometimes not work only at startup?

melon NG 291 Reputation points
2021-11-05T03:35:11.607+00:00

Here is the code of my dotnet console App :
using System;
using System.IO.Ports;
using System.Linq;
using System.Threading.Tasks;

namespace ConsoleApp1
{
    internal class Program
    {
        private static SerialPort SP1 = new SerialPort("/dev/ttyUSB0", 57600, Parity.None, 8, StopBits.One);
        private static SerialPort SP2 = new SerialPort("/dev/ttyUSB1", 115200, Parity.None, 8, StopBits.One);        
        static void Main(string[] args)
        {
            SP1.DataReceived += SP_DataReceived;
            try
            {
                SP1.Open();
                SP2.Open();
            }
            catch(Exception ex){ 
                Console.WriteLine(ex.Message);
            }
            Task.Run(() => {
                while (true)
                {
                    if (!SP1.IsOpen)
                    {
                        try
                        {
                            SP1.Open();
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine(ex.Message);
                        }
                    }
                    if (!SP2.IsOpen)
                    {
                        try
                        {
                            SP2.Open();
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine(ex.Message);
                        }
                    }
                    Task.Delay(1000).Wait();
                }
            });
            Console.WriteLine("Started");
            Console.ReadKey();
        }

     static List<byte> ByteList = new List<byte>();
    private static void SP_DataReceived(object sender, SerialDataReceivedEventArgs e)
    {
        byte[] buf = new byte[SP1.BytesToRead];
        Console.WriteLine("DATA RECEIVED!");
        SP1!.Read(buf, 0, buf.Length);
        foreach (Byte b in buf)
        {
            ByteList.Add(b);
        }
        int StartIndex = -1;
        int EndIndex = -1;
        for (int i = 0; i < ByteList.Count; i++)
        {
            if (ByteList[i] == 2)
            {
                StartIndex = i;
            }
            else if (ByteList[i] == 13 && ByteList.Count-1 > i&&ByteList[i+1]==10)
            {
                EndIndex = i + 1;
                break;
            }
        }
        List<byte> NewByteList = new List<byte>();
        if (StartIndex != -1 && EndIndex != -1)
        {                
            for (int i = StartIndex+1; i <= EndIndex-2; i++)
            {
                NewByteList.Add(ByteList[i]);
            }
        }
        ByteList.RemoveRange(StartIndex, EndIndex - StartIndex+1);
        var Result = Encoding.UTF8.GetString(NewByteList.ToArray()).Split(" ").Last().Replace(Environment.NewLine, "");            
        if (!string.IsNullOrEmpty(Result))
        {
            Console.WriteLine(Result);
            if (SP2.IsOpen)
            {
                SP2.Write(Result+Environment.NewLine);
            }
            else {
                Console.WriteLine("SP2 is not opened");
            }
        }
    }
    }
}

The program is running on raspberry with raspberry os. It is to get data from serial port A, then convert and transfer it to serial port B.

And it runs well if I run it by dotnet ConsoleApp1.dll

Now I want it run when the raspberry startup. So I create a service like this:
[Unit]
Description=Example .NET App

[Service]
WorkingDirectory=/home/pi/deployment-location
ExecStart=/home/pi/.dotnet/dotnet /home/pi/deployment-location/ConsoleApp1.dll
Restart=always
RestartSec=3
SyslogIdentifier=dotnet-example
User=pi
Environment=ASPNETCORE_ENVIRONMENT=Development

[Install]
WantedBy=multi-user.target

In spite, the program runs when startup. However, it met a strange problem. The program never works while startup. However, this problem never occurs while it running with "dotnet ConsoleApp1.dll"

And here is the result when I input "systemctl status ConsoleApp1.service":
● ConsoleApp1.service - Example .NET Web API App running on Ubuntu
Loaded: loaded (/etc/systemd/system/ConsoleApp1.service; enabled; vendor pres
Active: activating (auto-restart) (Result: signal) since Fri 2021-11-05 03:40
Process: 1204 ExecStart=/home/pi/.dotnet/dotnet /home/pi/deployment-location/C
Main PID: 1204 (code=killed, signal=ABRT)

Someone tell me to use journalctl -f -u ConsoleApp1.service to find the problem and soon I found this:
Nov 08 07:22:42 raspberrypi dotnet-example[1412]: System.InvalidOperationException: Cannot read keys when either application does not have a console or when console input has been redirected. Try Console.Read.
Nov 08 07:22:42 raspberrypi dotnet-example[1412]: at System.ConsolePal.ReadKey(Boolean intercept)
Nov 08 07:22:42 raspberrypi dotnet-example[1412]: at System.Console.ReadKey()
Nov 08 07:22:42 raspberrypi dotnet-example[1412]: at ConsoleApp1.Program.Main(String[] args) in C:\Users\mywatermelon\Desktop\ConsoleApp1\ConsoleApp1\Program.cs:line 57

It seems because it does not support console.Read. How can I solve this? Thank you.

ASP.NET Core
ASP.NET Core
A set of technologies in the .NET Framework for building web applications and XML web services.
4,157 questions
.NET CLI
.NET CLI
A cross-platform toolchain for developing, building, running, and publishing .NET applications.
322 questions
.NET Internet of things
.NET Internet of things
.NET: Microsoft Technologies based on the .NET software framework.Internet of things: A concept that aims to extend the benefits of the regular internet, including constant connectivity, remote control ability, and data sharing, to goods in the physical world.
28 questions
0 comments No comments
{count} votes

2 answers

Sort by: Most helpful
  1. AgaveJoe 26,191 Reputation points
    2021-11-05T12:11:43.457+00:00

    The design splits a message received on SP1 by a space. The code grabs the last element of the split string and sends it to SP2. Missing data is expected due to this design. Do not assume the serial port buffer always has one perfectly framed message in the receive buffer.

    On a side note, there is a loop executing on another thread every second effectively wasting clock cycles which does not make a lot of sense. Remove this code or explain the need for this code.

    You have not explained how the code is supposed to work but I assume SP1 (receiver) removes newlines from received messages then sends the processed messages to SP2 (sender).

    I would buffer the message in SP1 until there is a complete message or maybe the buffer reaches a certain size or maybe write messages to a stack. Write a loop or design an event that sends completed messages to SP2 for writing. Basically, your code is too simplistic to function in a production environment.

    1 person found this answer helpful.

  2. Sander van de Velde 28,311 Reputation points MVP
    2021-11-08T08:33:20.183+00:00

    Hello @melon NG ,

    as I understand, the code works fine now if your run it from the prompt.

    Then, the problem lays in the daemon.

    Can you check if your serial port access is successful?

    In general, in Linux access to serial ports needs elevated rights.