private void BroadcastTimer_Elapsed(object sender, ElapsedEventArgs e)
 {
     TxRxStatus             = TranmitingStatus.Idle;
     BroadcastTimer.Enabled = false;
     Console.Write("Broadcasting done!");
     IsBroadcastTimeout = true;
 }
 private void ACKTimer_Elapsed(object sender, ElapsedEventArgs e)
 {
     TxRxStatus       = TranmitingStatus.Idle;
     ACKTimer.Enabled = false;
     Console.Write("NO ACK!");
     IsACKTimeout = true;
 }
        public void ModbusReceiveData_SerialPort(object sender, SerialDataReceivedEventArgs e) //供外部SerialPort调用的数据接收事件
        {
            RxDataTimer.Enabled = false;                                                       //定时器停止计数并将计数值归零
            RxDataTimer.Enabled = true;                                                        //定时器重新开始计数
            TxRxStatus          = TranmitingStatus.Receiving;                                  //Modbus状态为标记为“接收中”
            UInt16 n = (UInt16)((SerialPort)sender).BytesToRead;                               //先记录下来,避免某种原因,人为的原因,操作几次之间时间长,缓存不一致

            ((SerialPort)sender).Read(TxRxBuffer, Pointer, n);                                 //读取缓冲数据
            Pointer += n;                                                                      //增加接收计数
            RxLength = Pointer;
        }
        public byte Disassemble_ReceivedADU()
        {
            if (IsMaster == true)
            {
                if (StationID != TxRxBuffer[0]) //站号错误不进行任何处理,立即返回(ACKTimeout定时器继续定时)
                {
                    return((byte)ErrorStatus.ERR_Station);
                }

                ACKTimer.Enabled = false;                 //通过上面站号检测的说明是期望子节点发送来的响应帧,因而停止ACKTimeout倒计时。
                TxRxStatus       = TranmitingStatus.Idle; //总线状态置为空闲,允许发送其他帧(会不会放在本函数最后好,不然要是Modbus发送了其他的帧,并接收了返回的帧,上一次此处的处理还未完成怎么办?)

                if (RxLength < 5)
                {
                    return((byte)ErrorStatus.ERR_BreakFrame);
                }

                TempWord.HByte = TxRxBuffer[RxLength - 2];
                TempWord.LByte = TxRxBuffer[RxLength - 1];
                if (TempWord.Word != CRCCaculation.CRC16(TxRxBuffer, (UInt16)(RxLength - 2)))
                {
                    return((byte)ErrorStatus.ERR_CRCCode); //检测CRC是否错误
                }
                FunctionCode = TxRxBuffer[1];              //记录功能码
                switch (FunctionCode)
                {
                case (byte)ModbusFuncCode.WriteSingleCoil:
                case (byte)ModbusFuncCode.WriteCoils:
                case (byte)ModbusFuncCode.WriteRegs:
                case (byte)ModbusFuncCode.WriteSingleReg:
                    TempWord.HByte = TxRxBuffer[2];    //检查地址是否正确
                    TempWord.LByte = TxRxBuffer[3];
                    if (TempWord.Word != Address)
                    {
                        return((byte)ErrorStatus.ERR_Address);
                    }
                    TempWord.HByte = TxRxBuffer[4];    //检查写入单元数量或写入的单个数据是否正确
                    TempWord.LByte = TxRxBuffer[5];
                    if (TempWord.Word != NumOrData)
                    {
                        return((byte)ErrorStatus.ERR_NumOrData);
                    }

                    ModbusWriteSuccessEvent();        //(事件引发)如果以上均正确,说明Modbus主向外写操作成功,引发“写成功”事件

                    break;

                case (byte)ModbusFuncCode.ReadCoils:
                case (byte)ModbusFuncCode.ReadDistrbuteBits:
                case (byte)ModbusFuncCode.ReadStorageRegs:
                case (byte)ModbusFuncCode.ReadInputRegs:
                    DataByteNumber = TxRxBuffer[2];
                    DataStorage[TempControlIndex] = new byte[DataByteNumber];
                    for (byte i = 0; i < DataByteNumber; i++)
                    {
                        DataStorage[TempControlIndex][i] = TxRxBuffer[i + 3];
                    }

                    ModbusReadSuccessEvent();        //(事件引发)如果以上均正确,说明Modbus主读输入寄存器成功,引发“读输入寄存器成功”事件
                    break;


                case ((byte)ModbusFuncCode.ReadCoils + 0x80):
                case ((byte)ModbusFuncCode.ReadDistrbuteBits + 0x80):
                case ((byte)ModbusFuncCode.ReadStorageRegs + 0x80):
                case ((byte)ModbusFuncCode.ReadInputRegs + 0x80):
                case ((byte)ModbusFuncCode.WriteSingleCoil + 0x80):
                case ((byte)ModbusFuncCode.WriteSingleReg + 0x80):
                case ((byte)ModbusFuncCode.WriteCoils + 0x80):
                case ((byte)ModbusFuncCode.WriteRegs + 0x80):

                    ModbusReceiveExceptionEvent();    //(事件引发)接收到异常帧
                    return((byte)ErrorStatus.ERR_Response);

                default:
                    return((byte)ErrorStatus.ERR_FunctionCode);   //检测FunctionCode是否错误
                }
            }
            else
            {
                //Slaver To Do...
            }
            return((byte)ErrorStatus.ERR_OK);
        }
        private Boolean MasterSendFrame()
        {
            byte[] TxBuffer;
            Console.Write(TxRxStatus + "\n");
            if (TxRxStatus == TranmitingStatus.Idle)
            {
                if ((HighPriorityFrameRdy == true) || (LowPriorityFrameRdy == true))
                {
                    Console.Write(LowPriorityTxBufferQueue.Count + " " + LPControlsIndexQueue.Count + "\n");

                    if (HighPriorityFrameRdy == true)
                    {
                        if (HighPriorityTxBufferQueue.Count <= 0)//如过FIFO空,则复位Ready标志位,禁止周期行为
                        {
                            HighPriorityFrameRdy = false;
                            return(true);
                        }
                        lock (HighPriorityTxBufferQueue)//锁定,防止线程间串扰(非常重要)
                        {
                            lock (HPControlsIndexQueue)
                            {
                                TxBuffer         = HighPriorityTxBufferQueue.Dequeue(); //从FIFO中取用待发送的帧
                                TempControlIndex = HPControlsIndexQueue.Dequeue();      //取用待发送帧对应的控件的索引
                            }
                        }
                    }
                    else
                    {
                        if (LowPriorityTxBufferQueue.Count <= 0)
                        {
                            LowPriorityFrameRdy = false;
                            return(true);
                        }
                        lock (LowPriorityTxBufferQueue)
                        {
                            lock (LPControlsIndexQueue)
                            {
                                TxBuffer         = LowPriorityTxBufferQueue.Dequeue();
                                TempControlIndex = LPControlsIndexQueue.Dequeue();
                            }
                        }
                    }

                    //Console.Write(TxBuffer.Length);
                    try                                                //此处不能用if语句简化
                    {
                        ModbusSendFrame(TxBuffer, 0, TxBuffer.Length); //调用发送函数(委托)
                    }
                    catch
                    {
                        Console.Write("Error:ModbusSendFrame未关联 或 Serialport未打开!\n");
                        return(false);
                    }

                    TxRxStatus = TranmitingStatus.Sending; //Modbus收发标志位置 “发送中”

                    if (TxBuffer[0] == 0)                  //此处用到StationID,说明全局的StationID变量是必要的,不可弃用
                    {
                        IsBroadcastTimeout     = false;    //如果是广播帧,先清广播帧超时标志位(其实没必要,只是为了以防不可预知的改变)
                        BroadcastTimer.Enabled = true;     //打开广播帧超时定时器
                    }
                    else
                    {
                        IsACKTimeout     = false;
                        ACKTimer.Enabled = true;
                    }
                }
            }

            return(true);
        }
 private void ModbusRTU_ModbusReadSuccessEvent()
 {
     DataStorageFlag[TempControlIndex] = true;
     TxRxStatus = TranmitingStatus.Idle;
 }