From 82e34364219cc2114247eb2c42ba86cad70276d1 Mon Sep 17 00:00:00 2001 From: Michael Buesch Date: Wed, 22 Oct 2008 21:28:57 +0200 Subject: Add more pressure_control stuff Signed-off-by: Michael Buesch --- pressure_control/firmware/main.c | 37 +++++--- pressure_control/firmware/main.h | 1 + pressure_control/firmware/remote.c | 79 ++++++++++++++--- pressure_control/firmware/remote.h | 20 ++++- pressure_control/remote/pctl-remote | 171 ++++++++++++++++++++++++++---------- 5 files changed, 233 insertions(+), 75 deletions(-) (limited to 'pressure_control') diff --git a/pressure_control/firmware/main.c b/pressure_control/firmware/main.c index 3dab38e..ef4c81e 100644 --- a/pressure_control/firmware/main.c +++ b/pressure_control/firmware/main.c @@ -58,6 +58,15 @@ void get_pressure_config(struct pressure_config *ret) irq_restore(sreg); } +void set_pressure_config(struct pressure_config *new_cfg) +{ + uint8_t sreg; + + sreg = irq_disable_save(); + memcpy(&cfg, new_cfg, sizeof(cfg)); + irq_restore(sreg); +} + void get_pressure_state(struct pressure_state *ret) { uint8_t sreg; @@ -140,21 +149,21 @@ static void check_pressure(void) uint16_t abs_offset; bool is_too_big; - if (!cfg.autoadjust_enable) - return; - - offset = (int32_t)state.mbar - (int32_t)cfg.desired; - abs_offset = abs(offset); - is_too_big = (offset >= 0); - - if (abs_offset > cfg.hysteresis) { - /* Adjust the pressure */ - adjust_pressure(abs_offset, !is_too_big); - } else { - /* The pressure is OK. Make sure the valves are - * all idle. */ - valves_force_state(VALVES_IDLE); + if (cfg.autoadjust_enable) { + offset = (int32_t)state.mbar - (int32_t)cfg.desired; + abs_offset = abs(offset); + is_too_big = (offset >= 0); + + if (abs_offset > cfg.hysteresis) { + /* Adjust the pressure */ + adjust_pressure(abs_offset, !is_too_big); + } else { + /* The pressure is OK. Make sure the valves are + * all idle. */ + valves_force_state(VALVES_IDLE); + } } +//FIXME remote_pressure_change_notification(state.mbar, cfg.hysteresis); } int main(void) diff --git a/pressure_control/firmware/main.h b/pressure_control/firmware/main.h index abdfa8f..9f5cef1 100644 --- a/pressure_control/firmware/main.h +++ b/pressure_control/firmware/main.h @@ -31,6 +31,7 @@ struct pressure_state { }; void get_pressure_config(struct pressure_config *cfg); +void set_pressure_config(struct pressure_config *cfg); void get_pressure_state(struct pressure_state *state); #endif /* MAIN_H_ */ diff --git a/pressure_control/firmware/remote.c b/pressure_control/firmware/remote.c index d759e7a..b012b4a 100644 --- a/pressure_control/firmware/remote.c +++ b/pressure_control/firmware/remote.c @@ -89,30 +89,21 @@ static void send_message(struct remote_message *msg) usart_tx_buf(msg, sizeof(*msg)); } -static void send_message_error(uint8_t error_code) -{ - struct remote_message msg; - - memset(&msg, 0, sizeof(msg)); - msg.id = MSG_ERROR; - msg.error.code = error_code; - - send_message(&msg); -} - static void handle_received_message(void) { struct remote_message reply; uint16_t calc_crc; + uint8_t err = MSG_ERR_NONE; calc_crc = crc16_block_update(0xFFFF, &rx_msg, sizeof(rx_msg) - sizeof(rx_msg.crc)); calc_crc ^= 0xFFFF; if (calc_crc != rx_msg.crc) { /* CRC mismatch. */ - send_message_error(MSG_ERR_CHKSUM); - return; + err = MSG_ERR_CHKSUM; + goto out; } + memset(&reply, 0, sizeof(reply)); switch (rx_msg.id) { @@ -156,7 +147,49 @@ static void handle_received_message(void) reply.config.flags |= (1 << CFG_FLAG_AUTOADJUST_ENABLE); send_message(&reply); break; - } } + } + case MSG_SET_DESIRED_PRESSURE: { + struct pressure_config conf; + + cli(); + get_pressure_config(&conf); + conf.desired = rx_msg.pressure.mbar; + set_pressure_config(&conf); + sei(); + break; + } + case MSG_SET_HYSTERESIS: { + struct pressure_config conf; + + cli(); + get_pressure_config(&conf); + conf.hysteresis = rx_msg.pressure.mbar; + set_pressure_config(&conf); + sei(); + break; + } + case MSG_SET_CONFIG_FLAGS: { + struct pressure_config conf; + + cli(); + get_pressure_config(&conf); + conf.autoadjust_enable = !!(rx_msg.config.flags & (1 << CFG_FLAG_AUTOADJUST_ENABLE)); + set_pressure_config(&conf); + sei(); + break; + } + default: + err = MSG_ERR_NOCMD; + break; + } + +out: + if (rx_msg.flags & (1 << MSG_FLAG_REQ_ERRCODE)) { + memset(&reply, 0, sizeof(reply)); + reply.id = MSG_ERROR; + reply.error.code = err; + send_message(&reply); + } } /* RX interrupt */ @@ -182,6 +215,7 @@ ISR(USART_RXC_vect) rx_msg_count = 0; mb(); rx_msg_valid = 1; + break; } } } @@ -217,6 +251,23 @@ void remote_work(void) } } +void remote_pressure_change_notification(uint16_t mbar, + uint16_t hysteresis) +{ + struct remote_message msg; + + static uint16_t prev_value; + + if (abs((int32_t)mbar - (int32_t)prev_value) <= hysteresis) + return; + prev_value = mbar; + + memset(&msg, 0, sizeof(msg)); + msg.id = MSG_CURRENT_PRESSURE; + msg.pressure.mbar = mbar; + send_message(&msg); +} + static void usart_init(void) { uint8_t dummy; diff --git a/pressure_control/firmware/remote.h b/pressure_control/firmware/remote.h index af18abf..46d35ff 100644 --- a/pressure_control/firmware/remote.h +++ b/pressure_control/firmware/remote.h @@ -23,11 +23,17 @@ enum remote_message_id { MSG_GET_CONFIG_FLAGS, MSG_CONFIG_FLAGS, MSG_SET_CONFIG_FLAGS, + MSG_SET_VALVE, }; enum remote_message_error { - MSG_ERR_NONE = 0, - MSG_ERR_CHKSUM, + MSG_ERR_NONE = 0, /* No error */ + MSG_ERR_CHKSUM, /* Checksum error */ + MSG_ERR_NOCMD, /* Unknown command */ +}; + +enum remote_message_flags { + MSG_FLAG_REQ_ERRCODE = 0, }; enum remote_message_config_flags { @@ -36,7 +42,8 @@ enum remote_message_config_flags { struct remote_message { uint8_t id; - uint8_t __padding0[3]; + uint8_t flags; + uint8_t __padding0[2]; union { struct { @@ -51,6 +58,10 @@ struct remote_message { struct { uint32_t flags; } __attribute__((packed)) config; + struct { + uint8_t nr; /* Valve ID */ + uint8_t state; + } __attribute__((packed)) valve; uint8_t __padding1[32]; } __attribute__((packed)); @@ -62,6 +73,9 @@ struct remote_message { void print_pgm(const prog_char *msg); #define print(string_literal) print_pgm(PSTR(string_literal)) +void remote_pressure_change_notification(uint16_t mbar, + uint16_t hysteresis); + void remote_work(void); void remote_init(void); diff --git a/pressure_control/remote/pctl-remote b/pressure_control/remote/pctl-remote index 9dba6f2..e3d8dcf 100755 --- a/pressure_control/remote/pctl-remote +++ b/pressure_control/remote/pctl-remote @@ -49,10 +49,14 @@ MSG_SET_HYSTERESIS = 12 MSG_GET_CONFIG_FLAGS = 13 MSG_CONFIG_FLAGS = 14 MSG_SET_CONFIG_FLAGS = 15 +MSG_SET_VALVE = 16 # Message error codes -MSG_ERR_NONE = 0 -MSG_ERR_CHKSUM = 1 +MSG_ERR_NONE = 0 # No error +MSG_ERR_CHKSUM = 1 # Checksum error +MSG_ERR_NOCMD = 2 # Unknown command MSG_ERR_NOREPLY = -1 # internal. Not sent over wire. +# Message flags +MSG_FLAG_REQ_ERRCODE = 0 # Config flags CFG_FLAG_AUTOADJUST_ENABLE = 0 @@ -92,7 +96,9 @@ def parseArgs(): class RemoteProtocol(QObject): def __init__(self, ttyfile): QObject.__init__(self) + global remote + remote = self self.serial = Serial(ttyfile, CONFIG_BAUDRATE, CONFIG_BYTESIZE, CONFIG_PARITY, CONFIG_STOPBITS) @@ -101,7 +107,7 @@ class RemoteProtocol(QObject): self.connect(self.pollTimer, SIGNAL("timeout()"), self.poll) self.pollTimer.start(50) - reply = self.sendMessageSyncReply(MSG_PING, "", MSG_PONG) + reply = self.sendMessageSyncReply(MSG_PING, 0, "", MSG_PONG) if not reply: print "Communication with device failed. No reply to PING request." sys.exit(1) @@ -127,22 +133,22 @@ class RemoteProtocol(QObject): if not self.checksumMessage(msg): return id = ord(msg[0]) + mainwnd.statusBar().showMessage(self.tr("Received message %u" % id)) if (id == MSG_LOGMESSAGE): str = self.getPayload(msg).rstrip('\0') mainwnd.centralWidget().log.addText(str) - if (id == MSG_PING): - sendMessage(MSG_PING, []) if (id == MSG_CURRENT_PRESSURE): mainwnd.centralWidget().parseCurrentPressureMsg(msg) + #TODO def getPayload(self, msg): return msg[4:-2] - def sendMessage(self, id, payload): + def sendMessage(self, id, flags, payload): """Send a message""" assert(len(payload) <= MSG_PAYLOAD_SIZE) # Create the header - msg = "%c\0\0\0" % id + msg = "%c%c\0\0" % (id, flags) # Add the payload msg += payload # Pad the payload up to the constant size @@ -158,19 +164,19 @@ class RemoteProtocol(QObject): # Send the message assert(len(msg) == MSG_SIZE) self.serial.write(msg) + mainwnd.statusBar().showMessage(self.tr("Sent message %u" % id)) - def sendMessageSyncReply(self, id, payload, replyId): + def sendMessageSyncReply(self, id, flags, payload, replyId): """Send a message and synchronously wait for the reply.""" self.pollTimer.stop() - self.sendMessage(id, payload) + self.sendMessage(id, flags, payload) timeout = QDateTime.currentDateTime().addSecs(2) while True: if QDateTime.currentDateTime() >= timeout: msg = None break if self.serial.inWaiting() < MSG_SIZE: - app.processEvents() - QThread.msleep(50) + QThread.msleep(1) continue msg = self.serial.read(MSG_SIZE) if not self.checksumMessage(msg): @@ -183,13 +189,40 @@ class RemoteProtocol(QObject): self.pollTimer.start() return msg - def sendMessageSyncError(self, id, payload): + def sendMessageSyncError(self, id, flags, payload): """Sends a message and synchronously waits for the MSG_ERROR reply.""" - reply = self.sendMessageSyncReply(id, payload, MSG_ERROR) + flags |= (1 << MSG_FLAG_REQ_ERRCODE) + reply = self.sendMessageSyncReply(id, flags, payload, MSG_ERROR) if not reply: return MSG_ERR_NOREPLY return ord(self.getPayload(reply)[0]) + def configFlagsFetch(self): + reply = self.sendMessageSyncReply(MSG_GET_CONFIG_FLAGS, 0, "", + MSG_CONFIG_FLAGS) + if not reply: + return None + reply = remote.getPayload(reply) + flags = ord(reply[0]) | (ord(reply[1]) << 8) | \ + (ord(reply[2]) << 16) | (ord(reply[3]) << 24) + return flags + + def configFlagsSet(self, flags): + data = "%c%c%c%c" % ((flags & 0xFF), ((flags >> 8) & 0xFF), + ((flags >> 16) & 0xFF), ((flags >> 24) & 0xFF)) + err = self.sendMessageSyncError(MSG_SET_CONFIG_FLAGS, 0, data) + return err + + def setValve(self, valveNr, state): + data = "%c%c" % (valveNr, (state != 0)) + i = 5 # Retry a few times + while i != 0: + err = self.sendMessageSyncError(MSG_SET_VALVE, 0, data) + if err == MSG_ERR_NONE: + break + i -= 1 + return err + def __crc16_update_buffer(self, crc, buf): for c in buf: crc ^= ord(c) @@ -202,7 +235,7 @@ class RemoteProtocol(QObject): class StatusBar(QStatusBar): def showMessage(self, msg): - QStatusBar.showMessage(self, msg, 10000) + QStatusBar.showMessage(self, msg, 3000) class LogBrowser(QTextEdit): def __init__(self, parent=None): @@ -239,12 +272,22 @@ class MainWidget(QWidget): h.addStretch() layout.addLayout(h) - self.autoCheckbox = QCheckBox(self.tr("Automatically adjust pressure"), self) - layout.addWidget(self.autoCheckbox) + h = QHBoxLayout() + label = QLabel(self.tr("Hysteresis:"), self) + h.addWidget(label) + self.hystSpin = QDoubleSpinBox(self) + self.hystSpin.setMinimum(0.1) + self.hystSpin.setMaximum(8) + self.hystSpin.setSingleStep(0.1) + self.hystSpin.setSuffix(self.tr(" Bar")) + self.connect(self.hystSpin, SIGNAL("valueChanged(double)"), + self.desiredHysteresisChanged) + h.addWidget(self.hystSpin) + h.addStretch() + layout.addLayout(h) h = QHBoxLayout() label = QLabel(self.tr("Desired pressure:"), self) - h.addStretch() h.addWidget(label) self.pressureSpin = QDoubleSpinBox(self) self.pressureSpin.setMinimum(1) @@ -254,30 +297,37 @@ class MainWidget(QWidget): self.connect(self.pressureSpin, SIGNAL("valueChanged(double)"), self.desiredPressureChanged) h.addWidget(self.pressureSpin) + self.autoCheckbox = QCheckBox(self.tr("Automatically adjust pressure"), self) + self.connect(self.autoCheckbox, SIGNAL("stateChanged(int)"), + self.autoadjustChanged) + h.addWidget(self.autoCheckbox) + h.addStretch() layout.addLayout(h) h = QHBoxLayout() - label = QLabel(self.tr("Hysteresis:"), self) - h.addStretch() - h.addWidget(label) - self.hystSpin = QDoubleSpinBox(self) - self.hystSpin.setMinimum(0.1) - self.hystSpin.setMaximum(8) - self.hystSpin.setSingleStep(0.1) - self.hystSpin.setSuffix(self.tr(" Bar")) - self.connect(self.hystSpin, SIGNAL("valueChanged(double)"), - self.desiredHysteresisChanged) - h.addWidget(self.hystSpin) + self.inButton = QPushButton(self.tr("IN-Valve"), self) + self.connect(self.inButton, SIGNAL("pressed()"), + self.inValvePressed) + self.connect(self.inButton, SIGNAL("released()"), + self.inValveReleased) + h.addWidget(self.inButton) + self.outButton = QPushButton(self.tr("OUT-Valve"), self) + h.addWidget(self.outButton) + self.connect(self.outButton, SIGNAL("pressed()"), + self.outValvePressed) + self.connect(self.outButton, SIGNAL("released()"), + self.outValveReleased) layout.addLayout(h) self.log = LogBrowser(self) layout.addWidget(self.log) + self.autoadjustChanged(Qt.Unchecked) self.setLayout(layout) def initializeState(self): # Get the current pressure - reply = remote.sendMessageSyncReply(MSG_GET_CURRENT_PRESSURE, "", + reply = remote.sendMessageSyncReply(MSG_GET_CURRENT_PRESSURE, 0, "", MSG_CURRENT_PRESSURE) if not reply: print "Failed to fetch current pressure. No reply." @@ -285,7 +335,7 @@ class MainWidget(QWidget): self.parseCurrentPressureMsg(reply) # Get the desired pressure - reply = remote.sendMessageSyncReply(MSG_GET_DESIRED_PRESSURE, "", + reply = remote.sendMessageSyncReply(MSG_GET_DESIRED_PRESSURE, 0, "", MSG_DESIRED_PRESSURE) if not reply: print "Failed to fetch desired pressure. No reply." @@ -295,7 +345,7 @@ class MainWidget(QWidget): self.pressureSpin.setValue(float(mbar) / 1000) # Get the hysteresis - reply = remote.sendMessageSyncReply(MSG_GET_HYSTERESIS, "", + reply = remote.sendMessageSyncReply(MSG_GET_HYSTERESIS, 0, "", MSG_HYSTERESIS) if not reply: print "Failed to fetch hysteresis. No reply." @@ -305,17 +355,12 @@ class MainWidget(QWidget): self.hystSpin.setValue(float(mbar) / 1000) # Get the config flags - reply = remote.sendMessageSyncReply(MSG_GET_CONFIG_FLAGS, "", - MSG_CONFIG_FLAGS) - if not reply: + flags = remote.configFlagsFetch() + if flags == None: print "Failed to fetch config flags. No reply." sys.exit(1) - reply = remote.getPayload(reply) - flags = ord(reply[0]) | (ord(reply[1]) << 8) | \ - (ord(reply[2]) << 16) | (ord(reply[3]) << 24) if flags & (1 << CFG_FLAG_AUTOADJUST_ENABLE): self.autoCheckbox.setCheckState(Qt.Checked) - #TODO self.initialized = True @@ -324,24 +369,62 @@ class MainWidget(QWidget): mbar = ord(msg[0]) | (ord(msg[1]) << 8) self.curPressure.display(float(mbar) / 1000) - def desiredPressureChanged(self): + def desiredPressureChanged(self, value): if not self.initialized: return - mbar = int(self.pressureSpin.value() * 1000) + mbar = int(value * 1000) data = "%c%c" % ((mbar & 0xFF), ((mbar >> 8) & 0xFF)) - err = remote.sendMessageSyncError(MSG_SET_DESIRED_PRESSURE, data) + err = remote.sendMessageSyncError(MSG_SET_DESIRED_PRESSURE, 0, data) if err != MSG_ERR_NONE: self.log.addText(self.tr("Failed to change pressure. Error=%u\n" % err)) - def desiredHysteresisChanged(self): + def desiredHysteresisChanged(self, value): if not self.initialized: return - mbar = int(self.hystSpin.value() * 1000) + mbar = int(value * 1000) data = "%c%c" % ((mbar & 0xFF), ((mbar >> 8) & 0xFF)) - err = remote.sendMessageSyncError(MSG_SET_HYSTERESIS, data) + err = remote.sendMessageSyncError(MSG_SET_HYSTERESIS, 0, data) if err != MSG_ERR_NONE: self.log.addText(self.tr("Failed to change hysteresis. Error=%u\n" % err)) + def autoadjustChanged(self, state): + self.pressureSpin.setEnabled(state == Qt.Checked) + self.inButton.setEnabled(state == Qt.Unchecked) + self.outButton.setEnabled(state == Qt.Unchecked) + if not self.initialized: + return + flags = remote.configFlagsFetch() + if flags == None: + self.log.addText(self.tr("Failed to fetch config flags\n")) + return + if state == Qt.Checked: + flags |= (1 << CFG_FLAG_AUTOADJUST_ENABLE) + else: + flags &= ~(1 << CFG_FLAG_AUTOADJUST_ENABLE) + err = remote.configFlagsSet(flags) + if err != MSG_ERR_NONE: + self.log.addText(self.tr("Failed to set config flags\n")) + + def inValvePressed(self): + err = remote.setValve(0, 1) + if err != MSG_ERR_NONE: + self.log.addText(self.tr("Failed to switch valve 0 ON\n")) + + def inValveReleased(self): + err = remote.setValve(0, 0) + if err != MSG_ERR_NONE: + self.log.addText(self.tr("Failed to switch valve 0 OFF\n")) + + def outValvePressed(self): + err = remote.setValve(1, 1) + if err != MSG_ERR_NONE: + self.log.addText(self.tr("Failed to switch valve 1 ON\n")) + + def outValveReleased(self): + err = remote.setValve(1, 0) + if err != MSG_ERR_NONE: + self.log.addText(self.tr("Failed to switch valve 1 OFF\n")) + class MainWindow(QMainWindow): def __init__(self, parent=None): QMainWindow.__init__(self, parent) -- cgit v1.2.3