Java 如何通过com终端将数据输出到应用程序?

Java 如何通过com终端将数据输出到应用程序?,java,processing,control-p5,com-port,Java,Processing,Control P5,Com Port,下午好,我正在使用一个使用RS-232连接的测试草图。我需要了解如何以及在com终端中键入什么命令,以便在文本变量列表附近获取和查看此草图的应用程序窗口中的数据,我附上了一个屏幕截图。我对这项业务完全陌生,请告诉我解决方案 这是调试所必需的,有时是配置所必需的。 我附上了草图和代码,你可以检查一下。 如果安装了应用程序,则草图工作正常 com0com.exe,并且com端口通过终端打开。 代码的含义是向COM端口发送一系列字节,并在屏幕上显示应用程序中变量的数据(数字) Com_接口: imp

下午好,我正在使用一个使用RS-232连接的测试草图。我需要了解如何以及在com终端中键入什么命令,以便在文本变量列表附近获取和查看此草图的应用程序窗口中的数据,我附上了一个屏幕截图。我对这项业务完全陌生,请告诉我解决方案

这是调试所必需的,有时是配置所必需的。 我附上了草图和代码,你可以检查一下。 如果安装了应用程序,则草图工作正常 com0com.exe,并且com端口通过终端打开。 代码的含义是向COM端口发送一系列字节,并在屏幕上显示应用程序中变量的数据(数字)

Com_接口:

import processing.serial.*;
import controlP5.*;

ControlP5 cp5;
DropdownList serialPortsList;


Textlabel tempIn;
Textlabel tempOut;
Textlabel timeIn;
Textlabel timeInC;
Textlabel Vin;
Textlabel I;
Textlabel PitETH;
Textlabel PitUSB;
Textlabel PitGSM;
Textlabel PitPI;
Textlabel PitETH2;
Textlabel PitUSB2;
Textlabel PitGSM2;
Textlabel PitPI2;
Textlabel Vent;
Textlabel ResetAll;
Textlabel Accele;
Textarea accel;
Button lalal;
Button PitPIb;
Button PitETHb;
Button PitUSBb;
Button PitGSMb;
Button Ventb;
Button resetb;
Group lal;

boolean strat=false;
boolean Vents=false;
boolean resets=false;
boolean PitETHs=false;
boolean PitUSBs=false;
boolean PitGSMs=false;
boolean PitPIs=false;


Serial serialPort;
final int BAUD_RATE = 19200;

char parity = 'N';
int dataBits = 8;
float stopBits = 1.0;

ModbusPort port_one; // create a Modbus port instance
int timeout = 500;
int polling = 100;
int no_of_retries = 10;
int total_no_of_packets = 3;
Packet[] packets = new Packet[total_no_of_packets]; // create an array of packets to transmit

int[] readRegs = new int[10]; // to store the requested data
int[] writeRegs = new int[10]; // data to be written using 

int previousMillis = 0;
int count = 0;

void setup() {
  size(800, 520, JAVA2D);
  smooth();
  frameRate(30);

  PFont fontn = createFont("Verdana", 12);
  cp5 = new ControlP5(this);
  PFont p= createFont("Verdana", 15);
  ControlFont font=new
    ControlFont(p);
  cp5.setFont(font);

  String[] portNames = Serial.list();

  lalal = cp5.addButton("lala")
    .setCaptionLabel("ПУСК")
    //.setValue(0)
    .setPosition(180, 10)
    .setSize(150, 30)
    .lock()
    ;
  PitPIb = cp5.addButton("PitPIb")
    .setCaptionLabel("ВКЛ")
    .setPosition(620, 415)
    .setSize(150, 30)
    .lock()
    ;    
  PitETHb = cp5.addButton("PitETHb")
    .setCaptionLabel("ВКЛ")
    .setPosition(620, 295)
    .setSize(150, 30)
    .lock()
    ;  
  PitUSBb = cp5.addButton("PitUSBb")
    .setCaptionLabel("ВКЛ")
    .setPosition(620, 335)
    .setSize(150, 30)
    .lock()
    ;  
  PitGSMb = cp5.addButton("PitGSMb")
    .setCaptionLabel("ВКЛ")
    .setPosition(620, 375)
    .setSize(150, 30)
    .lock()
    ;  
  Ventb = cp5.addButton("Ventb")
    .setCaptionLabel("ВКЛ")
    .setPosition(620, 215)
    .setSize(150, 30)
    .lock()
    ;  
  resetb = cp5.addButton("resetb")
    .setCaptionLabel("ВКЛ")
    .setPosition(620, 255)
    .setSize(150, 30)
    .lock()
    ;  
  tempIn  = cp5.addTextlabel("TempIn")
    .setText("Температура внутр.")
    .setPosition(20, 100)
    ;
  tempOut  = cp5.addTextlabel("TempOut")
    .setText("Температура внеш.")
    .setPosition(20, 140)
    ;
  timeIn   = cp5.addTextlabel("TimeIn")
    .setText("Дата/время")
    .setPosition(20, 180)
    ;
  timeInC   = cp5.addTextlabel("TimeInC")
    .setText("Дата/время ПК")
    .setPosition(20, 180)
    ;
  Vin  = cp5.addTextlabel("VIn")
    .setText("Входное напряжение")
    .setPosition(20, 220)
    ;
  I  = cp5.addTextlabel("I")
    .setText("Ток потребления")
    .setPosition(20, 260)
    ;
  PitETH  = cp5.addTextlabel("PitETH")
    .setText("Питание ETH")
    .setPosition(20, 295)
    ;
  PitUSB  = cp5.addTextlabel("PitUSB")
    .setText("Питание USB")
    .setPosition(20, 340)
    ;
  PitGSM  = cp5.addTextlabel("PitGSM")
    .setText("Питание GSM")
    .setPosition(20, 380)
    ;
  PitPI  = cp5.addTextlabel("PitPI")
    .setText("Питание PI")
    .setPosition(20, 420)
    ;
  Accele  = cp5.addTextlabel("Accele")
    .setText("Версия ПО")
    .setPosition(20, 460)
    ; 
  PitETH2  = cp5.addTextlabel("PitETH2")
    .setText("Питание ETH")
    .setPosition(500, 300)
    ;
  PitUSB2  = cp5.addTextlabel("PitUSB2")
    .setText("Питание USB")
    .setPosition(500, 340)
    ;
  PitGSM2  = cp5.addTextlabel("PitGSM2")
    .setText("Питание GSM")
    .setPosition(500, 380)
    ;
  PitPI2  = cp5.addTextlabel("PitPI2")
    .setText("Питание PI")
    .setPosition(500, 420)
    ;
  Vent  = cp5.addTextlabel("Vent")
    .setText("Вентилятор")
    .setPosition(500, 220)
    ;
  ResetAll  = cp5.addTextlabel("ResetAll")
    .setText("Сброс")
    .setPosition(500, 260)
    ;

  serialPortsList = cp5.addDropdownList("serialports")
    .setPosition(10, 10)
    .setSize(150, 200)
    .setItemHeight(30)
    .setBarHeight(30)
    ;
  for (int i = 0; i < portNames.length; i++) serialPortsList.addItem(portNames[i], i);  

  textFont(fontn);
}

void draw() {
  background(128);

  if (strat) {
    port_one.update();
    tempIn.setText("Температура внутр.:   "+ readRegs[7] +"°C");
    tempOut.setText("Температура внеш.:   "+ readRegs[8] +"°C");
    timeIn.setText("Дата/время:   "+(2000+readRegs[1])+"/"+readRegs[2]+"/"+readRegs[3]+"   "+readRegs[4]+"/"+readRegs[5]+"/"+readRegs[6]);
    Vin.setText("Входное напряжение:   "+readRegs[9]);
    Accele.setText("Версия ПО:   "+readRegs[0]);
  }
}
void controlEvent(ControlEvent theEvent) {
  // DropdownList is of type ControlGroup.
  // A controlEvent will be triggered from inside the ControlGroup class.
  // therefore you need to check the originator of the Event with
  // if (theEvent.isGroup())
  // to avoid an error message thrown by controlP5.
  if (theEvent.isGroup()) {
    // check if the Event was triggered from a ControlGroup
    println("event from group : "+theEvent.getGroup().getValue()+" from "+theEvent.getGroup());
    //check if there's a serial port open already, if so, close it
    if (serialPort != null) {
      serialPort.stop();
      serialPort = null;
    }
    //open the selected core
    //String portName = serialPortsList.getItem((int)theEvent.getValue()).getName();
    String portName = theEvent.getController().getName();
    try {
      /*serialPort = new Serial(this,Serial.list()[(int)theEvent.getController().getValue()],BAUD_RATE, parity, dataBits, stopBits);
       port_one = new ModbusPort(serialPort, timeout, polling, no_of_retries, packets, total_no_of_packets);   
       // The packet format for function 1, 2, 3, 4, 15 & 16 is:
       // Packet(id, function, address, data, data array)
       packets[0] = new Packet(11, 16, 1, 10, writeRegs); 
       packets[1] = new Packet(11, 3, 0, 10, readRegs);
       println("COM connected: "+ packets[0].connection );*/
    }
    catch(Exception e) {
      System.err.println("Error opening serial port " + portName);
      e.printStackTrace();
    }
  } else if (theEvent.isController()) {
    println("event from controller : "+ (int)theEvent.getController().getValue()+" from "+theEvent.getController());
  }
}
public void lala(int theValue) {
  println("a button event from colorB: "+theValue);
  strat =!strat;
  if (!strat) {
    lalal.setLabel("Пуск");
  } else {
    lalal.setLabel("СТОП");
  }
  //Button.lala.setLabel("СТОП");
}

/*public void serialports(int theValue) {
 serialPort = new Serial(this,Serial.list()[theValue],BAUD_RATE, parity, dataBits, stopBits);
 port_one = new ModbusPort(serialPort, timeout, polling, no_of_retries, packets, total_no_of_packets);   
 // The packet format for function 1, 2, 3, 4, 15 & 16 is:
 // Packet(id, function, address, data, data array)
 packets[0] = new Packet(11, 16, 1, 10, writeRegs); 
 packets[1] = new Packet(11, 3, 0, 10, readRegs);
 println("COM connected: "+ Serial.list()[theValue] );*/

public void serialports(int theValue) {
  try {
    serialPort = new Serial(this, Serial.list()[theValue], BAUD_RATE, parity, dataBits, stopBits);
    port_one = new ModbusPort(serialPort, timeout, polling, no_of_retries, packets, total_no_of_packets);   
    // The packet format for function 1, 2, 3, 4, 15 & 16 is:
    // Packet(id, function, address, data, data array)

    packets[0] = new Packet(11, 3, 0, 10, readRegs);
    packets[1] = new Packet(11, 16, 1, 1, writeRegs); 
    packets[2] = new Packet(11, 5, 1, 1, writeRegs);

    println("COM connected: "+ Serial.list()[theValue] );
    PitPIb.unlock();
    PitETHb.unlock();
    PitUSBb.unlock();
    lalal.unlock();
    resetb.unlock();
    Ventb.unlock();
    resetb.unlock();
    PitGSMb.unlock();
  } 
  catch(Exception e) {
    System.err.println("Error opening serial port zxzx" + Serial.list()[theValue]);
    e.printStackTrace();
  }
}


public void PitPIb() {

  PitPIs =!PitPIs;
  if (!PitPIs) {
    PitPIb.setLabel("ВКЛ");
  } else {
    PitPIb.setLabel("ВЫКЛ");
  }
  //Button.lala.setLabel("СТОП");
}

public void PitETHb() {

  PitETHs =!PitETHs;
  if (!PitETHs) {
    PitETHb.setLabel("ВКЛ");
  } else {
    PitETHb.setLabel("ВЫКЛ");
  }
  //Button.lala.setLabel("СТОП");
}

public void PitUSBb() {

  PitUSBs =!PitUSBs;
  if (!PitUSBs) {
    PitUSBb.setLabel("ВКЛ");
  } else {
    PitUSBb.setLabel("ВЫКЛ");
  }
  //Button.lala.setLabel("СТОП");
}

public void PitGSMb() {

  PitGSMs =!PitGSMs;
  if (!PitGSMs) {
    PitGSMb.setLabel("ВКЛ");
  } else {
    PitGSMb.setLabel("ВЫКЛ");
  }
  //Button.lala.setLabel("СТОП");
}

public void Ventb() {

  Vents =!Vents;
  if (!Vents) {
    Ventb.setLabel("ВКЛ");
  } else {
    Ventb.setLabel("ВЫКЛ");
  }
  //Button.lala.setLabel("СТОП");
}

public void resetb() {

  resets =!resets;
  if (!resets) {
    resetb.setLabel("ВКЛ");
    packet_index=2;
  } else {
    resetb.setLabel("ВЫКЛ");
  }
  //Button.lala.setLabel("СТОП");
}
import processing.serial.*;
进口管制P5.*;
控制p5-cp5;
dropdownlistserialportslist;
Textlabel tempIn;
文本标签输出;
文本标签时间;
Textlabel timeInC;
文本标签Vin;
文本标签I;
文本标签皮特;
text标签pitubs;
文本标签;
文本标签PitPI;
Textlabel PitETH2;
text标签PitUSB2;
text标签PitGSM2;
文本标签PitPI2;
文本标签通风口;
文本标签重置全部;
文本标签加速;
文本区域加速;
钮扣;
按钮PIB;
钮扣;
按钮式pitusb;
按钮PitGSMb;
纽扣静脉;
按钮复位B;
lal组;
布尔斯特拉特=假;
布尔值=假;
布尔重置=假;
布尔PitETHs=false;
布尔PitUSBs=false;
布尔PitGSMs=false;
布尔PitPIs=false;
串口;
最终整数波特率=19200;
字符奇偶性='N';
int-dataBits=8;
浮动停止位=1.0;
ModbusPort端口_one;//创建Modbus端口实例
int超时=500;
int=100;
int no_of_retries=10;
int total_no_of_数据包=3;
数据包[]数据包=新数据包[数据包总数];//创建要传输的数据包数组
int[]readRegs=new int[10];//存储请求的数据
int[]writeRegs=新int[10];//要使用
int-previousMillis=0;
整数计数=0;
无效设置(){
尺寸(800520,JAVA2D);
光滑的();
帧率(30);
PFont fontn=createFont(“Verdana”,12);
cp5=新控制P5(本);
PFont p=createFont(“Verdana”,15);
ControlFont=新建
对照组(p);
cp5.setFont(字体);
String[]portNames=Serial.list();
lalal=cp5.addButton(“lala”)
.setCaptionLabel(“ПУСК”)
//.setValue(0)
.设置位置(180,10)
.设置大小(150,30)
.lock()
;
PitPIb=cp5.addButton(“PitPIb”)
.setCaptionLabel(“БκЛ”)
.设置位置(620415)
.设置大小(150,30)
.lock()
;    
PitETHb=cp5.addButton(“PitETHb”)
.setCaptionLabel(“БκЛ”)
.设置位置(620295)
.设置大小(150,30)
.lock()
;  
PitUSBb=cp5.addButton(“PitUSBb”)
.setCaptionLabel(“БκЛ”)
.设置位置(620335)
.设置大小(150,30)
.lock()
;  
PitGSMb=cp5.addButton(“PitGSMb”)
.setCaptionLabel(“БκЛ”)
.设置位置(620375)
.设置大小(150,30)
.lock()
;  
Ventb=cp5.addButton(“Ventb”)
.setCaptionLabel(“БκЛ”)
.设置位置(620215)
.设置大小(150,30)
.lock()
;  
resetb=cp5.addButton(“resetb”)
.setCaptionLabel(“БκЛ”)
.设置位置(620255)
.设置大小(150,30)
.lock()
;  
tempIn=cp5.addTextlabel(“tempIn”)
.setText(“аааааааааааааа
.设置位置(20,100)
;
tempOut=cp5.addTextlabel(“tempOut”)
.setText(“аааааааааааа”
.设置位置(20、140)
;
timeIn=cp5.addTextlabel(“timeIn”)
.setText(“аааа/ааааааааа
.设置位置(20,180)
;
timeInC=cp5.addTextlabel(“timeInC”)
.setText(“ааа/аааааааааПа
.设置位置(20,180)
;
Vin=cp5.addTextlabel(“Vin”)
.setText(“ааажжжжа”)
.设置位置(20、220)
;
I=cp5.addTextlabel(“I”)
.setText(“бббббббб”)
.设置位置(20260)
;
PitETH=cp5.addTextlabel(“PitETH”)
.setText(“ПааааааETH”)
.设置位置(20295)
;
pitubs=cp5.addTextlabel(“pitubs”)
.setText(“ПаааааааааUSB”)
.设置位置(20340)
;
PitGSM=cp5.addTextlabel(“PitGSM”)
.setText(“ПааааааааGSM”)
.设置位置(20380)
;
PitPI=cp5.addTextlabel(“PitPI”)
.setText(“ПааааааааPI”)
.设置位置(20420)
;
Accele=cp5.addTextlabel(“Accele”)
.setText(“БССцПц”)
.设置位置(20460)
; 
PitETH2=cp5.addTextlabel(“PitETH2”)
.setText(“ПааааааETH”)
.设置位置(500300)
;
PitUSB2=cp5.addTextlabel(“PitUSB2”)
.setText(“ПаааааааааUSB”)
.设置位置(500340)
;
PitGSM2=cp5.addTextlabel(“PitGSM2”)
.setText(“ПааааааааGSM”)
.设置位置(500380)
;
PitPI2=cp5.addTextlabel(“PitPI2”)
.setText(“ПааааааааPI”)
.设置位置(500420)
;
Vent=cp5.addTextlabel(“Vent”)
.setText(“бббббб”)
.设置位置(500220)
;
ResetAll=cp5.addTextlabel(“ResetAll”)
.setText(“СбС”)
.设置位置(500260)
;
serialPortsList=cp5.addDropdownList(“serialports”)
.设置位置(10,10)
.设置大小(150200)
.setItemHeight(30)
.立根高度(30)
;
对于(int i=0;ipublic int packet_index;

class ModbusPort
{
  Serial serial_port;

  final int READ_COIL_STATUS = 1; // Reads the ON/OFF status of discrete outputs (0X references, coils) in the slave.
  final int READ_INPUT_STATUS = 2; // Reads the ON/OFF status of discrete inputs (1X references) in the slave.
  final int READ_HOLDING_REGISTERS = 3; // Reads the binary contents of holding registers (4X references) in the slave.
  final int READ_INPUT_REGISTERS = 4; // Reads the binary contents of input registers (3X references) in the slave. Not writable.
  final int FORCE_MULTIPLE_COILS = 15; // Forces each coil (0X reference) in a sequence of coils to either ON or OFF.
  final int PRESET_MULTIPLE_REGISTERS = 16; // Presets values into a sequence of holding registers (4X references).
  final int FORCE_OUTPUT_COILS=5;//tytytyty
  // State Machine States
  final int IDLE = 1;
  final int WAITING_FOR_REPLY = 2;
  final int WAITING_FOR_TURNAROUND = 3;

  int state;

  // frame[] is used to recieve and transmit packages. 
  // The maximum number of bytes in a modbus packet is 255
  final int BUFFER_SIZE = 255;
  int[] frame = new int[BUFFER_SIZE]; 
  int buffer;
  int timeout;
  int polling;
  int retry_count;

  /* It must be noted in order to overcome the inter-character 
   time out and the delays prevalent in the Processing/Java 
   environment when using the serial library (RXTX-lib) the 
   inter-character time out has been increased to 30ms diverging 
   from the modbus standard. To increase the packet rate transfer 
   from the FTDI chip the latency-timer has to be decreased from 
   16ms to 1ms and the usb transfer size has to be decreased from 
   4096 to 256 bytes. This can be done from device manager in port settings. 
   
   So if you are experiencing packet errors then increase the T1_5
   inter-character time out variable.
   */
  int T1_5 = 30; // inter character time out in milliseconds
  int delayStart;

  Packet[] packets; 

  int total_no_of_packets;
  Packet packet; // global active packet

  ModbusPort(Serial serial_port, int timeout, int polling, int retry_count, Packet[] packets, int total_no_of_packets)
  {
    this.serial_port = serial_port;
    this.timeout = timeout;
    this.polling = polling;
    this.retry_count = retry_count;
    this.packets = packets;
    this.total_no_of_packets = total_no_of_packets;
    state = IDLE;
    delayStart = 0;
    packet_index = 0;
  } 

  // Modbus Master State Machine
  void update() 
  {
    switch (state)
    {
    case IDLE:
      idle();
      break;
    case WAITING_FOR_REPLY:
      waiting_for_reply();
      break;
    case WAITING_FOR_TURNAROUND:
      waiting_for_turnaround();
      break;
    }
  }

  private void idle() 
  {
    // Initialize the connection_status variable to the
    // total_no_of_packets. This value cannot be used as 
    // an index (and normally you won't). Returning this 
    // value to the main sketch informs the user that the 
    // previously scanned packet has no connection error.

    int connection_status = total_no_of_packets;  
    int failed_connections = 0;
    boolean current_connection;

    do
    {      
      if (packet_index == total_no_of_packets) // wrap around to the beginning
        packet_index = 0;

      packet = packets[packet_index]; // get the next packet

      // get the current connection status
      current_connection = packet.connection;

      if (!current_connection)
      {
        connection_status = packet_index;

        // If all the connection attributes are false return
        // immediately to the main sketch
        if (++failed_connections == total_no_of_packets)
          return;
      }

      //packet_index++;/// тут дописать способ выбора пакеты для отсылки
    }
    while (!current_connection); // while a packet has no connection get the next one

    constructPacket();
  }

  private void constructPacket()
  {   
    packet.requests++;
    frame[0] = packet.id;
    frame[1] = packet.function;
    frame[2] = packet.address >> 8; // address High
    frame[3] = packet.address & 0xFF; // address Low
    // For functions 1 & 2 data is the number of points
    // For functions 3, 4 & 16 data is the number of registers
    // For function 15 data is the number of coils
    frame[4] = packet.data >> 8; // MSB
    frame[5] = packet.data & 0xFF; // LSB

    int frameSize;

    // construct the frame according to the modbus function  
    if (packet.function == PRESET_MULTIPLE_REGISTERS) 
      frameSize = construct_F16();   
    else if (packet.function == FORCE_MULTIPLE_COILS)
      frameSize = construct_F15();
    else // else functions 1,2,3 & 4 is assumed. They all share the exact same request format.
    frameSize = 8; // the request is always 8 bytes in size for the above mentioned functions.

    int crc16 = calculateCRC(frameSize - 2);  
    frame[frameSize - 2] = crc16 >> 8; // split crc into 2 bytes
    frame[frameSize - 1] = crc16 & 0xFF;
    sendPacket(frameSize);

    state = WAITING_FOR_REPLY; // state change

    // if broadcast is requested (id == 0) for function 15 or 16 then override 
    // the previous state and force a success since the slave won't respond
    if (packet.id == 0)
      processSuccess();
  }

  private int construct_F16()
  {
    int no_of_bytes = packet.data * 2;
    frame[6] = no_of_bytes; // number of bytes
    int index = 7; // user data starts at index 7
    int no_of_registers = packet.data;
    int temp;
    for (int i = 0; i < no_of_registers; i++)
    {
      temp = packet.register_array[i]; // get the data
      frame[index] = temp >> 8;
      index++;
      frame[index] = temp & 0xFF;
      index++;
    }
    int frameSize = 9 + no_of_bytes; // first 7 bytes of the array + 2 bytes CRC + noOfBytes
    return frameSize;
  }

  private int construct_F15()
  {
    // function 15 coil information is packed LSB first until the first 16 bits are completed
    // It is received the same way..
    int no_of_registers = packet.data / 16;
    int no_of_bytes = no_of_registers * 2; 

    // if the number of points dont fit in even 2byte amounts (one register) then use another register and pad 
    if (packet.data % 16 > 0) 
    {
      no_of_registers++;
      no_of_bytes++;
    }

    frame[6] = no_of_bytes;   
    int bytes_processed = 0;
    int index = 7; // user data starts at index 7
    int temp;

    for (int i = 0; i < no_of_registers; i++)
    {
      temp = packet.register_array[i]; // get the data
      frame[index] = temp & 0xFF; 
      bytes_processed++;

      if (bytes_processed < no_of_bytes)
      {
        frame[index + 1] = temp >> 8;
        bytes_processed++;
        index += 2;
      }
    }
    int frameSize = 9 + no_of_bytes; // first 7 bytes of the array + 2 bytes CRC + noOfBytes 
    return frameSize;
  }

  // get the serial data from the buffer
  void waiting_for_reply()
  {
    if (serial_port.available() > 0) // is there something to check?
    {
      boolean overflowFlag = false;
      buffer = 0;
      while (serial_port.available() > 0)
      {
        // The maximum number of bytes is limited to the serial buffer size 
        // of BUFFER_SIZE. If more bytes is received than the BUFFER_SIZE the 
        // overflow flag will be set and the serial buffer will be read until
        // all the data is cleared from the receive buffer, while the slave is 
        // still responding.
        if (overflowFlag) 
          serial_port.read();
        else
        {
          if (buffer == BUFFER_SIZE)
            overflowFlag = true;

          frame[buffer] = serial_port.read();
          buffer++;
        }
        // This is not 100% correct but it will suffice.
        // worst case scenario is if more than one character time expires
        // while reading from the buffer then the buffer is most likely empty
        // If there are more bytes after such a delay it is not supposed to
        // be received and thus will force a frame_error.
        delay(T1_5); // inter character time out
      }

      // The minimum buffer size from a slave can be an exception response of
      // 5 bytes. If the buffer was partially filled set a frame_error.
      // The maximum number of bytes in a modbus packet is 256 bytes.

      if ((buffer < 5) || overflowFlag)
        processError();       

      // Modbus over serial line datasheet states that if an unexpected slave 
      // responded the master must do nothing and continue with the time out.
      // This seems silly cause if an incorrect slave responded you would want to
      // have a quick turnaround and poll the right one again. If an unexpected 
      // slave responded it will most likely be a frame error in any event
      else if (frame[0] != packet.id) // check id returned
        processError();
      else
        processReply();
    } else if ((millis() - delayStart) > timeout) // check timeout
    {
      processError();
      state = IDLE; //state change, override processError() state
    }
  }

  private void processReply()
  {
    // combine the crc Low & High bytes
    int received_crc = ((frame[buffer - 2] << 8) | frame[buffer - 1]); 
    int calculated_crc = calculateCRC(buffer - 2);

    if (calculated_crc == received_crc) // verify checksum
    {
      // To indicate an exception response a slave will 'OR' 
      // the requested function with 0x80 
      if ((frame[1] & 0x80) == 0x80) // extract 0x80
      {
        packet.exception_errors++;
        processError();
      } else
      {
        switch (frame[1]) // check function returned
        {
        case READ_COIL_STATUS:
        case READ_INPUT_STATUS:
        case FORCE_OUTPUT_COILS:
          process_F1_F2();
          break;
        case READ_INPUT_REGISTERS:
        case READ_HOLDING_REGISTERS:
          process_F3_F4(); 
          break;
        case FORCE_MULTIPLE_COILS:
        case PRESET_MULTIPLE_REGISTERS:
          process_F15_F16();
          break;
        default: // illegal function returned
          processError();
          break;
        }
      }
    } else // checksum failed
    {
      processError();
    }
  }

  private void process_F1_F2()
  {
    // packet.data for function 1 & 2 is actually the number of boolean points
    int no_of_registers = packet.data / 16;
    int number_of_bytes = no_of_registers * 2; 

    // if the number of points dont fit in even 2byte amounts (one register) then use another register and pad 
    if (packet.data % 16 > 0) 
    {
      no_of_registers++;
      number_of_bytes++;
    }

    if (frame[2] == number_of_bytes) // check number of bytes returned
    { 
      int bytes_processed = 0;
      int index = 3; // start at the 4th element in the frame and combine the Lo byte  
      int temp;
      for (int i = 0; i < no_of_registers; i++)
      {
        temp = frame[index]; 
        bytes_processed++;
        if (bytes_processed < number_of_bytes)
        {
          temp = (frame[index + 1] << 8) | temp;
          bytes_processed++;
          index += 2;
        }
        packet.register_array[i] = temp;
      }
      processSuccess();
    } else // incorrect number of bytes returned 
    processError();
  }

  private void process_F3_F4()
  {
    // check number of bytes returned - unsigned int == 2 bytes
    // data for function 3 & 4 is the number of registers
    if (frame[2] == (packet.data * 2)) 
    {
      int index = 3;
      for (int i = 0; i < packet.data; i++)
      {
        // start at the 4th element in the frame and combine the Lo byte 
        packet.register_array[i] = (frame[index] << 8) | frame[index + 1]; 
        index += 2;
      }
      processSuccess();
    } else // incorrect number of bytes returned  
    processError();
  }

  private void process_F15_F16()
  {
    // Functions 15 & 16 have the exact same response from the slave
    // which is an echo of the query
    int recieved_address = ((frame[2] << 8) | frame[3]);
    int recieved_data = ((frame[4] << 8) | frame[5]);
    if ((recieved_address == packet.address) && (recieved_data == packet.data))
      processSuccess();
    else
      processError();
  }

  void waiting_for_turnaround()
  {
    if ((millis() - delayStart) >= polling)
      state = IDLE;
  }

  private void processError()
  {
    packet.retries++;
    packet.failed_requests++;

    // if the number of retries have reached the max number of retries 
    // allowable, stop requesting the specific packet
    if (packet.retries == retry_count)
    {
      packet.connection = false;
      packet.retries = 0;
    }
    state = WAITING_FOR_TURNAROUND;
    delayStart = millis(); // start the turnaround delay
  }

  private void processSuccess()
  {
    packet.successful_requests++; // transaction sent successfully
    packet.retries = 0; // if a request was successful reset the retry counter
    state = WAITING_FOR_TURNAROUND;
    delayStart = millis(); // start the turnaround delay
  }

  private int calculateCRC(int bufferSize) 
  {
    int temp, temp2, flag;
    temp = 0xFFFF;
    for (int i = 0; i < bufferSize; i++)
    {
      temp = temp ^ frame[i];
      for (int j = 1; j <= 8; j++)
      {
        flag = temp & 0x0001;
        temp >>= 1;
        if (flag == 1)
          temp ^= 0xA001;
      }
    }
    // Reverse byte order. 
    temp2 = temp >> 8;
    temp = (temp << 8) | temp2;
    temp &= 0xFFFF;
    return temp; // the returned value is already swopped - crcLo byte is first & crcHi byte is last
  }

  private void sendPacket(int bufferSize)  
  {
    serial_port.clear();

    // This is where the magic happens!
    // Initially the delay between characters were too great
    // when int's were being transmitted by indexing the
    // frame array. Java does not have an unsigned char 
    // to work with numbers from 0 - 255 it only has a byte type
    // which expects 127 to -128. This does not actually matter
    // since the number is still 8bits. It's only the protocol
    // that reconstructs the frame on the other side that dictates 
    // if it's signed or not. From modbus perspective it's still 
    // an 8bit byte value that being received and transmitted.

    // The write() method in the serial class expects any type
    // but the fastest type that will be transfered to the Serial
    // buffer is bytes or more specifically an array of bytes.
    // By casting the frame array containing our data to a byte
    // array of the exact size that we want to transmit we can
    // overcome the delay between the transmission of characters.
    // We can do this because the data in frame will never exceed
    // the value of an 8 bit byte.

    byte[] byteFrame = new byte[bufferSize];

    for (int i = 0; i < bufferSize; i++)
      byteFrame[i] = (byte)frame[i];  

    serial_port.write(byteFrame);
    delayStart = millis(); // initialize timeout delay
  }
}

class Packet
{
  // specific packet info
  int id, function, address;

  // For functions 1 & 2 data is the number of points
  // For functions 3, 4 & 16 data is the number of registers
  // For function 15 data is the number of coils
  int data; 
  int[] register_array;

  // non specific modbus information
  int requests;
  int successful_requests;
  int failed_requests;
  int exception_errors;
  int retries;
  boolean connection; // comms status of the packet

  Packet(int id, int function, int address, int data, int[] register_array)
  {
    this.id = id;
    this.function = function;
    this.address = address;
    this.data = data;
    this.register_array = register_array;
    connection = true; // enable packet requesting
  }
}