forked from Ellerbach/serialapp
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSerialDevice.cs
More file actions
141 lines (113 loc) · 3.83 KB
/
Copy pathSerialDevice.cs
File metadata and controls
141 lines (113 loc) · 3.83 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
namespace serialapp
{
public class SerialDevice
{
public const int READING_BUFFER_SIZE = 1024;
private readonly CancellationTokenSource cts = new CancellationTokenSource();
private CancellationToken CancellationToken => cts.Token;
private int? fd;
private readonly IntPtr readingBuffer = Marshal.AllocHGlobal(READING_BUFFER_SIZE);
protected readonly string portName;
protected readonly BaudRate baudRate;
public event Action<object, byte[]> DataReceived;
public SerialDevice(string portName, BaudRate baudRate)
{
this.portName = portName;
this.baudRate = baudRate;
}
public void Open()
{
// open serial port
int fd = Libc.open(portName, Libc.OpenFlags.O_RDWR | Libc.OpenFlags.O_NONBLOCK);
if (fd == -1)
{
throw new Exception($"failed to open port ({portName})");
}
// set baud rate
byte[] termiosData = new byte[256];
Libc.tcgetattr(fd, termiosData);
Libc.cfsetspeed(termiosData, baudRate);
Libc.tcsetattr(fd, 0, termiosData);
// start reading
Task.Run((Action)StartReading, CancellationToken);
this.fd = fd;
}
private void StartReading()
{
if (!fd.HasValue)
{
throw new Exception();
}
while (true)
{
CancellationToken.ThrowIfCancellationRequested();
int res = Libc.read(fd.Value, readingBuffer, READING_BUFFER_SIZE);
if (res != -1)
{
byte[] buf = new byte[res];
Marshal.Copy(readingBuffer, buf, 0, res);
OnDataReceived(buf);
}
Thread.Sleep(50);
}
}
protected virtual void OnDataReceived(byte[] data)
{
DataReceived?.Invoke(this, data);
}
public bool IsOpened => fd.HasValue;
public void Close()
{
if (!fd.HasValue)
{
throw new Exception();
}
cts.Cancel();
Libc.close(fd.Value);
Marshal.FreeHGlobal(readingBuffer);
}
public void Write(byte[] buf)
{
if (!fd.HasValue)
{
throw new Exception();
}
IntPtr ptr = Marshal.AllocHGlobal(buf.Length);
Marshal.Copy(buf, 0, ptr, buf.Length);
Libc.write(fd.Value, ptr, buf.Length);
Marshal.FreeHGlobal(ptr);
}
public static string[] GetPortNames()
{
int p = (int)Environment.OSVersion.Platform;
List<string> serial_ports = new List<string>();
// Are we on Unix?
if (p == 4 || p == 128 || p == 6)
{
string[] ttys = System.IO.Directory.GetFiles("/dev/", "tty*");
foreach (string dev in ttys)
{
//Arduino MEGAs show up as ttyACM due to their different USB<->RS232 chips
if (dev.StartsWith("/dev/ttyS") || dev.StartsWith("/dev/ttyUSB") || dev.StartsWith("/dev/ttyACM") || dev.StartsWith("/dev/ttyAMA"))
{
serial_ports.Add(dev);
//Console.WriteLine("Serial list: {0}", dev);
}
}
}
return serial_ports.ToArray();
}
public void Dispose()
{
if (IsOpened)
{
Close();
}
}
}
}