#!/usr/bin/python
#
# arch-tag: data acquisition client module
# Time-stamp: <2005-05-11 14:38:10 mike>

import sys
import struct
import socket

def adc_offset(spec):
    """Given an ADC line specification [board, channel], calculate
    the corresponding byte and element offsets in the NPC sample
    record.  The return value is the following tuple:

        (byte_offset, element_offset)
    """
    return (16 + spec[0]*68 + spec[1]*2,
            7 + spec[0]*36 + spec[1])

def dio_offset(spec):
    """Given a DIO line specification [board, port, bit], calculate
    the corresponding byte and element offsets in the NPC sample
    record.  The return value is the following tuple:

        (byte_offset, element_offset)
    """
    return (12 + spec[0]*68 + spec[1],
            3 + spec[0]*36 + spec[1])

class NPCData:
    """Class to read NPC sample records either in realtime from the NPC
    system via a TCP/IP socket or from a file.

    Usage:

        dsrc = NPCData('npc', port=4242)  # for socket connection
        dsrc = NPCData(filename)          # for data file

        for rec in dsrc:
            print rec
    """
    _hdrsize = 12
    _hdrformat = '>lll'
    def __init__(self, name, port=0):
        if not port:
            self._src = open(name, 'r')
            self._readf = self._src.read
        else:
            self._src = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self._src.connect((name, port))
            self._readf = self._read
        # Read the first record to determine the record format and size
        rec = list(struct.unpack(self._hdrformat, self._readf(self._hdrsize)))
        self.boards = rec[2]
        self._format = '>' + ('4B32h' * self.boards)
        n = self.boards * 68
        rec.extend(list(struct.unpack(self._format, self._readf(n))))
        self._datasize = n
        self._first = rec
        
    def __del__(self):
        self._src.close()
            
    def __iter__(self):
        return self

    def _read(self, n):
        nleft = n
        bufs = []
        while nleft > 0:
            buf = self._src.recv(nleft)
            if not buf:
                break
            bufs.append(buf)
            nleft -= len(buf)
        return ''.join(bufs)
        
        
    def next(self):
        try:
            sample = self._readf(self._hdrsize+self._datasize)
            rec = list(struct.unpack(self._hdrformat,
                                     sample[0:self._hdrsize]))
            rec.extend(list(struct.unpack(self._format,
                                          sample[self._hdrsize:])))
        except (IOError, struct.error):
            raise StopIteration
        return rec
        
if __name__ == '__main__':
    dsrc = NPCData('bitsy', port=4242)
    for i in range(int(sys.argv[1])):
        print str(dsrc.next())
        
