Попробуйте и жду Ваш отзыв о функционировании.
Пользователь решил продолжить мысль 24 Сентября 2009, 16:23:36:
Добавил событие по приему буфера и проверил с модбасовским контроллером. Упростил встраивавание.
// Main.cs created with MonoDevelop
// User: pronin-ae at 10:00 14.09.2009
//
//
using System;
//using System.ComponentModel;
using System.IO;
using System.Collections;
using System.IO.Ports;
using System.Threading;
namespace ModbusComponent
{
public delegate void ModbusDataReceved(byte[] buf);
// Modbus functions
enum FunctionModbus : byte{
// ReadCoilStatus=1,
// ReadInputStatus=2,
// ForceSingleCoil=5,
LoopBackDiagnosticTest=8, //echo function: 01 08 0000 1234 (ED7C)
// ForceMultipleCoils=15,
// ReportSlaveID =17,
UserFunction=65
};
// pages of user Modbus functions 65
enum UnderFunctionModbus : byte {
// ReadCurrent=0,
// ReadUstavki=1,
// ReadSrab=2,
// BreakerInfo =3,
// ReadPNU=5,
// Write_Value_PNU=6,
// Write_PUSK_PNU=7,
// Write_STOP_PNU=8,
// InfoBreak =20,
// ReadIOStatus =24,
Empty=255
};
//----------------------------
public class mbEvent
{
public event ModbusDataReceved FlagEvent;
public void OnFlagEvent(byte[] buffer)
{
if(FlagEvent!=null) FlagEvent(buffer);
}
}
//----------------------------
public class Modbus//:Component
{
public mbEvent evt = new mbEvent();
// портовые настройки
System.IO.Ports.SerialPort SPort1;
string Name="/dev/ttyUSB0";
int BaudRate=9600;
int DataBits=8;
StopBits stopBits=StopBits.One;
int readBufferSize=1024;
int writeBufferSize=1024;
int readTimeout=20;
int writeTimeout=20;
// модбасовские настройки
const ushort MagicValue= ((ushort)0xa001);
byte MySlaveAddress=1;
bool master=true;
public bool Master {
get {return (master);}
set {master=value;}
}
ushort KS_in;
ushort KS_out;
public byte[] rb;
byte[] wb;
int Pointer_in=0;
int Pointer_out=0;
bool stop;
public bool Stop {
get {return (stop);}
set {stop=value;}
}
Thread Thr;
// конструктор
public Modbus()
{
ConfigParse();
Console.WriteLine("Parameters of Port: Name={0}, BR={1}, bits={2}, rdBuf={3}, wrBuf={4}",Name,BaudRate,DataBits,readBufferSize,writeBufferSize);
Console.WriteLine("Parameters of ModBus: SL={0}, Master={1}",MySlaveAddress,Master);
SPort1 =new System.IO.Ports.SerialPort(this.Name);
SPort1.BaudRate=this.BaudRate;
SPort1.StopBits=this.stopBits;
SPort1.DataBits=this.DataBits;
SPort1.ReadTimeout=this.readTimeout;
SPort1.WriteTimeout=this.writeTimeout;
SPort1.ReadBufferSize=this.readBufferSize;
SPort1.WriteBufferSize=this.writeBufferSize;
rb = new byte[this.readBufferSize+1] ;
wb = new byte[this.writeBufferSize+1] ;
try {
SPort1.Open();
}
catch (IOException) {
Console.WriteLine("Error Opening of Port");
return;
}
Console.WriteLine("Serial Port opened");
Thr = new Thread(Receve); // готовим поток на прием
string strName;
if(Master) strName="Master";
else strName="Slave";
Thr.Name = "Receve"+strName;
Thr.Start();
}
// Парсим конфигурационный файл Modbus.cnf
void ConfigParse()
{
string str;
FileStream fin;
try {
fin= new FileStream("Modbus.cnf",FileMode.Open);
}
catch(FileNotFoundException) {
Console.WriteLine("File Modbus.cnf not found");
return;
}
StreamReader str_fin = new StreamReader(fin);
while((str=str_fin.ReadLine()) != null)
{
str = str.Trim(); // удаляем пробелы в начале и конце строки
if((str.Length>0) && (str[0]!='#')) // удаляем строки комментариев
{
char [] sep = {' ','=','\t',';'}; // разбиваем строку на части
string[] pars;
pars = str.Split(sep);
// удаляем пустые строки через коллекцию
ArrayList al=new ArrayList();
for(int i=0; i<pars.Length;i++)
al.Add(pars
);
M1:
foreach(string s in al) {
if(s.Length==0) {
al.Remove(s);
goto M1; // C# позволяет делать такую чушь без последствий
}
}
// Console.WriteLine("{0} {1}",al[0],al[1]);
switch ((string)al[0]){
case "PortName":
Name=(string)al[1];
break;
case "DataBits":
try {
DataBits=Int32.Parse((string)al[1]);
}
catch (FormatException) {
Console.WriteLine("Error DataBits");
}
catch (OverflowException) {
Console.WriteLine("Error DataBits");
}
break;
case "BaudRate":
try {
BaudRate=Int32.Parse((string)al[1]);
}
catch (FormatException) {
Console.WriteLine("Error BaudRate");
}
catch (OverflowException) {
Console.WriteLine("Error BaudRate");
}
break;
case "readBufferSize":
try {
readBufferSize=Int32.Parse((string)al[1]);
}
catch (FormatException) {
Console.WriteLine("Error readBufferSize");
}
catch (OverflowException) {
Console.WriteLine("Error readBufferSize");
}
break;
case "writeBufferSize":
try {
writeBufferSize=Int32.Parse((string)al[1]);
}
catch (FormatException) {
Console.WriteLine("Error writeBufferSize");
}
catch (OverflowException) {
Console.WriteLine("Error writeBufferSize");
}
break;
case "MySlaveAddress":
try {
MySlaveAddress=Byte.Parse((string)al[1]);
}
catch (FormatException) {
Console.WriteLine("Error MySlaveAddress");
}
catch (OverflowException) {
Console.WriteLine("Error MySlaveAddress");
}
break;
case "Master":
try {
Master=Boolean.Parse((string)al[1]);
}
catch (FormatException) {
Console.WriteLine("Error Master");
}
catch (OverflowException) {
Console.WriteLine("Error Master");
}
break;
default:
break;
}
}
}
str_fin.Close();
}
// деструктор
~Modbus()
{
if(SPort1.IsOpen) {
SPort1.Close();
Console.WriteLine("Serial Port closed");
Thr.Abort();
Console.WriteLine("Thread aborted");
}
// Dispose(false);
}
// Расчет CRC
ushort CalcCRC16(ushort CRC16, byte a)
{
ushort temp=CRC16;
// temp=XOR(temp,(ushort)a);
temp ^= a;
for (int i=0;i<8;i++) {
if((temp&1)!=0) {
temp/=2;
temp^=MagicValue;
}
else temp/=2;
}
return temp;
}
// запись байта в буфер с подсчетом КС
void WriteChar(byte ch) {
wb[Pointer_out++]=ch;
KS_out=CalcCRC16(KS_out, ch);
}
// прием данных в потоке
public void Receve()
{
Pointer_in=0;
int Bytes=0;
Console.WriteLine("Receve Thread");
if(!SPort1.IsOpen)
{
Console.WriteLine("Serial Port not opened");
return;
}
while(!Stop) {
if(Bytes==0) Thread.Sleep(5);
try {
Bytes=0;
Bytes=SPort1.Read(rb,0,this.readBufferSize);
Pointer_in += Bytes;
}
catch(TimeoutException) {
if((Pointer_in!=0)&&((rb[0]==MySlaveAddress)&&(!Master))|Master){
// Обработка принятых данных по таймауту если
// что-то приняли сейчас
// для кс==0 и
//Для мастера - принимается все
//Для слейва - если SL его
// Console.WriteLine("Read Timeout. Receve All {0} Current {1}",Pointer_in,Bytes);
KS_in=0xffff;
for(int i=0;i<Pointer_in;i++) {
KS_in=CalcCRC16(KS_in, rb);
}
if(KS_in==0) {
// Console.WriteLine("KS is OK");
if(!Master) {
Console.WriteLine("Answer for Slave");
byte SL=MySlaveAddress;
byte Func=(byte)FunctionModbus.LoopBackDiagnosticTest;
byte Page=(byte)UnderFunctionModbus.Empty;
Send(SL,Func,Page);
}
else {
// здесь можно инициировать событие по приему для мастера
evt.OnFlagEvent(rb);
// Console.WriteLine("Receve (only) for Master");
// Console.WriteLine("\n Answer (echo) from SL={0}",rb[0]);
Pointer_in=0;
}
}
else {Console.WriteLine("KS is bad");}
Pointer_in=0;
}
}
catch(IOException) {
Console.WriteLine("IOException error.");
Stop=true;
}
}
Console.WriteLine("Поток для приема данных закрыт");
}
// передача данных
public void Send(byte SL, byte Func, byte Page) {
// Console.WriteLine("Data send");
try {
if(SPort1.IsOpen) {
KS_out=0xffff;
Pointer_out=0;
WriteChar(SL);
WriteChar(Func);
switch((FunctionModbus) Func) {
case FunctionModbus.LoopBackDiagnosticTest:
WriteChar(0);
WriteChar(0);
WriteChar(0x12);
WriteChar(0x34);
break;
case FunctionModbus.UserFunction:
WriteChar(Page);
break;
default:
break;
}
//CRC16
wb[Pointer_out++]=(byte)KS_out;
wb[Pointer_out++]=(byte)(KS_out>>
;
SPort1.Write(wb,0,Pointer_out);
}
else {
Console.WriteLine("Serial Port not opened");
}
}
catch(TimeoutException) {
Console.WriteLine("Write Timeout");
}
// Console.WriteLine("Data sended");
}
}
//-------------------------------------------------------------------
// временный тестовый класс для мастера и слайва
class Demo
{
void handler1(byte[] buf)
{
Console.WriteLine("\nСлучилось событие по приему буфера мастером SL={0}",buf[0]);
}
public static void Main()
{
Demo d = new Demo();
d.Run();
}
public void Run()
{
Modbus mb = new Modbus();
mb.evt.FlagEvent+= new ModbusDataReceved(handler1); // добавим событие по приему буфера для мастера
byte SL;
byte Func;
byte Page;
Console.WriteLine(@"
----------------
0 - Device scaning (echo test)
Enter - exit
----------------");
string str = Console.ReadLine();
if(str=="0") {
if(mb.Master) // мастер
{
for (byte i=1;i<255;i++)
{
SL=i;
Func=(byte)FunctionModbus.LoopBackDiagnosticTest;
Page=(byte)UnderFunctionModbus.Empty;
mb.Send(SL,Func,Page); // запрос
// Console.Write("SL={0} ",SL);
Console.Write(".");
Thread.Sleep(50);
}
}
}
// Console.ReadLine();
mb.Stop=true;
Console.WriteLine("End");
}
}
//-------------------------------------------------------------------
}