diff --git a/Source/Processors/Serial/PulsePal.cpp b/Source/Processors/Serial/PulsePal.cpp
index b939e395bad8d1f2dc295d543927ecde5ed60b3c..a4ef5c8412f48f959b83e858c3ba0260ebe19530 100644
--- a/Source/Processors/Serial/PulsePal.cpp
+++ b/Source/Processors/Serial/PulsePal.cpp
@@ -20,12 +20,11 @@
     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 */
+// Modified by JS 1/30/2014: Updated op codes for firmware 0_4, added new functions (indicated in comments below)
 
 #include <vector>
 #include <stdio.h>
 #include <stdint.h>
-
-
 #include "PulsePal.h"
 
 #define ZERO_uS (uint32_t) 0
@@ -33,6 +32,7 @@
 #define MAX_uS (uint32_t) 3600000000
 #define NEWLINE 0xA
 #define RETURN 0xD
+#define makeLong(msb, byte2, byte3, lsb) ((msb << 24) | (byte2 << 16) | (byte3 << 8) | (lsb)) //JS  2/1/2014
 
 PulsePal::PulsePal()
 {
@@ -41,7 +41,7 @@ PulsePal::PulsePal()
 
 PulsePal::~PulsePal()
 {
-
+    disconnectClient();
     serial.close();
 }
 
@@ -64,108 +64,153 @@ void PulsePal::initialize()
 
    // bool foundDevice = false;
 
-	int id = devices[0].getDeviceID();
+    int id = devices[0].getDeviceID();
         string path = devices[0].getDevicePath();
         string name = devices[0].getDeviceName();
 
-	serial.setup(id, 115200); //115200);
-	
+    serial.setup(id, 115200);
+    std::cout << "Found!" << std::endl;
+}
+
+uint32_t PulsePal::getFirmwareVersion() // JS 1/30/2014
+{
+    uint32_t firmwareVersion = 0;
+    uint8_t handshakeByte = 72;
+    uint8_t responseBytes[5] = { 0 };
+    serial.writeByte(handshakeByte);
+    Sleep(100);
+    serial.readBytes(responseBytes,5);
+    firmwareVersion = makeLong(responseBytes[4], responseBytes[3], responseBytes[2], responseBytes[1]);
+    return firmwareVersion;
+}
+
+void PulsePal::setBiphasic(uint8_t channel, bool isBiphasic)
+{
+    uint8_t command = 0;
+
+    if (isBiphasic)
+    {
+        command = 1;
+    }
 
+    program(channel, 1, command);
+    PulsePal::currentOutputParams[channel].isBiphasic = command; //JS  2/1/2014 (Added this for all single-item programming functions)
 }
 
+void PulsePal::setPhase1Voltage(uint8_t channel, float voltage)
+{
+    program(channel, 2, voltageToByte(voltage));
+    PulsePal::currentOutputParams[channel].phase1Voltage = voltage;
+}
 
+void PulsePal::setPhase2Voltage(uint8_t channel, float voltage)
+{
+    program(channel, 3, voltageToByte(voltage));
+    PulsePal::currentOutputParams[channel].phase2Voltage = voltage;
+}
 
-void PulsePal::setPhase1Duration(uint8_t channel, uint32_t timeInMicroseconds)
+void PulsePal::setPhase1Duration(uint8_t channel, float timeInSeconds)
 {
+    uint32_t timeInMicroseconds = (uint32_t)(timeInSeconds * 1000000); //JS  2/1/2014
     constrain(&timeInMicroseconds, FIFTY_uS, MAX_uS);
-    program(channel, 0, timeInMicroseconds);
+    program(channel, 4, timeInMicroseconds);
+    PulsePal::currentOutputParams[channel].phase1Duration = timeInSeconds;
 }
 
-void PulsePal::setInterPhaseInterval(uint8_t channel, uint32_t timeInMicroseconds)
+void PulsePal::setInterPhaseInterval(uint8_t channel, float timeInSeconds)
 {
+    uint32_t timeInMicroseconds = (uint32_t)(timeInSeconds * 1000000);
     constrain(&timeInMicroseconds, FIFTY_uS, MAX_uS);
-    program(channel, 1, timeInMicroseconds);
+    program(channel, 5, timeInMicroseconds);
+    PulsePal::currentOutputParams[channel].interPhaseInterval = timeInSeconds;
 }
 
-void PulsePal::setPhase2Duration(uint8_t channel, uint32_t timeInMicroseconds)
+void PulsePal::setPhase2Duration(uint8_t channel, float timeInSeconds)
 {
+    uint32_t timeInMicroseconds = (uint32_t)(timeInSeconds * 1000000);
     constrain(&timeInMicroseconds, FIFTY_uS, MAX_uS);
-    program(channel, 2, timeInMicroseconds);
+    program(channel, 6, timeInMicroseconds);
+    PulsePal::currentOutputParams[channel].phase2Duration = timeInSeconds;
 }
 
-void PulsePal::setInterPulseInterval(uint8_t channel, uint32_t timeInMicroseconds)
+void PulsePal::setInterPulseInterval(uint8_t channel, float timeInSeconds)
 {
+    uint32_t timeInMicroseconds = (uint32_t)(timeInSeconds * 1000000);
     constrain(&timeInMicroseconds, FIFTY_uS, MAX_uS);
-    program(channel, 3, timeInMicroseconds);
+    program(channel, 7, timeInMicroseconds);
+    PulsePal::currentOutputParams[channel].interPhaseInterval = timeInSeconds;
 }
 
-void PulsePal::setBurstDuration(uint8_t channel, uint32_t timeInMicroseconds)
+void PulsePal::setBurstDuration(uint8_t channel, float timeInSeconds)
 {
+    uint32_t timeInMicroseconds = (uint32_t)(timeInSeconds * 1000000);
     constrain(&timeInMicroseconds, ZERO_uS, MAX_uS);
-    program(channel, 4, timeInMicroseconds);
+    program(channel, 8, timeInMicroseconds);
+    PulsePal::currentOutputParams[channel].burstDuration = timeInSeconds;
 }
 
-void PulsePal::setBurstInterval(uint8_t channel, uint32_t timeInMicroseconds)
+void PulsePal::setBurstInterval(uint8_t channel, float timeInSeconds)
 {
+    uint32_t timeInMicroseconds = (uint32_t)(timeInSeconds * 1000000);
     constrain(&timeInMicroseconds, ZERO_uS, MAX_uS);
-    program(channel, 5, timeInMicroseconds);
+    program(channel, 9, timeInMicroseconds);
+    PulsePal::currentOutputParams[channel].interBurstInterval = timeInSeconds;
 }
 
-void PulsePal::setStimulusTrainDuration(uint8_t channel, uint32_t timeInMicroseconds)
+void PulsePal::setPulseTrainDuration(uint8_t channel, float timeInSeconds)
 {
+    uint32_t timeInMicroseconds = (uint32_t)(timeInSeconds * 1000000);
     constrain(&timeInMicroseconds, FIFTY_uS, MAX_uS);
-    program(channel, 6, timeInMicroseconds);
+    program(channel, 10, timeInMicroseconds);
+    PulsePal::currentOutputParams[channel].pulseTrainDuration = timeInSeconds;
 }
 
-void PulsePal::setStimulusTrainDelay(uint8_t channel, uint32_t timeInMicroseconds)
+void PulsePal::setPulseTrainDelay(uint8_t channel, float timeInSeconds)
 {
+    uint32_t timeInMicroseconds = (uint32_t)(timeInSeconds * 1000000);
     constrain(&timeInMicroseconds, FIFTY_uS, MAX_uS);
-    program(channel, 7, timeInMicroseconds);
+    program(channel, 11, timeInMicroseconds);
+    PulsePal::currentOutputParams[channel].pulseTrainDelay = timeInSeconds;
 }
 
-void PulsePal::setBiphasic(uint8_t channel, bool isBiphasic)
+void PulsePal::setTrigger1Link(uint8_t channel, uint8_t link_state) // JS 1/30/2014
 {
-    uint8_t command = 0;
-
-    if (isBiphasic)
-    {
-        command = 1;
-    }
-
-    program(channel, 8, command);
+    program(channel, 12, link_state);
+    PulsePal::currentOutputParams[channel].linkTriggerChannel1 = link_state;
 }
-
-void PulsePal::setPhase1Voltage(uint8_t channel, float voltage)
+void PulsePal::setTrigger2Link(uint8_t channel, uint8_t link_state) // JS 1/30/2014
 {
-    program(channel, 9, voltageToByte(voltage));
+    program(channel, 13, link_state);
+    PulsePal::currentOutputParams[channel].linkTriggerChannel2 = link_state;
 }
-
-void PulsePal::setPhase2Voltage(uint8_t channel, float voltage)
+void PulsePal::setCustomTrainID(uint8_t channel, uint8_t ID) // JS 1/30/2014
 {
-    program(channel, 10, voltageToByte(voltage));
+    program(channel, 14, ID);
+    PulsePal::currentOutputParams[channel].customTrainID = ID;
 }
-
-void PulsePal::updateDisplay(string line1, string line2)
+void PulsePal::setCustomTrainTarget(uint8_t channel, uint8_t target) // JS 1/30/2014
 {
-    uint8_t message1 = 85;
-
-    serial.writeByte(message1);
-
-    serial.writeBytes((unsigned char*) line1.data(), line1.size());
-    //serial.writeByte(0);
-    //serial.writeByte(RETURN);
-    serial.writeByte(254);
-    serial.writeBytes((unsigned char*) line2.data(), line2.size());
-    //serial.writeByte(0);
-    //serial.writeByte(RETURN);
+    program(channel, 15, target);
+    PulsePal::currentOutputParams[channel].customTrainTarget = target;
+}
+void PulsePal::setCustomTrainLoop(uint8_t channel, uint8_t loop_state) // JS 1/30/2014
+{
+    program(channel, 16, loop_state);
+    PulsePal::currentOutputParams[channel].customTrainLoop = loop_state;
+}
 
+void PulsePal::setTriggerMode(uint8_t channel, uint8_t mode) // JS 1/30/2014
+{
+    program(channel, 128, mode);
+    PulsePal::currentInputParams[channel].triggerMode = mode;
 }
 
+
 void PulsePal::program(uint8_t channel, uint8_t paramCode, uint32_t paramValue)
 {
-    std::cout << "sending 32-bit message" << std::endl;
+    //std::cout << "sending 32-bit message" << std::endl;
 
-    uint8_t message1[3] = {79, paramCode, channel};
+    uint8_t message1[3] = {74, paramCode, channel};
 
     uint8_t message2[4];
 
@@ -178,32 +223,96 @@ void PulsePal::program(uint8_t channel, uint8_t paramCode, uint32_t paramValue)
     serial.writeBytes(message1, 3);
     serial.writeBytes(message2, 4);
 
-    std::cout << "Message 1: " << (int) message1[0] << " " << (int) message1[1] << " " << (int) message1[2] << std::endl;
-    std::cout << "Message 2: " << (int) message2[0] << " " << (int) message2[1] << " " << (int) message2[2] <<  " " << (int) message2[3] << std::endl;
+    //std::cout << "Message 1: " << (int) message1[0] << " " << (int) message1[1] << " " << (int) message1[2] << std::endl;
+    //std::cout << "Message 2: " << (int) message2[0] << " " << (int) message2[1] << " " << (int) message2[2] <<  " " << (int) message2[3] << std::endl;
 }
 
 
 void PulsePal::program(uint8_t channel, uint8_t paramCode, uint8_t paramValue)
 {
 
-    std::cout << "sending 8-bit message" << std::endl;
+    //std::cout << "sending 8-bit message" << std::endl;
 
-    uint8_t message1[3] = {79, paramCode, channel};
+    uint8_t message1[3] = {74, paramCode, channel};
 
     serial.writeBytes(message1, 3);
     serial.writeBytes(&paramValue, 1);
 
-    std::cout << "Message 1: " << (int) message1[0] << " " << (int) message1[1] << " " << (int) message1[2] << std::endl;
-    std::cout << "Message 2: " << paramValue << std::endl;
+    //std::cout << "Message 1: " << (int) message1[0] << " " << (int) message1[1] << " " << (int) message1[2] << std::endl;
+    //std::cout << "Message 2: " << paramValue << std::endl;
 }
 
+
+
+void PulsePal::triggerChannel(uint8_t chan)
+{
+    const uint8_t code = 1 << (chan - 1);
+
+    uint8_t bytesToWrite[2] = {77, code};
+
+    serial.writeBytes(bytesToWrite, 2);
+}
+
+void PulsePal::triggerChannels(uint8_t channel1, uint8_t channel2, uint8_t channel3, uint8_t channel4) // JS 1/30/2014
+{
+    uint8_t code = 0;
+    code = code + 1 * channel1;
+    code = code + 2 * channel2;
+    code = code + 4 * channel3;
+    code = code + 8 * channel4;
+
+    uint8_t bytesToWrite[2] = { 77, code };
+
+    serial.writeBytes(bytesToWrite, 2);
+}
+
+void PulsePal::updateDisplay(string line1, string line2)
+{
+    string Prefix;
+    string Message;
+    Message.append(line1);
+    Message += 254;
+    Message.append(line2);
+    Prefix += 78;
+    Prefix += Message.size();
+    Prefix.append(Message);
+    serial.writeBytes((unsigned char*)Prefix.data(), Prefix.size());
+}
+
+void PulsePal::setFixedVoltage(uint8_t channel, float voltage) // JS 1/30/2014
+{
+    uint8_t voltageByte = 0;
+    voltageByte = voltageToByte(voltage);
+    uint8_t message1[3] = { 79, channel, voltageByte };
+    serial.writeBytes(message1, 3);
+}
+
+void PulsePal::abortPulseTrains() // JS 1/30/2014
+{
+    uint8_t message1 = 80;
+    serial.writeByte(message1);
+}
+
+void PulsePal::disconnectClient() // JS 1/30/2014
+{
+    uint8_t message1 = 81;
+    serial.writeByte(message1);
+}
+
+void PulsePal::setContinuousLoop(uint8_t channel, uint8_t state) // JS 1/30/2014
+{
+    uint8_t message1[3] = {82, channel, state};
+    serial.writeBytes(message1, 3);
+}
+
+
 void PulsePal::constrain(uint32_t* value, uint32_t min, uint32_t max)
 {
 
-    // value must be a multiple of 50
-    if (*value % 50 > 0)
+    // value must be a multiple of 100
+    if (*value % 100 > 0)
     {
-        *value = *value - (*value % 50);
+        *value = *value - (*value % 100);
     }
 
     if (*value < min)
@@ -223,20 +332,133 @@ uint8_t PulsePal::voltageToByte(float voltage)
     // input: -10 to 10 V
     // output: 0-255
 
-    uint8_t output = (uint8_t)((voltage+10)/20)*255;
+    uint8_t output = uint8_t(((voltage+10)/20)*255);
 
     return output;
 
 }
 
+void PulsePal::programCustomTrain(uint8_t ID, uint8_t nPulses, float customPulseTimes[], float customVoltages[]){
+    int nMessageBytes = (nPulses * 5) + 6;
+    // Convert voltages to bytes
+    uint8_t voltageBytes[1000] = { 0 };
+    float thisVoltage = 0;
+    for (int i = 0; i < nPulses; i++) {
+        thisVoltage = customVoltages[i];
+        voltageBytes[i] = voltageToByte(thisVoltage);
+    }
+    // Convert times to bytes
+    uint8_t pulseTimeBytes[4000] = { 0 };
+    int pos = 0;
+    unsigned long pulseTimeMicroseconds;
+    for (int i = 0; i < nPulses; i++){
+        pulseTimeMicroseconds = (unsigned long)(customPulseTimes[i] * 1000000);
+        pulseTimeBytes[pos] = (uint8_t)(pulseTimeMicroseconds); pos++;
+        pulseTimeBytes[pos] = (uint8_t)(pulseTimeMicroseconds >> 8); pos++;
+        pulseTimeBytes[pos] = (uint8_t)(pulseTimeMicroseconds >> 16); pos++;
+        pulseTimeBytes[pos] = (uint8_t)(pulseTimeMicroseconds >> 24); pos++;
+    }
+    uint8_t *messageBytes = new uint8_t[nMessageBytes];
+    if (ID == 2) {
+        messageBytes[0] = 76; // Op code to program custom train 2
+    }
+    else {
+        messageBytes[0] = 75; // Op code to program custom train 1
+    }
+    messageBytes[1] = 0; // USB packet correction byte
+    messageBytes[2] = (uint8_t)(nPulses);
+    messageBytes[3] = (uint8_t)(nPulses >> 8);
+    messageBytes[4] = (uint8_t)(nPulses >> 16);
+    messageBytes[5] = (uint8_t)(nPulses >> 24);
+    int timeDataEnd = 6 + (nPulses * 4);
+    for (int i = 6; i < timeDataEnd; i++){
+        messageBytes[i] = pulseTimeBytes[i - 6];
+    }
+    for (int i = timeDataEnd; i < nMessageBytes; i++){
+        messageBytes[i] = voltageBytes[i - timeDataEnd];
+    }
+    serial.writeBytes(messageBytes, nMessageBytes);
+}
+
+void PulsePal::programAllParams() {
+    uint8_t messageBytes[163] = { 0 };
+    messageBytes[0] = 73;
+    int pos = 1;
+    uint32_t thisTime = 0;
+    float thisVoltage = 0;
+    uint8_t thisVoltageByte = 0;
+
+    // add time params
+    for (int i = 1; i < 5; i++){
+        thisTime = (uint32_t)(currentOutputParams[i].phase1Duration * 1000000);
+        messageBytes[pos] = (uint8_t)(thisTime); pos++;
+        messageBytes[pos] = (uint8_t)(thisTime >> 8); pos++;
+        messageBytes[pos] = (uint8_t)(thisTime >> 16); pos++;
+        messageBytes[pos] = (uint8_t)(thisTime >> 24); pos++;
+        thisTime = (uint32_t)(currentOutputParams[i].interPhaseInterval * 1000000);
+        messageBytes[pos] = (uint8_t)(thisTime); pos++;
+        messageBytes[pos] = (uint8_t)(thisTime >> 8); pos++;
+        messageBytes[pos] = (uint8_t)(thisTime >> 16); pos++;
+        messageBytes[pos] = (uint8_t)(thisTime >> 24); pos++;
+        thisTime = (uint32_t)(currentOutputParams[i].phase2Duration * 1000000);
+        messageBytes[pos] = (uint8_t)(thisTime); pos++;
+        messageBytes[pos] = (uint8_t)(thisTime >> 8); pos++;
+        messageBytes[pos] = (uint8_t)(thisTime >> 16); pos++;
+        messageBytes[pos] = (uint8_t)(thisTime >> 24); pos++;
+        thisTime = (uint32_t)(currentOutputParams[i].interPulseInterval * 1000000);
+        messageBytes[pos] = (uint8_t)(thisTime); pos++;
+        messageBytes[pos] = (uint8_t)(thisTime >> 8); pos++;
+        messageBytes[pos] = (uint8_t)(thisTime >> 16); pos++;
+        messageBytes[pos] = (uint8_t)(thisTime >> 24); pos++;
+        thisTime = (uint32_t)(currentOutputParams[i].burstDuration * 1000000);
+        messageBytes[pos] = (uint8_t)(thisTime); pos++;
+        messageBytes[pos] = (uint8_t)(thisTime >> 8); pos++;
+        messageBytes[pos] = (uint8_t)(thisTime >> 16); pos++;
+        messageBytes[pos] = (uint8_t)(thisTime >> 24); pos++;
+        thisTime = (uint32_t)(currentOutputParams[i].interBurstInterval * 1000000);
+        messageBytes[pos] = (uint8_t)(thisTime); pos++;
+        messageBytes[pos] = (uint8_t)(thisTime >> 8); pos++;
+        messageBytes[pos] = (uint8_t)(thisTime >> 16); pos++;
+        messageBytes[pos] = (uint8_t)(thisTime >> 24); pos++;
+        thisTime = (uint32_t)(currentOutputParams[i].pulseTrainDuration * 1000000);
+        messageBytes[pos] = (uint8_t)(thisTime); pos++;
+        messageBytes[pos] = (uint8_t)(thisTime >> 8); pos++;
+        messageBytes[pos] = (uint8_t)(thisTime >> 16); pos++;
+        messageBytes[pos] = (uint8_t)(thisTime >> 24); pos++;
+        thisTime = (uint32_t)(currentOutputParams[i].pulseTrainDelay * 1000000);
+        messageBytes[pos] = (uint8_t)(thisTime); pos++;
+        messageBytes[pos] = (uint8_t)(thisTime >> 8); pos++;
+        messageBytes[pos] = (uint8_t)(thisTime >> 16); pos++;
+        messageBytes[pos] = (uint8_t)(thisTime >> 24); pos++;
+    }
 
-void PulsePal::triggerChannel(uint8_t chan)
-{
-    const uint8_t code = 1 << (chan-1);
+    // add single-byte params
+    for (int i = 1; i < 5; i++){
+        messageBytes[pos] = (uint8_t)currentOutputParams[i].isBiphasic; pos++;
+        thisVoltage = PulsePal::currentOutputParams[i].phase1Voltage;
+        thisVoltageByte = voltageToByte(thisVoltage);
+        messageBytes[pos] = thisVoltageByte; pos++;
+        thisVoltage = PulsePal::currentOutputParams[i].phase2Voltage;
+        thisVoltageByte = voltageToByte(thisVoltage);
+        messageBytes[pos] = thisVoltageByte; pos++;
+        messageBytes[pos] = (uint8_t)currentOutputParams[i].customTrainID; pos++;
+        messageBytes[pos] = (uint8_t)currentOutputParams[i].customTrainTarget; pos++;
+        messageBytes[pos] = (uint8_t)currentOutputParams[i].customTrainLoop; pos++;
+    }
 
-    uint8_t bytesToWrite[2] = {84, code};
+    // add trigger channel 1 links
+    for (int i = 1; i < 5; i++){
+        messageBytes[pos] = (uint8_t)currentOutputParams[i].linkTriggerChannel1; pos++; 
+    }
+    // add trigger channel 2 links
+    for (int i = 1; i < 5; i++){
+        messageBytes[pos] = (uint8_t)currentOutputParams[i].linkTriggerChannel2; pos++;
+    }
 
-    serial.writeBytes(bytesToWrite, 2);
-}
+    // add trigger channel modes
+        messageBytes[pos] = (uint8_t)currentInputParams[1].triggerMode; pos++;
+        messageBytes[pos] = (uint8_t)currentInputParams[2].triggerMode; pos++;
 
 
+    serial.writeBytes(messageBytes, 163);
+}
\ No newline at end of file
diff --git a/Source/Processors/Serial/PulsePal.h b/Source/Processors/Serial/PulsePal.h
index 9b8bb2ad0a3fbdaaec11dda7ca97dc3b88423cc9..3e9167a93c4355731c05b6466822f950b14ab682 100644
--- a/Source/Processors/Serial/PulsePal.h
+++ b/Source/Processors/Serial/PulsePal.h
@@ -21,6 +21,8 @@
 
 */
 
+// Modified by JS 1/30/2014: Updated op codes for firmware 0_4, added new functions (indicated in comments below)
+
 #ifndef __PULSEPAL_H_F2B7B63E__
 #define __PULSEPAL_H_F2B7B63E__
 
@@ -29,11 +31,7 @@
 #include "ofSerial.h"
 
 /**
-
-  Interfaces with the PulsePal from Lucid Biosystems
-
-  (www.lucidbiosystems.com)
-
+  Interface to PulsePal 
   @see PulsePalOutput
 
 */
@@ -41,40 +39,77 @@
 class PulsePal
 {
 public:
+
+    // Initialization and termination
     PulsePal();
     ~PulsePal();
-
     void initialize();
+    uint32_t PulsePal::getFirmwareVersion();
+    void disconnectClient();
 
-    void setPhase1Duration(uint8_t channel, uint32_t timeInMicroseconds);
-    void setInterPhaseInterval(uint8_t channel, uint32_t timeInMicroseconds);
-    void setPhase2Duration(uint8_t channel, uint32_t timeInMicroseconds);
-    void setInterPulseInterval(uint8_t channel, uint32_t timeInMicroseconds);
-    void setBurstDuration(uint8_t channel, uint32_t timeInMicroseconds);
-    void setBurstInterval(uint8_t channel, uint32_t timeInMicroseconds);
-    void setStimulusTrainDuration(uint8_t channel, uint32_t timeInMicroseconds);
-    void setStimulusTrainDelay(uint8_t channel, uint32_t timeInMicroseconds);
+    // Program single parameter
     void setBiphasic(uint8_t channel, bool isBiphasic);
     void setPhase1Voltage(uint8_t channel, float voltage);
     void setPhase2Voltage(uint8_t channel, float voltage);
-
+    void setPhase1Duration(uint8_t channel, float timeInSeconds);
+    void setInterPhaseInterval(uint8_t channel, float timeInSeconds);
+    void setPhase2Duration(uint8_t channel, float timeInSeconds);
+    void setInterPulseInterval(uint8_t channel, float timeInSeconds);
+    void setBurstDuration(uint8_t channel, float timeInSeconds);
+    void setBurstInterval(uint8_t channel, float timeInSeconds);
+    void setPulseTrainDuration(uint8_t channel, float timeInSeconds);
+    void setPulseTrainDelay(uint8_t channel, float timeInSeconds);
+    void setTrigger1Link(uint8_t channel, uint8_t link_state);
+    void setTrigger2Link(uint8_t channel, uint8_t link_state);
+    void setCustomTrainID(uint8_t channel, uint8_t ID); // ID = 0: no custom train. ID = 1-2: custom trains 1 or 2
+    void setCustomTrainTarget(uint8_t channel, uint8_t target); // target = 0: Custom times define pulses Target = 1: They define bursts
+    void setCustomTrainLoop(uint8_t channel, uint8_t loop_state); // loop_state = 0: No loop 1: loop
+
+    // Program all parameters
+    void programAllParams();
+
+    // Program custom pulse train
+    void programCustomTrain(uint8_t ID, uint8_t nPulses, float customPulseTimes[], float customVoltages[]);
+
+    // Operations and settings
     void triggerChannel(uint8_t channel);
-
+    void triggerChannels(uint8_t channel1, uint8_t channel2, uint8_t channel3, uint8_t channel4);
     void updateDisplay(string line1, string line2);
+    void setFixedVoltage(uint8_t channel, float voltage);
+    void abortPulseTrains();
+    void setContinuousLoop(uint8_t channel, uint8_t state);
+    void setTriggerMode(uint8_t channel, uint8_t mode);
+    
+    // Fields
+    struct OutputParams {
+        int isBiphasic = 0;
+        float phase1Voltage = 5;
+        float phase2Voltage = -5;
+        float phase1Duration = 0.001;
+        float interPhaseInterval = 0.001;
+        float phase2Duration = 0.001;
+        float interPulseInterval = 0.01;
+        float burstDuration = 0;
+        float interBurstInterval = 0;
+        float pulseTrainDuration = 1;
+        float pulseTrainDelay = 0;
+        int linkTriggerChannel1 = 1;
+        int linkTriggerChannel2 = 0;
+        int customTrainID = 0;
+        int customTrainTarget = 0;
+        int customTrainLoop = 0;
+    } currentOutputParams[5]; // Use 1-indexing for the channels (output channels 1-4 = currentOutputParams[1]-currentOutputParams[4])
+    struct InputParams {
+        int triggerMode;
+    } currentInputParams[3]; // Use 1-indexing for the trigger channels
 
 private:
-
     void constrain(uint32_t* value, uint32_t min, uint32_t max);
-
     void program(uint8_t channel, uint8_t paramCode, uint32_t paramValue);
     void program(uint8_t channel, uint8_t paramCode, uint8_t paramValue);
-
     uint8_t voltageToByte(float voltage);
-
     ofSerial serial;
 
 };
 
-
-
-#endif  // __PULSEPAL_H_F2B7B63E__
+#endif  // __PULSEPAL_H_F2B7B63E__
\ No newline at end of file