Exemple #1
0
 def __fillbuffer(self, answer):
     """Read answers and save them as float values into the data buffer.
     An answerline with invalid data (non-number, missing column) will be skipped and error flag is set.
     @param answer : String of already readout answer.
     """
     numcolumns = len(self.__databuffer['data'])
     with self.__lock:
         while True:
             lines = answer.splitlines(True)  # keep line endings
             answer = ''
             for line in lines:
                 if '\n' not in line:
                     answer = line
                     break
                 msg = 'cannot convert to float: %r' % line
                 try:
                     values = [float(x) for x in line.split()]
                     if numcolumns != len(values):
                         msg = 'expected %d, got %d columns: %r' % (
                             numcolumns, len(values), line)
                         raise ValueError()
                 except ValueError:
                     exc = GCSError(gcserror.E_1004_PI_UNEXPECTED_RESPONSE,
                                    msg)
                     self.__databuffer['error'] = exc
                     error('GCSMessages: GCSError: %s', exc)
                 else:
                     for i in range(numcolumns):
                         self.__databuffer['data'][i].append(values[i])
                 self.__databuffer['index'] += 1
                 if self.__endofdata(line):
                     debug(
                         'GCSMessages: end background task to query GCS data'
                     )
                     self.__databuffer['error'] = self.__checkerror(
                         doraise=False)
                     self.__databuffer['size'] = True
                     return
             try:
                 answer += self.__read(stopon=' \n')
             except:  # No exception type(s) specified pylint: disable=W0702
                 exc = GCSError(gcserror.E_1090_PI_GCS_DATA_READ_ERROR,
                                sys.exc_info()[1])
                 self.__databuffer['error'] = exc
                 error('GCSMessages: end background task with GCSError: %s',
                       exc)
                 self.__databuffer['size'] = True
                 return
Exemple #2
0
 def __read(self, stopon):
     """Read answer from device until this ends with linefeed with no preceeding space.
     @param stopon: Addditional uppercase string that stops reading, too.
     @return : Received data as string.
     """
     timeout = time() + self.__timeout / 1000.
     chunks = []
     while True:
         if time() > timeout:
             raise GCSError(gcserror.E_7_COM_TIMEOUT)
         if self.__interface.answersize:
             timeout = time() + self.__timeout / 1000.
             received = self.__interface.getanswer(
                 self.__interface.answersize)
             chunks.append(received)
             if endofanswer(chunks[-1]):
                 break
             if stopon and stopon in chunks[-1].upper():
                 break
     try:
         answer = ''.join(chunks)
     except TypeError:
         answer = b''.join(chunks)
     self.__check_no_eol(answer)
     return answer
Exemple #3
0
 def bufstate(self):
     """False if no buffered data is available. True if buffered data is ready to use.
     Float value 0..1 indicates read progress. To wait, use "while bufstate is not True".
     """
     if self._databuffer['error']:
         self._stopthread = True
         raise self._databuffer['error']  # Raising NoneType pylint: disable=E0702
     if self._databuffer['lastupdate'] is None:
         self._databuffer['lastupdate'] = time()
     if self._databuffer['index'] == self._databuffer['lastindex']:
         if time() - float(
                 self._databuffer['lastupdate']) > self.timeout / 1000.:
             self._stopthread = True
             raise GCSError(
                 gcserror.COM_TIMEOUT__7,
                 '@ GCSMessages.bufstate after %.1f s' %
                 (self.timeout / 1000.))
     else:
         self._databuffer['lastupdate'] = time()
         self._databuffer['lastindex'] = self._databuffer['index']
     if not self._databuffer['size']:
         return False
     if self._databuffer['size'] is True:
         self._databuffer['lastupdate'] = None
         return True
     return float(self._databuffer['index']) / float(
         self._databuffer['size'])
 def GetAsyncBuffer(self, firstline=1, lastline=0, numtables=1):
     """Query all available data points, return list with 'numtables' columns.
     DEPRECATED: Use GCSMessages.bufdata instead.
     Buffer is used by qDRR(), qDDL(), qGWD(), qTWS(), qJLT() and qHIT().
     @param firstline : Optional, but must be >= 1 and smaller than 'lastline'.
     @param lastline : Optional, defaults to query all available data points.
     @param numtables : Arrange data into 'numtables' columns, defaults to "1".
     @return: List of data points as float with 'numtables' columns.
     """
     debug(
         'DEPRECATED -- GcsDll.GetAsyncBuffer(id%d, firstline=%r, lastline=%r, numtables=%r)',
         self.__id, firstline, lastline, numtables)
     maxindex = lastline * numtables or self.__asyncbufferindex
     assert firstline >= 1, 'firstline must be 1 or larger'
     minindex = (firstline - 1) * numtables
     assert minindex <= maxindex, 'firstline must not be larger than lastline'
     cvalues = ctypes.byref(ctypes.c_float)
     if not getattr(self.__handle, self.__prefix + 'GetAsyncBuffer')(
             self.__id, cvalues):
         raise GCSError(self.__error)
     data = [[] for _ in range(numtables)]
     for i in range(minindex, maxindex):
         data[i % numtables].append(float(cvalues[i]))
     debug('DEPRECATED -- GCSDll.GetAsyncBuffer(id%d): %r', self.__id, data)
     return data
 def OpenTCPIPDaisyChain(self, ipaddress, ipport=50000):
     """Open a TCPIP daisy chain connection.
     To get access to a daisy chain device you have to call ConnectDaisyChainDevice().
     @param ipaddress: IP address to connect to as string.
     @param ipport: Port to use as integer, defaults to 50000.
     @return: Found devices as list of strings.
     """
     debug('GCSDll.OpenTCPIPDaisyChain(ipaddress=%r, ipport=%s)', ipaddress,
           ipport)
     cipaddress = ctypes.c_char_p(ipaddress.encode())
     cipport = ctypes.c_int(ipport)
     numdev = ctypes.byref(ctypes.c_int())
     bufsize = 10000
     bufstr = ctypes.create_string_buffer('\000'.encode(), bufsize + 2)
     self.__dcid = getattr(self.__handle, self.__prefix +
                           'OpenTCPIPDaisyChain')(cipaddress, cipport,
                                                  numdev, bufstr, bufsize)
     if self.__dcid < 0:
         raise GCSError(self.__error)
     devlist = bufstr.value.decode().split('\n')[:-1]
     devlist = [item.strip() for item in devlist]
     debug('GCSDll.OpenTCPIPDaisyChain: %r', devlist)
     self.__ifdescription = 'TCPIP daisy chain at %s:%s' % (ipaddress,
                                                            ipport)
     return devlist
 def _endofdata(self, line):
     """Verify 'line' and return True if 'line' is last line of device answer.
     @param line : One answer line of device with trailing line feed character.
     @return : True if 'line' is last line of device answer.
     """
     if eol(line) and self._databuffer['size'] and self._databuffer['index'] < self._databuffer['size']:
         msg = '%s expected, %d received' % (self._databuffer['size'], self._databuffer['index'])
         exc = GCSError(gcserror.E_1088_PI_TOO_FEW_GCS_DATA, msg)
         self._databuffer['error'] = exc
         error('GCSMessages: GCSError: %s', exc)
     if self._databuffer['size'] and self._databuffer['index'] > self._databuffer['size']:
         msg = '%s expected, %d received' % (self._databuffer['size'], self._databuffer['index'])
         exc = GCSError(gcserror.E_1089_PI_TOO_MANY_GCS_DATA, msg)
         self._databuffer['error'] = exc
         error('GCSMessages: GCSError: %s', exc)
     return eol(line)
 def _fillbuffer(self, answer, stop):
     """Read answers and save them as float values into the data buffer.
     An answerline with invalid data (non-number, missing column) will be skipped and error flag is set.
     @param answer : String of already readout answer.
     @param stop : Callback function that stops the loop if True.
     """
     with self._lock:
         while True:
             lines = answer.splitlines(True)  # keep line endings
             answer = ''
             for line in lines:
                 if '\n' not in line:
                     answer = line
                     break
                 self._convertfloats(line)
                 if self._endofdata(line):
                     debug('GCSMessages: end background task to query GCS data')
                     if not self._databuffer['error']:
                         self._databuffer['error'] = self._checkerror(doraise=False)
                     if not self._databuffer['error']:
                         self._databuffer['size'] = True
                     return
             try:
                 answer += self._read(stopon=' \n')
             except:  # No exception type(s) specified pylint: disable=W0702
                 exc = GCSError(gcserror.E_1090_PI_GCS_DATA_READ_ERROR, sys.exc_info()[1])
                 self._databuffer['error'] = exc
                 error('GCSMessages: end background task with GCSError: %s', exc)
                 self._databuffer['size'] = True
                 return
             if stop():
                 error('GCSMessages: stop background task to query GCS data')
                 return
 def answersize(self):
     """Get the size of an answer of a GCS command as integer."""
     size = ctypes.c_int()
     if not getattr(self.__handle, self.__prefix + 'GcsGetAnswerSize')(
             self.__id, ctypes.byref(size)):
         raise GCSError(self.__error)
     return size.value
 def OpenRS232DaisyChain(self, comport, baudrate):
     """Open an RS-232 daisy chain connection.
     To get access to a daisy chain device you have to call ConnectDaisyChainDevice().
     @param comport: Port to use as integer (1 means "COM1").
     @param baudrate: Baudrate to use as integer.
     @return: Found devices as list of strings.
     """
     debug('GCSDll.OpenRS232DaisyChain(comport=%s, baudrate=%s)', comport,
           baudrate)
     ccomport = ctypes.c_int(comport)
     cbaudrate = ctypes.c_int(baudrate)
     numdev = ctypes.byref(ctypes.c_int())
     bufsize = 10000
     bufstr = ctypes.create_string_buffer('\000'.encode(), bufsize + 2)
     self.__dcid = getattr(self.__handle,
                           self.__prefix + 'OpenRS232DaisyChain')(ccomport,
                                                                  cbaudrate,
                                                                  numdev,
                                                                  bufstr,
                                                                  bufsize)
     if self.__dcid < 0:
         raise GCSError(self.__error)
     devlist = bufstr.value.decode().split('\n')[:-1]
     devlist = [item.strip() for item in devlist]
     debug('GCSDll.OpenRS232DaisyChain: %r', devlist)
     self.__ifdescription = 'RS-232 daisy chain at COM%s, %s Baud' % (
         comport, baudrate)
     return devlist
Exemple #10
0
 def send(self, command):
     """Send a GCS command to the device, do not query error from device.
     @param command : GCS command as string, with or without trailing line feed character.
     """
     debug('GCSDll.send(id%d): %r', self.__id, command)
     command = ctypes.c_char_p(command.encode())
     if not getattr(self.__handle, self.__prefix + 'GcsCommandset')(self.__id, command):
         raise GCSError(self.__error)
Exemple #11
0
 def RemoveStage(self, axis):
     """Remove a dataset of a user defined stage from the PI stages database.
     @param axis: Name of axis whose stage parameters should be removed as string.
     """
     debug('GCSDll.RemoveStage(axis=%r)', axis)
     axis = ctypes.c_char_p(str(axis).encode())
     if not getattr(self.__handle, self.__prefix + 'RemoveStage')(self.__id, axis):
         raise GCSError(self.__error)
Exemple #12
0
 def AddStage(self, axis):
     """Add a dataset for a user defined stage to the PI stages database.
     @param axis: Name of axis whose stage parameters should be added as string.
     """
     debug('GCSDll.AddStage(axis=%r)', axis)
     assert isinstance(axis, basestring), 'argument for AddStage must be string'
     axis = ctypes.c_char_p(str(axis).encode())
     if not getattr(self.__handle, self.__prefix + 'AddStage')(self.__id, axis):
         raise GCSError(self.__error)
 def _check_no_eol(answer):
     """Check that 'answer' does not contain a LF without a preceeding SPACE except at the end.
     @param answer : Answer to verify as string.
     """
     for i, char in enumerate(answer[:-1]):
         if char == '\n' or char == '\r':
             if i > 0 and answer[i - 1] != ' ':
                 msg = '@ GCSMessages._check_no_eol: LF/CR at %r' % answer[max(0, i - 10):min(i + 10, len(answer))]
                 raise GCSError(gcserror.E_1004_PI_UNEXPECTED_RESPONSE, msg)
Exemple #14
0
 def InterfaceSetupDlg(self, key=''):
     """Open dialog to select the interface.
     @param key: Optional key name as string to store the settings in the Windows registry.
     """
     debug('GCSDll.InterfaceSetupDlg(key=%r)', key)
     key = ctypes.c_char_p(key.encode())
     self.__id = getattr(self.__handle, self.__prefix + 'InterfaceSetupDlg')(key)
     if self.__id < 0:
         raise GCSError(self.__error)
     self.__ifdescription = 'Interface Setup Dialog'
Exemple #15
0
 def ConnectTCPIPByDescription(self, description):
     """Open a TCP/IP connection to the device using the device 'description'.
     @param description: One of the identification strings listed by EnumerateTCPIPDevices().
     """
     debug('GCSDll.ConnectTCPIPByDescription(description=%r)', description)
     cdescription = ctypes.c_char_p(description.encode())
     self.__id = getattr(self.__handle, self.__prefix + 'ConnectTCPIPByDescription')(cdescription)
     if self.__id < 0:
         raise GCSError(self.__error)
     self.__ifdescription = 'TCPIP %r' % description
Exemple #16
0
 def ConnectUSB(self, serialnum):
     """Open an USB connection to a device.
     @param serialnum: Serial number of device or one of the
     identification strings listed by EnumerateUSB().
     """
     debug('GCSDll.ConnectUSB(serialnum=%r)', serialnum)
     cserialnum = ctypes.c_char_p(serialnum.encode())
     self.__id = getattr(self.__handle, self.__prefix + 'ConnectUSB')(cserialnum)
     if self.__id < 0:
         raise GCSError(self.__error)
     self.__ifdescription = 'USB %r' % serialnum
Exemple #17
0
 def ConnectTCPIP(self, ipaddress, ipport=50000):
     """Open a TCP/IP connection to the device.
     @param ipaddress: IP address to connect to as string.
     @param ipport: Port to use as integer, defaults to 50000.
     """
     debug('GCSDll.ConnectTCPIP(ipaddress=%s, ipport=%s)', ipaddress, ipport)
     cipaddress = ctypes.c_char_p(ipaddress.encode())
     cipport = ctypes.c_int(ipport)
     self.__id = getattr(self.__handle, self.__prefix + 'ConnectTCPIP')(cipaddress, cipport)
     if self.__id < 0:
         raise GCSError(self.__error)
     self.__ifdescription = 'TCPIP %s:%s' % (ipaddress, ipport)
Exemple #18
0
 def ConnectNIgpib(self, board, device):
     """Open a connection from a NI IEEE 488 board to the device.
     @param board: GPIB board ID as integer.
     @param device: The GPIB device ID of the device as integer.
     """
     debug('GCSDll.ConnectNIgpib(board=%s, device=%s)', board, device)
     cboard = ctypes.c_int(board)
     cdevice = ctypes.c_int(device)
     self.__id = getattr(self.__handle, self.__prefix + 'ConnectNIgpib')(cboard, cdevice)
     if self.__id < 0:
         raise GCSError(self.__error)
     self.__ifdescription = 'GPIB board %s, device %s' % (board, device)
Exemple #19
0
 def __checkerror(self, senderr=True, doraise=True):
     """Query error from device and raise GCSError exception.
     @param senderr : If True send "ERR?\n" to the device.
     @param doraise : If True an error is raised, else the GCS error number is returned.
     @return : If doraise is False the GCS exception if an error occured else None.
     """
     if not self.__errcheck:
         return 0
     if senderr:
         self.__send('ERR?\n')
     answer = self.__read(stopon=None)
     exc = None
     try:
         err = int(answer)
     except ValueError:
         exc = GCSError(gcserror.E_1004_PI_UNEXPECTED_RESPONSE, answer)
     else:
         if err:
             exc = GCSError(err)
     if exc and doraise:
         raise exc  # Raising NoneType while only classes or instances are allowed pylint: disable=E0702
     return exc
Exemple #20
0
 def ConnectPciBoard(self, board):
     """Open a PCI board connection.
     @param board : PCI board number as integer.
     """
     debug('GCSDll.ConnectPciBoard(board=%s)', board)
     cboard = ctypes.c_int(board)
     if self.__prefix == 'C843_':
         self.__id = getattr(self.__handle, self.__prefix + 'Connect')(cboard)
     else:
         self.__id = getattr(self.__handle, self.__prefix + 'ConnectPciBoard')(cboard)
     if self.__id < 0:
         raise GCSError(self.__error)
     self.__ifdescription = 'PCI board %s' % board
Exemple #21
0
 def getconfigs(self):
     """Get available configurations in PIStages database for the connected controller.
     @return : Answer as string.
     """
     debug('GCSDll.getconfigs()')
     bufsize = 20000
     configs = ctypes.create_string_buffer('\000'.encode(), bufsize + 2)
     funcname = self.__prefix + 'GetAvailableControllerConfigurationsFromDatabase'
     if not getattr(self.__handle, funcname)(self.__id, configs, bufsize + 1):
         raise GCSError(self.__error)
     configs = configs.value.decode(encoding='cp1252')
     debug('GCSDll.getconfigs(id%d): %r', self.__id, configs)
     return configs
Exemple #22
0
 def getanswer(self, bufsize):
     """Get the answer of a GCS command.
     @param bufsize : Size in characters of string buffer to store the answer as integer.
     @return : Answer as string.
     """
     bufstr = ctypes.create_string_buffer('\000'.encode(), bufsize + 2)
     if not getattr(self.__handle, self.__prefix + 'GcsGetAnswer')(self.__id, bufstr, bufsize + 1):
         raise GCSError(self.__error)
     try:
         answer = bufstr.value.decode(encoding='cp1252')
     except UnicodeDecodeError:
         answer = bufstr.value
     debug('GCSDll.getanswer(id%d): %r', self.__id, answer)
     return answer
Exemple #23
0
 def saveconfig(self, items, config):
     """Read parameters according to 'config' from controller and write them to the PIStages database.
     @param items : Items of the controller the configuration is assigned to as string.
     Consists of the key word (e.g. "axis") and ID  (e.g. "4"), examples: "axis 1", "axis 4".
     @param config: Name of a configuration not yet existing in PIStages database as string.
     """
     debug('GCSDll.saveconfig(items=%r, config=%r)', items, config)
     items = ctypes.c_char_p(str(items).encode())
     config = ctypes.c_char_p(str(config).encode())
     bufsize = 20000
     warnings = ctypes.create_string_buffer('\000'.encode(), bufsize + 2)
     funcname = self.__prefix + 'ReadConfigurationFromControllerToDatabase'
     if not getattr(self.__handle, funcname)(self.__id, items, config, warnings, bufsize + 1):
         self.__warnmsg = warnings.value.decode(encoding='cp1252')
         raise GCSError(self.__error)
Exemple #24
0
 def EnumerateTCPIPDevices(self, mask=''):
     """Get identification strings of all TCP connected devices.
     @param mask: String to filter the results for certain text.
     @return: Found devices as list of strings.
     """
     debug('GCSDll.EnumerateTCPIPDevices(mask=%r)', mask)
     mask = ctypes.c_char_p(mask.encode())
     bufsize = 100000
     bufstr = ctypes.create_string_buffer('\000'.encode(), bufsize + 2)
     if getattr(self.__handle, self.__prefix + 'EnumerateTCPIPDevices')(bufstr, bufsize, mask) < 0:
         raise GCSError(self.__error)
     devlist = bufstr.value.decode().split('\n')[:-1]
     devlist = [item.strip() for item in devlist]
     debug('GCSDll.EnumerateTCPIPDevices: %r', devlist)
     return devlist
Exemple #25
0
 def ConnectDaisyChainDevice(self, deviceid, daisychainid=None):
     """Connect device with 'deviceid' on the daisy chain 'daisychainid'.
     Daisy chain has to be connected before, see Open<interface>DaisyChain() functions.
     @param daisychainid : Daisy chain ID as int from the daisy chain master instance or None.
     @param deviceid : Device ID on the daisy chain as integer.
     """
     debug('GCSDll.ConnectDaisyChainDevice(deviceid=%s, daisychainid=%s)', deviceid,
           daisychainid)
     if daisychainid is None:
         daisychainid = self.__dcid
     cdeviceid = ctypes.c_int(deviceid)
     cdaisychainid = ctypes.c_int(daisychainid)
     self.__id = getattr(self.__handle, self.__prefix + 'ConnectDaisyChainDevice')(cdaisychainid, cdeviceid)
     if self.__id < 0:
         raise GCSError(self.__error)
     if self.__ifdescription:
         self.__ifdescription += '; '
     self.__ifdescription += 'daisy chain %d, device %s' % (daisychainid, deviceid)
Exemple #26
0
 def _read(self, stopon):
     """Read answer from device until this ends with linefeed with no preceeding space.
     @param stopon: Addditional uppercase string that stops reading, too.
     @return : Received data as string.
     """
     rcvbuf = u''
     timeout = time() + self.timeout / 1000.
     while not eol(rcvbuf):
         received = self._interface.read()
         if received:
             rcvbuf += received.decode('cp1252', errors='replace')
             timeout = time() + self.timeout / 1000.
         if time() > timeout:
             raise GCSError(gcserror.E_7_COM_TIMEOUT, '@ GCSMessages._read')
         if stopon and stopon in rcvbuf.upper():
             break
     self._check_no_eol(rcvbuf)
     return rcvbuf
 def _convertfloats(self, line):
     """Convert items in 'line' to float and append them to 'self._databuffer'.
     @param line : One line in qDRR answer with data values as string.
     """
     numcolumns = len(self._databuffer['data'])
     msg = 'cannot convert to float: %r' % line
     try:
         values = [float(x) for x in line.split()]
         if numcolumns != len(values):
             msg = 'expected %d, got %d columns: %r' % (numcolumns, len(values), line)
             raise ValueError()
     except ValueError:
         exc = GCSError(gcserror.E_1004_PI_UNEXPECTED_RESPONSE, msg)
         self._databuffer['error'] = exc
         error('GCSMessages: GCSError: %s', exc)
     else:
         for i in range(numcolumns):
             self._databuffer['data'][i].append(values[i])
     self._databuffer['index'] += 1
Exemple #28
0
 def OpenUSBDaisyChain(self, description):
     """Open a USB daisy chain connection.
     To get access to a daisy chain device you have to call ConnectDaisyChainDevice().
     @param description: Description of the device returned by EnumerateUSB().
     @return: Found devices as list of strings.
     """
     debug('GCSDll.OpenUSBDaisyChain(description=%r)', description)
     cdescription = ctypes.c_char_p(description.encode())
     numdev = ctypes.byref(ctypes.c_int())
     bufsize = 10000
     bufstr = ctypes.create_string_buffer('\000'.encode(), bufsize + 2)
     self.__dcid = getattr(self.__handle, self.__prefix + 'OpenUSBDaisyChain')(cdescription, numdev, bufstr, bufsize)
     if self.__dcid < 0:
         raise GCSError(self.__error)
     devlist = bufstr.value.decode().split('\n')[:-1]
     devlist = [item.strip() for item in devlist]
     debug('GCSDll.OpenUSBDaisyChain: %r', devlist)
     self.__ifdescription = 'USB daisy chain at SN %r' % description
     return devlist
Exemple #29
0
 def ConnectRS232(self, comport, baudrate):
     """Open an RS-232 connection to the device.
     @param comport: Port to use as integer (1 means "COM1") or name ("dev/ttys0") as string.
     @param baudrate: Baudrate to use as integer.
     """
     cbaudrate = ctypes.c_int(baudrate)
     try:
         comport = int(comport)
     except ValueError:
         debug('GCSDll.ConnectRS232ByDevName(devname=%r, baudrate=%s)', comport, baudrate)
         cdevname = ctypes.c_char_p(comport.encode())
         self.__id = getattr(self.__handle, self.__prefix + 'ConnectRS232ByDevName')(cdevname, cbaudrate)
     else:
         debug('GCSDll.ConnectRS232(comport=%s, baudrate=%s)', comport, baudrate)
         ccomport = ctypes.c_int(comport)
         self.__id = getattr(self.__handle, self.__prefix + 'ConnectRS232')(ccomport, cbaudrate)
     if self.__id < 0:
         raise GCSError(self.__error)
     self.__ifdescription = 'RS-232 port %s, %s Baud' % (comport, baudrate)
Exemple #30
0
 def read(self, tosend, gcsdata=0):
     """Send 'tosend' to device, read answer and check for error.
     @param tosend : String to send to device.
     @param gcsdata : Number of lines, if != 0 then GCS data will be read in background task.
     @return : Device answer as string.
     """
     if gcsdata is not None:
         gcsdata = None if gcsdata < 0 else gcsdata
     stopon = None
     if gcsdata != 0:
         stopon = '# END_HEADER'
         self._databuffer['data'] = []
         self._databuffer['index'] = 0
         self._databuffer['error'] = None
     with self._lock:
         self._send(tosend)
         answer = self._read(stopon)
         if gcsdata != 0:
             splitpos = answer.upper().find(stopon)
             if splitpos < 0:
                 self._send('ERR?\n')
                 err = int(self._read(stopon=None).strip())
                 err = err or gcserror.E_1004_PI_UNEXPECTED_RESPONSE
                 raise GCSError(
                     err,
                     '@ GCSMessages.read, no %r in %r' % (stopon, answer))
             stopon += ' \n'
             splitpos += len(stopon)
             strbuf = answer[
                 splitpos:]  # split at "# END HEADER \n", this is the data
             answer = answer[:
                             splitpos]  # split at "# END HEADER \n", this is the header
             if stopon in answer.upper(
             ):  # "# END HEADER\n" will not start reading GCS data
                 self._databuffer['size'] = gcsdata
                 self._readgcsdata(strbuf)
             else:
                 self._databuffer['size'] = True
         else:
             self._checkerror()
     return answer