在 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.cs 和 mono 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 failAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
不确定我做错了什么,或者为什么它适用于 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/