From 3a9ad7c595d2b7e892d2eb6e1e39d789e3e0f575 Mon Sep 17 00:00:00 2001 From: Wolfgang Draxinger Date: Thu, 27 Oct 2011 17:19:16 +0200 Subject: extended status class, exception classes, extendedstatusquery --- Phytron.py | 152 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 143 insertions(+), 9 deletions(-) diff --git a/Phytron.py b/Phytron.py index c00d079..406913b 100644 --- a/Phytron.py +++ b/Phytron.py @@ -9,6 +9,21 @@ class ReceiveChecksumError(exceptions.Exception): self.received = received self.message = "Checksum Error: expected %x, got %x" % (expected, received) +class OverrunError(exceptions.EnvironmentError): + pass + +class NotNowWarning(exceptions.UserWarning): + pass + +class UnknownCommand(exceptions.Exception): + pass + +class BadValueError(exceptions.Exception): + pass + +class ParameterLimitsError(exceptions.ValueError): + pass + class Axis: def __init__(self, ipcomm, ID): self.ipcomm = ipcomm @@ -16,8 +31,7 @@ class Axis: def execute(self, cmd): result = self.ipcomm.execute(self.ID, cmd) - assert result['ID'] == self.ID - del result['ID'] + assert result.ID == self.ID return result def goToAbs(self, position): @@ -46,6 +60,14 @@ def checksum(data): return chksm class Status: + COLDBOOT = (1<<7) + ANY_ERROR = (1<<6) + RX_ERROR = (1<<5) + SFI_ERROR = (1<<4) + OUTPUTSTAGE_ERROR = (1<<3) + INITIATOR_M = (1<<2) + INITIATOR_P = (1<<1) + RUNNING = (1<<0) def __init__(self, bitvector): self.coldboot = not not (bitvector & (1<<7)) self.any_error = not not (bitvector & (1<<6)) @@ -76,6 +98,60 @@ class Status: status += ['Running'] return '{'+ ('|'.join(status)) + '}' +class ExtendedStatus: + CHECKSUM_ERROR = (1<<23) + # (1<<22) + RXBUFFER_OVERRUN = (1<<21) + NOT_NOW = (1<<20) + UNKNOWN_COMMAND = (1<<19) + BAD_VALUE = (1<<18) + PARAMETER_LIMITS = (1<<17) + # (1<<16) + NO_SYSTEM = (1<<15) + NO_RAMPS = (1<<14) + PARAMETER_CHANGED = (1<<13) + BUSY = (1<<12) + PROGRAMING_ERROR = (1<<11) + HIGH_TEMPERATURE = (1<<10) + INITIATOR_ERROR = (1<< 9) + INTERNAL_ERROR = (1<< 8) + DRIVER_ERROR = (1<< 7) + # (1<< 6) + WAIT_FOR_SYNC = (1<< 5) + LINEAR_AXIS = (1<< 4) + FREE_RUNNING = (1<< 3) + INITIALIZED = (1<< 2) + HW_DISABLE = (1<< 1) + INITIALIZING = (1<< 0) + def __init__(self, bitvector): + self.checksum_error = not not (bitvector & ExtendedStatus.CHECKSUM_ERROR) + self.rxbuffer_overrun = not not (bitvector & ExtendedStatus.RXBUFFER_OVERRUN) + self.not_now = not not (bitvector & ExtendedStatus.NOT_NOW) + self.unknown_command = not not (bitvector & ExtendedStatus.UNKNOWN_COMMAND) + self.bad_value = not not (bitvector & ExtendedStatus.BAD_VALUE) + self.parameter_limits = not not (bitvector & ExtendedStatus.PARAMETER_LIMITS) + self.no_system = not not (bitvector & ExtendedStatus.NO_SYSTEM) + self.no_ramps = not not (bitvector & ExtendedStatus.NO_RAMPS) + self.parameter_changed = not not (bitvector & ExtendedStatus.PARAMETER_CHANGED) + self.busy = not not (bitvector & ExtendedStatus.BUSY) + self.programing_error = not not (bitvector & ExtendedStatus.PROGRAMING_ERROR) + self.high_temperature = not not (bitvector & ExtendedStatus.HIGH_TEMPERATURE) + self.initiator_error = not not (bitvector & ExtendedStatus,INITIATOR_ERROR) + self.internal_error = not not (bitvector & ExtendedStatus.INTERNAL_ERROR) + self.driver_error = not not (bitvector & ExtendedStatus.DRIVER_ERROR) + self.wait_for_sync = not not (bitvector & ExtendedStatus.WAIT_FOR_SYNC) + self.linear_axis = not not (bitvector & ExtendedStatus.LINEAR_AXIS) + self.free_running = not not (bitvector & ExtendedStatus.FREE_RUNNING) + self.initialized = not not (bitvector & ExtendedStatus.INITIALIZED) + self.hw_disable = not not (bitvector & ExtendedStatus.HW_DISABLE) + self.initializing = not not (bitvector & ExtendedStatus.INITIALIZING) + +class ReceiveData: + def __init__(self, ID, status, data): + self.ID = ID + self.status = status + self.data = data + class IPCOMM: def __init__(self, url, baudrate = 38400, axisnames = None): self.conn = serial.serial_for_url(url) @@ -99,7 +175,7 @@ class IPCOMM: self.axisByName.clear() for ID in range(0x10): try: - assert self.execute(ID, 'IS?')['ID'] == ID + assert self.execute(ID, 'IS?').ID == ID axis = Axis(self, ID) self.axisByID[ID] = axis @@ -122,13 +198,13 @@ class IPCOMM: while c != '\x02': c = self.conn.read(1) if not c: - raise ReceiveTimeout + raise ReceiveTimeout() c = None while c != '\x03': c = self.conn.read(1) if not c: - raise ReceiveTimeout + raise ReceiveTimeout() buf += c status, data, chksm = buf[:-1].split(':') @@ -137,15 +213,18 @@ class IPCOMM: if expected_chksm != chksm: raise ReceiveChecksumError(expected_chksm, chksm) - return {'ID': string.atoi(status[0], 0x10), - 'status': Status(string.atoi(status[1:], 0x10)), - 'data': data} + return ReceiveData( ID = string.atoi(status[0], 0x10), + status = Status(string.atoi(status[1:], 0x10)), + data = data ) def broadcast(self, cmd): self.conn.flushInput() self.send( '@' + cmd ) def execute(self, ID, cmd): + if cmd == 'IS?': + return self.queryextendedstatus(ID) + self.conn.flushInput() self.send( ('%X' % ID) + cmd ) @@ -155,7 +234,62 @@ class IPCOMM: recv_data = self.recv() except ReceiveChecksumError: self.send( ('%X' % ID) + 'R') - # self.parseStatus(recv_status) + + if recv_data.status.rx_error: + extended_status = self.queryextendedstatus(ID) + + if extended_status.checksum_error: + self.conn.flushInput() + self.send( ('%X' % ID) + cmd ) + recv_data = None + continue + + if extended_status.overrun: + raise OverrunError() + + if extended_status.not_now: + raise NotNowWarning() + + if extended_status.unknown(): + raise UnknownCommand() + + if extended_status.bad_value: + raise BadValueError() + + if extended_status.parameter_limits(): + raise ParameterLimitsError() + + + return recv_data + + def queryextendedstatus(self, ID): + """ + Special function for querying the extended status. + Same basic structure like execute, with the following exceptions: + * does not take a command (always issued a IS?) + * will not resend query if status rx_error is reported + * will not request reply retransmission + * will not raise status related exceptions + + Since regular execute will raise exceptions based on IS? status + to query the status for further processing, this method must be used. + + If the extended status can not be requested, None is returned. + """ + self.conn.flushInput() + self.send( ('%X' % ID) + 'IS?' ) + + recv_data = None + try: + recv_data = self.recv() + except ReceiveChecksumError: + return None + + if recv_data: + recv_data.data = ExtendedStatus(string.atoi(recv_data.data, 0x10)) + else: + recv_data = None + return recv_data def goToAbs(self, positions): -- cgit v1.2.3