Skip to content
envbox_server.py 8.25 KiB
Newer Older
lucasgrelaud's avatar
lucasgrelaud committed
#!/usr/bin/env python

import select
import re
import time
import array 
import struct

"""*****************************************************"""
"""                                                     """
"""		Software Defines & Parmeters		"""
"""                                                     """
"""*****************************************************"""
SOFTWARE_VERSION = '1.0'

RS232_BAUDRATE = 115200

SERVER_TCP_IP = '192.168.1.1'
SERVER_TCP_PORT = 3081 
SERVER_BUFFER_SIZE = 128
SERVER_TIMEOUT = 600

RETRIES = 3 


"""*****************************************************"""
"""                                                     """
"""		Numeriflash Xml Parser			"""
"""                                                     """
"""*****************************************************"""
from xml.dom import minidom
class NumeriflashXmlParser:
  @staticmethod
  def getValueNode( node ):
     for nv in node.childNodes:
        if nv.nodeType == 1: ##Node.ELEMENT_NODE:
           if nv.nodeName == "value":
              return nv

  @staticmethod
  def parseCommandNode( node ):

     """ A command node should have the following form :
     <command name="XXXXX"><value type="XX">XXXXX</value></command> """

     try:
        nv = NumeriflashXmlParser.getValueNode( node )

        name = node.attributes.item(0).value
        try:    type = nv.attributes.item(0).value
        except: type = None
        try:    val = nv.childNodes[0].nodeValue
        except: val = None

        if   type is None:                return (name, val)
        elif type == "i" or type == "l":  return (name, int( val ))
        elif type == "f" or type == "d":  return (name, float( val ))
        else:				  return (name, val)

     except:
        return None

  @staticmethod
  def parse( data ):
     doc = minidom.parseString( data )
   
     """ First, get Numeriflash Node """

     node_Numeriflash = None
     for node in doc.childNodes:
        if node.nodeType == 1: ##Node.ELEMENT_NODE:
           if node.nodeName == "Numeriflash":
              node_Numeriflash = node
              break
     if node_Numeriflash is None:
        return None


     """ Then, get the command node(s) """
     
     resList = []
     for node in node_Numeriflash.childNodes:
        if node.nodeType == 1: ##Node.ELEMENT_NODE:
           if node.nodeName == "command":
	      res = NumeriflashXmlParser.parseCommandNode( node )
              if not res is None:
                 resList.append( res )
     return resList




"""*****************************************************"""
"""                                                     """
"""		Numeriflash Xml Server			"""
"""                                                     """
"""*****************************************************"""
import threading
import socket
class NumeriflashXmlServerThread( threading.Thread ):
  devLock = threading.Condition(threading.Lock())
  watchdog = False
  buf = None

  def __init__(self, conn, ip, port, device=None, NumeriflashCompat=True, args=None):
     threading.Thread.__init__( self )
     self.__conn = conn
     self.__ip = ip
     self.__port = port
     self.__compat = NumeriflashCompat
     self.__device = device
     self.__dargs = args
     self.Terminated = False
     print( 'Connected to ' + ip )
     self.start()

  def stop(self):
     self.Terminated = True
     self.__conn.close()	

  def __recoverSerial( self ):
     NumeriflashXmlServerThread.devLock.acquire()
     self.__device.close()
     NumeriflashXmlServerThread.devLock.release()

  def __listen( self ):
     while( True ):
        data = self.__conn.recv( SERVER_BUFFER_SIZE )
        if not data: 
           raise IOError( 'No data received' )
        
	try:
           start = data.index( '<Numeriflash>' )
           end = data.index( '</Numeriflash>', start )
           res = data[ start:(end+14) ]
           #self.buf = data[ (end+14): ]

           return res
	except:
	   pass

  def __send( self, msg ):
     msglen = len(msg)
     totalsent = 0
     while totalsent < msglen:
        sent = self.__conn.send( msg[totalsent:] )
        if sent == 0:
           print( 'socket connection broken' )
           raise IOError( 'socket connection broken' )
        totalsent = totalsent + sent

  def __parseRequest( self, data ):
     res = NumeriflashXmlParser.parse( data )
     name = (res[0])[0]
     value = (res[0])[1]
     return ( ( name, value ), Samsung2Distec.S2D( name, value ) )[ self.__compat ]

  def __execute( self, name, value ):
     NumeriflashXmlServerThread.devLock.acquire()
     try:
       result = None
       if value is None:
          result = self.__device.cmd( name )
       else:
          result = self.__device.cmd( name, value )
     except:
       NumeriflashXmlServerThread.devLock.release()
       raise
     NumeriflashXmlServerThread.devLock.release()
     return result

  def __validate( self, name, value ):
     if ( name=='Power' and value==2 ) or ( name=='Power' and value==8 ) or ( name=='MainSourceInput' and value==1 ) or ( name=='MainSourceInput' and value==2 ):
        return False
     else:
        return True

  def run( self ):
    while not self.Terminated:
      cname = None
      cvalue = None
      resname = None
      resvalue = None
      res = None
      # I - Recive data from client
      try:
         data = self.__listen()
      except Exception, e:
	 print "Unexpected error 0 :", e
         print( 'Socket Timeout => Connection closed by remote client' )
	 break

      #	II - Parse request
      try:	
         cname, cvalue = self.__parseRequest( data ) 
      except Exception, e:
	 print "Unexpected error:", e
	 print( 'Failed to parse client request' )
	 try:
	    self.__send( '<Numeriflash><error><value>Invalid or malformed request</value></error></Numeriflash>' )
         except:
            print( 'Socket Error => Connection closed by remote client' )
	    break
         continue


      #	III - Execute command
      try:
	 command = envbox_db.getCommandByName( cname )

         # Avoid timeout for Numeriflash Compatibility
	 if command is None:
	    try:
               ( resname, resvalue ) = ( ( cname, cvalue ), Samsung2Distec.D2S( cname, cvalue ) )[ self.__compat ]
	       self.__send( '<Numeriflash><command name="' + resname + '"><value type="i"></value></command></Numeriflash>' )
            except Exception, e:
	       print "Unexpected error:", e
               print( 'Socket Error => Connection closed by remote client' )
	       break
            continue

	 if cname=='Power':
	    if not cvalue is None:
	       if cvalue == 0:
		  try:
   		     self.__device.cmd( 'PowerOffType', 0 )
		  except:
		     pass

	 for i in range( 0, RETRIES ):
	    try:
               res = self.__execute( cname, cvalue )
            except:
	       print( 'Serial IO Error' )
	       self.__recoverSerial()
	       res = None

	    if res is None:
               print( 'Serial port timeout' )
	       self.__recoverSerial()

	    elif not self.__validate( cname, res ):
               print( 'Bug : Unexpected value returned by envbox (' + cname + '=' + str( res ) + ')' )
	       self.__recoverSerial()
               res=None

	    else:
               break

      except:
	 print( 'Serial IO Error' )
	 self.__recoverSerial()
	 try:
	    self.__send( '<Numeriflash><error><value type="s">error</value></error></Numeriflash>' )
         except Exception, e:
	    print "Unexpected error 2:", e
            print( 'Socket Error => Connection closed by remote client' )
	    break
	 continue


      #	IV - Build response
      try:
        ( resname, resvalue ) = ( ( cname, res ), Samsung2Distec.D2S( cname, res ) )[ self.__compat ]
        if not resvalue is None:
           msg = '<Numeriflash><command name="' + resname + '"><value type="i">' + str(resvalue) + '</value></command></Numeriflash>'
        else:
           msg = '<Numeriflash><error><value type="s">' + 'error' + '</value></error></Numeriflash>'
      except:
	pass


      #	V - Send response
      try:
	self.__send( msg )
      except Exception, e:
        print "Unexpected error 3:", e
        print( 'Socket Error => Connection closed by remote client' )
	break
        
      #	VI - Tick watchdog
      NumeriflashXmlServerThread.watchdog = False

    #
    #	End run function
    #  
    print( 'Connection from ' + str(self.__ip) + ':' + str(self.__port) + ' closed' )