c# - 使用单声道时出现 Serial.IO.Ports 问题,适用于 dotnet core 3.1/arm/raspberry pi 4

标签 c# .net-core arm mono

在 Raspberry Pi 4 和串行 I/O 上使用单声道与 dotnet 时遇到一个奇怪的问题。 当使用 VS 2019 编译并使用 dotnet 运行它时,它按预期工作,但是当使用 mono 编译时,我从未收到任何数据。对于 dotnet,我还使用了dotnet add package System.IO.Ports

这是组成项目的两个文件:

using System;
using System.Text;
using SerialPortListener.Serial;

namespace radio
{
    class Program
    {
        private static SerialPortManager _spManager;

        static void Main(string[] args)
        {
            Console.WriteLine("Starting");

            _spManager = new SerialPortManager();
            _spManager.NewSerialDataRecieved += new EventHandler<SerialDataEventArgs>(_spManager_NewSerialDataRecieved);
            _spManager.StartListening();

            Console.WriteLine("Waiting here forever...");
            while (true) ;
        }

        static void _spManager_NewSerialDataRecieved(object sender, SerialDataEventArgs e)
        {
            string str = Encoding.ASCII.GetString(e.Data);
            Console.WriteLine(str);
        }
    }
}
using System;
using System.IO.Ports;

namespace SerialPortListener.Serial
{
    /// <summary>
    /// Manager for serial port data
    /// </summary>
    public class SerialPortManager : IDisposable
    {
        public SerialPortManager()
        {
        }

        ~SerialPortManager()
        {
            Dispose(false);
        }

        #region Fields
        private SerialPort _serialPort;
        public event EventHandler<SerialDataEventArgs> NewSerialDataRecieved;
        #endregion

        #region Event handlers
        void _serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            Console.WriteLine("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");

            int dataLength = _serialPort.BytesToRead;
            byte[] data = new byte[dataLength];
            int nbrDataRead = _serialPort.Read(data, 0, dataLength);
            if (nbrDataRead == 0)
                return;

            NewSerialDataRecieved?.Invoke(this, new SerialDataEventArgs(data));
        }

        #endregion

        #region Methods
        /// <summary>
        /// Connects to a serial port defined through the current settings
        /// </summary>
        public void StartListening()
        {
            if (_serialPort != null && _serialPort.IsOpen)
                _serialPort.Close();

            _serialPort = new SerialPort("/dev/ttyUSB0", 115200, Parity.None, 8, StopBits.One)
            {
                Handshake = Handshake.None,
                DtrEnable = false,
                RtsEnable = false,
                ReadTimeout = 400,
            };
            _serialPort.DataReceived += new SerialDataReceivedEventHandler(_serialPort_DataReceived);
            _serialPort.Open();
        }

        /// <summary>
        /// Closes the serial port
        /// </summary>n
        public void StopListening()
        {
            _serialPort.Close();
        }

        // Call to release serial port
        public void Dispose()
        {
            Dispose(true);
        }

        // Part of basic design pattern for implementing Dispose
        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                _serialPort.DataReceived -= new SerialDataReceivedEventHandler(_serialPort_DataReceived);
            }

            if (_serialPort != null)
            {
                if (_serialPort.IsOpen)
                    _serialPort.Close();

                _serialPort.Dispose();
            }
        }

        #endregion
    }

    /// <summary>
    /// EventArgs used to send bytes recieved on serial port
    /// </summary>
    public class SerialDataEventArgs : EventArgs
    {
        public SerialDataEventArgs(byte[] dataInByteArray)
        {
            Data = dataInByteArray;
        }

        /// <summary>
        /// Byte array containing data from serial port
        /// </summary>
        public byte[] Data;
    }
}

使用 mcs Program.cs SerialPortManager.csmono Program.exe 编译它,我明白了:

/dab/source/radio# mono Program.exe Starting Waiting here forever...

使用 dotnet radio.dll,它工作正常。这是一个小摘录:

/dab/empeg# dotnet radio.dll Starting Waiting here forever... AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
serial_notify_thread.cpp: 180:@@ #70008000 0:01:46
serial_notify_thread.cpp: 180:@@ #70008000 0:04:47
serial_notify_thread.cpp: 180:@@ #70008000 0:01:46
serial_notify_thread.cpp: 180:@@ #70008000 0:04:48
serial_notify_thread.cpp: 180:@@ # Poll wait Poll fail

AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

不确定我做错了什么,或者为什么它适用于 dotnet,而不是单声道。我需要使用单声道作为 dotnet 的任何想法在 Raspberry Pi Zero 上都不可用。

约翰

最佳答案

完整修复:

using System;
using System.Text;
using SerialPortListener.Serial;

namespace radio
{
    class Program
    {
        private static SerialPortManager _spManager;

        static void Main(string[] args)
        {
            Console.WriteLine("Starting");

            _spManager = new SerialPortManager();
            _spManager.NewSerialDataRecieved += new EventHandler<SerialDataEventArgs>(_spManager_NewSerialDataRecieved);
            _spManager.StartListening();

            Console.WriteLine("Waiting here forever...");
            while (true) ;
        }

        static void _spManager_NewSerialDataRecieved(object sender, SerialDataEventArgs e)
        {
            string str = Encoding.ASCII.GetString(e.Data);
            Console.WriteLine(str);
        }
    }
}
using System;
using System.IO.Ports;

namespace SerialPortListener.Serial
{
    /// <summary>
    /// Manager for serial port data
    /// </summary>
    public class SerialPortManager : IDisposable
    {
        public SerialPortManager()
        {
        }

        ~SerialPortManager()
        {
            Dispose(false);
        }

        #region Fields
        private EnhancedSerialPort _serialPort;
        public event EventHandler<SerialDataEventArgs> NewSerialDataRecieved;
        #endregion

        #region Event handlers
        void _serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            Console.WriteLine("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");

            int dataLength = _serialPort.BytesToRead;
            byte[] data = new byte[dataLength];
            int nbrDataRead = _serialPort.Read(data, 0, dataLength);
            if (nbrDataRead == 0)
                return;

            NewSerialDataRecieved?.Invoke(this, new SerialDataEventArgs(data));
        }

        #endregion

        #region Methods
        /// <summary>
        /// Connects to a serial port defined through the current settings
        /// </summary>
        public void StartListening()
        {
            if (_serialPort != null && _serialPort.IsOpen)
                _serialPort.Close();

            _serialPort = new EnhancedSerialPort("/dev/ttyUSB0", 115200, Parity.None, 8, StopBits.One)
            {
                ReadTimeout = 400,
            };
            _serialPort.DataReceived += new SerialDataReceivedEventHandler(_serialPort_DataReceived);
            _serialPort.Open();
        }

        /// <summary>
        /// Closes the serial port
        /// </summary>n
        public void StopListening()
        {
            _serialPort.Close();
        }

        // Call to release serial port
        public void Dispose()
        {
            Dispose(true);
        }

        // Part of basic design pattern for implementing Dispose
        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                _serialPort.DataReceived -= new SerialDataReceivedEventHandler(_serialPort_DataReceived);
            }

            if (_serialPort != null)
            {
                if (_serialPort.IsOpen)
                    _serialPort.Close();

                _serialPort.Dispose();
            }
        }

        #endregion
    }

    /// <summary>
    /// EventArgs used to send bytes recieved on serial port
    /// </summary>
    public class SerialDataEventArgs : EventArgs
    {
        public SerialDataEventArgs(byte[] dataInByteArray)
        {
            Data = dataInByteArray;
        }

        /// <summary>
        /// Byte array containing data from serial port
        /// </summary>
        public byte[] Data;
    }
}
// /*
// Copyright 2013 Antanas Veiverys www.veiverys.com
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// */
//
using System;
using System.IO.Ports;
using System.ComponentModel;
using System.IO;
using System.Runtime.InteropServices;
using System.Reflection;

namespace SerialPortListener.Serial
{
    public class EnhancedSerialPort : SerialPort
    {
        public EnhancedSerialPort() : base()
        {
        }

        public EnhancedSerialPort(IContainer container) : base(container)
        {
        }

        public EnhancedSerialPort(string portName) : base(portName)
        {
        }

        public EnhancedSerialPort(string portName, int baudRate) : base(portName, baudRate)
        {
        }

        public EnhancedSerialPort(string portName, int baudRate, Parity parity) : base(portName, baudRate, parity)
        {
        }

        public EnhancedSerialPort(string portName, int baudRate, Parity parity, int dataBits) : base(portName, baudRate, parity, dataBits)
        {
        }

        public EnhancedSerialPort(string portName, int baudRate, Parity parity, int dataBits, StopBits stopBits) : base(portName, baudRate, parity, dataBits, stopBits)
        {
        }

        // private member access via reflection
        int fd;
        FieldInfo disposedFieldInfo;
        object data_received;

        public new void Open()
        {
            base.Open();

            if (IsWindows == false)
            {
                FieldInfo fieldInfo = BaseStream.GetType().GetField("fd", BindingFlags.Instance | BindingFlags.NonPublic);
                fd = (int)fieldInfo.GetValue(BaseStream);
                disposedFieldInfo = BaseStream.GetType().GetField("disposed", BindingFlags.Instance | BindingFlags.NonPublic);
                fieldInfo = typeof(SerialPort).GetField("data_received", BindingFlags.Instance | BindingFlags.NonPublic);
                data_received = fieldInfo.GetValue(this);

                new System.Threading.Thread(new System.Threading.ThreadStart(this.EventThreadFunction)).Start();
            }
        }

        static bool IsWindows
        {
            get
            {
                PlatformID id = Environment.OSVersion.Platform;
                return id == PlatformID.Win32Windows || id == PlatformID.Win32NT; // WinCE not supported
            }
        }

        private void EventThreadFunction()
        {
            do
            {
                try
                {
                    var _stream = BaseStream;
                    if (_stream == null)
                    {
                        return;
                    }
                    if (Poll(_stream, ReadTimeout))
                    {
                        OnDataReceived(null);
                    }
                }
                catch
                {
                    return;
                }
            }
            while (IsOpen);
        }

        void OnDataReceived(SerialDataReceivedEventArgs args)
        {
            SerialDataReceivedEventHandler handler = (SerialDataReceivedEventHandler)Events[data_received];

            if (handler != null)
            {
                handler(this, args);
            }
        }

        [DllImport("MonoPosixHelper", SetLastError = true)]
        static extern bool poll_serial(int fd, out int error, int timeout);

        private bool Poll(Stream stream, int timeout)
        {
            CheckDisposed(stream);
            if (IsOpen == false)
            {
                throw new Exception("port is closed");
            }
            int error;

            bool poll_result = poll_serial(fd, out error, ReadTimeout);
            if (error == -1)
            {
                ThrowIOException();
            }
            return poll_result;
        }

        [DllImport("libc")]
        static extern IntPtr strerror(int errnum);

        static void ThrowIOException()
        {
            int errnum = Marshal.GetLastWin32Error();
            string error_message = Marshal.PtrToStringAnsi(strerror(errnum));

            throw new IOException(error_message);
        }

        void CheckDisposed(Stream stream)
        {
            bool disposed = (bool)disposedFieldInfo.GetValue(stream);
            if (disposed)
            {
                throw new ObjectDisposedException(stream.GetType().FullName);
            }
        }
    }
}

关于c# - 使用单声道时出现 Serial.IO.Ports 问题,适用于 dotnet core 3.1/arm/raspberry pi 4,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67177068/

相关文章:

c# - 什么时候int?和 Nullable<int> 是相同的,为什么它们的行为方式不同?

c# - Asp.Net (c#) - 读取 Excel 工作表

asp.net-core - 将 JwtBearerOptions 注入(inject) Controller

arm - 如何将 _mm_shuffle_ps SSE 内在函数转换为 NEON 内在函数?

c# - 费马素性检验

c# - 使用 MEF 忽略构造函数异常,而 Visual Studio 不会在异常处中断

c# - 在本地调试 C# AWS Lambda 函数

c# - 调用 Blazor 应用程序时,Postman 调用无限旋转

android - 尝试为 amrv6 编译 x264 时如何修复所选处理器不支持 `movw '?

c++ - 如何让 crosstool-ng C++ 编译器工作