1357 lines
53 KiB
Python
Executable File
1357 lines
53 KiB
Python
Executable File
#!/usr/bin/env python2.6
|
|
#-*- coding: utf-8 -*-
|
|
__author__ = "Daniel Egger, Michael Rest"
|
|
__date__ = "22 March 2002"
|
|
__email__ = "egger@interearth.com, michi@rosstein.de"
|
|
__version__ = "$Revision: 1.2 $"[11:-2]
|
|
|
|
import sys, os
|
|
from ConfigParser import *
|
|
from log import strlog
|
|
from maillog import *
|
|
from cr_tpdu import CR_TPDU
|
|
from dt_tpdu import DT_TPDU
|
|
import pdb
|
|
from LEBE_tel import TEL_LEBE
|
|
from TAUF_tel import TEL_TAUF
|
|
import decode
|
|
import tel_decode
|
|
import tpdu
|
|
import tpkt
|
|
from DB import DB
|
|
from socket import *
|
|
from select import select
|
|
from time import time
|
|
from datetime import datetime
|
|
from locations import *
|
|
from IPKT import IPKT
|
|
from SCLS import SCLS
|
|
from TQUI import TQUI
|
|
|
|
STATE_CLOSED = 0 # Nothing happened yet
|
|
STATE_CONNECTED = 1 # Client connected and we're ready to serve
|
|
STATE_REQUESTPENDING = 2 # We're ready to establish an ISO connection
|
|
STATE_ESTABLISHED = 3 # ISO connection established
|
|
|
|
CONN_NEW = 0 # New connection not assigned to Comm. Channel
|
|
CONN_ASSIGNED = 1 # Connection is assigned to an Comm. Channel
|
|
|
|
#Reservation at ipoint
|
|
prioexp = 0
|
|
prioexp2= 0
|
|
|
|
|
|
def acknowledge (packet):
|
|
from cc_tpdu import CC_TPDU
|
|
reply = CC_TPDU (packet.srctsap (), packet.dsttsap (), srcref=packet.dstref + 1, dstref=packet.srcref)
|
|
_tpkt = tpkt.TPKT (len (reply) + 1)
|
|
return `_tpkt` + `reply`
|
|
|
|
|
|
def con_request (loc_TSAP, rem_TSAP):
|
|
_tpdu = CR_TPDU (loc_TSAP, rem_TSAP, srcref=0x0015)
|
|
_tpkt = tpkt.TPKT (len (_tpdu) + 1)
|
|
return `_tpkt`+`_tpdu`
|
|
|
|
|
|
def doublechar (value):
|
|
if len (value) == 1:
|
|
return '0' + value
|
|
elif len (value) > 2:
|
|
return value [len (value) -2: len (value)]
|
|
return value
|
|
|
|
|
|
def fillchar (value, l):
|
|
if len (value.rstrip()) < l:
|
|
_retval = ''
|
|
for i in range (0, l - len (value.rstrip())):
|
|
_retval += '0'
|
|
return _retval + value.rstrip()
|
|
return value
|
|
|
|
|
|
class ISOServer (IPKT, SCLS, TQUI):
|
|
def __init__ (self, *dummy, **args):
|
|
"""
|
|
Initialise a new server object: Open the socket, bind to it
|
|
and listen. This will NOT handle incomming connections.
|
|
|
|
Possible variable parameters are:
|
|
port: the port to listen on (default: 102)
|
|
address: the address to listen on (default: '' i.e. any)
|
|
verbose: if true be anal about anything (default: 0)
|
|
"""
|
|
self.connections = {}
|
|
self.parameter = {}
|
|
self.sockets = {}
|
|
# Parameter action
|
|
self.address = args.get ("address", '')
|
|
port = args.get ("port", 102)
|
|
self.verbose = args.get ("verbose", 0)
|
|
self.setdebug = args.get ("debug", 0)
|
|
|
|
#Later Articlebase wil be received via SOAP
|
|
self.articlemaster = {}
|
|
# ('article') : ['caption', 'ammountunit','normweight', 'weightunit', 'normammount', 'RLZ', 'zone', 'weightcheck', 'lottype'],
|
|
# '12345' : ['Testartikel', 'ST','1.0', 'KG', '1', '1', '1', '0', '0'],
|
|
# '23456' : ['Testartikel2', 'ST','1.0', 'KG', '1', '1', '1', '0', '0']}
|
|
|
|
self.lastsweep = time ()
|
|
self.lasterpsweep = 0
|
|
self.lastarticleupdate = time ()
|
|
self.lastordersweep = 0
|
|
self.lastordermovesweep = 0
|
|
self.lastodredelsweep = 0
|
|
self.listener_socket = socket (AF_INET, SOCK_STREAM)
|
|
self.listener_socket.setsockopt (SOL_SOCKET, SO_REUSEADDR, 1)
|
|
self.sockets[('listener', '102')] = (self.listener_socket, STATE_CLOSED)
|
|
|
|
while 1:
|
|
try:
|
|
self.listener_socket.bind ((self.address, port))
|
|
except error, msg:
|
|
self.message (0, "ISOServer Bind Socket error %d %s, Started as root?" % (msg[0], msg[1]))
|
|
sys.exit (0)
|
|
else:
|
|
break
|
|
|
|
self.listener_socket.listen (1)
|
|
self.sockets['listener', '102'] = (self.listener_socket, STATE_CONNECTED)
|
|
self.message (1, "Initialized serversocket")
|
|
|
|
|
|
def message (self, level, msg):
|
|
"""
|
|
Print message if in verbose mode.
|
|
"""
|
|
if self.verbose >= level:
|
|
dt = datetime.now ()
|
|
print ("%4d-%02d-%02d %02d:%02d:%02d.%06d:" %(dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.microsecond)),
|
|
print msg
|
|
|
|
|
|
def log (self, msg):
|
|
"""
|
|
Log message
|
|
also print if in verbose mode.
|
|
"""
|
|
lager = self.connections['client']
|
|
file = open ("/var/log/lvr/" + os.getcwd().split('/')[-1] + '-' + lager, "a")
|
|
dt = datetime.now ()
|
|
file.write ("%4d-%02d-%02d %02d:%02d:%02d.%06d: %s\n" %(dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.microsecond, msg))
|
|
self.message (1, msg)
|
|
file.close ()
|
|
|
|
|
|
def debug (self):
|
|
"""
|
|
Debuging
|
|
"""
|
|
if self.setdebug:
|
|
pdb.set_trace()
|
|
|
|
|
|
def add_client (self, client_id, parameter, DB_con, DB_ERP = None, Ordering = None):
|
|
"""
|
|
Add a Client to connections.dict
|
|
"""
|
|
if 'client' in self.connections:
|
|
self.message (1,"Client already exists")
|
|
raise Warning, "Client already exists"
|
|
|
|
self.message (0, "Added Client Storage")
|
|
self.connections['client'] = client_id
|
|
#Connectionditcs
|
|
self.connections['ISO'] = {}
|
|
#Sendqueue
|
|
self.connections['Queue'] = []
|
|
self.connections['LastBeat'] = time ()
|
|
#Databasees
|
|
self.connections['DB'] = DB_con
|
|
DB_con.setloggingmethods (self.log, self.message)
|
|
self.connections['DB_ERP'] = DB_ERP
|
|
|
|
#Ordering
|
|
self.connections['Ordering'] = Ordering
|
|
|
|
#Parameter came from config file
|
|
self.parameter = parameter
|
|
self.parameter.update (DB_con.getphysics ())
|
|
|
|
#Articlemaster
|
|
self.articlemaster.update (DB_con.getarticlemaster ())
|
|
|
|
#Transportmatrx
|
|
self.transportmatrix = {}
|
|
self.transportmatrix['dstbysrc'] = DB_con.gettransportmatrix_dstbysrc ()
|
|
self.transportmatrix['srcbydst'] = DB_con.gettransportmatrix_srcbydst ()
|
|
self.transportmatrix['errordst'] = DB_con.geterrordstbyposition ()
|
|
DB_con.checktransportmatrix (self.parameter, self.transportmatrix['dstbysrc'], DB_con.getstoragedict ())
|
|
|
|
|
|
def add_conn (self, loc_TSAP, rem_TSAP, mode = "passive"):
|
|
"""
|
|
Add a passive ISO connetion to connections.dict
|
|
"""
|
|
if mode not in ["passive", "active"]:
|
|
print "ISO Connection mode is not valid"
|
|
raise Warning
|
|
|
|
if 'client' not in self.connections:
|
|
self.message (1, "Client doesn't exist")
|
|
raise Warning, "Client doesnt't exist"
|
|
|
|
if (loc_TSAP, rem_TSAP) in self.connections['ISO']:
|
|
self.message (1, "Connection " + loc_TSAP + "-" + rem_TSAP + " already exists")
|
|
raise Warning, "Connection " + loc_TSAP + "-" + rem_TSAP + " already exists"
|
|
|
|
self.message (1, "Connection : " + loc_TSAP + "-" + rem_TSAP + " added " + mode)
|
|
#Socket , Counter, Mode
|
|
self.connections['ISO'][(loc_TSAP, rem_TSAP)] = [None, 0, mode]
|
|
|
|
|
|
def makeactiveisoconnection (self, loc_TSAP, rem_TSAP):
|
|
"""
|
|
Create a new active connection and place it in the connectionslist
|
|
possibly overwriting dead connections.
|
|
"""
|
|
# Loop until we successfuly managed to get a new connection
|
|
#while 1:
|
|
try:
|
|
self.message (2, "(Re-)open Socket to %s" % self.connections['client'])
|
|
s = socket (AF_INET, SOCK_STREAM)
|
|
s.connect ((self.connections['client'], 102))
|
|
self.connections['ISO'][(loc_TSAP, rem_TSAP)] = [s, 0, "active"]
|
|
return s
|
|
except:
|
|
self.message (1, "Couldn't open active socket to %s;" % self.connections['client'])
|
|
return None
|
|
|
|
|
|
def dt_handler (self, packet, client_id, source = ''):
|
|
"""
|
|
Handler for data telegrams
|
|
"""
|
|
self.message (3,'DT_handler : data packet Len %d "%s"' % (len(packet.data), packet.data[2:]))
|
|
self.message (3,'DT_handler : data packet Type %s' % (packet.data[6:10]))
|
|
ret_val = tel_decode.decodetelegram (packet.data)
|
|
teltype = ret_val['type']
|
|
key2 = teltype
|
|
|
|
|
|
if teltype == 'LEBE':
|
|
# Nothing to do any further with LEBE telegramms
|
|
# FIXME
|
|
count = ret_val['nr']
|
|
self.message (2,' DT_handler : LEBE Tel. Counter %d' % (count))
|
|
return 0
|
|
|
|
DB_con = self.connections['DB']
|
|
DB_ERP_con = self.connections['DB_ERP']
|
|
|
|
# Do counter checking if a valid telegram arrived
|
|
count_old = self.connections['ISO'][(teltype, key2)][1]
|
|
#if 'nr' in ret_val: FixMe add method to Telegram
|
|
if ret_val.has_key ('nr'):
|
|
count = ret_val['nr']
|
|
self.message (2,' DT_handler : Tel. Counter old %d new %d' % (count_old, count))
|
|
if ret_val ['type'] == "TAUF":
|
|
# Transport Telegram (only Quit) --> check and clear Transport from DB
|
|
_quit = -1 # block quit telegram
|
|
|
|
if not (count_old == count):
|
|
self.message (2, "DT_hander : TAUF Quit -> Nr inconsistence")
|
|
# FIXME repeat TAUF ??
|
|
self.message (1, " DT_handler : Taufquit inconssistence because of restart OK")
|
|
|
|
self.message (3, " DT_handler : TAUF Quit was: %s" %ret_val['state'])
|
|
# All right, received positive feedback
|
|
if ret_val['state'] == 0:
|
|
self.log ( " DT_handler positive TAUF Quit received %d" % (self.connections['ISO'][('TAUF' , 'TAUF')][1]))
|
|
self.connections['ISO'][('TAUF' , 'TAUF')][1] = (self.connections['ISO'][('TAUF' , 'TAUF')][1] % 32767) + 1
|
|
|
|
# Not so good, there was a problem
|
|
else:
|
|
self.log ( "Negative TAUF QUI received %d state %d" % (self.connections['ISO'][('TAUF' , 'TAUF')][1], ret_val['state']))
|
|
|
|
if ret_val['state'] == 20:
|
|
self.message (2, " DT_handler : TAUF Neg. Quit -->> Tel. Source invalid")
|
|
elif ret_val['state'] == 30:
|
|
self.message (2, " DT_handler : TAUF Neg. Quit -->> Tel. Destination invalid")
|
|
elif ret_val['state'] in range (51, 55):
|
|
self.message (2, " DT_handler : TAUF Neg.Quit -->> RFZ%d occupied " % (ret_val['state'] -50))
|
|
DB_con.setsenttransportnew ('RFZ%d' % (ret_val['state'] - 50), dummysrc = self.dummysrc)
|
|
elif ret_val['state'] == 97:
|
|
self.message (2, " DT_handler : TAUF Neg.Quit -->> Tel. length wrong")
|
|
elif ret_val['state'] == 98:
|
|
self.message (2, " DT_handler : TAUF Neg.Quit -->> Wrong Type ??")
|
|
elif ret_val['state'] == 99:
|
|
# Counter Error
|
|
self.message (2, " DT_handler : TAUF Counter errror -> reset and init tel")
|
|
self.connections['ISO'][('TAUF' , 'TAUF')][1] = 0
|
|
|
|
#============================================================================================
|
|
elif (count == 0):
|
|
self.log (' DT_handler : Tel counter 0 Synchronisation Tel accept')
|
|
_quit = 0
|
|
|
|
elif (count == count_old):
|
|
self.log ( "DT_handler : FixMe Repeated telegram %d" % (count))
|
|
_quit = 0
|
|
|
|
elif (count == (count_old % 32767) + 1) or (count == -1):
|
|
#Other Telegram received
|
|
self.message (3, " DT_handler Valid telegram counter %d" % (count))
|
|
_quit = ret_val['check']
|
|
|
|
if _quit == 0:
|
|
self.message (2,' DT_handler : Telegram specific header check passed ')
|
|
#============================================================================================
|
|
#IKT Telegrams - handled external
|
|
if (count <> -1) and ret_val ['type'] == "IPKT":
|
|
# IPKT Telegram --> reserve Box in Inquee
|
|
self.log ( "IPKT for Pos '%(location)s' box '%(box_nr)s' article '%(article)s' lotnr '%(lotnr)s' lotnr2 '%(lotnr2)s' gtin '%(gtin)s' pieces '%(pieces)s' with destination '%(destination)d'" \
|
|
% ret_val)
|
|
|
|
#Dest LVR and EXOT Create TAUFs for IPKT and RFZ1
|
|
_quit = self.ipkt (ret_val)
|
|
self.log ( "IPKT Quit is %d" % _quit)
|
|
|
|
#elif ret_val ['destination'] in range (1, 9):
|
|
#self.createtauf (ret_val ['box_nr'], 'IPKT', 'IPKT', 0, 0, 0, 'Puffer', 8, 0, 0)
|
|
#self.generatetransport ('IPKT', ret_val ['box_nr'])
|
|
#DB_con.deletetauf ('IPKT', int (ret_val ['box_nr']))
|
|
#FIXME Plausibility Check
|
|
|
|
#============================================================================================
|
|
#Scannerreads - handled external
|
|
elif (count <> -1) and ret_val ['type'] == "SCLS":
|
|
_quit = self.scls (ret_val)
|
|
|
|
#============================================================================================
|
|
#Transport results - handled external
|
|
elif ret_val ['type'] == "TQUI":
|
|
_quit = self.tqui (ret_val)
|
|
|
|
#============================================================================================
|
|
else:
|
|
self.message (2, ' DT_handler : Undefined Telegram or Counter')
|
|
_quit = 80
|
|
|
|
else:
|
|
# Countercheck failed negative quit telegram to force synchronisation
|
|
_quit = 99
|
|
self.log ( " DT_Handler Telegram counter FAILED --> Synchronization")
|
|
|
|
if _quit > -1:
|
|
# Prepare Quit teltgramm
|
|
self.generatequit (count, 'ISO', teltype, key2, ret_val ['src'], ret_val ['dst'], _quit)
|
|
self.message (5, ' DT_handler : Quit Tel queued:"')
|
|
self.connections['ISO'][(teltype, key2)][1] = count
|
|
else:
|
|
self.message (1,'"DT_Handler : unknown Telegram type, no Number')
|
|
self.debug ()
|
|
|
|
|
|
def generatequit (self, count, channel, msgtype, key2, src, dst, retval):
|
|
"""
|
|
Generate an ISO QUIT telegram and send it
|
|
"""
|
|
self. message (3, " generatequit : generate Quit Telegram for %s on channel %s, with retval %d" % (msgtype, channel, retval))
|
|
_data = chr((count >> 8) & 0xFF) + chr (count & 0xFF)
|
|
_data = _data +\
|
|
doublechar (src) +\
|
|
doublechar (dst) +\
|
|
msgtype +\
|
|
'%c%c' %(retval >> 8, retval % 256)
|
|
|
|
_tpdu = DT_TPDU (_data)
|
|
self.log (" generatequit Data: %s" % _data[2:])
|
|
_tpkt = tpkt.TPKT (len (_tpdu) + 1)
|
|
self.queue_add (channel, (msgtype, key2), `_tpkt` + `_tpdu`, 0, 0)
|
|
return
|
|
|
|
|
|
def findstorageplace (self, storage, article):
|
|
"""
|
|
Find a free (not locked) slot/place in an unmanaged storage
|
|
according to zone in article
|
|
returns Coordinate Tuple or None in case of no place (or undefined article)
|
|
"""
|
|
DB_con = self.connections['DB']
|
|
usedslots = DB_con.usedstorageslots (storage)
|
|
zones = int (self.parameter['ZONES_%s' % storage])
|
|
if zones > 1:
|
|
self.message (1, ' findstorageplace : get Zone from Articlebase')
|
|
if article not in self.articlemaster:
|
|
self.message (1, ' findstorageplace : Article not in Articlebase')
|
|
return None
|
|
zone = int (self.articlemaster[article][6])
|
|
if zone:
|
|
self.message (5, ' findstorageplace : zone %d for article in Articlebase found' %zone)
|
|
if zone >= 1 and zone <= zones:
|
|
xmin = int (self.parameter["ZONESTART_%s_%d" % (storage, zone)])
|
|
if zone == zones:
|
|
xmax = int (self.parameter['X_%s' % storage])
|
|
else:
|
|
xmax = int (self.parameter["ZONESTART_%s_%d" %(storage, zone + 1)]) - 1
|
|
else:
|
|
self.message (5, ' findstorageplace : no zone for Article')
|
|
return None
|
|
|
|
else:
|
|
#No zones defined
|
|
zone = 1
|
|
xmin = 1
|
|
xmax = int (self.parameter['X_%s' % storage])
|
|
|
|
ymax = int (self.parameter['Y_%s' % storage])
|
|
unusableslots = DB_con.getunusableslots (storage)
|
|
self.log ("Unusable Slots: %s" % repr (unusableslots))
|
|
|
|
#Specific code for multiple zones
|
|
mid = (int (self.parameter.get('XMid_%s_%d' % (storage, zone) , 1)),\
|
|
int (self.parameter.get('YMid_%s_%d' % (storage, zone), 1)))
|
|
|
|
self.message (5, ' findstorageplace : search x from %d to %d with mid x:%d y:%d' %(xmin, xmax, mid[0], mid[1]))
|
|
slots = [(x, y) for x in range (xmin, xmax + 1) for y in range (1, ymax + 1) if (not usedslots or ((x, y) not in usedslots)) and (not unusableslots or ((storage, x, y) not in unusableslots))]
|
|
slots.sort (lambda arg1, arg2: cmp (pow (arg1[0] - mid[0], 2) + pow (arg1[1] - mid[1], 2), pow (arg2[0] - mid[0], 2) + pow (arg2[1] - mid[1], 2)))
|
|
self.log ("Remaining Slots: %s" % repr (slots))
|
|
if len (slots) >= 1:
|
|
self.message (6, ' findstorageplace : using x %d y %d' %(slots[0][0], slots[0][1]))
|
|
return ((slots[0][0], slots[0][1], 1), len (slots))
|
|
|
|
return None
|
|
|
|
|
|
def lifebeat (self):
|
|
"""
|
|
Generate lifebeat
|
|
"""
|
|
count = self.connections['ISO'][('LEBE', 'LEBE')][1]
|
|
dt = TEL_LEBE (nr = count).data
|
|
self.connections['ISO'][('LEBE', 'LEBE')][1] = (count % 32767) + 1
|
|
td = DT_TPDU (dt)
|
|
tk = tpkt.TPKT (len (td) + 1)
|
|
try:
|
|
self.write ('LEBE','LEBE',`tk`+`td`)
|
|
except:
|
|
print ("FixMe Lifebeat")
|
|
|
|
def sendmovetransports (self, position):
|
|
"""
|
|
Send ISO TAUF pending for RFZ
|
|
"""
|
|
DB_con = self.connections['DB']
|
|
|
|
l = DB_con.getmovetransport (position)
|
|
|
|
if not l:
|
|
return 0
|
|
|
|
_data =''
|
|
self.message (3, " sendmovetransports : TAUF found in DB")
|
|
if l[10] == 'New':
|
|
count = self.connections['ISO'][('TAUF' , 'TAUF')][1]
|
|
_data = chr((count >> 8) & 0xFF) + chr (count & 0xFF)
|
|
_data = _data +\
|
|
'LV' +\
|
|
'TR' +\
|
|
'TAUF' +\
|
|
chr (10) +\
|
|
chr (10) +\
|
|
fillchar (str (l[0]), 10) +\
|
|
str (l[1]) +\
|
|
str (l[2]) +\
|
|
doublechar (str (l[3])) +\
|
|
doublechar (str (l[4])) +\
|
|
doublechar (str (l[5])) +\
|
|
str (l[6]) +\
|
|
doublechar (str (l[7])) +\
|
|
doublechar (str (l[8])) +\
|
|
doublechar (str (l[9]))
|
|
|
|
_tpdu = DT_TPDU (_data)
|
|
self.message (3, " sendmovetransports : " + _data)
|
|
_tpkt = tpkt.TPKT (len (_tpdu) + 1)
|
|
self.queue_add ('ISO', ('TAUF','TAUF'), `_tpkt` + `_tpdu`, position, int (fillchar (str (l[0]), 20)))
|
|
DB_con.settransportsending (position, int (l[0]))
|
|
return 1
|
|
return 0
|
|
|
|
|
|
def generatetransport (self, position, boxnr):
|
|
"""
|
|
Generate an ISO TAUF telegram from DB TAUF for boxes from IPKT or at VF
|
|
"""
|
|
DB_con =self.connections['DB']
|
|
self. message (3, " generatetransport : getting TAUF for Box %s at position %s " % (boxnr, position))
|
|
tauf = DB_con.gettransport (position, boxnr)
|
|
if tauf:
|
|
self.message (3, " generatetransport : TAUF found in DB")
|
|
count = self.connections['ISO'][('TAUF' , 'TAUF')][1]
|
|
tel = TEL_TAUF ( nr = count,\
|
|
src = 'LV',\
|
|
dst = 'TR',\
|
|
type = 'TAUF',\
|
|
boxnr = str (boxnr),\
|
|
position = tauf [1], \
|
|
source = tauf [2], \
|
|
srcx = tauf [3],\
|
|
srcy = tauf [4],\
|
|
srcz = tauf [5],\
|
|
dest = tauf [6],\
|
|
destx = tauf [7],\
|
|
desty = tauf [8],\
|
|
destz = tauf [9])
|
|
|
|
_tpdu = DT_TPDU (tel.data)
|
|
self.log ( " generatetransport : " + str (tel.attrib))
|
|
self.log ( " generatetransport : Data '%s' " % tel.data)
|
|
_tpkt = tpkt.TPKT (len (_tpdu) + 1)
|
|
self.queue_add ('ISO', ('TAUF','TAUF'), `_tpkt` + `_tpdu`, position, boxnr)
|
|
DB_con.settransportsending (position, boxnr)
|
|
else:
|
|
self.log (" generatetransport : No TAUF in DB --> FixMe ??")
|
|
return
|
|
return
|
|
|
|
|
|
def generateTFnoreadTAUF (self, boxnr):
|
|
# Throughfeed box in no read slot
|
|
DB_con = self.connections['DB']
|
|
ux, uy = DB_con.findthroughfeedslot ()
|
|
|
|
count = self.connections['ISO'][('TAUF' , 'TAUF')][1]
|
|
_data = chr((count >> 8) & 0xFF) + chr (count & 0xFF)
|
|
_data = _data +\
|
|
'LV' +\
|
|
'TR' +\
|
|
'TAUF' +\
|
|
chr (10) +\
|
|
chr (10) +\
|
|
fillchar (boxnr, 10) +\
|
|
RFZ2 +\
|
|
PUFFER +\
|
|
doublechar (str(ux)) +\
|
|
doublechar (str(uy)) +\
|
|
'01' +\
|
|
PICK +\
|
|
'19' +\
|
|
'06' +\
|
|
'00'
|
|
|
|
_tpdu = DT_TPDU (_data)
|
|
_tpkt = tpkt.TPKT (len (_tpdu) + 1)
|
|
self.queue_add ('ISO', ('TAUF','TAUF'), `_tpkt` + `_tpdu`)
|
|
DB_con.settaufsent (RFZ1, boxnr)
|
|
|
|
|
|
|
|
def checkarticletransfer (self, article, transferdest, transfersource):
|
|
"""
|
|
Move box from a specific article to external destination
|
|
Multiplexed Outqueues for Orderlines identified by findest 50+
|
|
Mainorder identifies a global Order for interlocking RBGs against each other
|
|
triggerbox tells boxnr which triggers the transport
|
|
"""
|
|
DB_con = self.connections['DB']
|
|
self.message (6, " Checkarticletransfer for article %d from %s to %s" \
|
|
% (article, transferdest, transfersource))
|
|
sources = []
|
|
for src, rfz, rfzOut, mode, prio in self.transportmatrix['srcbydst'][transferdest]:
|
|
if src == transfersource:
|
|
self.message (6, " Checkarticletransfer Possible Transport from %s to %s with RFZ%d%s with prio %s" %\
|
|
(src, transferdest, rfz, rfzOut and " Outfeedpoint %s" % rfzOut or '', prio))
|
|
sources.append (src)
|
|
arts = []
|
|
_resactive = 0
|
|
for src in sources:
|
|
srcarts = DB_con.findarticle (src, article)
|
|
if srcarts:
|
|
for i in srcarts:
|
|
arts.append (i)
|
|
|
|
locked = DB_con.getunusableslots ('')
|
|
|
|
# Found matching article Storage included in Transportmatrix
|
|
if arts:
|
|
# Check if box already
|
|
# is reserved in Destination
|
|
# is reserved for a Outjob (Express e.g.)
|
|
# id, boxnr, article, lotnr, duedate, weight, x, y, z, rfzts
|
|
# id, boxnr, article, lotnr, lotnr2, duedate, pieces, x, y, z, rfzts
|
|
# 0 1 2 3 4 5 6 7 8 9 10
|
|
boxes = [(str(box[10]).replace(' ','').replace('-',''), box[7], box[8], box[9], box[1], box[3], box[4], box[5], box[6], box[0]) for box in arts if box[10]\
|
|
and not DB_con.searchbox (int (box[1]), box[0], excl = 1) and not DB_con.searchbox (int (box[1]), 'Outqueue') and (box[0], box[7], box[8]) not in locked]
|
|
|
|
boxes.sort ()
|
|
|
|
if not boxes:
|
|
if _resactive:
|
|
return -1
|
|
return None
|
|
box = boxes [0]
|
|
|
|
if box:
|
|
rfzts, x, y, z, boxnr, lotnr, lotnr2, duedate, pieces, source = box
|
|
|
|
for src, rfzNr, rfzOut, mode, prio in self.transportmatrix['srcbydst'][transferdest]:
|
|
rfz = "RFZ%d" % rfzNr
|
|
destination = transferdest[0] == 'O' and "OP%s" % rfzOut or transferdest
|
|
if src == source:
|
|
#FixMe Get from Transportmatrix
|
|
self.log ( " Checkarticletransfer Creating Transport at %s for %s from %s to %s"\
|
|
% (rfz, boxnr, source, transferdest))
|
|
DB_con.reservebox (rfz, source, x, y, z, int (boxnr), article, lotnr, lotnr2, duedate, pieces, destination, 0, 0, 0)
|
|
#if transferdest in ['O001', 'O002'] and source [0] == 'T':
|
|
# self.message (3, "Cheackarticletransfer storing next triggerbox %d for %s" % (int (boxnr), transferdest))
|
|
# self.parameter['triggerbox-%s' % transferdest] = int (boxnr)
|
|
|
|
return box
|
|
else:
|
|
self.message (6, " Checkarticletransfer didn't find article %s" % article)
|
|
|
|
return None
|
|
|
|
|
|
def boxreserve (self, location, source, src_x, src_y, src_z, boxnr, article, lotnr, lotnr2, duedate, pieces, storage, zone, noreserve):
|
|
"""
|
|
Assign reservation for a Box from IPKT
|
|
try to find a place in storage
|
|
location - RFZ
|
|
source - IPoint ID
|
|
"""
|
|
DB_con = self.connections['DB']
|
|
self.message (3, " boxreserve : assign place for Box %s" %boxnr)
|
|
place = None
|
|
tshelffull = 0
|
|
if storage[0] == 'T':
|
|
#Storage with Throughfeed Check for Refill an Slot
|
|
self.message (3, " boxreserve : check if article is in Througfeedstorage --> get a free place")
|
|
place = DB_con.placeinthroughfeed (storage, article, zone, self.parameter)
|
|
if place == (0, 0, 0):
|
|
# Slots for article in Throughfeed occupied
|
|
if '%s_Managed' % storage in self.parameter:
|
|
self.message (3, " boxreserve: All slots for article in managed T-Shelf are occupied")
|
|
else:
|
|
self.message (3, " boxreserve: Used for article in unmanaged T-Shelf are occupied --> assign new slot")
|
|
place, emptyslots = self.findstorageplace (storage, article)
|
|
self.message (3, " boxreserve: Used for article in unmanaged T-Shelf are occupied Nr of Emtpy Slots %d" % emptyslots)
|
|
if not place:
|
|
tshelffull = 1
|
|
|
|
if place:
|
|
#Found place in Throughfeed
|
|
self.message (3, " boxreserve : Box Found Place in T Storage %s at %s" % (storage, repr (place)))
|
|
_dx = place[0]
|
|
_dy = place[1]
|
|
_dz = place[2]
|
|
if noreserve:
|
|
inqsize = DB_con.getinqueuesize (storage)
|
|
self.message (3, " boxreserve : Box Found Place in T Storage no Reservation so from Ixx Test Spare Queuesize is %d" % inqsize)
|
|
slotlen = int (self.parameter['Z_%s' % storage])
|
|
if int (_dz) > (slotlen - inqsize - 1):
|
|
self.message (3, " boxreserve : Box Found Place in T Storage no Reservation Rem. Slotspace to small check rem. Slots")
|
|
testplace = self.findstorageplace (storage, article)
|
|
if not testplace:
|
|
self.message (3, " boxreserve : Box Found Place in T Storage no Reservation Rem. No more Space")
|
|
return None
|
|
|
|
|
|
if not noreserve:
|
|
DB_con.reservebox (location, source, src_x, src_y, src_z, int (boxnr), article, lotnr, lotnr2, duedate, pieces, storage, place[0], place[1], place[2])
|
|
self.message (3, " boxreserve : Box reserved in T Storage %s at %s" % (storage, repr (place)))
|
|
|
|
else:
|
|
self.message (3, " boxreserve : article not in Storage (or not Throughfeed) yet -> try to find a place")
|
|
inqsize = DB_con.getinqueuesize (storage)
|
|
|
|
|
|
place, emptyslots = self.findstorageplace (storage, article)
|
|
if not place:
|
|
self.message (3, " boxreserve : No Place in Storage return and maybe get another place")
|
|
return None
|
|
if storage in ['S001', 'S002']:
|
|
self.message (3, " boxreserve : Singleplace Storage check remaining Space %d against queuesize %d" % (emptyslots, inqsize))
|
|
if emptyslots <= inqsize:
|
|
self.message (3, " boxreserve : Singleplace Storage does not have enough space")
|
|
return None
|
|
|
|
|
|
|
|
#Do boxreservatoion
|
|
self.message (3, " boxreserve : Box Found Place in Storage %s " % storage + str (place))
|
|
_dx = place[0]
|
|
_dy = place[1]
|
|
_dz = place[2]
|
|
if not noreserve:
|
|
DB_con.reservebox (location, source, src_x, src_y, src_z, int (boxnr), article, lotnr, lotnr2, duedate, pieces, storage, place[0], place[1], place[2])
|
|
self.message (3, " boxreserve : Box reserved in Storage %s " % storage + str (place))
|
|
|
|
return (storage, _dx, _dy, _dz)
|
|
|
|
|
|
def queue_add (self, channel, connection, data, position, boxnr):
|
|
"""
|
|
Add a telegram to sendqueue
|
|
for SOAP telegrams data is a list of (RPCfunction, data)
|
|
"""
|
|
self.message (3, "Added telegram to sendqueue")
|
|
self.connections['Queue'].append ([channel, connection, data, position, boxnr])
|
|
|
|
|
|
def listen (self, socket):
|
|
"""
|
|
Wait for a client to open a connection to our socket.
|
|
"""
|
|
try:
|
|
new_socket, client = socket.accept ()
|
|
self.message (1, "Server connected by %s port %s" % client)
|
|
if self.connections['client'] == client[0]:
|
|
self.sockets [client]= (new_socket, CONN_NEW)
|
|
self.message (3, "** Checking for active Connections to request")
|
|
else:
|
|
self.message (1, "Unauthorized connection from %s port %s " % client)
|
|
|
|
except KeyboardInterrupt:
|
|
self.message (1,"Interrupted by user")
|
|
return
|
|
|
|
|
|
def blocknxmit (self):
|
|
"""
|
|
Wait for incomming data on any of the open connections, decode it and take
|
|
appropriate action and also check for outgoing data and free channels to
|
|
transmit it.
|
|
"""
|
|
global prioexp, prioexp2
|
|
# lifebeats
|
|
nt = time ()
|
|
DB_con = self.connections['DB']
|
|
# Send lifebeat every 5s
|
|
if nt - self.connections['LastBeat'] > 5:
|
|
self.lifebeat ()
|
|
self.connections['LastBeat'] = nt
|
|
|
|
writecons = []
|
|
#Check for active ISO connections
|
|
for c in self.connections['ISO']:
|
|
if len (c) != 2 and type (c) != type (()):
|
|
raise Warning, "Invalid item in ISO connections"
|
|
|
|
# Connection Tuple found
|
|
loc_TSAP, rem_TSAP = c
|
|
socket, counter, mode = self.connections['ISO'][c]
|
|
if mode == 'active' and not socket:
|
|
s = self.makeactiveisoconnection (loc_TSAP, rem_TSAP)
|
|
if s:
|
|
self.message (3, "*** queue CR for connection: %s - %s " %(loc_TSAP, rem_TSAP))
|
|
_tel = con_request (loc_TSAP, rem_TSAP)
|
|
self.queue_add ('ISO', (loc_TSAP, rem_TSAP), _tel, 0, 0)
|
|
self.sockets[s.getpeername ()] = (s, CONN_NEW)
|
|
|
|
if len (self.connections['Queue']):
|
|
channel, conn_name, data, position, boxnr = self.connections['Queue'][0]
|
|
if channel == 'ISO':
|
|
#conn_name == ISO-Tuple
|
|
self.message (3, "blocknxmit - Found to-be-send telegramm %s" % repr (conn_name))
|
|
con = self.connections[channel][conn_name][0]
|
|
if con:
|
|
writecons.append ((con, data, self.connections['client'], conn_name))
|
|
|
|
# Select free sockets for transmission
|
|
# self.sockets = {(socket, STATE)}
|
|
writes = [i[0] for i in writecons]
|
|
reads = [self.sockets[i] for i in self.sockets]
|
|
|
|
(read, writes, xlist) = select ([i[0] for i in reads], writes, [], 0.1)
|
|
readcons = [i for i in reads if i[0] in read]
|
|
writecons = [i for i in writecons if i[0] in writes]
|
|
|
|
# First write all remaining messages
|
|
for conn, data, client_id, contyp in writecons:
|
|
self.message (1, "blocknxmit - Write to Socket %s" % str (conn))
|
|
# Loop until we successfuly got the data through
|
|
while 1:
|
|
try:
|
|
conn.send (data)
|
|
except error, msg:
|
|
# In case of a failure we'll need a new connection
|
|
self.message (1, "blocknxmit - Error on write: %d %s" %(msg[0], msg[1]))
|
|
if len (contyp) == 2 and type (contyp) == type (()):
|
|
socket, counter, mode = self.connections[c]
|
|
if mode == 'active':
|
|
print "hoit"
|
|
raise Warning
|
|
loc_TSAP, rem_TSAP = contyp
|
|
self.makeactiveisoconnection (loc_TSAP, rem_TSAP)
|
|
conn = self.connections['ISO'][(loc_TSAP, rem_TSAP)][0]
|
|
else:
|
|
# Break on success
|
|
break
|
|
|
|
channel, conn_name, data, position, boxnr = self.connections['Queue'][0]
|
|
self.message (3, "Channel: '%s' Connection '%s' Data '%s' positon %s boxnr %s" % (channel, conn_name[0], data[9:], position, boxnr))
|
|
if conn_name == ('TAUF', 'TAUF') and position:
|
|
if position[0] in ['I', 'P', 'O']:
|
|
self.message (6, "Delete %s Tauf After Sending" % position)
|
|
DB_con.deletetransport (position, boxnr)
|
|
elif (position[0:3] == 'RFZ') and '%sIRFZ000000%s000001' % (position, position) in data[9:]:
|
|
self.message (7, "Delete %s Take Off Tauf after Sending" % position)
|
|
DB_con.deletetransport (position, boxnr)
|
|
elif (position[0:3] == 'RFZ') and '%s%s000000%s000001' % (position, position, position) in data[9:]:
|
|
self.message (7, "Delete %s Take Off Tauf after Sending" % position)
|
|
DB_con.deletetransport (position, boxnr)
|
|
else:
|
|
self.message (6, "Set Transport Sent at Position %s" % position)
|
|
DB_con.settransportsent (position, boxnr)
|
|
del self.connections['Queue'][0]
|
|
|
|
# Then read all remaining messages from ready sockets
|
|
for conn in readcons:
|
|
#self.message (1, "blocknxmit - Read from Socket " )
|
|
|
|
if conn[0] == self.listener_socket:
|
|
self.message (3, " blocknxmit - Read on listener socket")
|
|
self.listen (conn[0])
|
|
|
|
else:
|
|
#self.message (3, " blocknxmit - Read on other socket")
|
|
self.read (conn)
|
|
# Update Articlemaster
|
|
nt = time ()
|
|
if nt -self.lastarticleupdate > 120:
|
|
self.articlemaster.update (DB_con.getarticlemaster ())
|
|
self.lastarticleupdate = nt
|
|
|
|
# Sweep over DB for empty space in pick every once in a while
|
|
nt = time ()
|
|
if nt - self.lastsweep > 1:
|
|
self.message (3, "Sweeping for jobs")
|
|
_max = 4
|
|
DB_con = self.connections['DB']
|
|
self.parameter.update (DB_con.getphysics ())
|
|
|
|
#1st send pending Transports
|
|
for i in range (int (self.parameter['RFZs'])):
|
|
self.message (3, "Queue Pending Move Transports for RFZ %d" % (i + 1))
|
|
_r = self.sendmovetransports ('RFZ%d' % (i + 1))
|
|
if _r:
|
|
break
|
|
|
|
#FixmMe ToDo New methods for Chaos, Move and Expressjobs
|
|
for i in range (int (self.parameter['RFZs'])):
|
|
_count = DB_con.getnewmovetransportcount ('RFZ%d' % (i + 1))
|
|
_sentcount = DB_con.getmovetransportsentcount ('RFZ%d' % (i + 1))
|
|
self.message (3, "Queue Move Transports for RFZ %d Count %d Sent %d" % (i + 1, _count[0], _sentcount[0]))
|
|
#Check if Errorboxes have to be moved
|
|
|
|
_count = DB_con.getnewmovetransportcount ('RFZ%d' % (i + 1))
|
|
|
|
_count = [0]
|
|
#automatic Storage moves - add timecontrol
|
|
|
|
|
|
if 'ordering' in self.parameter:
|
|
nt = time ()
|
|
if 0 and nt - self.lastordersweep > 30:
|
|
self.message (6, "Ordering Time to check if new Orders arived")
|
|
Ordering = self.connections ['Ordering']
|
|
for orderfile in Ordering.orderfiles ():
|
|
self.log ("Ordering: Processing new File %s" % orderfile)
|
|
_ordhd, _ordln = Ordering.decodefile (orderfile)
|
|
if _ordhd:
|
|
if DB_con.searchorder (id = int (_ordhd['orderid'])):
|
|
self.log ("Ordering: Processed Files contains already existing Order %d" % int (_ordhd['orderid']))
|
|
else:
|
|
DB_con.addorder (orderid = int (_ordhd['orderid']), \
|
|
customer_name = _ordhd['cust'] + "\n" + _ordhd['cust2'], \
|
|
customer_address = _ordhd['cust_country'] + "-" + _ordhd['cust_postcode'] + " " + \
|
|
_ordhd['cust_city'] + "\n" + _ordhd['cust_street'],
|
|
deliverydate = _ordhd['deliverydate'])
|
|
|
|
for _ln in _ordln:
|
|
DB_con.addorderline (orderid = int (_ordhd['orderid']), \
|
|
article = int (_ln['article']), \
|
|
caption = _ln['caption'], \
|
|
amount = _ln ['order_amount'], \
|
|
amount_unit = _ln ['order_amount_unit'], \
|
|
weight = _ln ['order_weight'], \
|
|
weight_unit = _ln ['order_weight_unit'])
|
|
|
|
Ordering.archiveorderfile (orderfile)
|
|
|
|
self.lastordersweep = nt
|
|
|
|
nt = time ()
|
|
if 0 and nt - self.lastodredelsweep >= 3600:
|
|
self.lastodredelsweep = nt
|
|
self.message (6, "Ordering Time to delete old orders")
|
|
for oldorder in DB_con.getoldorders ():
|
|
_orderid, _deldate, _state = oldorder
|
|
DB_con.deleteorder (int (_orderid))
|
|
|
|
nt = time ()
|
|
if nt - self.lastordermovesweep >= 1:
|
|
self.lastordermovesweep = nt
|
|
self.message (6, "Ordering Time to check for new moves")
|
|
for _dest in filter (lambda a: a[0] == 'O', self.transportmatrix['srcbydst'].keys ()):
|
|
if 3 >= 1:
|
|
self.message (6, "Ordereng Current Outqueuesize %d for dest %s reached maximum - stop sweep" % (1, _dest))
|
|
continue
|
|
|
|
#FixMe ignore Expressdestinations
|
|
|
|
_activeorders = DB_con.searchorder (id = 0, destination = _dest, state = 'Active')
|
|
if _activeorders:
|
|
self.message (6, "Found active Order, scan orderlines")
|
|
_orderid, _state, _dest = _activeorders [0]
|
|
_activeorderlines = DB_con.searchorderline (orderid = int (_orderid), state = 'Active')
|
|
if _activeorderlines:
|
|
key = 'OrderingMainorder_%s' % _dest
|
|
if key not in self.parameter:
|
|
self.message (6, "Mainorder for Outqueue doesn't exist, create value")
|
|
self.parameter[key] = 0
|
|
DB_con.addphysics (key, str (self.parameter[key]))
|
|
mainorder = int (self.parameter[key])
|
|
_olid, _art, _amnt, amnt_unit, amnt_dlrd, weight, weight_unit, weight_dlrd, state = _activeorderlines[0]
|
|
triggerbox = 0
|
|
if int (self.parameter.get ('triggertransports-%s' % _dest, 0)):
|
|
triggerbox = int (self.parameter.get ('triggerbox-%s' % _dest, 0))
|
|
self.message (6, "Found active Orderline for Odrer %d with Article %d%s" % (int (_orderid), _art, triggerbox and ' and Trigger %d' %triggerbox or ''))
|
|
_box = self.checkarticletransfer (_art, _dest, finedest = int (_dest[1:]) + 50, mainorder = mainorder, triggerbox = triggerbox)
|
|
_weight = 0.0
|
|
if _box and _box != -1:
|
|
|
|
_rfzts, _x, _y, _z, _boxnr, _lotnr, _duedate, _weight, _source = _box
|
|
if self.parameter.get ('triggerbox-%s' % _dest, 0) == -1:
|
|
self.message (6, ' : Ordering box %d reserved for Triggertransport so not adding to outqueue %s' % (int (_boxnr), _dest))
|
|
self.parameter['triggerbox-%s' % _dest] = 0
|
|
else:
|
|
self.message (6, ' : Ordering add box %d to outqueue %s' % (int (_boxnr), _dest))
|
|
DB_con.addoutgoingbox (_dest, int (_boxnr), '', '', '', '', 99)
|
|
DB_con.setphysics (key, str ((mainorder + 1) % 100))
|
|
#ToDo add box to order
|
|
self.log ("Orderline generate Triggertransport to show Orderid on Panel for Box %d" % int (_boxnr))
|
|
DB_con.createtransport (int (_orderid), _dest, _dest, 0, 0, 0, _dest, 0, 0, 0, state = 'Trigger-%d' % int (_boxnr))
|
|
|
|
DB_con.orderlineaddweight (_olid, _weight)
|
|
elif _box and _box == -1:
|
|
self.message (6, "Waiting for done Storagemoves for Orderline")
|
|
#DB_con.setorderlinestate (orderlineid = int (_olid), state = 'Paused')
|
|
#self.lastordermovesweep = nt - 1
|
|
else:
|
|
self.message (6, "Didn't find any box for Orderline")
|
|
if str (_art) not in DB_con.getslotbasearticles ('T002'):
|
|
#FixMe Startup Stuff
|
|
self.log ("Article of Orderline not in Base close")
|
|
DB_con.setorderlinestate (orderlineid = int (_olid), state = 'Done')
|
|
self.lastordermovesweep = nt - 1
|
|
else:
|
|
DB_con.setorderlinestate (orderlineid = int (_olid), state = 'Paused')
|
|
self.lastordermovesweep = nt - 1
|
|
|
|
if weight_dlrd +_weight >= weight:
|
|
self.message (6, "Requested Weight of Orderline reached, close")
|
|
DB_con.setorderlinestate (orderlineid = int (_olid), state = 'Done')
|
|
|
|
else:
|
|
_neworderlines = DB_con.searchorderline (orderid = int (_orderid), state = 'New')
|
|
if _neworderlines:
|
|
_olid, _art, _amnt, amnt_unit, amnt_dlrd, weight, weight_unit, weight_dlrd, state = _neworderlines[0]
|
|
self.message (6, "Activating Orderline %d for order %d with article %d" % (int (_olid), int (_orderid), int (_art)))
|
|
DB_con.setorderlinestate (orderlineid = int (_olid), state = 'Active')
|
|
|
|
else:
|
|
_pausedorderlines = DB_con.searchorderline (orderid = int (_orderid), state = 'Paused')
|
|
if _pausedorderlines:
|
|
for i in _pausedorderlines:
|
|
_olid, _art, _amnt, amnt_unit, amnt_dlrd, weight, weight_unit, weight_dlrd, state = i
|
|
DB_con.setorderlinestate (orderlineid = int (_olid), state = 'New')
|
|
self.log ("Pausing Order %d due to no more Orderlines to process" % int (_orderid))
|
|
DB_con.setorderstate (orderid = int (_orderid), state = 'Paused')
|
|
else:
|
|
self.log ("Closing Order %d due to no more Orderlines to process" % int (_orderid))
|
|
DB_con.setorderstate (orderid = int (_orderid), state = 'Done')
|
|
self.lastordermovesweep = nt - 1
|
|
|
|
else:
|
|
_neworders = DB_con.searchorder (id = 0, destination = _dest, state = 'New')
|
|
if _neworders:
|
|
_orderid, _state, _dest = _neworders[0]
|
|
self.message (6, "Activating Order %d" % int (_orderid))
|
|
DB_con.setorderstate (orderid = int (_orderid), state = 'Active')
|
|
|
|
prioexp = 1
|
|
if prioexp:
|
|
prioexp = 0
|
|
self.message (3, " Sweep over Expressjobs")
|
|
_exp = 1
|
|
if _exp:
|
|
self.message (3, "Exp: Sweeping over Expressjobs for ")
|
|
_count = DB_con.getnewmovetransportcount ('RFZ2')
|
|
_sentcount = DB_con.getmovetransportsentcount ('RFZ2')
|
|
self.message (3, " Exp: count for RFZ2 Taufs %d sent %d" % (_count[0], _sentcount[0]))
|
|
DB_con = self.connections['DB']
|
|
job = DB_con.findactiveexpressjob ()
|
|
if job:
|
|
self.message (3, "Exp: found active job")
|
|
_expjob, _source, _state, _customer, _packl, _article, _boxes, _boxes_delivered, _ts, _info = job
|
|
|
|
if (int (_boxes) and (int (_boxes_delivered) >= int (_boxes))):
|
|
self.message (3, "Exp: Job is finished now")
|
|
DB_con.closeexpressjob (job[0], 'Auftrag beendet')
|
|
try:
|
|
explog = DB_con.expressloggetdata (_expjob)
|
|
mailexplog (job, explog)
|
|
except:
|
|
print ('Problem')
|
|
elif _sentcount[0] == 0 and _count[0] == 0:
|
|
#FixMe just RBG 2 at the moment
|
|
if _source == 'T001':
|
|
self.message (3, "Exp: Check Article From T001 due to no Move Job active")
|
|
_box = self.checkarticletransfer (int (_article), 'O002', 'T001')
|
|
if _box and _box != -1:
|
|
_brfzts, _bx, _by, _bz, _boxnr, _lotnr, _lotnr2, _duedate, _bpieces, _bsource = _box
|
|
|
|
DB_con.expressjobaddbox (job[0])
|
|
DB_con.expresslogaddbox (_expjob, _boxnr, _lotnr, _lotnr2, _bpieces)
|
|
|
|
else:
|
|
DB_con.closeexpressjob (job[0], 'Paletten fehlen')
|
|
|
|
else:
|
|
self.message (3, "Exp : Look for new express job")
|
|
for j in DB_con.findnewexpressjobs ():
|
|
self.message (3, "Exp: Assigned new Express Job")
|
|
DB_con.activateexpressjob (j[0])
|
|
break
|
|
self.message (3, "Exp: Sweeping over Expressjobs Done")
|
|
|
|
|
|
#ES Move Jobs
|
|
_esjob = DB_con.findnewesmovejobs ()
|
|
_count = DB_con.getnewmovetransportcount ('RFZ2')
|
|
self.message (3, " Sweep: count for RFZ2 Taufs %d" %_count[0])
|
|
|
|
if _esjob and _count[0] > 0:
|
|
self.message (3, " Sweep: Found Singletransfer jobs so 1st block all further jobs")
|
|
elif _esjob:
|
|
self.message (3, " Sweep: Found Singletransfer jobs and no other job")
|
|
c_id, c_pos, c_state, c_anr, c_srcid, c_srcx, c_srcy, c_ts = _esjob[0]
|
|
DB_con.assignesmovejob (c_id, 'RFZ2')
|
|
aboxes = {}
|
|
c_anr = int (c_anr)
|
|
|
|
srcboxes = DB_con.getboxesslot (c_srcid, c_srcx, c_srcy)
|
|
if srcboxes:
|
|
self.message (3, " Sweep: Found Boxes for Singleplacetransfer")
|
|
for a_id, a_knr, a_anr, a_lnr, a_due, a_w, a_x, a_y, a_z, a_ts in srcboxes:
|
|
aboxes [(a_x, a_y, a_z)] = (a_id, a_knr, a_anr, a_lnr, a_due, a_w, a_ts)
|
|
nusage = len (aboxes)
|
|
unusableslots = DB_con.getunusableslots ('S001')
|
|
usedslots = DB_con.usedstorageslots (storage)
|
|
xmin = 5
|
|
mid = (20, 4)
|
|
xmax = 35
|
|
ymax = 8
|
|
|
|
l = [(x, y) for x in range (xmin, xmax + 1) for y in range (1, ymax + 1) if (x, y) not in usedslots and ('S001', x, y) not in unusableslots]
|
|
l.sort (lambda arg1, arg2: cmp (pow (arg1[0] - mid[0], 2) + pow (arg1[1] - mid[1], 2), pow (arg2[0] - mid[0], 2) + pow (arg2[1] - mid[1], 2)))
|
|
nstart = 1
|
|
for slot in l:
|
|
if nstart > nusage:
|
|
break
|
|
cx, cy = slot
|
|
self.message (3, " Sweep: Singleplacetransfer moving box %s from 'T002' %d %d %d to 'S001' %d %d %d " %( str (aboxes [(c_srcx, c_srcy, nstart)]) ,c_srcx, c_srcy, nstart, cx, cy, 1))
|
|
boxdata = aboxes [(c_srcx, c_srcy, nstart)]
|
|
#Reserve Here
|
|
if boxdata[0] <> 'T001':
|
|
print "Not Allowed"
|
|
sys.exit (0)
|
|
if int (boxdata[1]) > 999999900:
|
|
self.message (4, "Sweep: Stopping because of Dummy in slot")
|
|
nstart = nusage + 1
|
|
else:
|
|
DB_con.reservebox ('RFZ2', 'T001', c_srcx, c_srcy, nstart, int (boxdata[1]), boxdata[2], boxdata[3], boxdata[4], boxdata[5], 'S001', cx, cy, 1, '', '')
|
|
nstart += 1
|
|
if nstart > nusage:
|
|
self.message (3, " Sweep: Chaos finished")
|
|
DB_con.closeesmovejob (c_id, 'OK')
|
|
else:
|
|
self.message (3, " Sweep: Chaos broken no Space")
|
|
DB_con.closeesmovejob (c_id, 'No Space')
|
|
|
|
else:
|
|
self.message (3, " Sweep: Singletransfer broken no Boxes exist in Slot")
|
|
DB_con.closeesmovejob (c_id, 'No Boxes')
|
|
|
|
|
|
|
|
|
|
|
|
self.lastsweep = time ()
|
|
|
|
# Sweep over ERP Entrys and create file
|
|
DB_ERP_con = self.connections['DB_ERP']
|
|
if DB_ERP_con:
|
|
nt = time ()
|
|
_erpsweepcycle = 300
|
|
try:
|
|
config = ConfigParser ()
|
|
config.read ('/opt/sap/sap.cfg')
|
|
_erpsweepcycle = 60 * config.getint ('SAP', 'cycletime')
|
|
except:
|
|
_erpsweepcycle = 300
|
|
|
|
if _erpsweepcycle <= 0 or _erpsweepcycle > 3600:
|
|
_erpsweepcycle = 300
|
|
|
|
if (nt - self.lasterpsweep > _erpsweepcacle):
|
|
self.message (3, " Sweeping over ERP msgs")
|
|
sapfile = pySAP (path = "/opt/sap/")
|
|
|
|
DB_ERP_con = self.connections['DB_ERP']
|
|
for a, c, m, u in DB_ERP_con.getinsertions ():
|
|
sapfile.log ('%05d;%010d;%s;%s' % (int (a), int (c), m, u))
|
|
DB_ERP_con.markinsertionsasread ()
|
|
self.lasterpsweep = nt
|
|
|
|
|
|
|
|
def read (self, conn):
|
|
sock, state = conn
|
|
try:
|
|
data = sock.recv (32768)
|
|
except error, msg:
|
|
self.message (1, 'Socket error on read: ' + msg[1])
|
|
return
|
|
|
|
# Bail out if connection closed by client
|
|
if not data:
|
|
try:
|
|
client_ip, client_port = sock.getpeername ()
|
|
except:
|
|
client_ip, client_port = '0.0.0.0', 0
|
|
self.message (1, ' read empty telegramm - client %s %d closed connection - close socket !!!!'% (client_ip, client_port))
|
|
|
|
if (client_ip, client_port) in self.sockets:
|
|
socket, state = self.sockets [(client_ip, client_port)]
|
|
self.message (2, ' delete socket')
|
|
del self.sockets[(client_ip, client_port)]
|
|
for typ in self.connections:
|
|
try:
|
|
if self.connections[typ][0] == sock:
|
|
self.message (2, ' found socket in connection delete Reference %s' % str (typ))
|
|
self.connections[typ][0] = None
|
|
except:
|
|
a = 0
|
|
sock.close ()
|
|
else:
|
|
self.log ("Socket not in self.sockets")
|
|
print self.sockets
|
|
print sock
|
|
for (client_ip, client_port) in self.sockets.keys ():
|
|
if self.sockets [(client_ip, client_port)][0] == sock:
|
|
self.log (" Closing Socket with empty telegram")
|
|
del self.sockets[(client_ip, client_port)]
|
|
for typ in self.connections:
|
|
try:
|
|
if self.connections[typ][0] == sock:
|
|
self.log ("Found socket in connection delete Reference %s" % str (typ))
|
|
self.connections[typ][0] = None
|
|
except:
|
|
a = 0
|
|
sock.close ()
|
|
|
|
return
|
|
|
|
packet = decode.decodepacket (data)
|
|
ptype = packet.type ()
|
|
# Check for connection request
|
|
if ptype == tpdu.TPDU_CR:
|
|
self.message (1," read : Received CR "+ packet.srctsap () + packet.dsttsap ())
|
|
connreq = (packet.srctsap (), packet.dsttsap ())
|
|
client_ip, client_port = sock.getpeername ()
|
|
#if conn[1] <> CONN_NEW:
|
|
# raise RuntimeError, "Connection already assigned"
|
|
if connreq in self.connections['ISO']:
|
|
if self.connections['ISO'][connreq][0] == None:
|
|
self.message (1, " Request acknowledged")
|
|
else:
|
|
self.message (1, " Client tried to open an established connection Closing Socket")
|
|
oldsock = self.connections['ISO'][connreq][0]
|
|
oldsock.close ()
|
|
for ip, port in self.sockets:
|
|
if self.sockets[(ip, port)][0] == oldsock:
|
|
self.message (1, " read delete socket")
|
|
del self.sockets[(ip, port)]
|
|
break
|
|
|
|
#Socket , Counter, Mode
|
|
self.connections['ISO'][connreq] = [sock, 0, 'passive']
|
|
sock.send (acknowledge (packet))
|
|
|
|
else:
|
|
self.message (1," Received undefined connection request Close Socket")
|
|
self.message (1, " "+ packet.srctsap () + packet.dsttsap ())
|
|
self.message (1," " + client_ip)
|
|
if (client_ip, client_port) in self.sockets:
|
|
self.message (2, 'delete socket')
|
|
del self.sockets[(client_ip, client_port)]
|
|
sock.close ()
|
|
|
|
# Check for connection confirmation
|
|
elif ptype == tpdu.TPDU_CC:
|
|
self.message (1, " read : Received CC "+ packet.srctsap () + packet.dsttsap ())
|
|
self.message (1, " read : FixME State was %d" % state)
|
|
|
|
# Check for data transfer
|
|
elif ptype == tpdu.TPDU_DT:
|
|
self.message (1," read : Received data packet")
|
|
"""
|
|
if state != STATE_ESTABLISHED:
|
|
raise RuntimeError, "Connection not established but data received"
|
|
else:
|
|
"""
|
|
client_id = conn[0].getpeername()[0]
|
|
ret_val = self.dt_handler (packet, client_id, source = '')
|
|
else:
|
|
self.message (1, " read : Unknown packet received : 's%'" %str (packet))
|
|
|
|
|
|
def write (self, loc_TSAP, rem_TSAP, data):
|
|
"""
|
|
Send Data via ISO Connection
|
|
"""
|
|
if 'client' in self.connections:
|
|
if (loc_TSAP, rem_TSAP) in self.connections['ISO']:
|
|
conn_data = self.connections['ISO'][(loc_TSAP, rem_TSAP)]
|
|
conn = conn_data[0]
|
|
if conn:
|
|
if conn_data[1] == "active":
|
|
# Loop until we successfuly got the data through
|
|
while 1:
|
|
try:
|
|
conn.send (data)
|
|
# In case of a failure we'll need a new connection
|
|
except error:
|
|
self.makeactiveisoconnection (loc_TSAP, rem_TSAP)
|
|
conn = self.connections['ISO'][(loc_TSAP, rem_TSAP)][0]
|
|
# Break on success
|
|
else:
|
|
break
|
|
else:
|
|
try:
|
|
conn.send (data)
|
|
except error:
|
|
print "ISO Send Error"
|
|
|
|
else:
|
|
self.message (1,"write: Connection" + loc_TSAP + "-" + rem_TSAP + " not active")
|
|
else:
|
|
self.message (1,"write: Connection " + loc_TSAP + "-" + rem_TSAP + " doesn't exist")
|
|
else:
|
|
self.message (1,"write: Client " + " doesn't exist")
|
|
|
|
|
|
def shutdown (self):
|
|
"""
|
|
Shut down socket and cleanup.
|
|
"""
|
|
self.socket.close ()
|
|
self.message (1,"Server shut down normally")
|
|
|
|
|
|
if __name__ == '__main__':
|
|
config = ConfigParser ()
|
|
config.read ('storage.cfg')
|
|
IP_LVR = config.get ('IP Settings', 'iplvr')
|
|
if not IP_LVR:
|
|
print ('No IP for LVR')
|
|
sys.exit (0)
|
|
print ('LVR configured for IP %s' %IP_LVR)
|
|
|
|
IP_LAGER1 = config.get ('IP Settings', 'ipsps')
|
|
if not IP_LAGER1:
|
|
print ('No IP for PLC')
|
|
sys.exit (0)
|
|
print ('PLC configured for IP %s' %IP_LAGER1)
|
|
|
|
DBFILE = config.get ('DB Settings', 'dbfile')
|
|
if not DBFILE:
|
|
print ('No DB file configured')
|
|
sys.exit (0)
|
|
|
|
DBTALOG = config.get ('DB Settings', 'logfile')
|
|
if not DBTALOG:
|
|
print ('No DB TA Logfile configured')
|
|
sys.exit (0)
|
|
|
|
loglevel = config.getint ('DEBUG', 'loglevel')
|
|
if not loglevel:
|
|
loglevel = 0
|
|
print ('loglevel :%d' %loglevel)
|
|
|
|
debuglevel = config.getint ('DEBUG', 'debuglevel')
|
|
if not debuglevel:
|
|
debuglevel = 0
|
|
print ('debuglevel :%d' %debuglevel)
|
|
|
|
# PARAM
|
|
parameter = {}
|
|
for param in config.options ('PARAM'):
|
|
val = config.getint ('PARAM', param)
|
|
print ("Added Parameter %s with value %d" % (param,val))
|
|
parameter [param] = val
|
|
|
|
if parameter.get ('ordering', 0):
|
|
print ("Ordering active")
|
|
orderpath = config.get ('OPTIONS', 'OrderPath')
|
|
if not orderpath:
|
|
print ("Need Path to orderfiles")
|
|
sys.exit (0)
|
|
print ("Configured Path for Orders '%s'" % orderpath)
|
|
from Ordering import ORDERING
|
|
_Ordering = ORDERING (path = orderpath)
|
|
|
|
#ERP Trace
|
|
if config.getint ('OPTIONS', 'ERPTrace'):
|
|
print ('ERPTrace configured')
|
|
erptype = config.get ('OPTIONS', 'ERPType')
|
|
if not erptype:
|
|
print ('No ERPType configured')
|
|
sys.exit (0)
|
|
print ('ERPType %s' %erptype)
|
|
erpdbfile = config.get ('OPTIONS', 'ERPDB')
|
|
if not erpdbfile:
|
|
print ('No Database file configured')
|
|
sys.exit (0)
|
|
from DB_ERP import DB_ERP
|
|
#from pySAP import pySAP
|
|
_DB_ERP = DB_ERP (erpdbfile)
|
|
else:
|
|
_DB_ERP = None
|
|
|
|
|
|
|
|
server = ISOServer (address = IP_LVR, verbose = loglevel, debug = debuglevel)
|
|
server.add_client (IP_LAGER1, parameter, DB (DBFILE, DBTALOG), _DB_ERP, _Ordering)
|
|
server.add_conn ('LEBE','LEBE')
|
|
server.add_conn ('TQUI','TQUI')
|
|
server.add_conn ('SCLS','SCLS')
|
|
server.add_conn ('IPKT','IPKT')
|
|
server.add_conn ('TAUF','TAUF', 'active')
|
|
ot = time ()
|
|
while 1:
|
|
server.blocknxmit ()
|
|
|
|
|
|
server.shutdown ()
|
|
sys.exit (0)
|
|
|
|
|
|
|