#!/usr/bin/env python2
# -*- coding: utf-8 -*-
#
# Copyright 2012-2017 Frédéric Magniette, Miguel Rubio-Roy
# This file is part of Pyrame.
#
# Pyrame is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Pyrame is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrame. If not, see <http://www.gnu.org/licenses/>
import pools,conf_strings,buses,socket
socket.setdefaulttimeout(60)
# TCP_BUS ########################################################
class tcp_bus(buses.buses):
def __init__(self):
self.tcp_pool=pools.pool("tcp")
super(tcp_bus,self).__init__()
def init(self,tcp_id,conf_string):
try:
conf=conf_strings.parse(conf_string)
except Exception as e:
return 0,str(e)
if conf.name!="tcp":
return 0,"Invalid module name %s in conf_string. Should be tcp"%(conf.name)
if not conf.has("host","port"):
return 0,"A required parameter in conf_string is not present"
host=conf.params["host"]
port=int(conf.params["port"])
if conf.has("timeout") and conf.params["timeout"]!="undef":
timeout=float(conf.params["timeout"])
else:
timeout=socket.getdefaulttimeout()
# Validate parameters
if (port < 0 or port > 65535):
return 0,"Invalid destination port: %d"%(port)
#build the canonical name
canonical="%s,%s"%(socket.gethostbyname(host),port)
# Add to the pool
self.tcp_pool.new(tcp_id,{"name":tcp_id,"host": host, "port": port, "timeout": timeout, "descr":canonical, "connected":0})
return 1,"ok"
def deinit(self,tcp_id):
try:
tcp=self.tcp_pool.get(tcp_id)
except Exception as e:
return 1,str(e)
# Check status
if tcp["connected"]:
self.inval(tcp_id)
try:
self.tcp_pool.remove(tcp_id)
except Exception as e:
return 0,str(e)
return 1,"ok"
def config(self,tcp_id):
#get pool object
try:
tcp=self.tcp_pool.get(tcp_id)
except Exception as e:
return 0,str(e)
retcode,res=self.ll_new_link(tcp)
if retcode==0:
return 0,res
return 1,tcp["descr"]
def inval(self,tcp_id):
try:
tcp=self.tcp_pool.get(tcp_id)
except Exception as e:
return 0,str(e)
self.ll_del_link(tcp)
return 1,"ok"
def write(self,tcp_id,mode,data):
try:
tcp=self.tcp_pool.get(tcp_id)
except Exception as e:
return 0,str(e)
return super(tcp_bus,self).write(tcp,mode,data)
def read(self,tcp_id,mode,bytes_to_read,timeout="undef"):
try:
tcp=self.tcp_pool.get(tcp_id)
except Exception as e:
return 0,str(e)
return super(tcp_bus,self).read(tcp,mode,bytes_to_read,timeout)
def read_until(self,tcp_id,mode,eot,timeout="undef"):
try:
tcp=self.tcp_pool.get(tcp_id)
except Exception as e:
return 0,str(e)
return super(tcp_bus,self).read_until(tcp,mode,eot,timeout)
def expect(self,tcp_id,pattern,timeout="undef"):
try:
tcp=self.tcp_pool.get(tcp_id)
except Exception as e:
return 0,str(e)
return super(tcp_bus,self).expect(tcp,pattern,timeout)
def ll_open(self,tcp):
try:
s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((tcp["host"],tcp["port"]))
except:
return None
return s
def ll_close(self,sock):
try:
sock.close()
except:
print("warning: unable to close socket")
def ll_send(self,sock,tcp,data):
try:
if sock.sendall(data) != None:
return 0,"Error sending data %s to %s:%s"%(data,sock.getpeername()[0],sock.getpeername()[1])
except Exception as e:
return 0,"Error sending data %s to %s:%s <- %s"%(data,sock.getpeername()[0],sock.getpeername()[1],str(e))
return 1,"ok"
def ll_receive(self,sock,tcp,bytes_to_read,timeout="undef"):
# Set timeout
if timeout=="" or timeout=="undef":
sock.settimeout(tcp["timeout"])
else:
sock.settimeout(float(timeout))
# Read
bytes_read=0
try:
response=""
while bytes_read<int(bytes_to_read):
response += sock.recv(int(bytes_to_read)-bytes_read)
bytes_read=len(response)
#print("read so far (%d bytes): %s"%(bytes_read,response.encode("hex")))
except socket.timeout as e:
return 0,"%s:%s is not responding <- %s"%(sock.getpeername()[0],sock.getpeername()[1],e)
except Exception as e:
return 0,"error at tcp to %s:%s <- %s"%(sock.getpeername()[0],sock.getpeername()[1],e)
return 1,response
# CREATE BUS POOL ################################################
bus=tcp_bus()
# COMMANDS #######################################################
[docs]def init_tcp(tcp_id,conf_string):
"""Initialize a TCP link.
*conf_string* must include:
- host: hostname or IP address of the remote device
- port: port on the remote device
optionally:
- timeout: default timeout in seconds for this link. Can be float"""
return bus.init(tcp_id,conf_string)
[docs]def deinit_tcp(tcp_id):
"Deinitialize and deregister TCP link *tcp_id*."
return bus.deinit(tcp_id)
[docs]def config_tcp(tcp_id):
"Configure tcp link *tcp_id*."
return bus.config(tcp_id)
[docs]def inval_tcp(tcp_id):
"Invalidate configuration of tcp link *tcp_id*."
return bus.inval(tcp_id)
# WRITE ##########################################################
[docs]def write_tcp(tcp_id,data):
"Write *data* to TCP link *tcp_id*."
return bus.write(tcp_id,"escaped",data)
[docs]def write_bin_tcp(tcp_id,data):
"Write binary *data* to TCP link *tcp_id*. *data* is a string where each character represents 4 bits in hexadecimal base. Little endian for each group of 8 bits."
return bus.write(tcp_id,"bin",data)
# READ ###########################################################
[docs]def read_tcp(tcp_id,bytes_to_read,timeout="undef"):
"Read up to *bytes_to_read* bytes from TCP link *tcp_id*"
return bus.read(tcp_id,"ignore_chars",bytes_to_read,timeout)
[docs]def read_bin_tcp(tcp_id,bytes_to_read,timeout="undef"):
"Read up to *bytes_to_read* bytes from TCP link *tcp_id* in binary format. The data read is encoded by blocks of 8 bits with two hexadecimal characters little endian."
return bus.read(tcp_id,"bin",bytes_to_read,timeout)
# READ UNTIL #####################################################
[docs]def read_until_tcp(tcp_id,eot,timeout="undef"):
"Read from TCP link *tcp_id* until a character from *eot* comma-separated list is found"
return bus.read_until(tcp_id,"ignore_chars",eot,timeout)
[docs]def read_bin_until_tcp(tcp_id,eot,timeout="undef"):
"Read from TCP link *tcp_id* until a character from *eot* comma-separated list is found. The data read is encoded by blocks of 8 bits with two hexadecimal characters little endian."
return bus.read_until(tcp_id,"bin",eot,timeout)
# WRNRD ##########################################################
[docs]def wrnrd_tcp(tcp_id,data,bytes_to_read,timeout="undef"):
"Write and read *data* to and from TCP link *tcp_id*"
retcode,res=bus.write(tcp_id,"escaped",data)
if retcode==0:
return 0,res
return bus.read(tcp_id,"ignore_chars",bytes_to_read,timeout)
[docs]def wrnrd_bin_tcp(tcp_id,data,bytes_to_read,timeout="undef"):
"Write and read binary *data* to and from TCP link *tcp_id*. *data* is a string where each character represents 4 bits in hexadecimal base. Little endian for each group of 8 bits."
retcode,res=bus.write(tcp_id,"bin",data)
if retcode==0:
return 0,res
return bus.read(tcp_id,"bin",bytes_to_read,timeout)
# WRNRD_UNTIL ####################################################
[docs]def wrnrd_until_tcp(tcp_id,data,eot,timeout="undef"):
"Write and read *data* to and from TCP link *tcp_id* until a character from comma-separated list *eot* is found"
retcode,res=bus.write(tcp_id,"escaped",data)
if retcode==0:
return 0,res
return bus.read_until(tcp_id,"ignore_chars",eot,timeout)
[docs]def wrnrd_bin_until_tcp(tcp_id,data,eot,timeout="undef"):
"Write and read *data* to and from TCP link *tcp_id* until a character from comma-separated list *eot* is found. *data* is a string where each character represents 4 bits in hexadecimal base. Little endian for each group of 8 bits. Read data is return in the same format."
retcode,res=bus.write(tcp_id,"bin",data)
if retcode==0:
return 0,res
return bus.read_until(tcp_id,"bin",eot,timeout)
# EXPECT #########################################################
[docs]def expect_tcp(tcp_id,pattern,timeout="undef"):
"Read data from TCP link *tcp_id* until *pattern* is found or timeout."
return bus.expect(tcp_id,pattern,timeout)