#! python
# -*- coding: utf-8 -*-
"""tem13 extended command module

Author: <NAME> <<EMAIL>>
"""
import time
import struct
import socket

HOST = "172.17.41.1"
PORT = 2001

STREAM = None
TIMEOUT = 4
OFFLINE = False


def open():
    global STREAM
    host = HOST
    port = PORT
    if not STREAM:
        print("Initializing Request port {}:{}... ".format(host, port), end='')
        ## STREAM = socket.create_connection((host, port), timeout=TIMEOUT)
        ## return True
        STREAM = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        STREAM.settimeout(TIMEOUT)
        errno = STREAM.connect_ex((host, port))
        if errno:
            print("failed to open ({}): ".format(errno), end='')
            STREAM = None
        print(errno == 0)
        return errno == 0
    close()
    return open()


def close():
    global STREAM
    if STREAM:
        STREAM.close()
        STREAM = None
        print("Request port is closed.")


def flush():
    bufsize = 4096
    buf = b""
    while 1:
        s = STREAM.recv(bufsize)
        buf += s
        if len(s) < bufsize:
            break
    return buf


class Command(object):
    """アプリケーションコマンドクラスを登録します
    name : コマンド名
   fmtin : 送信データバイト列のフォーマットを struct 形式で指定します
  fmtout : 受信データ 〃
  device : 論理デバイス種類
 cmdtype : Ack=1, Done=2 (Ack+Doneは Done-指定で良い)
     """
    CMDTYPE = {
          'ACK' : 1,
         'DONE' : 2,
    }
    DEVICE = {
           'PC' : 0x01,
        'PANEL' : 0x02,
           'HT' : 0x03,
        'GONIO' : 0x04,
        'IMSRV' : 0x05,
         'ASID' : 0x09,
          'FIS' : 0x0A,
        'PHOTO' : 0x10,
          'EOS' : 0x11,
          'APT' : 0x12,
          'VAC' : 0x13,
       'EOSMON' : 0x17,
       'VACMON' : 0x18,
        'HTMON' : 0x19,
     'GONIOMON' : 0x1A,
    }
    def __init__(self, name, fmtin, fmtout, doc="", device='EOS', cmdtype='DONE'):
        self.name = name
        self.fmtin = fmtin or ""
        self.fmtout = fmtout or ""
        self.device = self.DEVICE[device]
        self.cmdtype = self.CMDTYPE[cmdtype]
        self.doc = doc
        self.__doc__ = "{0.name:4s} {0.doc:36s} [ {0.fmtin:8s}|{0.fmtout:8s} ]".format(self)
        
        self.cin = struct.Struct(self.fmtin)
        self.cout = struct.Struct(self.fmtout)
        
        self.nerr = 0 # format error count
    
    busy = 0
    header = struct.Struct("!HI4sHI")
    
    def __call__(self, *args):
        if not STREAM:
            return
        
        if OFFLINE:
            return self.cout.unpack(b'\0' * self.cout.size)
        
        N = 16 + self.cin.size
        R = 16 + self.cout.size
        iid = 0x46400000 + (self.cmdtype<<12) + 0x0100 + self.device
        name = self.name.encode()
        status = 0
        pid = 0
        head = self.header.pack(N, iid, name, status, pid)
        data = self.cin.pack(*args)
        try:
            while Command.busy:
                time.sleep(0.005) # ここで通信待機
            Command.busy += 1
            
            ## Request command is sent and received here
            nbytes = STREAM.send(head + data)
            buf = flush()
            N, iid, _name, status, pid = self.header.unpack(buf[:16])
            if _name != name:
                print("- cmdl received {!r}, not {!r}".format(_name, name))
                flush()
                return False
            if len(buf) != R:
                if self.nerr < 1:
                    print("- cmdl received {!r}:{:,d}bytes, not {:,d}bytes".format(name, len(buf), R))
                    print("- Command {!r} format may be wrong or deprecated.".format(name))
                    self.nerr += 1
                return False
            return self.cout.unpack(buf[16:N])
        except socket.timeout:
            print("- Command {!r} timeout".format(name))
            return False
        except struct.error as e:
            print("- Command {!r} failed because {}.".format(name, e))
            return False
        finally:
            Command.busy -= 1

#! python
# -*- coding: utf-8 -*-
"""tem13 extended command module

Author: <NAME> <<EMAIL>>
"""
import time
import struct
import socket

HOST = "172.17.41.1"
PORT = 2001

STREAM = None
TIMEOUT = 4
OFFLINE = False


def open():
    global STREAM
    host = HOST
    port = PORT
    if not STREAM:
        print("Initializing Request port {}:{}... ".format(host, port), end='')
        ## STREAM = socket.create_connection((host, port), timeout=TIMEOUT)
        ## return True
        STREAM = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        STREAM.settimeout(TIMEOUT)
        errno = STREAM.connect_ex((host, port))
        if errno:
            print("failed to open ({}): ".format(errno), end='')
            STREAM = None
        print(errno == 0)
        return errno == 0
    close()
    return open()


def close():
    global STREAM
    if STREAM:
        STREAM.close()
        STREAM = None
        print("Request port is closed.")


def flush():
    bufsize = 4096
    buf = b""
    while 1:
        s = STREAM.recv(bufsize)
        buf += s
        if len(s) < bufsize:
            break
    return buf


class Command(object):
    """アプリケーションコマンドクラスを登録します
    name : コマンド名
   fmtin : 送信データバイト列のフォーマットを struct 形式で指定します
  fmtout : 受信データ 〃
  device : 論理デバイス種類
 cmdtype : Ack=1, Done=2 (Ack+Doneは Done-指定で良い)
     """
    CMDTYPE = {
          'ACK' : 1,
         'DONE' : 2,
    }
    DEVICE = {
           'PC' : 0x01,
        'PANEL' : 0x02,
           'HT' : 0x03,
        'GONIO' : 0x04,
        'IMSRV' : 0x05,
         'ASID' : 0x09,
          'FIS' : 0x0A,
        'PHOTO' : 0x10,
          'EOS' : 0x11,
          'APT' : 0x12,
          'VAC' : 0x13,
       'EOSMON' : 0x17,
       'VACMON' : 0x18,
        'HTMON' : 0x19,
     'GONIOMON' : 0x1A,
    }
    def __init__(self, name, fmtin, fmtout, doc="", device='EOS', cmdtype='DONE'):
        self.name = name
        self.fmtin = fmtin or ""
        self.fmtout = fmtout or ""
        self.device = self.DEVICE[device]
        self.cmdtype = self.CMDTYPE[cmdtype]
        self.doc = doc
        self.__doc__ = "{0.name:4s} {0.doc:36s} [ {0.fmtin:8s}|{0.fmtout:8s} ]".format(self)
        
        self.cin = struct.Struct(self.fmtin)
        self.cout = struct.Struct(self.fmtout)
        
        self.nerr = 0 # format error count
    
    busy = 0
    header = struct.Struct("!HI4sHI")
    
    def __call__(self, *args):
        if not STREAM:
            return
        
        if OFFLINE:
            return self.cout.unpack(b'\0' * self.cout.size)
        
        N = 16 + self.cin.size
        R = 16 + self.cout.size
        iid = 0x46400000 + (self.cmdtype<<12) + 0x0100 + self.device
        name = self.name.encode()
        status = 0
        pid = 0
        head = self.header.pack(N, iid, name, status, pid)
        data = self.cin.pack(*args)
        try:
            while Command.busy:
                time.sleep(0.005) # ここで通信待機
            Command.busy += 1
            
            ## Request command is sent and received here
            nbytes = STREAM.send(head + data)
            buf = flush()
            N, iid, _name, status, pid = self.header.unpack(buf[:16])
            if _name != name:
                print("- cmdl received {!r}, not {!r}".format(_name, name))
                flush()
                return False
            if len(buf) != R:
                if self.nerr < 1:
                    print("- cmdl received {!r}:{:,d}bytes, not {:,d}bytes".format(name, len(buf), R))
                    print("- Command {!r} format may be wrong or deprecated.".format(name))
                    self.nerr += 1
                return False
            return self.cout.unpack(buf[16:N])
        except socket.timeout:
            print("- Command {!r} timeout".format(name))
            return False
        except struct.error as e:
            print("- Command {!r} failed because {}.".format(name, e))
            return False
        finally:
            Command.busy -= 1

#! python # -*- coding: utf-8 -*- tem13 extended command module  Author: <NAME> <<EMAIL>> ## STREAM = socket.create_connection((host, port), timeout=TIMEOUT) ## return True アプリケーションコマンドクラスを登録します     name : コマンド名    fmtin : 送信データバイト列のフォーマットを struct 形式で指定します   fmtout : 受信データ 〃   device : 論理デバイス種類  cmdtype : Ack=1, Done=2 (Ack+Doneは Done-指定で良い) # format error count # ここで通信待機 ## Request command is sent and received here