public class WinSerialPort : IDisposable
{
#region Win32 API宣言
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr CreateFile(
string lpFileName, // ファイル名
DesiredAccess dwDesiredAccess, // アクセスモード
ShareMode dwShareMode, // 共有モード
int lpSecurityAttributes, // セキュリティ記述子
CreationDisposition dwCreationDisposition, // 作成方法
FlagsAndAttributes dwFlagsAndAttributes, // ファイル属性
IntPtr hTemplateFile // テンプレートファイルのハンドル
);
[DllImport("kernel32.dll", SetLastError = true)]
public static extern bool CloseHandle(IntPtr hObject);
[DllImport("kernel32.dll")]
static extern bool GetCommState(IntPtr hFile, ref DCB lpDCB);
[DllImport("kernel32.dll")]
static extern bool SetCommState(IntPtr hFile, ref DCB lpDCB);
[DllImport("kernel32.dll", SetLastError = true)]
//static extern bool ReadFile(IntPtr hFile, [Out] byte[] lpBuffer, uint nNumberOfBytesToRead, out uint lpNumberOfBytesRead, IntPtr lpOverlapped);
static extern bool ReadFile(IntPtr hFile, [Out] byte[] lpBuffer, uint nNumberOfBytesToRead, out uint lpNumberOfBytesRead, int lpOverlapped);
[DllImport("kernel32.dll")]
//static extern bool WriteFile(IntPtr hFile, byte[] lpBuffer, uint nNumberOfBytesToWrite, out uint lpNumberOfBytesWritten, [In] ref NativeOverlapped lpOverlapped);
static extern bool WriteFile(IntPtr hFile, byte[] lpBuffer, uint nNumberOfBytesToWrite, out uint lpNumberOfBytesWritten, int lpOverlapped);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool GetCommTimeouts(IntPtr hFile, ref COMMTIMEOUTS lpCommTimeouts);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool SetCommTimeouts(IntPtr hFile, [In] ref COMMTIMEOUTS lpCommTimeouts);
[DllImport("kernel32.dll")]
static extern bool PurgeComm(IntPtr hFile, Purge dwFlags);
#endregion
#region 列挙体
private enum DesiredAccess : uint
{
GENERIC_READ = 0x80000000,
GENERIC_WRITE = 0x40000000,
GENERIC_EXECUTE = 0x20000000
}
private enum ShareMode : uint
{
FILE_SHARE_READ = 0x00000001,
FILE_SHARE_WRITE = 0x00000002,
FILE_SHARE_DELETE = 0x00000004
}
private enum CreationDisposition : uint
{
CREATE_NEW = 1,
CREATE_ALWAYS = 2,
OPEN_EXISTING = 3,
OPEN_ALWAYS = 4,
TRUNCATE_EXISTING = 5
}
private enum FlagsAndAttributes : uint
{
FILE_ATTRIBUTE_ARCHIVE = 0x00000020,
FILE_ATTRIBUTE_ENCRYPTED = 0x00004000,
FILE_ATTRIBUTE_HIDDEN = 0x00000002,
FILE_ATTRIBUTE_NORMAL = 0x00000080,
FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x00002000,
FILE_ATTRIBUTE_OFFLINE = 0x00001000,
FILE_ATTRIBUTE_READONLY = 0x00000001,
FILE_ATTRIBUTE_SYSTEM = 0x00000004,
FILE_ATTRIBUTE_TEMPORARY = 0x00000100
}
public enum DtrControl : int
{
/// <summary>
/// Disables the DTR line when the device is opened and leaves it disabled.
/// </summary>
Disable = 0,
/// <summary>
/// Enables the DTR line when the device is opened and leaves it on.
/// </summary>
Enable = 1,
/// <summary>
/// Enables DTR handshaking. If handshaking is enabled, it is an error for the application to adjust the line by
/// using the EscapeCommFunction function.
/// </summary>
Handshake = 2
}
public enum RtsControl : int
{
/// <summary>
/// Disables the RTS line when the device is opened and leaves it disabled.
/// </summary>
Disable = 0,
/// <summary>
/// Enables the RTS line when the device is opened and leaves it on.
/// </summary>
Enable = 1,
/// <summary>
/// Enables RTS handshaking. The driver raises the RTS line when the "type-ahead" (input) buffer
/// is less than one-half full and lowers the RTS line when the buffer is more than
/// three-quarters full. If handshaking is enabled, it is an error for the application to
/// adjust the line by using the EscapeCommFunction function.
/// </summary>
Handshake = 2,
/// <summary>
/// Specifies that the RTS line will be high if bytes are available for transmission. After
/// all buffered bytes have been sent, the RTS line will be low.
/// </summary>
Toggle = 3
}
public enum Purge : uint
{
TxAbort = 1,
ExAbort = 2,
TxClear = 4,
RxClear = 8,
}
#endregion
#region "構造体"
struct COMMTIMEOUTS
{
public UInt32 ReadIntervalTimeout;
public UInt32 ReadTotalTimeoutMultiplier;
public UInt32 ReadTotalTimeoutConstant;
public UInt32 WriteTotalTimeoutMultiplier;
public UInt32 WriteTotalTimeoutConstant;
}
#endregion
#region "DCB構造体"
[StructLayout(LayoutKind.Sequential)]
internal struct DCB
{
internal uint DCBLength;
internal uint BaudRate;
private BitVector32 Flags;
private ushort wReserved; // not currently used
internal ushort XonLim; // transmit XON threshold
internal ushort XoffLim; // transmit XOFF threshold
internal byte ByteSize;
internal Parity Parity;
internal StopBits StopBits;
internal sbyte XonChar; // Tx and Rx XON character
internal sbyte XoffChar; // Tx and Rx XOFF character
internal sbyte ErrorChar; // error replacement character
internal sbyte EofChar; // end of input character
internal sbyte EvtChar; // received event character
private ushort wReserved1; // reserved; do not use
private static readonly int fBinary;
private static readonly int fParity;
private static readonly int fOutxCtsFlow;
private static readonly int fOutxDsrFlow;
private static readonly BitVector32.Section fDtrControl;
private static readonly int fDsrSensitivity;
private static readonly int fTXContinueOnXoff;
private static readonly int fOutX;
private static readonly int fInX;
private static readonly int fErrorChar;
private static readonly int fNull;
private static readonly BitVector32.Section fRtsControl;
private static readonly int fAbortOnError;
static DCB()
{
// Create Boolean Mask
int previousMask;
fBinary = BitVector32.CreateMask();
fParity = BitVector32.CreateMask(fBinary);
fOutxCtsFlow = BitVector32.CreateMask(fParity);
fOutxDsrFlow = BitVector32.CreateMask(fOutxCtsFlow);
previousMask = BitVector32.CreateMask(fOutxDsrFlow);
previousMask = BitVector32.CreateMask(previousMask);
fDsrSensitivity = BitVector32.CreateMask(previousMask);
fTXContinueOnXoff = BitVector32.CreateMask(fDsrSensitivity);
fOutX = BitVector32.CreateMask(fTXContinueOnXoff);
fInX = BitVector32.CreateMask(fOutX);
fErrorChar = BitVector32.CreateMask(fInX);
fNull = BitVector32.CreateMask(fErrorChar);
previousMask = BitVector32.CreateMask(fNull);
previousMask = BitVector32.CreateMask(previousMask);
fAbortOnError = BitVector32.CreateMask(previousMask);
// Create section Mask
BitVector32.Section previousSection;
previousSection = BitVector32.CreateSection(1);
previousSection = BitVector32.CreateSection(1, previousSection);
previousSection = BitVector32.CreateSection(1, previousSection);
previousSection = BitVector32.CreateSection(1, previousSection);
fDtrControl = BitVector32.CreateSection(2, previousSection);
previousSection = BitVector32.CreateSection(1, fDtrControl);
previousSection = BitVector32.CreateSection(1, previousSection);
previousSection = BitVector32.CreateSection(1, previousSection);
previousSection = BitVector32.CreateSection(1, previousSection);
previousSection = BitVector32.CreateSection(1, previousSection);
previousSection = BitVector32.CreateSection(1, previousSection);
fRtsControl = BitVector32.CreateSection(3, previousSection);
previousSection = BitVector32.CreateSection(1, fRtsControl);
}
public bool Binary
{
get { return Flags[fBinary]; }
set { Flags[fBinary] = value; }
}
public bool CheckParity
{
get { return Flags[fParity]; }
set { Flags[fParity] = value; }
}
public bool OutxCtsFlow
{
get { return Flags[fOutxCtsFlow]; }
set { Flags[fOutxCtsFlow] = value; }
}
public bool OutxDsrFlow
{
get { return Flags[fOutxDsrFlow]; }
set { Flags[fOutxDsrFlow] = value; }
}
public DtrControl DtrControl
{
get { return (DtrControl)Flags[fDtrControl]; }
set { Flags[fDtrControl] = (int)value; }
}
public bool DsrSensitivity
{
get { return Flags[fDsrSensitivity]; }
set { Flags[fDsrSensitivity] = value; }
}
public bool TxContinueOnXoff
{
get { return Flags[fTXContinueOnXoff]; }
set { Flags[fTXContinueOnXoff] = value; }
}
public bool OutX
{
get { return Flags[fOutX]; }
set { Flags[fOutX] = value; }
}
public bool InX
{
get { return Flags[fInX]; }
set { Flags[fInX] = value; }
}
public bool ReplaceErrorChar
{
get { return Flags[fErrorChar]; }
set { Flags[fErrorChar] = value; }
}
public bool Null
{
get { return Flags[fNull]; }
set { Flags[fNull] = value; }
}
public RtsControl RtsControl
{
get { return (RtsControl)Flags[fRtsControl]; }
set { Flags[fRtsControl] = (int)value; }
}
public bool AbortOnError
{
get { return Flags[fAbortOnError]; }
set { Flags[fAbortOnError] = value; }
}
}
#endregion
IntPtr port { get; set; }
string portName { get; }
uint baudRate { get; }
Parity parity { get; }
byte dataBits { get; }
StopBits stopBits { get; }
byte[] recvBuffer { get; } = new byte[1];
public WinSerialPort(string portName, uint baudRate, Parity parity, byte dataBits, StopBits stopBits)
{
this.portName = portName;
this.baudRate = baudRate;
this.parity = parity;
this.dataBits = dataBits;
this.stopBits = stopBits;
}
public bool Open()
{
port = CreateFile(portName, DesiredAccess.GENERIC_READ | DesiredAccess.GENERIC_WRITE, 0, 0, CreationDisposition.OPEN_EXISTING, FlagsAndAttributes.FILE_ATTRIBUTE_NORMAL, IntPtr.Zero);
//ポートオープン
if (0 >= port.ToInt32())
return false;
//通信設定
var dcb = new DCB();
if (!GetCommState(port, ref dcb))
return false;
dcb.RtsControl = RtsControl.Enable;
dcb.DtrControl = DtrControl.Enable;
dcb.BaudRate = 250 * 1000;
dcb.ByteSize = 8;
dcb.Parity = parity;
dcb.StopBits = stopBits;
dcb.Binary = true;
dcb.CheckParity = true;
if (!SetCommState(port, ref dcb))
return false;
//タイムアウト設定
var Commtimeouts = new COMMTIMEOUTS();
if (!GetCommTimeouts(port, ref Commtimeouts))
return false;
Commtimeouts.ReadIntervalTimeout = 100;
if (!SetCommTimeouts(port, ref Commtimeouts))
return false;
return true;
}
public void Close()
{
CloseHandle(port);
port = IntPtr.Zero;
}
public void Write(byte[] buffer, uint offset, uint size)
{
uint writen = 0;
WriteFile(port, buffer, (uint)size, out writen, 0);
}
public int ReadByte()
{
uint recved = 0;
if (ReadFile(port, recvBuffer, 1, out recved, 0))
{
if (0 < recved)
{
return recvBuffer[0];
}
}
return -1;
}
public void DiscardInBuffer()
{
PurgeComm(port, Purge.RxClear);
}
public void DiscardOutBuffer()
{
PurgeComm(port, Purge.TxClear);
}
public void Dispose()
{
if (port != IntPtr.Zero)
{
Close();
}
}
}
インターネット上にある断片化された情報を切り取って、リブログする。 主にソフトウェア、Ubuntu関連、CPUなど気になったニュース、また、日々の面白い出来事やニュースもリブログします。
2016年1月21日木曜日
[C#]WinAPIを用いたシリアル通信
シリアル通信の機能をフル活用したい場合にどうぞ
登録:
コメントの投稿 (Atom)
0 件のコメント:
コメントを投稿