##// END OF EJS Templates
updating repository....
updating repository. git-svn-id: http://jro-dev.igp.gob.pe/svn/jro_hard/radarsys/trunk/webapp@179 aa17d016-51d5-4e8b-934c-7b2bbb1bbe71

File last commit:

r158:03c8e52d0d74
r158:03c8e52d0d74
Show More
jro_device.py
398 lines | 10.7 KiB | text/x-python | PythonLexer
'''
Created on Dec 2, 2014
@author: Miguel Urco
'''
import time
import struct
import socket
DEBUG = False
CMD_RESET =0X01
CMD_ENABLE =0X02
CMD_CHANGEIP =0X03
IdClass={
"rc" : 0x01,
"dds" : 0x02,
"jars" : 0x03,
"usrp" : 0x04,
"echotek" : 0x05,
"abs" : 0x06,
"clk_gen" : 0x07
}
def ascii2hex(cadena):
hex_cad = ''
for c in cadena:
hex_cad += hex(ord(c))[2:].rjust(2,'0') + ' '
return hex_cad
def ping(host):
"""
Returns True if host responds to a ping request
"""
import os, platform
# Ping parameters as function of OS
ping_str = "-n 1" if platform.system().lower()=="windows" else "-c 1"
# Ping
return os.system("ping " + ping_str + " " + host) == 0
class IPData(object):
'''
Clase para manejar la trama de datos provenientes del/hacia un dispositivo Ethernet.
La trama de datos es la siguiente:
**********************************
** FORMATO GENERAL DE UNA TRAMA **
**********************************
1. Cabecera (5 bytes): Secuencia Fija que deber ser "$JRO$"
2. Longitud (3 bytes): Cantidad de bytes de la Data, contados desde IdClass hasta el Xor
3. Id class (1 byte) : Clase de dispositivo a configurar. Por defecto 0
4. Id device (1 byte): Identificar del dispositivo a configurar. Por defecto 0
5. Cmd (2 bytes): Identificador del comando a ejecutarse.
3. Payload (n bytes): Carga Util conteniendo secuencia,comandos y parametros
4. Xor (1 byte): Byte de revision de consistencia de la data al aplicar Xor a todos los bytes,
desde la longitud hasta el payload.
'''
__HEADER = "$JRO$"
def __init__(self, ip, port, id_class=0, id_dev=0):
'''
'''
self.id_class = id_class
self.id_dev = id_dev
self.address = (str(ip), int(port))
self.__iniVariables()
def __iniVariables(self):
self.tx_buffer = None
self.rx_buffer = None
#self.header = None
self.len = None
self.cmd = None
self.payload = None
self.invalid = True
self.errormsg = ''
self.hasPayload = False
def __getXor(self, cadena):
'''
'''
#trama = '%03d' %lenght + ipPayload
xor = 0
for character in cadena:
xor = xor ^ ord(character)
# xor_hex = hex(xor)
# xor_hex = xor_hex[2:]
# xor_hex = xor_hex.rjust(2,'0')
return xor
def __verifyXor(self, cadena):
xor = self.__getXor(cadena)
if xor != 0:
return 0
return 1
def __encoder(self, cmd, payload):
'''
Inputs:
cmd : Entero que indica el tipo de comando
payload : Cadena de caracteres con informacion, depende del comando
'''
#seq = '%04d' %(sequence)
#conf = '%04d' %(confcode)
#Number to Cad: 2 Bytes <> H, 4 Bytes <> I
cmd_cad = struct.pack(">H", cmd)
data = chr(self.id_class) + chr(self.id_dev) + cmd_cad + payload
len_data = len(data) + 1 # + xor
len_cad = struct.pack('>I', len_data)
lenAndData = len_cad + chr(self.id_class) + chr(self.id_dev) + cmd_cad + payload
xor = self.__getXor(lenAndData)
trama = self.__HEADER + lenAndData + chr(xor)
self.tx_buffer = trama
return trama
def __decoder(self, rx_buffer):
'''
Evalua la trama y la separa en los campos correspondientes
4Bytes | 4Bytes | 1Byte | 1 Byte | 2 Bytes | n Bytes | 1 Byte
Header | Len | Id class | Id dev | Cmd | Payload | Xor
'''
self.invalid = True
self.hasPayload = False
self.rx_buffer = rx_buffer
try:
index = rx_buffer.find(self.__HEADER)
except:
self.errormsg = "rx_buffer is not a string"
return 0
if index == -1:
self.errormsg = "No header found: %s" %ascii2hex(rx_buffer)
return 0
rx_buffer = rx_buffer[index + len(self.__HEADER):]
len_cad = rx_buffer[0:4]
len_data = struct.unpack('>I',len_cad)[0]
lenAndDataAndXor = rx_buffer[0:len_data + 4] #Incluye los 4 bytes de la longitud
dataAndXor = lenAndDataAndXor[4:]
if len(dataAndXor) < len_data:
self.errormsg = "Data length is lower than %s" %(len_data)
return 0
# print self.header, ", ", ascii2hex(lenCad), ", ", ascii2hex(ipDataAndXor), ", ", hex(self.xor)
if not self.__verifyXor(lenAndDataAndXor):
self.errormsg = "Invalid xor: %s" %lenAndDataAndXor[-1]
return 0
self.invalid = False
len_payload = len_data - 5 #Decrementar 1B (id_class), 1B (id_dev), 2B (cmd) y 1B (xor)
id_class = ord(dataAndXor[0])
id_dev = ord(dataAndXor[1])
cmd_cad = dataAndXor[2:4]
payload = dataAndXor[4:4+len_payload]
cmd = struct.unpack('>H',cmd_cad)[0]
self.id_class = id_class
self.id_dev = id_dev
self.cmd = cmd
if len(payload) < 1:
self.errormsg = "IP data is valid but it hasn't payload"
return 1
self.hasPayload = True
self.payload = payload
self.errormsg = "Successful"
return 1
def __decoder_api(self, rx_buffer, debug = DEBUG):
"""
Input:
rx_buffer : Trama recibida como respuesta a un comando enviada a un dispositivo.
Return:
0 : Trama recibida incorrecta. La cadena "rx_buffer" no ha sido decodificada correctamente.
-1 : Dispositivo no inicializado. El dispositivo, dds o rc, no ha sido inicializado
correctamente.
-2 : Trama enviada no reconocida. La cadena recibida es correcta y el dispositivo ha sido
inicializaado correctamente pero la trama enviada no ha sido reconocida por el
dispositivo o el comando enviado no ha sido implementado.
>0 : Trama enviada y recibida correctamente
"""
if not self.__decoder(rx_buffer):
return "0:Error decoding eth data: " + ascii2hex(self.rx_buffer)
# if self.getPayload() == "OK":
# return 1
#
# if self.getPayload() == "NI":
# return -1
#
# if self.getPayload() == "KO":
# return -2
if debug:
print ascii2hex(self.rx_buffer)
return self.payload
def getRxBufferHex(self):
if self.rx_buffer == None:
return ''
cad = ascii2hex(self.rx_buffer)
return cad
def getTxBufferHex(self):
if self.tx_buffer == None:
return ''
cad = ascii2hex(self.tx_buffer)
return cad
def isInvalid(self):
return self.invalid
def getCmd(self):
return self.cmd
def getPayload(self):
return self.payload
def getErrorMessage(self):
return self.errormsg
def getTxBuffer(self):
return self.tx_buffer
def getRxBuffer(self):
return self.rx_buffer
def __encodeIpCmd(self, ip, mask, gateway):
payload = ip + '/' + mask + '/' + gateway
return self.__encoder(CMD_CHANGEIP, payload)
def __encodeResetCmd(self):
payload = ""
return self.__encoder(CMD_RESET, payload)
def __sendTCPData(self, cadena):
sck = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sck.settimeout(3)
try:
sck.connect(self.address)
except:
return None
# print "TX: ", ascii2hex(cadena)
sck.send(cadena)
rx_buffer = ""
ini = time.time()
try:
while True:
if time.time() - ini > 0.5:
break
try:
tmp = sck.recv(4096)
except:
break
if len(tmp) < 1:
continue
ini = time.time()
rx_buffer += tmp
finally:
sck.close()
# print "RX: ", ascii2hex(rx_buffer)
return rx_buffer
def changeIP(self, ip, mask, gateway):
tx_buffer = self.__encodeIpCmd(ip, mask, gateway)
rx_buffer = self.__sendTCPData(tx_buffer)
sts = self.__decoder_api(rx_buffer)
if sts > 0:
self.address = (ip, self.address[1])
return sts
def reset(self):
tx_buffer = self.__encodeResetCmd()
rx_buffer = self.__sendTCPData(tx_buffer)
return self.__decoder_api(rx_buffer)
def sendData(self, cmd, payload, server=False):
if server:
tx_buffer = self.__encoder(cmd, payload)
print "TX: ", ascii2hex(tx_buffer)
self.client_connection.sendall(tx_buffer)
else:
tx_buffer = self.__encoder(cmd, payload)
print "TX: ", ascii2hex(tx_buffer)
rx_buffer = self.__sendTCPData(tx_buffer)
if not rx_buffer:
msg = "0:Could not connect to Device %s" %str(self.address)
return msg
print "RX: ", ascii2hex(rx_buffer)
return self.__decoder_api(rx_buffer)
def receiveData(self, rx_buffer):
print "RX: ", ascii2hex(rx_buffer)
return self.__decoder(rx_buffer)
def eth_device(id_class):
def inner_func(func):
def func_wrapper(ip, port, *args):
cmd, payload = func(*args)
ipObj = IPData(ip, port, id_class=id_class)
rx = ipObj.sendData(cmd, payload)
return rx
return func_wrapper
return inner_func