package mashmonitor;
import java.util.*;
import javax.swing.*;
import gnu.io.*;
import java.io.*;
import java.math.BigDecimal;
/**
* Application to monitor and/or control mash temperatures during beer brewing
* Intended for use with an Arduino USB/Serial board
* Has built in ability to almost completely control an Arduino board
*
* @author Yuri
*
* NOTE: When comments reference bits within a byte,
* they are numbered 0-7, with 7 being the 1's place
*/
public class MashMonitorUI extends javax.swing.JFrame implements SerialPortEventListener{
//"constant" declarations
private static final String PORT = "COM3"; //which comm port to open
private static final int HIGH = 1;
private static final int LOW = 0;
//transfer functions for 10 bit input from Arduino board
//first number is a multiplier, second number is additive
private static final double[][] aPinTransferFunctions = {{.25,.02,0,0,0,0},{32,0,0,0,0,0}};
private static final int STEAMPRESSURE = 1;
private static final int MASHTEMP = 0;
private static final int STEAMHEAT = 13;
private static final int MASHHEAT = 12;
private static InputStream in; //input stream of serial port
private static OutputStream out; //output stream of serial port
private static int[] aPins = new int[6];
private static double[] sensorValues = new double[6];
private static Boolean isAutomated = false; //variable to determine the control state
private static SerialPort serialPort = null; //serial port on which to connect
private static TempController controller; //control class that does most of the work here
private static boolean successfulTransfer = false; //first successful data transfer sets this true
/** Creates new form MashMonitorUI */
public MashMonitorUI() {
initComponents();
//open a serial port with an event listener
//perhaps this code should be a separate procedure
//so that the user can try to re-establish the serial connection
//on the port of his/her choice if serial communication fails
try {
//find the port
CommPortIdentifier portId = CommPortIdentifier.getPortIdentifier(PORT);
//open the port
serialPort = (SerialPort)portId.open("MashMonitor", 2000);
//set the port up for communication
serialPort.setSerialPortParams(9600,serialPort.DATABITS_8,serialPort.STOPBITS_1,serialPort.PARITY_NONE);
//set the input and output stream variables
in = serialPort.getInputStream();
out = serialPort.getOutputStream();
//add an event listener
serialPort.addEventListener(this);
serialPort.notifyOnDataAvailable(true);
jLabelStatus.setText("Listening on port: "+portId.getName());
} catch (Exception e) { //catch everything
jLabelStatus.setText("ERROR: "+e.toString()+" - "+e.getMessage());
}
}
//hande serial events - read only
//wait for 14 bytes of data before reading (corresponding to each analog pin)
//two "wrapper" bytes of all 1's surround
//2 bytes per value, upper 8 bits first, followed by lower 2 bits (to get 10 bit precision)
public void serialEvent(SerialPortEvent event) {
if (event.getEventType()== SerialPortEvent.DATA_AVAILABLE) {
int[] tempArray = new int[aPins.length * 2 + 2]; //an array to hold all input
try {
//wait for 14 bytes
if (in.available() >= tempArray.length) {
for (int i = 0; i < tempArray.length; i++) {
tempArray[i] = in.read();
}
//if the first and last bytes aren't all 1's (255), discard everything
if ((tempArray[0] & tempArray[tempArray.length - 1]) != 255) {
while (in.available() > 0) {
in.read();
}
//else, read the bytes into the values for the sensors
} else {
for (int i = 0; i < aPins.length; i++) {
aPins[i] = (tempArray[i * 2 + 1] << 2) + tempArray[i * 2 + 2];
}
if (!successfulTransfer) {
successfulTransfer = true;
jLabelStatus.setText("Data transfer initiated.");
}
}
updateSensorValues();
}
} catch (Exception e) {
successfulTransfer = false;
jLabelStatus.setText(e.toString()+": "+e.getMessage());
}
}
}
//write data to the Arduino
//dPin holds the pin number to change
//state is the digital state to set the pin (HIGH or LOW)
private static void serialUpdate(int dPin, int state) {
try {
//write a single byte command
//bits 5 and 6 hold the pin number
//bit 7 holds the pin state
out.write((dPin << 1) + state);
} catch (Exception e) {
successfulTransfer = false;
jLabelStatus.setText("Serial write failed.");
}
}
//very brute force code to set sensor values
//would be nice if controls were somewhat user-assignable against values
//perhaps an init text file could be incorporated to save settings
//instead of hard coding controls against values
private static void updateSensorValues() {
for (int i = 0; i < aPins.length; i++) {
sensorValues[i] = aPins[i] * aPinTransferFunctions[0][i] + aPinTransferFunctions[1][i];
}
jProgressBarMash.setValue((int)sensorValues[MASHTEMP]);
jLabelMashActualTemp.setText(Integer.toString((int)sensorValues[MASHTEMP]));
jProgressBarSteam.setValue((int)sensorValues[STEAMPRESSURE]);
//how to round double values in Java
BigDecimal bd = new BigDecimal(sensorValues[STEAMPRESSURE]);
bd = bd.setScale(2,BigDecimal.ROUND_UP);
jLabelSteamActualPressure.setText(bd.toString());
}