Initial Start Commit

This commit is contained in:
2019-05-23 13:36:01 +00:00
parent 1e11b66155
commit 0ba930b035
61 changed files with 7423 additions and 0 deletions

1
.gitignore vendored
View File

@@ -5,3 +5,4 @@ storage.cfg
*.AppleDouble/
.DS_Store
doc/build/*
log.txt

39
CSB_LEBE.py Executable file
View File

@@ -0,0 +1,39 @@
#! /usr/bin/python
__author__ = "Michael rest"
__date__ = "2006/02/13"
__email__ = "michi@rosstein.de"
__version__ = "$Revision: 1.1 $"[11:-2]
import sys
from cr_tpdu import CR_TPDU
from dt_tpdu import DT_TPDU
from tpkt import TPKT
from socket import *
from time import sleep
def print_lebe (data):
print '\nLivebeat an SPS'
print ' Telegrammnr: %d ' %((ord (data[0]) << 8) + ord (data[1]))
print ' Sender : %s ' %data [2:4]
print ' Empfaenger : %s ' %data [4:6]
print ' Typ : %s ' %data [6:10]
print ' Telegrammnr: %d ' %((ord (data[10]) << 8) + ord (data[11]))
#LEBE
tpdu = CR_TPDU ("LEBE", "LEBE", srcref=0x0015)
tpkt = TPKT (len (tpdu) + 1)
tel = 'LV' + 'TP' + 'LEBE' + '%c%c' %(0,1)
dt = '%c%c' %(id >> 8, id % 256) + tel
id = id + 1
print_lebe (dt)
tpdu = DT_TPDU (dt)
tpkt = TPKT (len (tpdu) + 1)
sleb.send(`tpkt`+`tpdu`)
sleep (4.1)

1771
DB.py Normal file

File diff suppressed because it is too large Load Diff

112
DB_ERP.py Executable file
View File

@@ -0,0 +1,112 @@
#/usr/bin/python2.4
#!/opt/local/bin/python3.0
import sqlite3 as sqlite
#from pysqlite2 import dbapi2 as sqlite
from sys import exit
from time import strftime
from locations import *
def connectdb (dbfile):
"""
Create connection to database
return DB Object
user gets information if failure
"""
print ("Verbindung zu %s herstellen" %dbfile)
try:
db = sqlite.connect (dbfile)
return db
except:
print ("Konnte DB Verbindung nicht herstellen")
exit (1)
class DB_ERP:
# Database Stuff
# --------------
def __init__ (self, dbfile):
self.db = connectdb (dbfile)
def executesql (self, dbstring, arguments = ()):
"""
Fuehre den uebergebenen SQL-Befehl aus und liefere ein Cursor-Objekt
zurueck.
"""
try:
cursor = self.db.cursor ()
cursor.execute (dbstring, arguments)
except OperationalError: #, msg:
print ("Datenbankausfuehrung fehlgeschlagen. Ausgeloest durch: " + dbstring)
raise Warning
except IntegrityError: #, msg:
print ("Doppelter Eintrag. Ausgeloest durch: " + dbstring)
raise Warning
except ProgrammingError: #, msg:
print ("Fehlerhaftes SQL. Ausgeloest durch: " + dbstring)
raise Warning
except Warning: #, msg:
pass
self.db.commit ()
return cursor
def getinsertions (self):
"""
"""
try:
cursor = self.executesql ("SELECT kistennummer, artikelnummer, charge, menge, einheit, rfzts from ERPTrace where action = 'In Puffer inserted'")
except:
return None
return cursor.fetchall ()
def getinsertionsgrouped (self):
"""
Get summarized information of insertions grouped by article / charge
"""
try:
cursor = self.executesql ("SELECT artikelnummer, charge, sum(menge), einheit from ERPTrace where action = 'In Puffer inserted' GROUP BY artikelnummer, charge;")
except:
return None
return cursor.fetchall ()
def addinsertion (self, kistennummer, artikelnummer, charge, menge, einheit):
"""
log insertion
"""
try:
cursor = self.executesql ("INSERT INTO ERPTrace (kistennummer, artikelnummer, charge, menge, einheit, rfzts, action) VALUES ('%s', '%s', '%s', '%s', '%s', current_timestamp, 'In Puffer inserted')"\
%(kistennummer, artikelnummer, charge, menge, einheit))
except:
print ("Couldn't add insertion to ERPTrace")
def markinsertionsasread (self):
"""
Mark all insertions as read
"""
try:
cursor = self.executesql ("UPDATE ERPTrace set action = 'Logged Puffer insertion' where action = 'In Puffer inserted';")
except:
return None
if __name__ == "__main__":
conn = DB_ERP ("/opt/data/storage_ERPTrace.db3")
conn.markinsertionsasread ()
conn.addinsertion ('123456', '1235','12','1234','KG')
print conn.getinsertions ()

112
DB_Trace.py Executable file
View File

@@ -0,0 +1,112 @@
#!/usr/bin/python2.4
#!/opt/local/bin/python3.0
#import sqlite3 as sqlite
from pysqlite2 import dbapi2 as sqlite
from sys import exit
from locations import *
def connectdb (dbfile):
"""
Create connection to database
return DB Object
user gets information if failure
"""
print ("Verbindung zu %s herstellen" %dbfile)
try:
db = sqlite.connect (dbfile)
return db
except:
print ("Konnte DB Verbindung nicht herstellen")
exit (1)
class DB:
# Database Stuff
# --------------
def __init__ (self, dbfile):
self.db = connectdb (dbfile)
def executesql (self, dbstring):
"""
Fuehre den uebergebenen SQL-Befehl aus und liefere ein Cursor-Objekt
zurueck.
"""
try:
cursor = self.db.cursor ()
cursor.execute (dbstring)
except OperationalError: #, msg:
print ("Datenbankausfuehrung fehlgeschlagen. Ausgeloest durch: " + dbstring)
raise Warning
except IntegrityError: #, msg:
print ("Doppelter Eintrag. Ausgeloest durch: " + dbstring)
raise Warning
except ProgrammingError: #, msg:
print ("Fehlerhaftes SQL. Ausgeloest durch: " + dbstring)
raise Warning
except Warning: #, msg:
pass
self.db.commit ()
return cursor
# Trace
#------------------
def ghosts (self):
"""
Suche als Geisterkisten entfernte Kisten
"""
try:
cursor = self.executesql ("SELECT * FROM Trace WHERE action='as Ghost removed'")
except:
print ("Konnte Kisten nicht finden")
raise Warning
boxes = cursor.fetchall ()
return boxes
# Dayly insertions
#-----------------
def daylyinsertions (self):
"""
Liefert eine Auflistung aller Einlagerungen der letzten 24h
"""
try:
cursor = self.executesql ("SELECT kistennummer,rfzts FROM Trace WHERE (action='in Puffer inserted') AND ((julianday(current_timestamp) - julianday(rfzts)) * 24) <= 24 ORDER BY kistennummer;")
cursor2 = self.executesql ("SELECT kistennummer,artikelnummer,charge,gewicht FROM Trace WHERE (action='in Puffer reserved') AND ((julianday(current_timestamp) - julianday(rfzts)) * 24) <= 24 ORDER BY kistennummer;")
except:
print ("Konnte Daten nicht ermitteln")
reservations = cursor2.fetchall ()
reservationdict = {}
for knr, anr, lot, weight in reservations:
reservationdict [knr] = (anr, lot, int (weight))
sumary = {}
artboxes = {}
insertions = cursor.fetchall ()
for knr, rfzts in insertions:
key = (reservationdict [knr][0], reservationdict [knr][1])
curval = sumary.get (key, (0,0))
sumary [key] = (curval[0] + 1, curval[1] + reservationdict [knr][2])
curval = artboxes.get (key)
if not curval: artboxes[key] = []
artboxes [key].append ((knr, reservationdict [knr][2], rfzts))
return sumary, artboxes
if __name__ == "__main__":
#conn = DB ("/opt/data/storage.db3")
conn = DB ("/home/michi/storage.db3.1")
insertions, artboxes = conn.daylyinsertions ()
print 'Artikel;Charge;Kisten;Gewicht'
for key in insertions:
print ('%s;%s;%d;%0.2f' %(key[0], key[1], insertions[key][0], insertions[key][1]/100.0))
print ('\nArtikel;Charge;Kiste;Gewicht;Timestamp')
for key in artboxes:
for knr, weight, rfzts in artboxes [key]:
print ('%s;%s;%s;%0.2f;%s' % (key[0], key[1], knr, weight / 100.0, rfzts))

151
IPKT.py Normal file
View File

@@ -0,0 +1,151 @@
#l!/usr/bin/env python2.6
#-*- coding: utf-8 -*-
__author__ = "Michael Rest"
__date__ = "1 August 2010"
__email__ = "michi@rosstein.de"
__version__ = "$Revision: 1.0 $"[11:-2]
class IPKT:
def ipkt (self, values):
ipoint_id = values ['location']
boxnr = values ['box_nr']
try:
boxnr = int (boxnr)
except:
self.log ( "At IPKT: Bad Box Nr reset to 0")
boxnr = 0
gtin = values ['gtin']
article = values ['article']
duedate = values ['duedate']
pieces = values ['pieces']
try:
pieces = int (pieces)
except:
self.log ( "At IPKT: Bad Pieces '%s' reset to 0 " % pieces)
pieces = 0
destination = values ['destination']
try:
destination = int (destination)
except:
self.log ( "At IPKT: Bad Destination reset to 99")
destination = 99
lotnr = values ['lotnr']
try:
int (lotnr)
except:
lotnr = '0'
lotnr2 = values ['lotnr2']
# IPKT Telegram --> check data and rem. place in Storage and res in Iqueue
DB_con = self.connections['DB']
if ipoint_id not in self.transportmatrix['dstbysrc']:
self.log ( "At IPKT: Not Transports in Matrix for IPKT %s" % ipoint_id)
if not boxnr:
self.message (6, ' At IPKT bad Boxnr')
return 98 # Bad BoxNr
_state = 0
boxes = DB_con.searchbox (boxnr)
storage = 'NONE'
if not _state and boxes:
self.message (6, ' At IPKT Box is already in Storage further checks')
for _rid, _rboxnr, _rarticle, _rlotnr, _rlotnr2, _duedate, _rpieces, _rx, _ry, _rz, _rrfzts in boxes:
if _rrfzts:
#Already Inserted
_state = 94 #Already exists
self.log ( "At IPKT: box %s already inserted in Storage %s" % (boxnr, _rid))
self.message (6, " At IPKT Box %s is already inserted in %s X:%d, Y:%d, Z:%d with article %s" \
% (_rboxnr, _rid, _rx, _ry, _rz, _rarticle))
else:
#Just reserved
if len (boxes) == 1:
self.message (6, " At IPKT Box is only reserved (one time) in %s" % _rid)
DB_con.deletetransport (ipoint_id, boxnr)
#DB_con.removebox (_boxnr)
DB_con.deletealltransports (boxnr)
DB_con.deleteincomingbox (boxnr)
DB_con.removebox (_rid , boxnr)
if DB_con.getincomingbox (boxnr):
self.message (6, " At IPKT Box %s is already in Inqueue delete first" % boxnr)
DB_con.deleteincomingbox (boxnr)
if not _state:
#Box not existing - Reserve Box
self.log ( "At IPKT: box %s not inserted try to find a Place" % boxnr)
DB_con.deletealltransports (boxnr)
#Get Article information
if article not in self.articlemaster and not _state:
self.message (5,' IPKT Article not in Articlebase')
if self.parameter.get ('articlemustbedefined', 1):
_state = 91 #Article not existent
else:
_anr = article
_cap = 'undefined',
_gtin = ''
_normam = 0
_minam = 0
_zone = 1
else:
_cap, _gtin, _normam, _minam, _zone = self.articlemaster[article]
#Disabled
#_state = 93 #Younger Lots in Storage
_deststorage = ''
if not _state:
#All Ok till now so check the weight
self.message (5,' IPKT Check Pieces')
if not pieces:
_state = 90 #90 Bad weight
elif (pieces >= _normam) or 1: #Assume Full Pallet
#Full Pallet into T001
if ipoint_id in ['I001', 'I002']:
_deststorage = 'T001'
else:
_deststorage = 'S002'
elif pieces >= _minam:
#Full Pallet into S001
if ipoint_id in ['I001', 'I002']:
_deststorage = 'S001'
else:
_deststorage = 'S002'
if not _state:
#default article try to find a Place
self.message (5,' IPKT Reserve Place Article at %s' %_deststorage)
_res = None
for storage, rfzNr, rfzOut, mode, prio in self.transportmatrix['dstbysrc'][ipoint_id]:
#Normal article
if (storage == _deststorage):
self.message (6, " At IPKT: check possible Transport for Std Article to %s by RFZ %s with prio %s" % (storage, rfzNr, prio))
_res = self.boxreserve ('RFZ%s' % rfzNr, ipoint_id, 0, 0, 0, \
boxnr, article, lotnr, lotnr2, duedate, pieces, storage, _zone, noreserve = 1)
if not _res:
_state = 92 #No Place
if not _state:
DB_con.addincomingbox (ipoint_id, boxnr, article, gtin, lotnr, lotnr2, duedate, pieces, _deststorage, destination)
self.message (6, " At IPKT: Create Transport with State %s" % (_state))
DB_con.createtransport (boxnr, ipoint_id, ipoint_id, 0, 0, 0, storage, destination, 0, _state)
self.generatetransport (ipoint_id, boxnr)
#DB_con.deletetransport ('IPKT', int (boxnr))
return _state

113
IPKT_tel.py Normal file
View File

@@ -0,0 +1,113 @@
#!/usr/bin/env python2.6
#-*- coding: utf-8 -*-
__author__ = "Michael Rest"
__date__ = "2006/02/15"
__email__ = "michi@rosstein.de"
__version__ = "$Revision: 1.1 $"[11:-2]
from telegram import TELEGRAM, TEL_IPKT
from utility import *
# String representation for a DT TPDU
DT_STRING = \
"""\
Length: %d
Number: 0x%02x
Contained Data: %s
"""
def fromstring (data):
"""
Decode the binary representation of a IPKT from the given
parameter and note the data in the instance of the object.
Parameters:
data: The binary form of the TELEGRAM
"""
tel = TEL_IPKT ()
tel.attrib['nr'] = (ord (data [0]) << 8) + ord (data [1])
tel.attrib['src'] = data [2:4]
tel.attrib['dst'] = data [4:6]
tel.attrib['type'] = data [6:10]
tel.attrib['box_nr'] = data [12:12 + ord (data [11])]
#tel.attrib['box_nr'] = (ord (data [10]) << 24) + (ord (data [11]) << 16) + (ord (data [12]) << 8) + ord (data [13])
tel.attrib['location'] = data [22:26].strip ().lstrip ('0')
tel.attrib['gtin'] = data [28:28 + ord (data [27])].strip ().lstrip ('0')
tel.attrib['article'] = data [44:44 + ord (data [43])].strip ().lstrip ('0')
tel.attrib['duedate'] = data [56:56 + ord (data [55])].strip ().lstrip ('0')
tel.attrib['lotnr'] = data [66:66 + ord (data [65])].strip ().lstrip ('0')
tel.attrib['lotnr2'] = data [74:74 + ord (data [73])].replace (' ','0') #99,99 Kilos
tel.attrib['pieces'] = data [82:82 + ord (data [81])].replace (' ','0').lstrip ('0')
#tel.attrib['destination'] = (ord (data [60]) << 8) + ord (data [59])
return tel
class TEL_IPKT (TELEGRAM):
def __init__ (self, nr = 0, src = 'LV', dst = 'TP', location = 'I001', boxnr = 123 , artnr ='12345', lotnr='123', duedate='123456', weight='12.34', pieces='1234', destination = 123, *args, **args2):
TELEGRAM.__init__(self)
self.code = TEL_IPKT
self.data = ''
self.attrib['nr'] = nr
self.attrib['src'] = src
self.attrib['dst'] = dst
self.attrib['type'] = 'IPKT'
self.attrib['box_nr'] = boxnr
self.attrib['location'] = location
self.attrib['gtin'] = artnr
self.attrib['article'] = artnr
self.attrib['duedate'] = duedate
self.attrib['lotnr'] = lotnr
self.attrib['lotnr2'] = lotnr
self.attrib['pieces'] = pieces
self.attrib['destination'] = destination
self.__buildstring ()
self.__recalclen ()
return
def identify (self):
"""
This method can be used to identify a TELEGRAM by string.
"""
return "IPKT TELEGRAM\n"
def __buildstring (self):
"""
Creates Datastring from Attributes
"""
self.data = chr ((self.attrib['nr'] >> 8) & 0xFF) + chr (self.attrib['nr'] & 0xFF) +\
self.attrib['src'] +\
self.attrib['dst'] +\
self.attrib['type'] +\
chr ((self.attrib['box_nr'] >> 24) & 0xFF) + chr ((self.attrib['box_nr'] >> 16) & 0xFF) + chr((self.attrib['box_nr'] >> 8) & 0xFF) + chr (self.attrib['box_nr'] & 0xFF) +\
self.attrib['location'] +\
fillchar (str (self.attrib['article']), 10) +\
fillchar (str (self.attrib['lotnr']), 10) +\
fillchar (str (self.attrib['pieces']), 10) +\
chr ((self.attrib['destination'] >> 8) & 0xFF) + chr (self.attrib['destination'] & 0xFF)
def __recalclen (self):
"""
Return the length of the TPDU. This function is for
internal use only!
"""
self.len = 2 + 4l
def __repr__ (self):
"""
Print a representation of the TPDU. Use this method via
`-pair to transfer it over the wire. This will just return
the header data and not the real data!
"""
# Note that the data is not included in the length
return "%c%c%c" % (2, self.code << 4, self.number) + self.data
def __str__ (self):
"""
Return a readable and quite verbose overview of the TPDU instance.
Use this for debugging purposes or if you're just curious.
"""
string = self.identify () #+ DT_STRING % (self.len, self.number, self.data)
return string

104
LEBE_tel.py Normal file
View File

@@ -0,0 +1,104 @@
#!/usr/bin/python
"""
lifebeat (LEBE) - Telegram
.. module:: LEBE
.. todo: Test
.. _lebe-content:
Lifebeat
========
=============== ======== ======== ============================= ========================================================
ID Byte-Pos Type Value Description
=============== ======== ======== ============================= ========================================================
Sequence-Nr 0:2 SINT16 0..32767 Telegramcounter
Tel-Source 2:4 CHAR[2] ['TP','LV'] Source of Telegram (to be removed in next versions)
Tel-Destination 4:6 CHAR[2] ['TP','LV'] Destination of Telegram (to be removed in next versions)
Tel-Type 6:10 CHAR[4] 'LEBE' Ident of Telegram (prepared to multiplex Channels)
STATE 10:12 WORD irrelevant for future use
=============== ======== ======== ============================= ========================================================
"""
__date__ = "2006/02/15"
__email__ = "michi@rosstein.de"
__version__ = "$Revision: 1.1 $"[11:-2]
from telegram import TELEGRAM, TEL_LEBE
# String representation for a DT TPDU
DT_STRING = \
"""\
Length: %d
Number: 0x%02x
Contained Data: %s
"""
def fromstring (data):
"""
Decode the binary representation of a LEBE_Tel from the given
parameter and note the data in the instance of the object.
Parameters:
data: The binary form of the TPDU
"""
tel = TEL_LEBE ()
tel.attrib['nr'] = ord (data [0]) << 8 + ord (data [1])
tel.attrib['src'] = data [2:4]
tel.attrib['dst'] = data [4:6]
tel.attrib['type'] = data [6:10]
tel.attrib['state'] = data [10:12]
return tel
class TEL_LEBE (TELEGRAM):
def __init__ (self, nr = 0, src = 'LV', dst = 'TP', *args, **args2):
TELEGRAM.__init__(self)
self.code = TEL_LEBE
self.attrib['nr'] = nr
self.attrib['src'] = src
self.attrib['dst'] = dst
self.attrib['type'] = 'LEBE'
self.attrib['state'] = '%c%c' % (1, 0)
self.__buildstring ()
self.__recalclen ()
return
def identify (self):
"""
This method can be used to identify a TELEGRAM by string.
"""
return "LEBE TELEGRAM\n"
def __buildstring (self):
"""
Creates Datastring from Attribs
"""
self.data = chr ((self.attrib['nr'] >> 8) & 0xFF) + chr (self.attrib['nr'] & 0xFF) +\
self.attrib['src'] + self.attrib['dst'] + self.attrib['type'] + self.attrib['state']
def __recalclen (self):
"""
Return the length of the TPDU. This function is for
internal use only!
"""
self.len = 2
def __repr__ (self):
"""
Print a representation of the TPDU. Use this method via
`-pair to transfer it over the wire. This will just return
the header data and not the real data!
"""
# Note that the data is not included in the length
return "%c%c%c" % (2, self.code << 4, self.number) + self.data
def __str__ (self):
"""
Return a readable and quite verbose overview of the TPDU instance.
Use this for debugging purposes or if you're just curious.
"""
string = self.identify () # + DT_STRING % (self.len, self.number, self.data)
return string

110
Ordering.py Executable file
View File

@@ -0,0 +1,110 @@
#!/usr/bin/env python
import sys,string
from datetime import datetime
import os
import codecs
class ORDERING:
def __init__ (self, *dummy, **args):
"""
Initialize an new Ordering module
"""
self.path = args.get ("path", "/opt/sap")
self.path += self.path[-1] != '/' and '/' or ''
def setloggingmethods (self, log, message):
self.log = log
self.message = message
def message (self, level, msg):
"""
Dummy Message if not overloaded
"""
dt = datetime.now ()
print ("DB-LOG %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):
"""
Dummy Logging if not overloaded
"""
dt = datetime.now ()
print ("DB-LOG %4d-%02d-%02d %02d:%02d:%02d.%06d: " %(dt.year, dt.month, dt.day, dt.hour, dt.minute, dt.second, dt.microsecond)),
print msg
def orderfiles (self):
"""
returns list of exportfiles found in path
"""
#return filter (lambda f: ".exp" in f, os.listdir (self.path))
return filter (lambda f: "O_" == f[:2], os.listdir (self.path))
def archiveorderfile (self, filename):
"""
Move file to archive
processed Subfolder is obligatoric
"""
os.rename (self.path + filename, self.path + "processed/" + filename)
def orderheader (self, data):
"""
E2VPPIH 03400000000024436740000010000000100011835090001 002010100620101006 44.850 KG 0.000 MENSA UNI KLAGENFURT OESTERR.MENSEN BETRIEBSGMBH UNI - BUFFET UNIVERSITAETSSTR. 65-67 AT 9020 KLAGENFURT
"""
ret_val = {}
ret_val ['orderid'] = data [63:73].lstrip ('0')
ret_val ['overall_weight'] = data [121:135].lstrip (' ')
ret_val ['overall_weight_unit'] = data [135:138].lstrip (' ')
ret_val ['deliverydate'] = data [113:121]
ret_val ['cust'] = data [153:192].lstrip (' ').rstrip (' ').replace ("'",'')
ret_val ['cust2'] = data [192:254].lstrip (' ').rstrip (' ').replace ("'",'')
ret_val ['cust_street'] = data [254:335].lstrip (' ').rstrip (' ')
ret_val ['cust_country'] = data [335:370].lstrip (' ').rstrip (' ')
ret_val ['cust_postcode'] = data [370:374].lstrip (' ').rstrip (' ')
ret_val ['cust_city'] = data [376:390].lstrip (' ').rstrip (' ')
return ret_val
def orderline (self, data):
"""
E2VPPII 0.00 14.780 034000000000241359800000300000102000116862300004001 000000000000001320R-KALBIN H?FTE AT 0001001 15.000 15.000 15.000 KG KG 1 1 601000 20100902 0011149314 15.000 15.000 KG 0.000
E2VPPII002 034000000000244361100000400000102008018550500003002 000000000000007603K?RNTNER ROHWURST 300g 0001001 4.000 4.000 4.000 ST ST 1 1 647000 20101006 4500185836 1.200 1.200 KG 0.000
"""
ret_val = {}
ret_val ['article'] = data [121:139].lstrip ('0')
ret_val ['caption'] = data [139:179].rstrip (' ')
ret_val ['order_amount'] = data [236:251].lstrip (' ')
ret_val ['order_amount_unit'] = data [251:254].lstrip (' ')
ret_val ['order_weight'] = data [334:349].lstrip (' ')
ret_val ['order_weight_unit'] = data [349:352].lstrip (' ')
return ret_val
def decodefile (self, filename):
"""
Decodes Orderfile and returns (orderheader, [orderlines])
"""
_header = None
_orderlines = []
self.message (6, "Ordering: Decoding Orderfile %s" % filename)
sfile = codecs.open (self.path + filename, "r", "latin-1")
for line in sfile:
if line.find ("EDI_DC40") >= 0:
self.message (6, "Ordering: EDoc-Header found")
elif line.find ("E2VPPIH") >= 0:
self.message (6, "Ordering: Order-Header found")
_header = self.orderheader (line)
elif line.find ("E2VPPII") >= 0:
_orderlines.append (self.orderline (line))
else:
self.log ("Ordering: found invalid line in Orderfile: '%s'" % line)
sfile.close ()
return (_header, _orderlines)
if __name__ == "__main__":
ordering = ORDERING (path ='/opt/sap')
for i in ordering.orderfiles ():
print ordering.decodefile (i)

75
QUIT_tel.py Executable file
View File

@@ -0,0 +1,75 @@
#!/usr/bin/python
__author__ = "Michael Rest"
__date__ = "2006/02/15"
__email__ = "michi@rosstein.de"
__version__ = "$Revision: 1.1 $"[11:-2]
from telegram import TELEGRAM, TEL_QUIT
# String representation for a DT TPDU
DT_STRING = \
"""\
Length: %d
Number: 0x%02x
Contained Data: %s
"""
def fromstring (data):
"""
Decode the binary representation of a LEBE_Tel from the given
parameter and note the data in the instance of the object.
Parameters:
data: The binary form of the TPDU
"""
tel = TELLEBE ()
tel.attrib['nr'] = ord (data [0]) << 8 + ord (data [1])
tel.attrib['src'] = data [2:4]
tel.attrib['dst'] = data [4:6]
tel.attrib['type'] = data [6:10]
return tel
class TELQUIT (TELEGRAM):
def __init__ (self, data = "", *args, **args2):
TELEGRAM.__init__(self)
self.code = TEL_LEBE
self.attrib['nr'] = data [0:2]
self.attrib['src'] = data [2:4]
self.attrib['dst'] = data [4:6]
self.attrib['type'] = data [6:10]
self.__recalclen ()
return
def identify (self):
"""
This method can be used to identify a TELEGRAM by string.
"""
return "LEBE TELEGRAM\n"
def __recalclen (self):
"""
Return the length of the TPDU. This function is for
internal use only!
"""
self.len = 2
def __repr__ (self):
"""
Print a representation of the TPDU. Use this method via
`-pair to transfer it over the wire. This will just return
the header data and not the real data!
"""
# Note that the data is not included in the length
return "%c%c%c" % (2, self.code << 4, self.number) + self.data
def __str__ (self):
"""
Return a readable and quite verbose overview of the TPDU instance.
Use this for debugging purposes or if you're just curious.
"""
string = self.identify () # + DT_STRING % (self.len, self.number, self.data)
return string

173
SCLS.py Normal file
View File

@@ -0,0 +1,173 @@
from time import time
class SCLS:
def scls (self, ret_val):
DB_con = self.connections['DB']
# SCLS Telegram --> act according to Read position
if ret_val ['location'] == 'IPKT':
#IKPT
self.log ( "SCLS at IPKT box %(box_nr)s destiation %(destination)d" % ret_val)
elif ret_val ['location'] in ['RFZ1', 'RFZ2']:
#FiXMe
_quit = 0
#RFZ
_dz = 0
self.log ( "SCLS at %(location)s box %(box_nr)s destiation %(destination)d" % ret_val)
self.message (6, "SCLS at %(location)s box %(box_nr)s destiation %(destination)d" % ret_val)
if ret_val ['destination'] == 0:
#Destination 0 - Box from Pickup Position loaded --> get TAUF
self.message (3, ' DT_handler : SCLS from %s (Box from Pickuppos) --> generate TAUF for RFZ' % ret_val ['location'])
_box = None
sboxnr = int (ret_val['box_nr'])
if sboxnr != 0:
#No NOREAD
_boxes = DB_con.getincomingbox (sboxnr)
if _boxes and len(_boxes):
_box = _boxes [0]
if _box:
self.message (3, ' DT_handler : SCLS Box is in Inqueue search a Place')
_boxes = DB_con.searchbox (sboxnr)
storage = 'NONE'
if _boxes:
self.message (6, ' DT_handler : SCLS Box is already in Storage further checks')
for _rid, _rboxnr, _rarticle, _rlotnr, _rlotnr2, _duedate, _rpieces, _rx, _ry, _rz, _rrfzts in _boxes:
if _rrfzts:
self.log ( " DT_handler : SCLS Box %s is already inserted in Storage %s" % (sboxnr, _rid))
print ("Already in Storage impossible")
raise Warning
else:
self.message (6, " DT_handler : SCLS Box is only reserved in %s" % _rid)
#Just reserved
if len (_boxes) == 1:
self.message (6, " DT_handler : SCLS Box is only reserved (one time) in %s" % _rid)
DB_con.removebox (_rid , sboxnr)
DB_con.deletealltransports (sboxnr)
location, boxnr, article, gtin, lotnr, lotnr2, duedate, pieces, deststorage, destination = _box
#Fixme Zone from Articlebase
_zone = 1
_res = 0
for storage, rfzNr, rfzOut, mode, prio in self.transportmatrix['dstbysrc'][location]:
#Normal article
if (storage == deststorage):
self.message (6, " DT_handler : SCLSTransport for Std Article to %s by RFZ %s with prio %s" % (storage, rfzNr, prio))
_res = self.boxreserve ('RFZ%s' % rfzNr, location, 0, 0, 0, \
boxnr, article, lotnr, lotnr2, duedate, pieces, storage, _zone, noreserve = 0)
if not _res:
print ("Kann nicht sein dass kein Platz ist")
raise Warning
self.generatetransport (ret_val['location'], sboxnr)
else:
print ("Scheisse")
raise Warning
#Box is not in Inqueue
self.log ( "At %(location)s: box %(box_nr)s is not in Inqueue --> try to find Transport or generate Errorslot" % ret_val)
if ret_val ['location'] in self.transportmatrix['errordst']:
_dst, _dstx, _dsty, _prio = self.transportmatrix['errordst'][ret_val ['location']]
DB_con.createtransport (ret_val['box_nr'], ret_val['location'], 'IRFZ', 0, 0, 0, _dst, _dstx, _dsty, 0)
self.generatetransport (ret_val['location'], ret_val['box_nr'])
else:
self.log ( "At %(location)s: Nor Errordestination for this Position - send Takeoff Transport" % ret_val)
DB_con.createtransport (ret_val['box_nr'], ret_val['location'], 'IRFZ', 0, 0, 0, ret_val['location'], 0, 0, 1)
self.generatetransport (ret_val['location'], ret_val['box_nr'])
elif ret_val ['destination'] == 2:
self.message (3, ' DT_handler : SCLS from RFZ1 --> deletebox')
self.log ( "SCLS at RFZ1 box %(box_nr)s destiation %(destination)d" % ret_val)
# Make sure that manual intervention gets rid of the box also
article = None
box = None
if _storage_type != 4:
box = DB_con.searchbox (ret_val['box_nr'], 'Puffer')
if box:
self.removebox ('Puffer', ret_val['box_nr'])
article = box[1]
# space is available
# NewPRIO
#if article:
# self.checkspaceandmove (article)
elif ret_val ['location'] == 'HBCL1':
_quit = 0
self.message (3, ' DT_handler : SCLS from HBCL1 --> delete Boxes from Storage')
self.log ( "SCLS at HBCL1 box %(box_nr)s destination %(destination)d " % ret_val)
try:
_boxnr = int (ret_val['box_nr'])
_dest = ret_val['destination']
if int (_dest) > 0:
DB_con.deletetauf ('DEST', _boxnr)
self.createtauf (_boxnr, 'DEST', 'MDES', 0, 0, 0, 'Puffer', 0, 0, _dest)
self.generatetauf ('DEST', _boxnr)
DB_con.deletetauf ('DEST', _boxnr)
except:
_dest = 0
print ('Shit')
raise Warning
# Make sure that manual intervention gets rid of the box also
article = None
box = None
if _storage_type != 4:
box = DB_con.searchbox (ret_val['box_nr'], 'Puffer')
if box:
self.removebox ('Puffer', ret_val['box_nr'])
article = box[1]
if not box:
box = DB_con.searchbox (ret_val['box_nr'], 'Pick')
if box: #DANI return war scheie wg. counter zaehlung
self.log ( "SCLS at HBCL1 box %(box_nr)s was in Pick %(destination)d " % ret_val)
self.removebox ('Pick', ret_val['box_nr'])
article = box[1]
if not box:
box = DB_con.searchbox (ret_val['box_nr'], 'ENESPi')
if box:
self.removebox ('ENESPi' , ret_val['box_nr'])
elif ret_val ['location'] in ['B004', 'B006']:
self.log ("SCLS at %(location)s for box %(box_nr)s with destination %(destination)d Delete from Outqueue" % ret_val)
deletedz = DB_con.removebox ('Outqueue', int (ret_val['box_nr']))
_waitinjection = 0
DB_con.createtransport (int (ret_val['box_nr']), _pusher, _pusher, 0, 0, 0, _pusher, 0, _waitinjection, 0)
self.generatetransport (_pusher, int (ret_val['box_nr']))
_quit = 0
elif ret_val ['location'] in ['B005', 'B007', 'H001', 'H002']:
deletedz = DB_con.removebox ('Outqueue', int (ret_val['box_nr']))
self.log ( "SCLS at %(location)s for box %(box_nr)s with destination %(destination)d Sending TAUF to indicate new Box" % ret_val)
if ret_val ['location'] in ['B005', 'H002']:
_opoint = 'O001'
elif ret_val ['location'] in ['B007', 'H001']:
_opoint = 'O002'
if self.parameter.get ('triggerbox-%s' % _opoint, -1) == int (ret_val['box_nr']):
self.message (3, "SCLS resetting triggerbox for %s" % _opoint)
self.parameter['triggerbox-%s' % _opoint] = 0
elif ret_val ['location'][0] == 'B':
self.log ( "SCLS at %(location)s for box %(box_nr)s with destination %(destination)d " % ret_val)
_quit = 0
elif ret_val ['location'][0] == 'H':
self.log ( "SCLS at %(location)s for box %(box_nr)s with destination %(destination)d " % ret_val)
_quit = 0
else:
self.log ( "SCLS at undefined postion %(location)s for box %(box_nr)s with destination %(destination)d " % ret_val)
_quit = 20
#Return Value for Quit telegram
return _quit

125
SCLS_tel.py Executable file
View File

@@ -0,0 +1,125 @@
#!/usr/bin/python
"""
Scanner (SCLS) - Telegram
.. module:: SCLS
.. _scls-content:
Scanner
=======
=============== ======== ======== ============================= ========================================================
ID Byte-Pos Type Value Description
=============== ======== ======== ============================= ========================================================
Sequence-Nr 0:2 SINT16 0..32767 Telegramcounter
Tel-Source 2:4 CHAR[2] ['TP','LV'] Source of Telegram (to be removed in next versions)
Tel-Destination 4:6 CHAR[2] ['TP','LV'] Destination of Telegram (to be removed in next versions)
Tel-Type 6:10 CHAR[4] 'SCLS' Ident of Telegram (prepared to multiplex Channels)
BoxNr 10:14 UINT32 '2147483647' BoxNr - PLC uses UINT32 by now so Max=2147483647
Positon 14:18 CHAR[4] '0001', 'RFZ1' Position of Scanner
Destination 18:20 SINT16 0..32767 Destination (e.g. to tell state / content of box)
=============== ======== ======== ============================= ========================================================
Positions
=========
A Scanner telegram leads to different actions according to the Position. So the positions are in several Domains.
Valid Positiondomains are. (every Position may have higher Numbers)
======== ==================== ===========================================================
Position Pos-Type Action
======== ==================== ===========================================================
'I001' I-Point No Action - just logging - future Usage
'RFZ1' Shelf access equ. | Depending on Destination (Beta State: ToDo declare dests)
| 0: Box from Pickuppostiion --> generate Transport
| 1: Box from Reefedslot (will be changed)
| 2: just logging
'C001' Commisioning Shelf | PLC generated BCL - Read for storages with virtual BoxNrs
| Dest contains slotNr and indicates box removal
'B001' Scanner at conveyors Just a Scanner read anywhere log or do special funcitons
'H001' Handheld Reader Delete from Storage, and further fuctions
just for PLC hosted Handheld readers.
======== ==================== ===========================================================
"""
__date__ = "2006/02/15"
__email__ = "michi@rosstein.de"
__version__ = "$Revision: 1.1 $"[11:-2]
from telegram import TELEGRAM, TEL_SCLS
# String representation for a DT TPDU
DT_STRING = \
"""\
Length: %d
Number: 0x%02x
Contained Data: %s
"""
def fromstring (data):
"""
Decode the binary representation of a SCLS_tel from the given
parameter and note the data in the instance of the object.
Parameters:
data: The binary form of the TELEGRAM
"""
tel = TEL_SCLS ()
tel.attrib['nr'] = (ord (data [0]) << 8) + ord (data [1])
tel.attrib['src'] = data [2:4]
tel.attrib['dst'] = data [4:6]
tel.attrib['type'] = data [6:10]
#tel.attrib['box_nr'] = (ord (data [10]) << 24) + (ord (data [11]) << 16) + (ord (data [12]) << 8) + ord (data [13]) #data [10:14].strip ()
tel.attrib['box_nr'] = data [12:12 + ord (data [11])]
tel.attrib['location'] = data [22:26].strip ().lstrip ('0')
tel.attrib['destination'] = (ord (data [26]) << 8) + ord (data [27])
return tel
class TEL_SCLS (TELEGRAM):
def __init__ (self, nr = 0, src = 'LV', dst = 'TP', loc = 123, box = 123, dest=123 , *args, **args2):
TELEGRAM.__init__(self)
self.code = TEL_SCLS
self.attrib['nr'] = nr
self.attrib['src'] = src
self.attrib['dst'] = dst
self.attrib['type'] = 'SCLS'
self.attrib['location'] = loc
self.attrib['box_nr'] = box
self.attrib['destination'] = dest
self.__recalclen ()
return
def identify (self):
"""
This method can be used to identify a TELEGRAM by string.
"""
return "LEBE TELEGRAM\n"
def __recalclen (self):
"""
Return the length of the TPDU. This function is for
internal use only!
"""
self.len = 2 + 4l
def __repr__ (self):
"""
Print a representation of the TPDU. Use this method via
`-pair to transfer it over the wire. This will just return
the header data and not the real data!
"""
# Note that the data is not included in the length
return "%c%c%c" % (2, self.code << 4, self.number) + self.data
def __str__ (self):
"""
Return a readable and quite verbose overview of the TPDU instance.
Use this for debugging purposes or if you're just curious.
"""
print self.attrib
string = self.identify () #+ DT_STRING % (self.len, self.number, self.data)
return string

82
STAT_tel.py Executable file
View File

@@ -0,0 +1,82 @@
#!/usr/bin/python
__author__ = "Michael Rest"
__date__ = "2006/02/15"
__email__ = "michi@rosstein.de"
__version__ = "$Revision: 1.1 $"[11:-2]
from telegram import TELEGRAM, TEL_STAT
# String representation for a DT TPDU
DT_STRING = \
"""\
Length: %d
Number: 0x%02x
Contained Data: %s
"""
def fromstring (data):
"""
Decode the binary representation of a STAT_tel from the given
parameter and note the data in the instance of the object.
Parameters:
data: The binary form of the TELEGRAM
"""
tel = TEL_STAT ()
tel.attrib['nr'] = (ord (data [0]) << 8) + ord (data [1])
tel.attrib['src'] = data [2:4]
tel.attrib['dst'] = data [4:6]
tel.attrib['type'] = data [6:10]
tel.attrib['location'] = data [10:14]
tel.attrib['state'] = data [14:16]
tel.attrib['error'] = data [16:len(data)]
return tel
class TEL_STAT (TELEGRAM):
def __init__ (self, nr = 0, src = 'LV', dst = 'TP', loc = '1000', state='00', error = '0000' , *args, **args2):
TELEGRAM.__init__(self)
self.code = TEL_STAT
self.attrib['nr'] = nr
self.attrib['src'] = src
self.attrib['dst'] = dst
self.attrib['type'] = 'STAT'
self.attrib['location'] = loc
self.attrib['state'] = state
self.attrib['error'] = error
self.__recalclen ()
return
def identify (self):
"""
This method can be used to identify a TELEGRAM by string.
"""
return "STAT TELEGRAM\n"
def __recalclen (self):
"""
Return the length of the TPDU. This function is for
internal use only!
"""
self.len = 2 + 4l
def __repr__ (self):
"""
Print a representation of the TPDU. Use this method via
`-pair to transfer it over the wire. This will just return
the header data and not the real data!
"""
# Note that the data is not included in the length
return "%c%c%c" % (2, self.code << 4, self.number) + self.data
def __str__ (self):
"""
Return a readable and quite verbose overview of the TPDU instance.
Use this for debugging purposes or if you're just curious.
"""
print self.attrib
string = self.identify () #+ DT_STRING % (self.len, self.number, self.data)
return string

203
TAUF_tel.py Normal file
View File

@@ -0,0 +1,203 @@
#!/usr/bin/python
"""
transport (TAUF) - Telegram
.. module:: TAUF
.. _tauf-content:
Transport content
-----------------
=============== ======== ======== ============================= ========================================================
ID Byte-Pos Type Value Description
=============== ======== ======== ============================= ========================================================
Sequence-Nr 0:2 SINT16 0..32767 Telegramcounter
Tel-Source 2:4 CHAR[2] ['TP','LV'] Source of Telegram (to be removed in next versions)
Tel-Destination 4:6 CHAR[2] ['TP','LV'] Destination of Telegram (to be removed in next versions)
Tel-Type 6:10 CHAR[4] 'TAUF' Ident of Telegram (prepared to multiplex Channels)
BoxNr 10:30 CHAR[20] '2147483647' BoxNr - PLC uses UINT32 by now so Max=2147483647
Positon 30:34 CHAR[4] 'I001', 'RFZ1' Position for executing Transport
Source 34:38 CHAR[4] 'I001', 'RFZ1', 'S001','T001' Sourcearea (I-Point, RFZ1, Storage) for Transport
SourceXX 38:40 CHAR[2] '00' Source-Coordinates X where neccersary
SourceYY 40:42 CHAR[2] '00' Source-Coordinates Y where neccersary
SourceZZ 42:44 CHAR[2] '00' Source-Coordinates Z where neccersary
Destination 44:48 CHAR[4] 'S001', 'T001' DestinationArea (Storage, Outfeedposition) for Transport
DestinationXX 48:50 CHAR[2] '00' Destination-Coordinates X where neccersary
DestinationYY 50:52 CHAR[2] '00' Destination-Coordinates Y where neccersary
DestinationZZ 52:54 CHAR[2] '00' Destination-Coordinates Z where neccersary
=============== ======== ======== ============================= ========================================================
Positions
---------
Valid positions for Transports Indices may differ.
In case Source is a Storage, the fine Sources (XX, YY, ZZ) will also beused.
+---------+---------------------+-------+------------------------------------------------------+
|Position |Pos Type |Source |Action |
+=========+=====================+=======+======================================================+
|I001 |I-Point |I001 | | Start Box |
| | | | | DestinationXX finedestination put in PLC Hashtable |
| | | | | DestinationZZ errorcodes (see later) |
+---------+---------------------+-------+------------------------------------------------------+
|RFZ1 |Storage retrival eqm.| | I001| | Transport generated by an Scanner telegram on RFZ |
| | | | | | for inserting a box from an Pickup position |
| | | | RFZ1| | Alternative Transport (in case of overfill e.g.) |
| | | | T,S | | Automatic transport from a storage (refill, move) |
+---------+---------------------+-------+------------------------------------------------------+
|PU01 |Pusher |P001 | | Duouble function |
| | | | | DestinationXX finedestination put in PLC Hashtable |
| | | | | DestinationYY Unlock (0) Wait injection (1) |
+---------+---------------------+-------+------------------------------------------------------+
|O001 |Outpoint |O001 | | Indicate a new Order |
+---------+---------------------+-------+------------------------------------------------------+
Destinations
------------
The destinations for Transports are
+---------+---------------------+-----------------------------------------+
|T001 |Troughfeedshelf |Using fine Destinations (XX, YY, ZZ) |
+=========+=====================+=========================================+
|S002 |Single-Place-shelf | | Using fine Destinations (XX, YY, ZZ) |
| | | | ZZ == 1, will be used inf future |
+---------+---------------------+-----------------------------------------+
|C001 |Commisioning-shelf |Using fine Destinations (XX, YY, ZZ) |
+---------+---------------------+-----------------------------------------+
|O001 |Outfeedposition | | XX : Destination for PLC Hashtable |
| | | | Multiplexing 50 + |
| | | | ZZ : Order in ordered Outqueue |
+---------+---------------------+-----------------------------------------+
I-Point Errorcodes (in DestZZ)
------------------------------
Errorcodes handled (displayed) on the PLC
- 90 : Bad Weight (weightcheck active)
- 91 : Article not defined in articlemaster
- 92 : No place in storage
- 93 : Lotcheck failed (FIFO error)
- 94 : Box already in system
- 99 : Invalid BoxNr
Return Codes
------------
Transport specific Codes extenging the overall valid Codes
- 20 : Invalid source (main or finesource) in Transport
- 30 : Invalid destination (main or finedest) in Transport
- 5x : RFZx Occupied - Transport will be resent later
"""
__date__ = "2006/02/15"
__email__ = "michi@rosstein.de"
__version__ = "$Revision: 1.1 $"[11:-2]
from telegram import TELEGRAM, TEL_TAUF
from utility import *
# String representation for a DT TPDU
DT_STRING = \
"""\
Length: %d
Number: 0x%02x
Contained Data: %s
"""
def fromstring (data):
"""
Decode the binary representation of a TAUF from the given
parameter and note the data in the instance of the object.
Parameters:
data: The binary form of the TELEGRAM
"""
tel = TEL_TAUF ()
tel.attrib['nr'] = (ord (data [0]) << 8) + ord (data [1])
tel.attrib['src'] = data [2:4]
tel.attrib['dst'] = data [4:6]
tel.attrib['type'] = data [6:10]
tel.attrib['state'] = (ord (data [10]) << 8) + ord (data [11])
return tel
class TEL_TAUF (TELEGRAM):
def __init__ (self, nr = 0, src = 'LV', dst = 'TP', boxnr = 20 * ['0'], position = 'XXXX', source = 'XXXX', srcx = 'XX', srcy = 'YY', srcz = 'ZZ', dest = 'DDDD', destx = 'XX', desty = 'YY',destz = 'ZZ', *args, **args2):
TELEGRAM.__init__(self)
self.code = TEL_TAUF
self.data = ''
self.attrib['nr'] = nr
self.attrib['src'] = str (src)
self.attrib['dst'] = str (dst)
self.attrib['type'] = 'TAUF'
self.attrib['boxnr'] = str (boxnr)
self.attrib['position'] = str (position)
self.attrib['source'] = str (source)
self.attrib['srcx'] = str (srcx)
self.attrib['srcy'] = str (srcy)
self.attrib['srcz'] = str (srcz)
self.attrib['dest'] = str (dest)
self.attrib['destx'] = str (destx)
self.attrib['desty'] = str (desty)
self.attrib['destz'] = str (destz)
self.__buildstring ()
self.__recalclen ()
return
def identify (self):
"""
This method can be used to identify a TELEGRAM by string.
"""
return "TAUF TELEGRAM\n"
def __buildstring (self):
"""
Creates Datastring from Attributes
chr (len (str (self.attrib['boxnr']))) +\
"""
self.data = chr ((self.attrib['nr'] >> 8) & 0xFF) + chr (self.attrib['nr'] & 0xFF) +\
self.attrib['src'] +\
self.attrib['dst'] +\
self.attrib['type'] +\
chr (10) +\
chr (10) +\
fillchar (str (self.attrib['boxnr']), 10) +\
self.attrib['position'] +\
self.attrib['source'] +\
doublechar (self.attrib['srcx']) +\
doublechar (self.attrib['srcy']) +\
doublechar (self.attrib['srcz']) +\
self.attrib['dest'] +\
doublechar (self.attrib['destx']) +\
doublechar (self.attrib['desty']) +\
doublechar (self.attrib['destz'])
def __recalclen (self):
"""
Return the length of the TPDU. This function is for
internal use only!
"""
self.len = 2 + 4l
def __repr__ (self):
"""
Print a representation of the TPDU. Use this method via
`-pair to transfer it over the wire. This will just return
the header data and not the real data!
"""
# Note that the data is not included in the length
return "%c%c%c" % (2, self.code << 4, self.number) + self.data
def __str__ (self):
"""
Return a readable and quite verbose overview of the TPDU instance.
Use this for debugging purposes or if you're just curious.
"""
string = self.identify () #+ DT_STRING % (self.len, self.number, self.data)
return string

322
TQUI.py Normal file
View File

@@ -0,0 +1,322 @@
class TQUI:
def tqui (self, ret_val):
_quit = 0
DB_con = self.connections['DB']
self.log ( " DT_handler : TQUI at %(location)s box %(box_nr)s src %(src_id)s dst %(dst_id)s state %(state)s" % ret_val)
# TQUI Telegram --> update DB
# 01 Order Complete, 11 Order Complete Dummy detected
if (ret_val ['state'] == "01"):
self.message (3, ' DT_handler : TQUI -- Order complete')
if int (ret_val['box_nr'] >= 0):
if ret_val['location'] in ['RFZ1', 'RFZ2']:
DB_con.deletetransport (ret_val['location'], int (ret_val['box_nr']))
else:
self.message (3, ' DT_handler : TQUI invalid Position - IGNORE')
if ret_val['location'] in ['RFZ1', 'RFZ2']:
self.message (3, ' DT_handler : TQUI location is %(location)s for box %(box_nr)s into storage %(dst_id)s' % ret_val)
self.message (3, ' DT_handler : TQUI -- Update Box remove ghosts')
#Use Timestamp on storage moves
#Disabled Setting Insertiondate
_rfzts = None
#Other Transport
DB_con.setboxtimefillgap (ret_val['dst_id'], int (ret_val['box_nr']), _rfzts and _rfzts[0] or '')
#Box was From I-Point
if ret_val['src_id'][0:2] == 'I0':
DB_con.removebox ('Inqueue', int (ret_val['box_nr']))
else:
DB_con.removebox (ret_val['src_id'], int (ret_val['box_nr']))
if ret_val['src_id'] != 'IRFZ' and ret_val['dst_id'][0:2] == 'OP':
#Checking Transportmatrix what destination is kind of
self.message (6, ' DT_handler : TQUI for Transport to Outpoint')
DB_con.deleteoutgoingbox (int (ret_val['box_nr']), queueid = ret_val['dst_id'])
for dest, rfzNr, rfzOut, mode, prio in self.transportmatrix['dstbysrc'][ret_val['src_id']]:
if 'RFZ%d' % rfzNr == ret_val['location'] and 'OP%s' % rfzOut == ret_val['dst_id']:
#FixMe check also source
self.message (6, ' DT_handler : TQUI - Outpoint is at primary RFZ')
#In This case Check the box where to go
if 'ordering' in self.parameter and int (ret_val['dst_xx']) == int (dest[1:]) + 50:
#self.message (6, ' DT_handler : TQUI - Ordering is active add box to outqueue %s' % dest)
#DB_con.addoutgoingbox (dest, ret_val ['box_nr'], '', '', '', '', 99)
break
#Errorboxes
boxnr = int (ret_val['box_nr'])
if ret_val['dst_id'][0] == 'T':
slot = None # DB_con.finderrorslot (ret_val['dst_id'])
if slot:
_dx, _dy = slot
if int (ret_val['dst_xx']) == _dx and int (ret_val['dst_yy']) == _dy:
#NoRead Boxes
boxes = DB_con.getboxesslot (ret_val['dst_id'], int (_dx), int (_dy))
boxnr = 0
if boxes:
nrs = [int (i[1]) for i in boxes]
print nrs
for i in range (999999800, 999999900):
if i not in nrs:
boxnr = i
break
else:
boxnr = 999999800
if not boxnr:
self.log (" DT_handler couldn't find a boxNr for Errorslot")
DB_con.insertbox (ret_val['dst_id'], boxnr, int (_dx), int (_dy))
self.message (3, ' DT_handler : TQUI for Box in %s Errorslot with boxnr %s' % (ret_val['dst_id'], str (boxnr)))
else:
self.message (3, ' DT_handler : TQUI location was %s' %ret_val['location'] )
#was setboxtime
#DB_con.setboxtimefillgap (ret_val['dst_id'], ret_val['box_nr'], '')
# 02 Order Aborted
elif ret_val ['state'] == "02":
self.message (3, ' DT_handler : TQUI -- Order aborted')
#if ret_val['location'] == 'RFZ1':
#self.message (3, ' DT_handler : TQUI location was illegal')
#self.debug ()
#elif ret_val['location'] == 'RFZ2':
#self.deletetauf (ret_val['location'], ret_val['box_nr'])
#if (ret_val['dst_id'] is not 'Nota'):
# DB_con.removebox ('Puffer', ret_val['box_nr'])
# DB_con.removebox ('Pick', ret_val['box_nr'])
#if (ret_val['dst_id'] is 'Expr'):
# DB_con.removebox ('Express', ret_val['box_nr'])
# 03 Src result no crate --> getting boxes
elif ret_val ['state'] == "03":
self.message (3, ' DT_handler : TQUI -- No Crate ')
_unusableslots = DB_con.getunusableslots (ret_val['src_id'])
_x = int (ret_val['src_xx'])
_y = int (ret_val['src_yy'])
if (ret_val['src_id'], _x, _y) in _unusableslots:
self.message (3, ' DT_handler : TQUI -- No Crate from Unusable slot')
else:
self.log ( " DT_handler : TQUI No Crate %(location)s box %(box_nr)s src %(src_id)s x %(src_xx)s y %(src_yy)s dst %(dst_id)s state %(state)s" % ret_val)
# 04 Dest result occupied --> lock slot assign box --> alternative
# TAUF Prio 1
elif ret_val ['state'] == "04":
self.message (3, ' DT_handler : TQUI -- Dest Occupied')
#FixMe alternative jobs
if ret_val['location'] == 'RFZ':
self.deletetauf (ret_val['location'], ret_val['box_nr'])
DB_con.removebox ('Inqueue', ret_val['box_nr'])
_dx, _dy = DB_con.finderrorslot (_dest)
_dz = 0
self.createtauf (ret_val['box_nr'], 'RFZ1', 'RFZ1', 0, 0, 0, _dest, _dx, _dy, _dz)
self.generatetransport ('RFZ1', ret_val['box_nr'])
# 05 Wrong box loaded
elif ret_val ['state'] == "05":
crtauf = 0
self.log (' DT_handler : TQUI -- Wrong Box Loaded at %s' % ret_val['location'])
if ret_val['location'] in ['RFZ1', 'RFZ2']:
ttauf = DB_con.getmovetransport (ret_val['location'], state = 'Sent')
if ttauf:
#Tauf for RFZ exists
tboxnr, tposition, tsrc, tsrcx, tsrcy, tsrcz, tdst, tdstx, tdsty, tdstz, tstate, tts = ttauf
#Box was from Throughfeed shelf
if (tsrc[0] == 'T'):
self.message (3, " DT_handler : TQUI -- Wrong Box Loaded from %s" % tsrc)
locked = DB_con. getunusableslots (tsrc)
srcbox = DB_con.searchbox (int (ret_val['box_nr']), tsrc)
if not srcbox:
self.message (3, " DT_handler : TQUI -- Wrong Box doesnt exist in source %s" % tsrc)
#Box is not in Source so create transport to errorslot and regenerate Transport because correct box may come
if tstate == 'Sent':
DB_con.setsenttransportnew (ret_val['location'], int (tboxnr), self.dummysrc)
#check if box is anywhere else
wboxes = DB_con.searchbox (int (ret_val['box_nr']))
for wbox in wboxes:
wboxstorage, wboxnr, wboxart, wboxlotnr, wboxweight, wboxx, wboxy, wboxz, wboxts = wbox
self.message (3, " DT_handler : TQUI -- Wrong Box is in %s at x:%s y:%s z:%s" % (wboxstorage, wboxx, wboxy, wboxy))
DB_con.removebox (int (ret_val['box_nr']))
#Fixme Check if Box is in Refeed
#rfbox = DB_con.findrefeedbox (ret_val['box_nr'])
#if rfbox:
# rfknr, rfanr, rflog, rfgew, rfz, rfts = rfbox
# DB_con.deletefromrefeedatz (rfz)
DB_con.deletealltransports (ret_val['box_nr'])
if ret_val ['location'] in self.transportmatrix['errordst']:
_dst, _dstx, _dsty, _prio = self.transportmatrix['errordst'][ret_val ['location']]
_dest = _dst
_dx, _dy = _dstx, _dsty
_dz = 0
else:
self.log ( "At %(location)s: Nor Errordestination for this Position - send Takeoff Transport" % ret_val)
_dest = ret_val ['location']
_dx, _dy = 0, 0
_dz = 1
crtauf = 1
#elif True:
# print "FixMe TQUI"
else:
# Box exists in source
self.log (" Wrong loaded box exists in Source - sending Takeoff Transport")
_dest = ret_val ['location']
_dx, _dy = 0,0
_dz = 1
crtauf = 0
orgbnr = DB_con.getsenttrasnport (ret_val['location'], ret_val['src_id'], int (ret_val['src_xx']), int (ret_val['src_yy']))
try:
orgbnr = int (orgbnr[0])
except:
orgbnr = 0
if orgbnr:
#check if box is anywhere else
self.message (3, " DT_handler : TQUI -- Wrong Box will be deleted from Outqucue ")
DB_con.removebox ('Outqueue', orgbnr)
wboxes = DB_con.searchbox (orgbnr)
for wbox in wboxes:
wboxstorage, wboxnr, wboxart, wboxlotnr, wboxduedate, wboxweight, wboxx, wboxy, wboxz, wboxts = wbox
if (ret_val['src_id'] <> wboxstorage):
self.message (3, " DT_handler : TQUI -- Wrong Box exists also in %s at x:%s y:%s z:%s" % (wboxstorage, wboxx, wboxy, wboxy))
if not wboxts:
self.message (3, " DT_handler : TQUI -- Wrong Box is only reserved in other location and will be deleted ")
DB_con.removebox (wboxstorage, orgbnr)
else:
self.message (3, " DT_handler : TQUI -- Wrong Box is also in other location PROBLEM")
DB_con.deletetransport (ret_val['location'], orgbnr)
DB_con.createtransport (orgbnr, ret_val['location'], ret_val['location'], 0, 0, 0, ret_val['location'], 0, 0, 1)
self.generatetransport (ret_val['location'], orgbnr)
"""
srcboxstorage, srcboxnr, srcboxart, srcboxlotnr, srcboxweight, srcboxx, srcboxy, srcboxz, srcboxts = srcbox
if (int (tsrcx) == int (srcboxx)) and (int (tsrcy) == int (srcboxy)):
self.message (3, " DT_handler : TQUI -- Wrong Box is from same Sourceslot")
#Correct slot -1st delete Transport and box as original reservation
self.deletettransport (ret_val['location'], tboxnr)
if (int (srcboxz) > 2):
self.message (3, " DT_handler : TQUI -- Wrong Box is from same Sourceslot and z > 2 delete also previous")
#FixMecheck for Chaotic slot
#if locked.get ((pbx, pby), 'None') == 'chaotisch':
# self.message (3, ' DT_handler : TQUI -- Wrong Box is from same Pufferslot, slot was chaotic')
# find boxes, check for TAUFs and for reservations chaos is impossible
zs = range (1, int (srcboxz))
zs.reverse ()
for i in zs:
self.message (5, "DT_handler : TQUI --Wrong Box from is from same Sourceslot an z > 2 cleaning x:%d, y:%d, z:%d" \
% (int (srcboxx), int (srcboxy), i))
prebox = DB_con.getboxbycoordinates (srcboxstorage, int (srcboxx), int (srcboxy), i)
#No check - MUST NOT FAIL
prbstorage, prbknr, prbanr, prbcharge, prbweight, prbx, prby, prbz, prbts = prebox
self.message (3, ' DT_handler : TQUI -- Delete Box %s from %s x%s y%s z%s' % (prbknr, prbstorage, prbx, prby, prbz))
wbtauf = DB_con.gettransport ('RFZ2', int (prbknr))
#position, boxnr, state = ''
self.deletetauf ('RFZ2', int (prbknr))
DB_con.removepufferbox (int (prbknr))
DB_con.removepickbox (int (prbknr))
DB_con.removebox ('Express', int (prbknr)) # kill eventual reservation
rfbox = DB_con.findrefeedbox (ret_val['box_nr'])
if rfbox:
rfknr, rfanr, rflog, rfgew, rfz, rfts = rfbox
DB_con.deletefromrefeedatz (rfz)
DB_con.removepufferbox (int (tboxnr))
DB_con.removepickbox (int (tboxnr))
#Check for TAUFs on wrong box from same slot
wbtauf = DB_con.gettauf ('RFZ2', int (pbknr))
if wbtauf:
self.message (3, ' DT_handler : TQUI -- Wrong Box already has TAUF')
wbtboxnr, wbtposition, wbtsrc, wbtsrcx, wbtsrcy, wbtsrcz, wbtdst, wbtdstx, wbtdsty, wbtdstz, wbtstate, wbtts = wbtauf[0]
if (wbtdst == tdst) and (wbtdstx == tdstx) and (wbtdsty == tdsty):
#Same destination so delete Transport and generat new one
self.message (3, ' DT_handler : TQUI -- Wrong Box already has Transport destination is ok so go on')
self.deletetauf ('RFZ2', int (wbtboxnr))
_dest = wbtdst
_dx = wbtdstx
_dy = wbtdsty
_dz = wbtdstz
crtauf = 1
elif (locked.get ((pbx, pby), 'None') != 'chaotisch'):
self.message (3, ' DT_handler : TQUI -- Wrong Box doesnt have Transport try to make pickreservation because from normal slot')
stamminfo = DB_con.getschachtstammarticle (pbanr)
if stamminfo:
stx, sty, stanr, stbez, stzone = stamminfo [0]
fill = DB_con.getfilllevel ('Pick')
stz = int (fill.get ((stx, sty), 0))
if stz < int (self.parameter["Z_PI"][int (stx) -1][int (sty) - 1]):
#Pick Rerservation is ok
DB_con.reservepickbox ('RFZ2', 'RFZ2', '0', '0', '0', int (pbknr), pbanr, pbweight, pbcharge, stx, sty, str (stz + 1))
self.deletetauf ('RFZ2', int (pbknr))
_dest = 'Pick'
_dx = stx
_dy = sty
_dz = str (stz + 1)
crtauf = 1
else:
self.message (3, ' DT_handler : TQUI -- Wrong Box doesnt have Place in Pick so move to Errorslot')
_dest = 'Pick'
_dx, _dy = DB_con.finderrorslot ('Pick')
_dz = 0
crtauf = 1
else:
self.message (3, ' DT_handler : TQUI -- Wrong Box doesnt have Stamminfo so move to Errrorslot')
_dest = 'Pick'
_dx, _dy = DB_con.finderrorslot ('Pick')
_dz = 0
crtauf = 1
else:
self.message (3, ' DT_handler : TQUI -- Wrong Box doesnt have Transport and is from chaotic slot so move to Errrorslot')
_dest = 'Pick'
_dx, _dy = DB_con.finderrorslot ('Pick')
_dz = 0
crtauf = 1
else:
#Other slot
self.message (3, ' DT_handler : TQUI -- Wrong Box is from other Pufferslot x:%s y:%s instead of x:%s y:%s ' %(pbx, pby, tsrcx, tsrcy))
DB_con.removepufferbox (ret_val['box_nr'])
self.message (3, ' DT_handler : TQUI -- Wrong Box move to Errrorslot')
_dest = 'Pick'
_dx, _dy = DB_con.finderrorslot ('Pick')
_dz = 0
crtauf = 1
"""
else:
self.message (3, ' DT_handler : TQUI -- No Sent TAUF')
self.log (" Wrong box Loaded")
#raise Warning
#There is no Transport for RFZ2 in sent taufs
if crtauf:
self.message (3, ' DT_handler : TQUI -- Wrong Box create alternative job')
DB_con.createtransport (ret_val['box_nr'], ret_val['location'], ret_val['location'], 0, 0, 0, _dest, _dx, _dy, _dz)
self.generatetransport (ret_val['location'], ret_val['box_nr'])
else:
self.message (3, ' DT_handler : TQUI -- Wrong Box Loaded invalid Position')
# unknown result
else:
self.message (2, ' DT_handler : TQUI -- unknown result')
_quit = 98
self.debug()
#Return Value for Quit telegram
return _quit

132
TQUI_tel.py Executable file
View File

@@ -0,0 +1,132 @@
#!/usr/bin/python
"""
transport result (TQUI) - Telegram
.. module:: TQUI
.. _tqui-content:
Transport result
================
=============== ======== ======== ============================= ========================================================
ID Byte-Pos Type Value Description
=============== ======== ======== ============================= ========================================================
Sequence-Nr 0:2 SINT16 0..32767 Telegramcounter
Tel-Source 2:4 CHAR[2] ['TP','LV'] Source of Telegram (to be removed in next versions)
Tel-Destination 4:6 CHAR[2] ['TP','LV'] Destination of Telegram (to be removed in next versions)
Tel-Type 6:10 CHAR[4] 'TQUI' Ident of Telegram (prepared to multiplex Channels)
BoxNr 10:30 CHAR[20] '2147483647' BoxNr - PLC uses UINT32 by now so Max=2147483647
Positon 30:34 CHAR[4] 'I001', 'RFZ1' Position for executing Transport
Source 34:38 CHAR[4] 'I001', 'RFZ1', 'S001','T001' Sourcearea (I-Point, RFZ1, Storage) for Transport
SourceXX 38:40 CHAR[2] '00' Source-Coordinates X where neccersary
SourceYY 40:42 CHAR[2] '00' Source-Coordinates Y where neccersary
SourceZZ 42:44 CHAR[2] '00' Source-Coordinates Z where neccersary
Destination 44:48 CHAR[4] 'S001', 'T001' DestinationArea (Storage, Outfeedposition) for Transport
DestinationXX 48:50 CHAR[2] '00' Destination-Coordinates X where neccersary
DestinationYY 50:52 CHAR[2] '00' Destination-Coordinates Y where neccersary
DestinationZZ 52:54 CHAR[2] '00' Destination-Coordinates Z where neccersary
State 54:56 CHAR[2] '00' State of Transport - Result
=============== ======== ======== ============================= ========================================================
.. _tqui-results:
Transport results
=================
Every Transport of a Shelf access equipment returns a TQUI with the following states
- 01: Order complete - box was transported correctly
- 02: Order aborted - no transport happened
- 03: No crate - there was no box in the source of the Transport may cause dummybox transport
- 04: Destination occupied - there is no place for the box in destination
- 05: Wrong box loaded - generate alternate Transport
- 11: Order complete Dummy - detected dummy and return it to depot
"""
__author__ = "Michael Rest"
__date__ = "2006/02/15"
__email__ = "michi@rosstein.de"
__version__ = "$Revision: 1.1 $"[11:-2]
from telegram import TELEGRAM, TEL_TQUI
# String representation for a DT TPDU
DT_STRING = \
"""\
Length: %d
Number: 0x%02x
Contained Data: %s
"""
def fromstring (data):
"""
Decode the binary representation of a TQUI from the given
parameter and note the data in the instance of the object.
Parameters:
data: The binary form of the TELEGRAM
"""
tel = TEL_TQUI ()
tel.attrib['nr'] = (ord (data [0]) << 8) + ord (data [1])
tel.attrib['src'] = data [2:4]
tel.attrib['dst'] = data [4:6]
tel.attrib['type'] = data [6:10]
#tel.attrib['box_nr'] =data [10:30]
tel.attrib['box_nr'] = data [12:12 + ord (data [11])]
tel.attrib['location'] = data [22:26]
tel.attrib['src_id'] = data [26:30]
tel.attrib['src_xx'] = data [30:32]
tel.attrib['src_yy'] = data [32:34]
tel.attrib['src_zz'] = data [34:36]
tel.attrib['dst_id'] = data [36:40]
tel.attrib['dst_xx'] = data [40:42]
tel.attrib['dst_yy'] = data [42:44]
tel.attrib['dst_zz'] = data [44:46]
tel.attrib['state'] = data [46:len(data)]
return tel
class TEL_TQUI (TELEGRAM):
def __init__ (self, nr = 0, src = 'LV', dst = 'TP', state='00', *args, **args2):
TELEGRAM.__init__(self)
self.code = TEL_TQUI
self.attrib['nr'] = nr
self.attrib['src'] = src
self.attrib['dst'] = dst
self.attrib['type'] = 'TQUI'
self.attrib['state'] = state
self.__recalclen ()
return
def identify (self):
"""
This method can be used to identify a TELEGRAM by string.
"""
return "TQUI TELEGRAM\n"
def __recalclen (self):
"""
Return the length of the TPDU. This function is for
internal use only!
"""
self.len = 2 + 4l
def __repr__ (self):
"""
Print a representation of the TPDU. Use this method via
`-pair to transfer it over the wire. This will just return
the header data and not the real data!
"""
# Note that the data is not included in the length
return "%c%c%c" % (2, self.code << 4, self.number) + self.data
def __str__ (self):
"""
Return a readable and quite verbose overview of the TPDU instance.
Use this for debugging purposes or if you're just curious.
"""
print self.attrib
string = self.identify () #+ DT_STRING % (self.len, self.number, self.data)
return string

238
cany_telegram.py Executable file
View File

@@ -0,0 +1,238 @@
#!/usr/bin/python
__author__ = "Michael Rest"
__date__ = "2006/02/15"
__email__ = "michi@rosstein.de"
__version__ = "$Revision: 1.1 $"[11:-2]
from telegram import telegram
__all__ = ["cany_telegram"]
# String representation for any C type telegram
CANY_STRING = \
"""\
Counter: %d
Destination reference: 0x%04x
Source reference: 0x%04x
Class option: 0x%x
Parameter packets:
"""
# List of all possible parameters in a c-type TPDU
possible_parameters = [
PARM_NR,
PARM_SRC,
PARM_DST,
PARM_TYPE
]
def internal_formatbytes (list):
"""
This is a special hack to output data based on information in
a list. This is for internal use only!
"""
string = ""
for i in list:
bytes, value = i
# Special case: seems to be a 4bit value
if bytes == 0:
string += "%c" % (value << 4)
elif bytes == 1:
string += "%c" % value
elif bytes == 2:
string += "%c%c" % ((value >> 8) & 0xff, value & 0xff)
else:
raise Error, "Can only output one or two bytes hexadecimals"
return string
class CANY_TEL (TEL):
def __init__ (self, nr, src, dst, type, *args, **args2):
self.parms = {}
self.code = type
self.dstref = args2.get ("dstref", 0x0000)
self.srcref = args2.get ("srcref", 0x0000)
self.classoption = args2.get ("classoption", 0x00)
# Auskommentiert, da nur AK TPDUs von CP im Fetch-Modus
#self.parms[PARM_OPTIONS] = 0x0
self.parms[PARM_NR] = nr
self.parms[PARM_SRC] = src
self.parms[PARM_DST] = dst
self.parms[PARM_TYPE] = type
self.__recalclen ()
return
def identify (self):
return "C type Telegram\n"
def __recalclen (self):
"""
Return the length of the TPDU. This function is for
internal use only!
"""
# 1 for the code, 2 for the destination reference
# 2 for the source reference and 1 for the class
# option -> 6
length = 6
for i in self.parms.keys ():
# The code and the size each are one byte
length += 2
if i == PARM_SIZE or i == PARM_OPTIONS:
length += 1
else:
length += len (self.parms[i])
self.len = length
def __repr__ (self):
"""
Print a representation of the TPDU. Use this method via
`-pair to transfer it over the wire.
"""
# Fixed header information
list = [
(1, self.len),
(0, self.code),
(2, self.dstref),
(2, self.srcref),
(1, self.classoption)]
# Dynamically add all remaining parms
for i in self.parms.keys ():
content = self.parms[i]
list.append ((1, i))
if i == PARM_SIZE or i == PARM_OPTIONS:
list.append ((1, 1))
list.append ((1, chr (content)))
else:
list.append ((1, len (content)))
for j in content:
list.append ((1, j))
return internal_formatbytes (list)
def fromstring (self, data):
"""
Decode the binary representation of a TPDU from the given
parameter and note the data in the instance of the object.
Parameters:
data: The binary form of the TPDU
"""
self.len = ord (data[0])
self.code = ord (data[1]) >> 4
self.dstref = (ord (data[2]) << 8) | ord (data[3])
self.srcref = (ord (data[4]) << 8) | ord (data[5])
self.classoption = ord (data[6])
index = 7
while index < len (data):
code = ord (data[index])
size = ord (data[index+1])
# The acknowledge time is only used in class 4 which we don't
# implement. The time is given in milliseconds.
# The throughput is only set when not in class 0 which we
# implement here. It denotes the throughput in Octets/s.
if code in possible_parameters:
if code == PARM_SIZE or code == PARM_OPTIONS:
self.parms[code] = ord (data[index+2])
else:
self.parms[code] = data[index+2:index+2+size]
else:
raise Warning, "Unknown parameter 0x%02x" % code
index += (size + 2)
def __str__ (self):
"""
Return a readable and quite verbose overview of the TPDU instance.
Use this for debugging purposes or if you're just curious.
"""
string = self.identify () + CANY_STRING % (self.len, self.dstref, self.srcref, self.classoption)
for i in self.parms.keys ():
arg = self.parms[i]
if i == PARM_SIZE:
string += " TPDU size: %d\n" % 2**arg
elif i == PARM_SRCTSAP:
string += " Sender: %s (" % arg
for i in arg:
string += "0x%x " % ord (i)
string = string[:-1] + ")\n"
elif i == PARM_DSTTSAP:
string += " Receiver: %s (" % arg
for i in arg:
string += "0x%x " % ord (i)
string = string[:-1] + ")\n"
elif i == PARM_ACKTIME:
string += " Acknowledge time: %s (ms) [Not used in Class 0]\n" % arg
elif i == PARM_THROUGHPUT:
string += " Throughput: %d (octects/s) [Not used in Class 0]\n" % arg
elif i == PARM_CHECKSUM:
string += " Checksum: %s\n" % arg
elif i == PARM_VERSION:
string += " Version: %d (default: 1)\n" % arg
elif i == PARM_PROTECTION:
string += " Protection: %s\n" % arg
elif i == PARM_OPTIONS:
string += " Options:\n"
if arg & 8 != 0:
string += " Use network expedited (Class 1)\n"
else:
string += " Don't use network expedited (Class 1)\n"
if arg & 4 != 0:
string += " Use receipt confirmation (Class 1)\n"
else:
string += " Don't use receipt confirmation (Class 1)\n"
if arg & 2 != 0:
string += " 16 bit checksum (Class 4)\n"
else:
string += " No 16 bit checksum (Class 4)\n"
if arg & 1 != 0:
string += " Use transport expedited data transfer service\n"
else:
string += " Don't use transport expedited data transfer service\n"
elif i == PARM_ALTERNATIVE:
string += " Alternative: %s\n" % arg
else:
string += UNKNOWN_PARM_STRING % i
return string
# Integrated tests start here
if __name__ == '__main__':
testnum = 1
tpdu = CANY_TPDU (0x1, "SOURCE", "DEST")
print "Test %0d sucessful" % testnum
testnum += 1
print tpdu
print "Test %0d sucessful" % testnum
testnum += 1
tpdu2 = CANY_TPDU (0x1, "SOURCE", "DEST")
tpdu3 = CANY_TPDU (0x1, "", "")
tpdu3.fromstring (`tpdu2`)
if `tpdu` != `tpdu3`:
raise Warning, "Serialisation/Deserialisation test failed"
print "Test %0d sucessful" % testnum
testnum += 1

257
cany_tpdu.py Executable file
View File

@@ -0,0 +1,257 @@
#!/usr/bin/python
__author__ = "Daniel Egger"
__date__ = "22 March 2002"
__email__ = "egger@interearth.com"
__version__ = "$Revision: 1.1 $"[11:-2]
from tpdu import TPDU, PARM_ACKTIME, PARM_THROUGHPUT, PARM_SIZE, PARM_SRCTSAP, PARM_DSTTSAP, PARM_CHECKSUM, PARM_VERSION, PARM_PROTECTION, PARM_OPTIONS, PARM_ALTERNATIVE
__all__ = ["CANY_TPDU"]
# String representation for any C type TPDU
CANY_STRING = \
"""\
Length: %d
Destination reference: 0x%04x
Source reference: 0x%04x
Class option: 0x%x
Parameter packets:
"""
# String representation for an unknown parameter
# in a c-type TPDU. Shouldn't happen anymore since
# all parameters are at least mentioned now.
UNKNOWN_PARM_STRING = \
"""\
Unknown param:
Parameter code: 0x%x
Parameter length: 0x%x
Parameter argument: %s
"""
# List of all possible parameters in a c-type TPDU
possible_parameters = [
PARM_ACKTIME,
PARM_THROUGHPUT,
PARM_SIZE,
PARM_SRCTSAP,
PARM_DSTTSAP,
PARM_CHECKSUM,
PARM_VERSION,
PARM_PROTECTION,
PARM_OPTIONS,
PARM_ALTERNATIVE
]
def internal_formatbytes (list):
"""
This is a special hack to output data based on information in
a list. This is for internal use only!
"""
string = ""
for i in list:
bytes, value = i
# Special case: seems to be a 4bit value
if bytes == 0:
string += "%c" % (value << 4)
elif bytes == 1:
string += "%c" % value
elif bytes == 2:
string += "%c%c" % ((value >> 8) & 0xff, value & 0xff)
else:
raise Error, "Can only output one or two bytes hexadecimals"
return string
class CANY_TPDU (TPDU):
def __init__ (self, type, srctsap, dsttsap, *args, **args2):
self.parms = {}
self.code = type
self.dstref = args2.get ("dstref", 0x0000)
self.srcref = args2.get ("srcref", 0x0000)
self.classoption = args2.get ("classoption", 0x00)
# Auskommentiert, da nur AK TPDUs von CP im Fetch-Modus
#self.parms[PARM_OPTIONS] = 0x0
self.parms[PARM_SIZE] = 0x9
self.parms[PARM_SRCTSAP] = srctsap
self.parms[PARM_DSTTSAP] = dsttsap
self.__recalclen ()
return
def srctsap (self):
return self.parms [PARM_SRCTSAP]
def dsttsap (self):
return self.parms [PARM_DSTTSAP]
def identify (self):
return "C type TPDU\n"
def __recalclen (self):
"""
Return the length of the TPDU. This function is for
internal use only!
"""
# 1 for the code, 2 for the destination reference
# 2 for the source reference and 1 for the class
# option -> 6
length = 6
for i in self.parms.keys ():
# The code and the size each are one byte
length += 2
if i == PARM_SIZE or i == PARM_OPTIONS:
length += 1
else:
length += len (self.parms[i])
self.len = length
def __repr__ (self):
"""
Print a representation of the TPDU. Use this method via
`-pair to transfer it over the wire.
"""
# Fixed header information
list = [
(1, self.len),
(0, self.code),
(2, self.dstref),
(2, self.srcref),
(1, self.classoption)]
# Dynamically add all remaining parms
for i in self.parms.keys ():
content = self.parms[i]
list.append ((1, i))
if i == PARM_SIZE or i == PARM_OPTIONS:
list.append ((1, 1))
list.append ((1, chr (content)))
else:
list.append ((1, len (content)))
for j in content:
list.append ((1, j))
return internal_formatbytes (list)
def fromstring (self, data):
"""
Decode the binary representation of a TPDU from the given
parameter and note the data in the instance of the object.
Parameters:
data: The binary form of the TPDU
"""
self.len = ord (data[0])
self.code = ord (data[1]) >> 4
self.dstref = (ord (data[2]) << 8) | ord (data[3])
self.srcref = (ord (data[4]) << 8) | ord (data[5])
self.classoption = ord (data[6])
index = 7
while index < len (data):
code = ord (data[index])
size = ord (data[index+1])
# The acknowledge time is only used in class 4 which we don't
# implement. The time is given in milliseconds.
# The throughput is only set when not in class 0 which we
# implement here. It denotes the throughput in Octets/s.
if code in possible_parameters:
if code == PARM_SIZE or code == PARM_OPTIONS:
self.parms[code] = ord (data[index+2])
else:
self.parms[code] = data[index+2:index+2+size]
else:
raise Warning, "Unknown parameter 0x%02x" % code
index += (size + 2)
def __str__ (self):
"""
Return a readable and quite verbose overview of the TPDU instance.
Use this for debugging purposes or if you're just curious.
"""
string = self.identify () + CANY_STRING % (self.len, self.dstref, self.srcref, self.classoption)
for i in self.parms.keys ():
arg = self.parms[i]
if i == PARM_SIZE:
string += " TPDU size: %d\n" % 2**arg
elif i == PARM_SRCTSAP:
string += " Sender: %s (" % arg
for i in arg:
string += "0x%x " % ord (i)
string = string[:-1] + ")\n"
elif i == PARM_DSTTSAP:
string += " Receiver: %s (" % arg
for i in arg:
string += "0x%x " % ord (i)
string = string[:-1] + ")\n"
elif i == PARM_ACKTIME:
string += " Acknowledge time: %s (ms) [Not used in Class 0]\n" % arg
elif i == PARM_THROUGHPUT:
string += " Throughput: %d (octects/s) [Not used in Class 0]\n" % arg
elif i == PARM_CHECKSUM:
string += " Checksum: %s\n" % arg
elif i == PARM_VERSION:
string += " Version: %d (default: 1)\n" % arg
elif i == PARM_PROTECTION:
string += " Protection: %s\n" % arg
elif i == PARM_OPTIONS:
string += " Options:\n"
if arg & 8 != 0:
string += " Use network expedited (Class 1)\n"
else:
string += " Don't use network expedited (Class 1)\n"
if arg & 4 != 0:
string += " Use receipt confirmation (Class 1)\n"
else:
string += " Don't use receipt confirmation (Class 1)\n"
if arg & 2 != 0:
string += " 16 bit checksum (Class 4)\n"
else:
string += " No 16 bit checksum (Class 4)\n"
if arg & 1 != 0:
string += " Use transport expedited data transfer service\n"
else:
string += " Don't use transport expedited data transfer service\n"
elif i == PARM_ALTERNATIVE:
string += " Alternative: %s\n" % arg
else:
string += UNKNOWN_PARM_STRING % i
return string
# Integrated tests start here
if __name__ == '__main__':
testnum = 1
tpdu = CANY_TPDU (0x1, "SOURCE", "DEST")
print "Test %0d sucessful" % testnum
testnum += 1
print tpdu
print "Test %0d sucessful" % testnum
testnum += 1
tpdu2 = CANY_TPDU (0x1, "SOURCE", "DEST")
tpdu3 = CANY_TPDU (0x1, "", "")
tpdu3.fromstring (`tpdu2`)
if `tpdu` != `tpdu3`:
raise Warning, "Serialisation/Deserialisation test failed"
print "Test %0d sucessful" % testnum
testnum += 1

54
cc_tpdu.py Executable file
View File

@@ -0,0 +1,54 @@
#!/usr/bin/python
__author__ = "Daniel Egger"
__date__ = "22 March 2002"
__email__ = "egger@interearth.com"
__version__ = "$Revision: 1.1 $"[11:-2]
from cany_tpdu import CANY_TPDU
from tpdu import TPDU_CC
__all__ = ["fromstring", "CC_TPDU"]
def fromstring (data):
"""
Decode the binary representation of a TPDU from the given
parameter and note the data in the instance of the object.
Parameters:
data: The binary form of the TPDU
"""
tpdu = CC_TPDU ()
tpdu.fromstring (data)
return tpdu
class CC_TPDU (CANY_TPDU):
def __init__ (self, srctsap = "", dsttsap = "", *args, **args2):
CANY_TPDU.__init__ (self, TPDU_CC, srctsap, dsttsap, *args, **args2)
return
def identify (self):
"""
This method can be used to identify a TPDU by string.
"""
return "CC TPDU (Connection request reply)\n"
# Integrated tests start here
if __name__ == '__main__':
testnum = 1
tpdu = CC_TPDU ("SOURCE", "DEST")
print "Test %0d sucessful" % testnum
testnum += 1
tpdu = CC_TPDU ("TCP-1", "TCP", dstref=0x005, srcref=0x4431)
print "Test %0d sucessful" % testnum
testnum += 1
print tpdu
print "Test %0d sucessful" % testnum
testnum += 1

46
client.py Executable file
View File

@@ -0,0 +1,46 @@
#! /usr/bin/python
__author__ = "Daniel Egger"
__date__ = "22 March 2002"
__email__ = "egger@interearth.com"
__version__ = "$Revision: 1.1 $"[11:-2]
import sys
from cr_tpdu import CR_TPDU
from dt_tpdu import DT_TPDU
from tpkt import TPKT
from socket import *
from time import sleep
BUFSIZE = 1024
tpdu = CR_TPDU ("TAUF", "TAUF", srcref=0x0015)
tpkt = TPKT (len (tpdu) + 1)
print "Laenge: " + str (len (tpdu))
s = socket(AF_INET, SOCK_STREAM)
s.connect(("192.168.0.130", 102))
s.send(`tpkt`+`tpdu`)
data = s.recv (16384)
print data
id =32000
dt = '%c%c' %( id >> 8, id % 256) +\
'SE' +\
'EM' +\
'SCLS' +\
'12345678901234567890' +\
'XXXX'
print dt
tpdu = DT_TPDU (dt)
tpkt = TPKT (len (tpdu) + 1)
#s.send(`tpkt`+`tpdu`)
sleep (0.1)
#tpdu = DT_TPDU ("And another test message")
#tpkt = TPKT (len (tpdu) + 1)
#s.send(`tpkt`+`tpdu`, MSG_WAITALL)
#sleep (0.1)
sleep (25.1)
s.close ()

53
cr_tpdu.py Executable file
View File

@@ -0,0 +1,53 @@
#!/usr/bin/python
__author__ = "Daniel Egger"
__date__ = "22 March 2002"
__email__ = "egger@interearth.com"
__version__ = "$Revision: 1.1 $"[11:-2]
from cany_tpdu import CANY_TPDU
from tpdu import TPDU_CR
__all__ = ["fromstring", "CR_TPDU"]
def fromstring (data):
"""
Decode the binary representation of a TPDU from the given
parameter and note the data in the instance of the object.
Parameters:
data: The binary form of the TPDU
"""
tpdu = CR_TPDU ()
tpdu.fromstring (data)
return tpdu
class CR_TPDU (CANY_TPDU):
def __init__ (self, srctsap = "", dsttsap = "", *args, **args2):
CANY_TPDU.__init__ (self, TPDU_CR, srctsap, dsttsap, *args, **args2)
return
def identify (self):
"""
This method can be used to identify a TPDU by string.
"""
return "CR TPDU (Connection request)\n"
# Integrated tests start here
if __name__ == '__main__':
testnum = 1
tpdu = CR_TPDU ("SOURCE", "DEST")
print "Test %0d sucessful" % testnum
testnum += 1
tpdu = CR_TPDU ("TCP-1", "TCP", srcref=0x0005)
print "Test %0d sucessful" % testnum
testnum += 1
print tpdu
print "Test %0d sucessful" % testnum
testnum += 1

52
decode.py Executable file
View File

@@ -0,0 +1,52 @@
#!/usr/bin/python
__author__ = "Daniel Egger"
__date__ = "22 March 2002"
__email__ = "egger@interearth.com"
__version__ = "$Revision: 1.1 $"[11:-2]
from tpdu import TPDU_CC, TPDU_CR, TPDU_DT
__all__ = ["decode_packet"]
def decode_cc (data):
from cc_tpdu import fromstring
return fromstring (data)
def decode_cr (data):
from cr_tpdu import fromstring
return fromstring (data)
def decode_dt (data):
from dt_tpdu import fromstring
return fromstring (data)
decoderlist = [
(TPDU_CC, decode_cc),
(TPDU_CR, decode_cr),
(TPDU_DT, decode_dt)
]
def decodepacket (data):
if not ord (data[0]) == 0x03:
print ("No valid tpkt header")
return
size = (ord (data[2]) << 8) | ord (data[3])
#print "TPKT size %d" % size
if len (data) < size:
print ("Packet too short! Is %d" % len (data))
return
type = (ord (data[5]) >> 4)
for i in decoderlist:
id, function = i
if id == type:
return function (data[4:size])
print "Undhandled packettype"
#raise Warning, "Undhandled packettype"

89
doc/Makefile Normal file
View File

@@ -0,0 +1,89 @@
# Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = build
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source
.PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
clean:
-rm -rf $(BUILDDIR)/*
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/LV.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/LV.qhc"
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \
"run these through (pdf)latex."
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."

194
doc/source/conf.py Normal file
View File

@@ -0,0 +1,194 @@
# -*- coding: utf-8 -*-
#
# LV documentation build configuration file, created by
# sphinx-quickstart on Fri Oct 8 11:35:36 2010.
#
# This file is execfile()d with the current directory set to its containing dir.
#
# Note that not all possible configuration values are present in this
# autogenerated file.
#
# All configuration values have a default; values that are commented out
# serve to show the default.
import sys, os
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
sys.path.append(os.path.abspath('../../'))
# -- General configuration -----------------------------------------------------
# Add any Sphinx extension module names here, as strings. They can be extensions
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
extensions = ['sphinx.ext.todo', 'sphinx.ext.autodoc']
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# The suffix of source filenames.
source_suffix = '.rst'
# The encoding of source files.
#source_encoding = 'utf-8'
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'LV'
copyright = u'2010, Daniel Egger, Michael Rest'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
# built documents.
#
# The short X.Y version.
version = '1.0'
# The full version, including alpha/beta/rc tags.
release = '1.0'
# The language for content autogenerated by Sphinx. Refer to documentation
# for a list of supported languages.
#language = None
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
#today = ''
# Else, today_fmt is used as the format for a strftime call.
#today_fmt = '%B %d, %Y'
# List of documents that shouldn't be included in the build.
#unused_docs = []
# List of directories, relative to source directory, that shouldn't be searched
# for source files.
exclude_trees = []
# The reST default role (used for this markup: `text`) to use for all documents.
#default_role = None
# If true, '()' will be appended to :func: etc. cross-reference text.
#add_function_parentheses = True
# If true, the current module name will be prepended to all description
# unit titles (such as .. function::).
#add_module_names = True
# If true, sectionauthor and moduleauthor directives will be shown in the
# output. They are ignored by default.
#show_authors = False
# The name of the Pygments (syntax highlighting) style to use.
pygments_style = 'sphinx'
# A list of ignored prefixes for module index sorting.
#modindex_common_prefix = []
# -- Options for HTML output ---------------------------------------------------
# The theme to use for HTML and HTML Help pages. Major themes that come with
# Sphinx are currently 'default' and 'sphinxdoc'.
html_theme = 'default'
# Theme options are theme-specific and customize the look and feel of a theme
# further. For a list of options available for each theme, see the
# documentation.
#html_theme_options = {}
# Add any paths that contain custom themes here, relative to this directory.
#html_theme_path = []
# The name for this set of Sphinx documents. If None, it defaults to
# "<project> v<release> documentation".
#html_title = None
# A shorter title for the navigation bar. Default is the same as html_title.
#html_short_title = None
# The name of an image file (relative to this directory) to place at the top
# of the sidebar.
#html_logo = None
# The name of an image file (within the static path) to use as favicon of the
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
# pixels large.
#html_favicon = None
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
# using the given strftime format.
#html_last_updated_fmt = '%b %d, %Y'
# If true, SmartyPants will be used to convert quotes and dashes to
# typographically correct entities.
#html_use_smartypants = True
# Custom sidebar templates, maps document names to template names.
#html_sidebars = {}
# Additional templates that should be rendered to pages, maps page names to
# template names.
#html_additional_pages = {}
# If false, no module index is generated.
#html_use_modindex = True
# If false, no index is generated.
#html_use_index = True
# If true, the index is split into individual pages for each letter.
#html_split_index = False
# If true, links to the reST sources are added to the pages.
#html_show_sourcelink = True
# If true, an OpenSearch description file will be output, and all pages will
# contain a <link> tag referring to it. The value of this option must be the
# base URL from which the finished HTML is served.
#html_use_opensearch = ''
# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
#html_file_suffix = ''
# Output file base name for HTML help builder.
htmlhelp_basename = 'LVdoc'
# -- Options for LaTeX output --------------------------------------------------
# The paper size ('letter' or 'a4').
#latex_paper_size = 'letter'
# The font size ('10pt', '11pt' or '12pt').
#latex_font_size = '10pt'
# Grouping the document tree into LaTeX files. List of tuples
# (source start file, target name, title, author, documentclass [howto/manual]).
latex_documents = [
('index', 'LV.tex', u'LV Documentation',
u'Daniel Egger, Michael Rest', 'manual'),
]
# The name of an image file (relative to this directory) to place at the top of
# the title page.
#latex_logo = None
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
# Additional stuff for the LaTeX preamble.
#latex_preamble = ''
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
#latex_use_modindex = True

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

36
doc/source/index.rst Normal file
View File

@@ -0,0 +1,36 @@
.. LV documentation master file, created by
sphinx-quickstart on Fri Oct 8 11:35:36 2010.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Storage Control documentation
#############################
.. image:: images/ela_logo.png
Contents:
This document contains confidential developer infomation about the (`ELA <http://www.ela-ft.de/>`_)-Storage Control System and may not be used without
explicit acknowlede of the authors).
In the Following sections the developer-level configuration and options of the system and the used telegram syntax
(in order to give other sytems the ability to connect the ELA storage retival system with the main counfiguration.)
will be explained.
This document is still in Beta - State.
.. toctree::
:maxdepth: 2
telegrams.rst
transportmatrix.rst
.. database.rst.
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`

3
doc/source/loglevels.rst Normal file
View File

@@ -0,0 +1,3 @@
11 - unused
7 - Very verbose information about movements
6 - startup information

25
doc/source/startup.rst Normal file
View File

@@ -0,0 +1,25 @@
.. _plc_comm:
*****************
Safety
*****************
E-Stop Check
==================
Every E-Stop / Saftey Switch has to be activated seperately. After that the errormessages have to
be checked and the Safety Circle reseted.
This is to be done again with a responsible Person of the customer which signs a E-Stop Protocol.
Startup
===================
Every machine protection (Gap-Sensors) has to be dropout and the errormessage has to be checked.
Automatic
=============
On every Insertion Point the singularization of queued boxes has to be tested exactly.

90
doc/source/telegrams.rst Normal file
View File

@@ -0,0 +1,90 @@
.. _plc_comm:
*****************
PLC-Communication
*****************
.. _plc-comm_iscomm_iso:
Transport-Protocol
==================
The communication between the storage control system and the PLC is Ethernetbased and uses
ISOonTCP (`RFC1006 <http://www.faqs.org/rfcs/rfc1006.html/>`_) as Transport protocol.
The PLC uses the following Channels for communication, the local_TSAP, remote_TSAP are identical
to the Telegramtype.
==== ================================
Type Connection mode (view from PLC)
==== ================================
LEBE active
SLCS active
TAUF passive
TQUI active
STAT active
==== ================================
Communication-Cycle
===================
After restart or Sequence-Errors, every channel has to be initialized. Therefore the to-be-sent telegram
will be sent 1st with Sequence-Nr = 0. The Init-Telegram is not checked and not processed. After Acknowledge the
Telegram will be sent again with Sequence-Nr = 1, now it will run through the content checks and may be processed.
Now the Channel is initialized (The lifebeat channel is excluded from this procedure).
Answer-Telegram
***************
Every Telegram (except from the lifebeat) is replied by an Answer-telegram, containing an return code with Errorinformation.
=============== ======== ======== ============================= ========================================================
ID Byte-Pos Type Value Description
=============== ======== ======== ============================= ========================================================
Sequence-Nr 0:2 SINT16 0..32767 Telegramcounter
Tel-Source 2:4 CHAR[2] ['TP','LV'] Source of Telegram (to be removed in next versions)
Tel-Destination 4:6 CHAR[2] ['TP','LV'] Destination of Telegram (to be removed in next versions)
Tel-Type 6:10 CHAR[4] like Answered Telegram Ident of Telegram (prepared to multiplex Channels)
STATE 10:12 WORD depend on Telegramtype Contains Replycode to identify errors
=============== ======== ======== ============================= ========================================================
Return-codes
------------
Returncodes valid for all Telegramtypes, supporting anwser telegrams.
- 0 : OK - Transport will be processed
- 97 : Wrong Telegram length
- 98 : Wrong Telegram type
- 99 : Counter error - resend Transport with Sequence-Nr 0 then 1 to resync
TelegramTypes
=============
The listed TelegramTypes containing information as followed.
LEBE
****
.. automodule:: LEBE_tel
:members:
:exclude-members: fromstring
SCLS
****
.. automodule:: SCLS_tel
:members:
:exclude-members: fromstring
TAUF
****
.. automodule:: TAUF_tel
:members:
:exclude-members: fromstring
TQUI
****
.. automodule:: TQUI_tel
:members:
:exclude-members: fromstring
STAT
****
Sending Error, State, Process information from PLC.
Will be documentated in future.

View File

@@ -0,0 +1,26 @@
.. _transportmatrix:
***************
Transportmatrix
***************
The Transportmatrix keeps all availiable transport connections.
.. _transportmatrix_modes:
Modes
=====
The communication between the storage control system and the PLC is Ethernetbased and uses
ISOonTCP (`RFC1006 <http://www.faqs.org/rfcs/rfc1006.html/>`_) as Transport protocol.
The PLC uses the following Channels for communication, the local_TSAP, remote_TSAP are identical
to the Telegramtype.
========== ================================
Mode Description
========== ================================
auto Automatic Reload of C,T Shelfes
autosched Scheduled Auto
========== ================================

98
dt_tpdu.py Normal file
View File

@@ -0,0 +1,98 @@
#!/usr/bin/python
__author__ = "Daniel Egger"
__date__ = "22 March 2002"
__email__ = "egger@interearth.com"
__version__ = "$Revision: 1.1 $"[11:-2]
from tpdu import TPDU, TPDU_DT
# String representation for a DT TPDU
DT_STRING = \
"""\
Length: %d
Number: 0x%02x
Contained Data: %s
"""
def fromstring (data):
"""
Decode the binary representation of a TPDU from the given
parameter and note the data in the instance of the object.
Parameters:
data: The binary form of the TPDU
"""
tpdu = DT_TPDU ()
tpdu.data = data[3:]
return tpdu
class DT_TPDU (TPDU):
def __init__ (self, data = "", *args, **args2):
self.code = TPDU_DT
self.data = data
# Bit 8 indicates complete DT Packet, may need to
# be fixed though
self.number = 0x80
#self.number = 0x00 # is fragment
self.__recalclen ()
return
def identify (self):
"""
This method can be used to identify a TPDU by string.
"""
return "DT type TPDU (Data transmit)\n"
def __recalclen (self):
"""
Return the length of the TPDU. This function is for
internal use only!
"""
self.len = 2 + len (self.data)
def __repr__ (self):
"""
Print a representation of the TPDU. Use this method via
`-pair to transfer it over the wire. This will just return
the header data and not the real data!
"""
# Note that the data is not included in the length
return "%c%c%c" % (2, self.code << 4, self.number) + self.data
def __str__ (self):
"""
Return a readable and quite verbose overview of the TPDU instance.
Use this for debugging purposes or if you're just curious.
"""
string = self.identify () + DT_STRING % (self.len, self.number, self.data)
return string
# Integrated tests start here
if __name__ == '__main__':
testnum = 1
tpdu = DT_TPDU ("")
print "Test %0d sucessful" % testnum
testnum += 1
tpdu = DT_TPDU (" Noch")
print "Test %0d sucessful" % testnum
print tpdu
testnum += 1
if tpdu.len == 14:
print "Test %0d sucessful" % testnum
testnum += 1
else:
raise Warning, "Test %0d failed" % testnum
print tpdu
print "Test %0d sucessful" % testnum
testnum += 1
print `tpdu`
print "Test %0d sucessful" % testnum
testnum += 1

29
generatemails.py Normal file
View File

@@ -0,0 +1,29 @@
#!/usr/bin/python
import os
import smtplib
sender = 'lvr@gustavogusto.com'
receivers = ['w.niedersetz@gustavogusto.com']
message = """From: ELA LVR <lvr@gustavogusto.com>
To: Waldemar Niedersetz <w.niedersetz@gustavogusto.com>
Subject: SMTP e-mail test
This is a test e-mail message.
"""
mailpath = '/opt/mails'
if __name__ == "__main__":
while 1:
files = os.listdir (mailpath)
for fname in files:
f = open ("/opt/mails/" + fname, "r")
data = f.read ()
print data
f.close ()
try:
smtpObj = smtplib.SMTP('104.47.10.36') #, 587)
smtpObj.sendmail(sender, receivers, message)
os.remove ("/opt/mails/" + fname)
print "Successfully sent email"
except:
print "Error: unable to send email"

View File

@@ -0,0 +1,9 @@
--Articlemaster Karnerta Teigwaren--
BEGIN TRANSACTION;
DELETE FROM Articlemaster;
INSERT INTO Articlemaster (article, caption, gtin, normammount, minammount, zone) VALUES (118, 'Pizza Margherita', '4260414150685', 81, 50, 1);
INSERT INTO Articlemaster (article, caption, gtin, normammount, minammount, zone) VALUES (119, 'Pizza Prosciutto Funghi', '4260414150692', 81, 50, 1);
INSERT INTO Articlemaster (article, caption, gtin, normammount, minammount, zone) VALUES (129, 'Pizza Salame', '4250414150715', 81, 50, 1);
INSERT INTO Articlemaster (article, caption, gtin, normammount, minammount, zone) VALUES (218, 'Pizza Tonno e Cipolla', '4260414150722', 81, 50, 1);
INSERT INTO Articlemaster (article, caption, gtin, normammount, minammount, zone) VALUES (342, 'Pizza Spinaci e Ricotta', '4260414150623', 81, 50, 1);
END TRANSACTION;

View File

@@ -0,0 +1,8 @@
--Locked Slots Karnerta -Wurst--
DELETE FROM Lockedslots;
--INSERT INTO Lockedslots VALUES ('T001', 16, 2, 'dummy');
-- INSERT INTO Lockedslots VALUES ('T001', 17, 5, 'express');
-- INSERT INTO Lockedslots VALUES ('T001', 18, 7, 'error');
--INSERT INTO Lockedslots VALUES ('T001', 18, 6, 'throughfeed-I001');
-- INSERT INTO Lockedslots VALUES ('T001', 18, 5, 'throughfeed-I002');
-- INSERT INTO Lockedslots VALUES ('T002', 1, 1, 'blocked');

View File

@@ -0,0 +1,41 @@
-- Storages configured
DELETE FROM Physics;
-- RFZs configured
INSERT INTO Physics VALUES ('RFZs', '2');
INSERT INTO Physics VALUES ('Storages', '3');
-- Throughfeed shelf configured
INSERT INTO Physics VALUES ('Storage0', 'T001');
INSERT INTO Physics VALUES ('X_T001','14');
INSERT INTO Physics VALUES ('Y_T001','3');
INSERT INTO Physics VALUES ('ZONES_T001','1');
INSERT INTO Physics VALUES ('ZONESTART_T001_1','1');
INSERT INTO Physics VALUES ('XMid_T001_1','5');
INSERT INTO Physics VALUES ('YMid_T001_1','3');
INSERT INTO Physics VALUES ('Z_T001','21');
-- INSERT INTO Physics VALUES ('T001_Managed', 1);
-- Singleplace shelf configured
INSERT INTO Physics VALUES ('Storage1', 'S001');
INSERT INTO Physics VALUES ('Z_S001','1');
INSERT INTO Physics VALUES ('X_S001','10');
INSERT INTO Physics VALUES ('Y_S001','3');
INSERT INTO Physics VALUES ('ZONES_S001','1');
INSERT INTO Physics VALUES ('ZONESTART_S001_1','1');
INSERT INTO Physics VALUES ('XMid_S001_1','2');
INSERT INTO Physics VALUES ('YMid_S001_1','3');
-- Singleplace shelf configured
INSERT INTO Physics VALUES ('Storage2', 'S002');
INSERT INTO Physics VALUES ('Z_S002','1');
INSERT INTO Physics VALUES ('X_S002','10');
INSERT INTO Physics VALUES ('Y_S002','3');
INSERT INTO Physics VALUES ('ZONES_S002','1');
INSERT INTO Physics VALUES ('ZONESTART_S002_1','1');
INSERT INTO Physics VALUES ('XMid_S002_1','2');
INSERT INTO Physics VALUES ('YMid_S002_1','3');
-- BoxNrStart for I-Point
INSERT INTO Physics VALUES ('BoxNr_I002', '2000100');
INSERT INTO Physics VALUES ('BoxNr_I001', '1000100');
-- Ordering --
-- Slotbase --
DELETE FROM Slotbase;
-- Build Slotbase for managed Throughfeed Storage T002 --
--INSERT INTO Slotbase (id, x, y, article) VALUES ('T002', 1, 1, 'dynamic');

View File

@@ -0,0 +1,14 @@
-- Transportmatrix
BEGIN TRANSACTION;
DELETE FROM Transportmatrix;
INSERT INTO Transportmatrix (src, dst, rfz, mode, prio) VALUES ('I001', 'T001', 1, '', 1);
INSERT INTO Transportmatrix (src, dst, rfz, mode, prio) VALUES ('I001', 'S001', 1, '', 1);
INSERT INTO Transportmatrix (src, dst, rfz, mode, prio) VALUES ('I002', 'S001', 1, '', 1);
INSERT INTO Transportmatrix (src, dst, rfz, mode, prio) VALUES ('I003', 'S002', 2, '', 1);
--INSERT INTO Transportmatrix (src, dst, rfz, mode, prio) VALUES ('T001', 'T002', 2, 'autosched', 1);
INSERT INTO Transportmatrix (src, dst, rfz, mode, prio) VALUES ('S001', 'O001', '1_D1', '', 0);
INSERT INTO Transportmatrix (src, dst, rfz, mode, prio) VALUES ('S002', 'O002', '2_A1', '', 0);
INSERT INTO Transportmatrix (src, dst, rfz, mode, prio) VALUES ('T001', 'O002', '2_A1', '', 1);
--Error-Transport-RFZ2
--INSERT INTO Transportmatrix (src, dst, rfz, mode, prio) VALUES ('RFZ2', 'OPD3', 2, '', 'error', 0);
END TRANSACTION;

View File

@@ -0,0 +1,9 @@
CREATE TABLE Articlemaster (
article varchar(20) NOT NULL default '',
caption varchar(50) NOT NULL default '',
gtin varchar(14) NOT NULL default '',
normammount INTEGER NULL default '',
minammount INTEGER NULL default '',
zone INTEGER NOT NULL default '1',
PRIMARY KEY (article)
);

View File

@@ -0,0 +1,272 @@
-- sqldum : sqlite
--
-- Database : storage
-- ------------------------------------------------------
-- Server version 4.0.24_Debian-10sarge1-log
--
-- Table structure for table Physics
--
CREATE TABLE Physics (
k varchar(30) NOT NULL default '',
v varchar(255) default NULL
);
--
-- Table structure for Transportmartrix
--
CREATE TABLE Transportmatrix (
src varchar(4) NOT NULL,
dst varchar(4) NOT NULL,
rfz varchar (4) NOT NULL,
mode varchar (10) default '',
prio integer NOT NULL
);
--
-- Table structure for table Inqueue
--
CREATE TABLE Inqueue (
location varchar (4) NOT NULL default 'I001',
boxnr varchar(20) NOT NULL default '',
article varchar(20) NOT NULL default '',
gtin varchar(20) NOT NULL default '',
lotnr varchar(20) NOT NULL default '',
lotnr2 varchar(20) NOT NULL default '',
duedate varchar(20) NOT NULL default '',
pieces varchar(20) NOT NULL default '',
deststorage varchar(4) NOT NULL default '',
destination INTEGER NOT NULL default '0',
PRIMARY KEY (location, boxnr)
);
--
-- Table structure for table Storage
--
CREATE TABLE Storage (
id varchar (4) NOT NULL default '',
boxnr varchar(20) NOT NULL default '',
article varchar(20) NOT NULL default '',
lotnr varchar(20) NOT NULL default '',
lotnr2 varchar(20) NOT NULL default '',
duedate varchar(20) NOT NULL default '',
pieces INTEGER NOT NULL default '0',
x INTEGER NOT NULL default '0',
y INTEGER NOT NULL default '0',
z INTEGER NOT NULL default '0',
rfzts timestamp(14) NOT NULL,
PRIMARY KEY (id, boxnr)
);
CREATE UNIQUE INDEX Storage_xyz ON Storage (id, x, y, z);
--
-- Table structure for table Insertiontimestamps
--
CREATE TABLE Insertiontimestamps (
boxnr varchar(20) NOT NULL default '',
rfzts timestamp(14) NOT NULL,
PRIMARY KEY (boxnr)
);
--
-- Table structure for table Outqueue
--
CREATE TABLE Outqueue (
id varchar (4) NOT NULL default 'O001',
boxnr varchar(20) NOT NULL default '',
article varchar(20) NOT NULL default '',
lotnr varchar(20) NOT NULL default '',
lotnr2 varchar(20) NOT NULL default '',
duedate varchar(20) NOT NULL default '',
pieces varchar(20) NOT NULL default '',
x INTEGER NOT NULL default '0',
y INTEGER NOT NULL default '0',
z INTEGER NOT NULL default '0',
rfzts timestamp(14) NOT NULL,
PRIMARY KEY (id, boxnr)
);
--
-- Table structure for table Slotbase
--
CREATE TABLE Slotbase (
id varchar (4) NOT NULL default '',
x INTEGER NOT NULL default '0',
y INTEGER NOT NULL default '0',
article varchar(20) NOT NULL default '',
PRIMARY KEY (id, x, y)
);
--
-- Table structure for table Lockedslots
--
CREATE TABLE Lockedslots (
id INTEGER NOT NULL default '0',
x INTEGER NOT NULL default '0',
y INTEGER NOT NULL default '0',
reason varchar(255) NOT NULL default ''
);
CREATE UNIQUE INDEX Lockedslots_idcy ON Lockedslots (id, x, y);
--
-- Table structure for table Transports
--
CREATE TABLE Transports (
boxnr varchar(20) NOT NULL default '',
position varchar(6) NOT NULL default '',
src varchar(6) NOT NULL default '',
src_x varchar(2) NOT NULL default '',
src_y varchar(2) NOT NULL default '',
src_z varchar(2) NOT NULL default '',
dst varchar(6) NOT NULL default '',
dst_x varchar(2) NOT NULL default '',
dst_y varchar(2) NOT NULL default '',
dst_z varchar(2) NOT NULL default '',
state varchar(5) NOT NULL default '',
ts timestamp(14)
);
--
-- Table structure for Trace
--
CREATE TABLE Trace (
boxnr varchar(20) NOT NULL default '',
article varchar(20) NOT NULL default '',
lotnr varchar(20) NOT NULL default '',
lotnr2 varchar(20) NOT NULL default '',
pieces INTEGER NOT NULL default '0',
x INTEGER NOT NULL default '0',
y INTEGER NOT NULL default '0',
z INTEGER NOT NULL default '0',
rfzts timestamp(14) NOT NULL,
action varchar(20) NOT NULL default ''
);
--
-- Table structure for table Expressjobs
--
CREATE TABLE Expressjobs (
id INTEGER PRIMARY KEY,
source varchar(6) NOT NULL default '',
state varchar(5) NOT NULL default '',
customer varchar(20) NOT NULL default '',
packlist varchar(20) NOT NULL default '',
article varchar(20) NOT NULL default '',
boxes integer not NULL default '0',
boxes_delivered integer not NULL default '0',
created timestamp(14) NOT NULL,
info varchar(50) NOT NULL default ''
);
--
-- Table structure for Expresslog
--
CREATE TABLE Expresslog (
expressjob INTEGER NOT NULL,
boxnr varchar(20) NOT NULL default '',
lotnr varchar(20) NOT NULL default '',
lotnr2 varchar(20) NOT NULL default '',
pieces INTEGER NOT NULL default '0',
rfzts timestamp(14) NOT NULL
);
--
-- Table structure for table Reefeed
--
CREATE TABLE Refeed (
kistennummer varchar(20) NOT NULL default '',
artikelnummer varchar(20) NOT NULL default '',
charge varchar(20) NOT NULL default '',
gewicht decimal(10,0) NOT NULL default '0',
z INTEGER NOT NULL default '0',
reserved timestamp(14) NOT NULL,
PRIMARY KEY (kistennummer)
);
--
-- Compression Jobs
--
CREATE TABLE Compressionjobs (
id INTEGER PRIMARY KEY,
position varchar(6) NOT NULL default '',
state varchar(5) NOT NULL default '',
artikelnummer varchar(20) NOT NULL default '',
created timestamp(14) NOT NULL,
info varchar(50) NOT NULL default ''
);
--
-- Umlager Jobs Chaos
--
CREATE TABLE Umlagerchaosjobs (
id INTEGER PRIMARY KEY,
position varchar(6) NOT NULL default '',
state varchar(5) NOT NULL default '',
artikelnummer varchar(20) NOT NULL default '',
sourcex INTEGER NOT NULL default '0',
sourcey INTEGER NOT NULL default '0',
created timestamp(14) NOT NULL,
info varchar(50) NOT NULL default ''
);
--
-- Umlager Jobs ES
--
CREATE TABLE Umlageresjobs (
id INTEGER PRIMARY KEY,
position varchar(6) NOT NULL default '',
state varchar(5) NOT NULL default '',
artikelnummer varchar(20) NOT NULL default '',
sourcex INTEGER NOT NULL default '0',
sourcey INTEGER NOT NULL default '0',
created timestamp(14) NOT NULL,
info varchar(50) NOT NULL default ''
);
--
-- Umlager Jobs ES
--
CREATE TABLE singlemovejobs (
id INTEGER PRIMARY KEY,
position varchar(6) NOT NULL default '',
state varchar(5) NOT NULL default '',
artikelnummer varchar(20) NOT NULL default '',
src_id varchar (4) NOT NULL default '',
sourcex INTEGER NOT NULL default '0',
sourcey INTEGER NOT NULL default '0',
created timestamp(14) NOT NULL,
info varchar(50) NOT NULL default ''
);

View File

@@ -0,0 +1,16 @@
--
-- Table structure for ERP Trace
--
CREATE TABLE ERPTrace (
kistennummer varchar(20) NOT NULL default '',
artikelnummer varchar(20) NOT NULL default '',
charge varchar(20) NOT NULL default '',
menge decimal(10,0) NOT NULL default '0',
einheit varchar(20) NOT NULL default 'KP',
rfzts timestamp(14) NOT NULL,
action varchar(20) NOT NULL default ''
);

View File

@@ -0,0 +1,25 @@
CREATE TABLE Orders (
id INT NOT NULL ,
customer_name VARCHAR(45) NULL ,
customer_address VARCHAR(45) NULL ,
deliverydate VARCHAR(10) NOT NULL ,
state VARCHAR(10) NULL DEFAULT 'New' ,
destination VARCHAR(10) NOT NULL ,
prio INT NOT NULL,
PRIMARY KEY (id) );
CREATE TABLE Orderlines (
id INTEGER PRIMARY KEY,
orderid INT NOT NULL ,
article INT NOT NULL ,
caption VARCHAR(45) NULL ,
amount DECIMAL(10,0) NOT NULL ,
amount_unit VARCHAR(2) NOT NULL DEFAULT 'KG' ,
amount_delivered DECIMAL(10,0) NOT NULL DEFAULT 0.0 ,
weight DECIMAL(10,0) NOT NULL ,
weight_unit VARCHAR(2) NOT NULL DEFAULT 'KG' ,
weight_delivered DECIMAL(10,0) NOT NULL DEFAULT 0.0 ,
state VARCHAR(10) NULL DEFAULT 'New' ,
CONSTRAINT uk_IdOrderId UNIQUE (id, orderid) ,
CONSTRAINT fk_OrderId FOREIGN KEY (orderid) REFERENCES Orders (id)
);

View File

@@ -0,0 +1,9 @@
CREATE TABLE ERPTrace (
kistennummer varchar(20) NOT NULL default '',
artikelnummer varchar(20) NOT NULL default '',
charge varchar(20) NOT NULL default '',
menge decimal(10,0) NOT NULL default '0',
einheit varchar(20) NOT NULL default 'KG',
rfzts timestamp(14) NOT NULL,
action varchar(20) NOT NULL default ''
);

10
initdata/locked.py Normal file
View File

@@ -0,0 +1,10 @@
#!/usr/bin/python
storages = ['S001','S002','S003','S004']
x = 16
y = 12
for i in range (1, x + 1):
for j in range (1, y + 1):
for storage in storages:
print ("INSERT INTO Lockedslots VALUES ('%s', %d, %d, 'startup');" % (storage, i, j))

View File

@@ -0,0 +1,5 @@
UPDATE Schachtstamm SET artikelnummer = '801', zone = 1 WHERE x = 2 AND y = 1;
UPDATE Schachtstamm SET artikelnummer = '802', zone = 1 WHERE x = 2 AND y = 2;
UPDATE Schachtstamm SET artikelnummer = '803', zone = 1 WHERE x = 2 AND y = 3;
UPDATE Schachtstamm SET artikelnummer = '804', zone = 2 WHERE x = 2 AND y = 4;
UPDATE Schachtstamm SET artikelnummer = '805', zone = 2 WHERE x = 2 AND y = 5;

91
initdata/storagephysics.py Executable file
View File

@@ -0,0 +1,91 @@
#!/usr/bin/python
"""
Generate Physics Databasecontent
"""
import sys
if __name__ == '__main__':
storages = ['T001', 'T002', 'S001']
rfzs = 2
xSt = [18, 18, 39]
ySt = [7, 7, 8]
#Number of zones, followed by list with Zonestart X-Values
zones = [1, 1, 1, 1, 1]
zonestart = [[1], [1], [1], [1], [1]]
#Midvalue - where to start inserting Boxes (liste for each storage, with Tuple for each zone)
midSt = [[(18, 9), (12, 1)],\
[(16, 9)],\
[(16, 9)],\
[(16, 9)],\
[(1, 1)]]
#Z-value for Throughfeed shelfes
zTr = {'T001' : 7, \
'T002' : 7}
#Decide if a Throughfeed Storage is managed by a Slotbase
TrManaged = ['T002']
#Z-value dict for Commisioning shelfes
zCo = {'C001' : [1, 1, 1, 1, 1]}
#BoxnrCircles for IPoints
Nrs = {'I001': 1000100,\
'I002': 2000100}
idx = 0
print ("-- Storages configured")
print ("DELETE FROM Physics;")
print ("-- RFZs configured")
print ("INSERT INTO Physics VALUES ('RFZs', '%d');" % rfzs)
print ("INSERT INTO Physics VALUES ('Storages', '%d');" %len (storages))
for storage in storages:
print ("INSERT INTO Physics VALUES ('Storage%d', '%s');" %(idx, storage))
print ("INSERT INTO Physics VALUES ('X_%s','%d');" %(storage, xSt[idx]))
print ("INSERT INTO Physics VALUES ('Y_%s','%d');" %(storage, ySt[idx]))
#FixMe
if storage[0] in ['S', 'T']:
print ("INSERT INTO Physics VALUES ('ZONES_%s','%d');" %(storage, zones[idx]))
for i in range (1, zones[idx] + 1):
print ("INSERT INTO Physics VALUES ('ZONESTART_%s_%d','%d');" %(storage, i, zonestart[idx][i - 1]))
print ("INSERT INTO Physics VALUES ('XMid_%s_%d','%d');" %(storage, i, midSt[idx][i - 1][0]))
print ("INSERT INTO Physics VALUES ('YMid_%s_%d','%d');" %(storage, i, midSt[idx][i - 1][1]))
if storage[0] == 'S':
print ("-- Singleplace shelf configured")
print ("INSERT INTO Physics VALUES ('Z_%s','1');" %(storage))
elif storage[0] == 'T':
print ("-- Throughfeed shelf configured")
print ("INSERT INTO Physics VALUES ('Z_%s','%d');" %(storage, zTr[storage]))
elif storage[0] == 'C':
print ("-- Commisioning shelf configured")
for x in range (1 , xSt[idx] + 1):
for y in range (1, ySt[idx] + 1):
print ("INSERT INTO Physics VALUES ('Z_%s_%d_%d','%d');" %(storage, x, y, zCo[storage][y - 1]))
else:
print ("Invalid Storage")
sys.exit (0)
idx += 1
idx = 0
#slotbase for Commisioning shelfes
print ("-- Slotbase --")
print ("DELETE FROM Slotbase;")
for storage in storages:
if storage[0] == 'C':
print ("-- Build Slotbase for Commisioning storage %s --" % storage)
for x in range (1, xSt[idx] + 1):
for y in range (1, ySt[idx] + 1):
print ("INSERT INTO Slotbase (id, x, y) VALUES ('%s', %d, %d);" %(storage, x, y))
elif storage[0] == 'T' and storage in TrManaged:
print ("INSERT INTO Physics VALUES ('%s_Managed', 1);" %storage)
print ("-- Build Slotbase for managed Throughfeed Storage %s --" % storage)
for x in range (1, xSt[idx] + 1):
for y in range (1, ySt[idx] + 1):
print ("INSERT INTO Slotbase (id, x, y, article) VALUES ('%s', %d, %d, 'dynamic');" %(storage, x, y))
idx += 1
print ("-- BoxNrStart for I-Point")
for ipoint in Nrs:
print ("INSERT INTO Physics VALUES ('BoxNr_%s', '%d');" %(ipoint, Nrs[ipoint]))

39
locations.py Executable file
View File

@@ -0,0 +1,39 @@
#! /usr/bin/python
__author__ = "Daniel Egger, Michael Rest"
__date__ = "22 Okt 2007"
__email__ = "egger@interearth.com, michi@rosstein.de"
__version__ = "$Revision: 1.2 $"[11:-2]
#Locations
locations = {}
locations ['Pick'] = ''
locations ['Puffer'] = ''
locations ['RFZ1'] = ''
locations ['RFZ2'] = ''
locations ['RFZ3'] = ''
locations ['IPKT'] = ''
locations ['DEST'] = ''
locations ['VF01'] = ''
#scanners
scanners = {}
scanners ['IPKT'] = 1
scanners ['RFZ1'] = 2
scanners ['RFZ2'] = 3
scanners ['RFZ3'] = 4
scanners ['BCL1'] = 101
scanners ['BCL2'] = 102
scanners ['BCL3'] = 103
scanners ['BCL4'] = 104
scanners ['BCL5'] = 105
scanners ['BCL6'] = 106
scanners ['HBCL1'] = 201
scanners ['MDE'] = 300
HBCL1 = 201

32
log.py Normal file
View File

@@ -0,0 +1,32 @@
from time import time, strftime
loglevel = 7
def log (msg, _level = 3):
"""
Print message if in verbose mode.
"""
if _level <= loglevel:
file = open ("log.txt", "a")
file.write (strftime ("%Y-%m-%d %H:%M:%S "))
file.write (msg + "\n")
file.close ()
def strlog (instr):
"""
Converts String into readable format
"""
oustr = ''
for c in instr:
#if (ord (c) >= 33) & (ord (c) <= 127):
# oustr = oustr + c
#else:
oustr = oustr + " x%2X " %ord(c)
return oustr
def doublechar (i):
"""
build double char val out of int
"""
return chr (i % 256) + chr ((i >> 8) % 256)

71
lvr_BEAT.py Executable file
View File

@@ -0,0 +1,71 @@
#! /usr/bin/python
__author__ = "Michael rest"
__date__ = "2006/02/13"
__email__ = "michi@rosstein.de"
__version__ = "$Revision: 1.1 $"[11:-2]
import sys
from cr_tpdu import CR_TPDU
from dt_tpdu import DT_TPDU
from tpkt import TPKT
from socket import *
from time import sleep
BUFSIZE = 1024
def print_lebe (data):
print '\nTransportauftrag'
print ' Telegrammnr: %d ' %((ord (data[0]) << 8) + ord (data[1]))
print ' Sender : %s ' %data [2:4]
print ' Empfaenger : %s ' %data [4:6]
print ' Typ : %s ' %data [6:10]
print ' Telegrammnr: %d ' %((ord (data[10]) << 8) + ord (data[11]))
#LEBE
tpdu = CR_TPDU ("BEAT", "BEAT", srcref=0x0015)
tpkt = TPKT (len (tpdu) + 1)
print "Laenge: " + str (len (tpdu))
sleb = socket(AF_INET, SOCK_STREAM)
sleb.connect(("192.168.0.130", 102))
sleb.send(`tpkt`+`tpdu`)
data = sleb.recv (16384)
#Telegramme
id =0
#An I-Punkt
tel = 'LV' + 'TP' + 'LEBE' + '%c%c' %(0,1)
while 1:
try:
print '========================='
dt = '%c%c' %(id >> 8, id % 256) + tel
id = id + 1
print_lebe (dt)
tpdu = DT_TPDU (dt)
tpkt = TPKT (len (tpdu) + 1)
sleb.send(`tpkt`+`tpdu`)
data = sleb.recv (16384)
print_lebe (data[7:20])
sleep (4.1)
except KeyboardInterrupt:
self.message ("Interrupted by user")
sleep (25.1)
#close connecthons
sleb.close ()
#while 1:
# data = sstau.recv(BUFSIZE)
#
# if not data:
# print "Stopping"
# sys.exit (0)

58
maillog.py Normal file
View File

@@ -0,0 +1,58 @@
from time import time, strftime
def mailexplog (expjob, explog):
"""
Creates Mail for Expressjob
"""
_expjob, _source, _state, _customer, _packl, _article, _boxes, _boxes_delivered, _ts, _info = expjob
lotnrs = ''
pcssum = 0
for elboxnr, ellotnr, ellotnr2, elpieces, elrfzts in explog:
if ellotnr and not ellotnr in lotnrs:
lotnrs = lotnrs + ellotnr +', '
if ellotnr2 and not ellotnr2 in lotnrs:
lotnrs = lotnrs + ellotnr +', '
pcs = 0
try:
pcs = int (elpieces)
except:
print ("Is hoid so")
pcssum = pcssum + pcs
prettyexplog = ''
for i in explog:
prettyexplog = prettyexplog + str (i).replace ("u''", '__').replace ("u'", "").replace ("'","") + '\n '
message = """From: ELA LVR <lvr@gustavogusto.com>
To: Waldemar Niedersetz <w.niedersetz@gustavogusto.com>
Subject: Auslagerung Kunde %s Lieferschein %s
Fuer den Kunden %s mit Lieferschein %s wurden
vom Artikel %s in Summe %s Paletten mit %s Gebinden ausgelagert.
Es waren folgende Chargen enthalten
%s
Auslagerauftrag %s vom %s
Die Ausgelagerten Paletten
(PaletteNr, Charge1, Charge 2, Anzahl Geb, Einlagerdatum)
%s
Ende
""" % (_customer, _packl,
_customer, _packl,
_article, len (explog), pcssum,
lotnrs,
_expjob, _ts,
prettyexplog)
file = open ("/opt/mails/" + strftime ("%Y-%m-%d_%H%M%S-mail.txt"), "a")
file.write (message)
file.close ()
if __name__ == "__main__":
expjob = (23, u'T001', u'Done', u'0', u'0', u'119', 10, 10, u'2019-05-23 11:07:16', u'Job done')
explog = [(u'239', u'14319', u'', 81, u'2019-05-23 11:07:18'), (u'240', u'14319', u'', 81, u'2019-05-23 11:08:03'), (u'241', u'14319', u'', 81, u'2019-05-23 11:09:06'), (u'242', u'14319', u'', 81, u'2019-05-23 11:10:10'), (u'243', u'14319', u'', 81, u'2019-05-23 11:11:14'), (u'244', u'14319', u'', 81, u'2019-05-23 11:12:18'), (u'245', u'14319', u'', 81, u'2019-05-23 11:13:21'), (u'246', u'14319', u'', 81, u'2019-05-23 11:20:03'), (u'247', u'14319', u'', 81, u'2019-05-23 11:21:06'), (u'248', u'14319', u'', 81, u'2019-05-23 11:22:05')]
mailexplog (expjob, explog)

42
pySAP.py Executable file
View File

@@ -0,0 +1,42 @@
#!/usr/bin/python
import sys, os
sys.path.append (".")
from time import time, strftime, sleep
class pySAP:
def __init__ (self, *dummy, **args):
"""
Initialize a new SAP exporter
"""
self.path = args.get ("path", "/opt/sap/")
self.time = time ()
def log (self, msg):
"""
Print message if in verbose mode.
"""
mins = int (strftime ("%M"))
file = open (self.path + strftime ("%Y_%m_%d_%H_") + '%02d' %(mins), "a")
file.write ( msg )
file.close ()
if __name__ == "__main__":
from pySAP import *
from DB_ERP import DB_ERP
#sapfile = pySAP (path = "/opt/sap/")
sapfile = pySAP (path = "/Users/michi/logtest/")
#conn = DB_ERP ("/opt/data/storage_ERPTrace.db3")
conn = DB_ERP ("/Users/michi/devel/S7ISO/data/storage_ERPTrace.db3")
conn.markinsertionsasunread ()
sapfile.log ('')
for a, c, m, u in conn.getinsertions ():
if c=='':
c = 0
sapfile.log ('%05d;%010d;%s;%s\n' % (int (a), int (c), m, u))
conn.markinsertionsasread ()

36
scripts/cron_move.sh Executable file
View File

@@ -0,0 +1,36 @@
#!/bin/sh -e
#
# move files to storage
#
DATER=`date +%b%_3d%_9T`
#
#
echo $DATER chargencopy: starting procedure
FILES=`/usr/bin/find /opt/smb_lotnr -maxdepth 1 -name "*txt" -type f | /usr/bin/wc -l`
if [ $FILES -eq 0 ];
then
echo $DATER chargencopy: Nothing to do
echo $DATER chargencopy: terminated with error 2
exit 2
fi
if !(/bin/mount -t smbfs -o user=ela,password=matstamm,domain=linznet //172.41.31.16/input/pick /mnt/chargen_bizerba)
then
#/bin/umount //172.41.31.16/input
echo $DATER chargencopy: mount failed: could not mount remote share
echo $DATER chargencopy: terminated with error 1
exit 1
fi
#if !(/usr/bin/find /opt/smb_lotnr -maxdepth 1 -name "*txt" )
if [ $FILES -eq 0 ];
then
/bin/umount //172.41.31.16/input
echo $DATER chargencopy: no files
echo $DATER chargencopy: terminated with error 2
exit 2
fi
cp /opt/smb_lotnr/*txt /mnt/chargen_bizerba
#mv /opt/smb_lotnr/*txt /opt/smb_lotnr/archive
rm /opt/smb_lotnr/*txt
/bin/umount //172.41.31.16/input

21
scripts/smbmove.sh Executable file
View File

@@ -0,0 +1,21 @@
#!/bin/bash
DATER=`date +%b%_3d%_9T`
echo $DATER IPointlog: starting procedure
FILES=`/usr/bin/find /opt/sap -maxdepth 1 -name "*txt" -type f | /usr/bin/wc -l`
if [ $FILES -eq 0 ]; then
echo $DATER IPointlog: Nothing to do
echo $DATER IPointlog: terminated with error 2
exit 2
fi
#mount | grep "/opt/sap/remote" /etc/mtab > /dev/null
#if [ $? -ne 0 ]; then
if !(smbmount //172.41.3.8/ELA /opt/sap/remote -o user=ela,pass=matstamm ,dom=LANDHOF) then
echo $DATER IPointlog: mount failed: could not mount remote share
echo $DATER IPointlog: terminated with error 1
exit 1
fi
mv /opt/sap/20*.txt /opt/sap/remote/IPOINTLOG
/bin/umount /opt/sap/remote

9
start.sh Executable file
View File

@@ -0,0 +1,9 @@
#! /bin/bash
while true; do
echo "Starting LVR in `pwd` at `date`" >> /var/log/lvr/startstop.log
#python ./storage.py `pwd` 2>&1 >> log_`date -Idate`.txt
python ./storage.py `pwd` 2>&1 >> log.txt
echo "LVR stopped in `pwd` at `date`" >> /var/log/lvr/startstop.log
sleep 10
done

32
storage.cfg.tpl Normal file
View File

@@ -0,0 +1,32 @@
[IP Settings]
iplvr = 192.168.0.100
ipsps = 192.168.0.106
[DB Settings]
dbfile = /opt/data/storageWu.db3
logfile = /opt/data/storageWu_talog.sql
[DEBUG]
loglevel = 6
debuglevel = 1
[PARAM]
ipktreservation = 1
keepinqueue = 0
articlemustbedefined = 1
dummyactive = 0
ordering = 0
expressendtovf = 0
[OPTIONS]
rk512 = 0
rkdev = /dev/ttyS0
ERPTrace = 1
ERPDB = /opt/data/storage_ERPTrace.db3
ERPType = 1
ERPCycl = 30
MDE = 1
MDEDB = /opt/data/mdedata.db3
CSBCOM = 1
CSBSOCK = /tmp/lv_csb.socket
OrderPath = /opt/sap

98
storage.init Executable file
View File

@@ -0,0 +1,98 @@
#! /bin/bash
### BEGIN INIT INFO
# Provides: skeleton
# Required-Start: $local_fs $remote_fs
# Required-Stop: $local_fs $remote_fs
# Default-Start: 2 3 4 5
# Default-Stop: S 0 1 6
# Short-Description: Example initscript
# Description: This file should be used to construct scripts to be
# placed in /etc/init.d.
### END INIT INFO
# Author: Foo Bar <foobar@baz.org>
#
# Please remove the "Author" lines above and replace them
# with your own name if you copy and modify this script.
# Do NOT "set -e"
# PATH should only include /usr/* if it runs after the mountnfs.sh script
PATH=/usr/sbin:/usr/bin:/sbin:/bin
DESC="Storage System"
NAME=storage
STORAGE=/opt/storage-karnertaWU
SCRIPTNAME=/etc/init.d/$NAME
# Define LSB log_* functions.
# Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
. /lib/lsb/init-functions
#
# Function that starts the daemon/service
#
do_start()
{
pushd $STORAGE
$STORAGE/start.sh &
popd
return 0
}
#
# Function that stops the daemon/service
#
do_stop()
{
pkill -f $STORAGE/start.sh
sleep 5s
pkill -KILL -f $STORAGE/start.sh
return 0
}
case "$1" in
start)
[ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
do_start
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
stop)
[ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
do_stop
case "$?" in
0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
esac
;;
restart|force-reload)
#
# If the "reload" option is implemented then remove the
# 'force-reload' alias
#
log_daemon_msg "Restarting $DESC" "$NAME"
do_stop
case "$?" in
0|1)
do_start
case "$?" in
0) log_end_msg 0 ;;
1) log_end_msg 1 ;; # Old process is still running
*) log_end_msg 1 ;; # Failed to start
esac
;;
*)
# Failed to stop
log_end_msg 1
;;
esac
;;
*)
echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload}" >&2
exit 3
;;
esac
:

1333
storage.py Executable file

File diff suppressed because it is too large Load Diff

54
tel_decode.py Executable file
View File

@@ -0,0 +1,54 @@
#!/usr/bin/python
__author__ = "Daniel Egger, Michael Rest"
__date__ = "2006/02/15"
__email__ = "michi@rosstein.de"
__version__ = "$Revision: 1.1 $"[11:-2]
from telegram import TEL_LEBE, TEL_TAUF, TEL_TQUI, TEL_SCLS, TEL_STAT, TEL_IPKT
__all__ = ["decode_packet"]
def decode_LEBE (data):
from LEBE_tel import fromstring
return fromstring (data)
def decode_TQUI (data):
from TQUI_tel import fromstring
return fromstring (data)
def decode_SCLS (data):
from SCLS_tel import fromstring
return fromstring (data)
def decode_STAT (data):
from STAT_tel import fromstring
return fromstring (data)
def decode_IPKT (data):
from IPKT_tel import fromstring
return fromstring (data)
def decode_TAUF (data):
from TAUF_tel import fromstring
return fromstring (data)
decoderlist = {
'LEBE': decode_LEBE,
'TQUI': decode_TQUI,
'SCLS': decode_SCLS,
'STAT': decode_STAT,
'IPKT': decode_IPKT,
'TAUF': decode_TAUF
}
def decodetelegram (data):
type = data[6:10]
if type in decoderlist:
return decoderlist[type](data)
else:
print ("Unhandled telegramtype %s" %type)
raise Warning, "Undhandled packettype"
return

66
telegram.py Normal file
View File

@@ -0,0 +1,66 @@
#!/usr/bin/python
__author__ = "Michael Rest"
__date__ = "2006/02/15"
__email__ = "michi@rosstein.de"
__version__ = "$Revision: 1.1 $"[11:-2]
# Packet types
TEL_LEBE = 0xa #
TEL_TAUF = 0xb #
TEL_TQUI = 0xc #
TEL_SCLS = 0xd #
TEL_STAT = 0xe #
TEL_QUIT = 0xf #
TEL_IPKT = 0x9 #
class TELEGRAM:
def __init__ (self):
self.len = 0
self.code = 0
self.attrib = {'src': ' ', 'dst': ' ', 'type': 'NONE', 'check' : 0}
def type (self):
"""
Return type hexadecimal type of the TELEGRAM. This function is
common for all TPDUs.
"""
return self.code
def __len__ (self):
"""
Return the calcuclated length of the TELEGRAM. The value is
always WITHOUT the coded type, add 1 to it if in doubt.
"""
return self.len
def __getitem__ (self, key):
"""
Return Attrib
"""
return self.attrib[key]
def has_key (self, key):
"""
Check for Key
"""
return self.attrib.has_key(key)
def __repr__ (self):
"""
Print a representation of the TELEGRAM. Use this method via
`-pair to transfer it over the wire. This will just return
the header data and not the real data!
"""
# Note that the data is not included in the length
return "%c%c" % (2, self.code << 4, self.number)
def __str__ (self):
"""
Return a readable and quite verbose overview of the TPDU instance.
Use this for debugging purposes or if you're just curious.
"""
string = DT_STRING % (self.len, self.number, self.data)
return string

67
tpdu.py Executable file
View File

@@ -0,0 +1,67 @@
#!/usr/bin/python
__author__ = "Daniel Egger"
__date__ = "22 March 2002"
__email__ = "egger@interearth.com"
__version__ = "$Revision: 1.1 $"[11:-2]
# Packet types
TPDU_CC = 0xd # Connection reply
TPDU_CR = 0xe # Connection request
TPDU_DT = 0xf # Datapacket transfer
# Packet parameters
PARM_ACKTIME = 0x85 # Acknowledge time
PARM_RER = 0x86 # Residual error rate
PARM_PRIORITY = 0x87 # Priority
PARM_TRANSITDELAY = 0x88 # Transit delay
PARM_THROUGHPUT = 0x89 # Troughput
PARM_SUBSEQNUM = 0x8a # Subsequence number
PARM_REASSTIME = 0x8b # Reassignment time
PARM_FLOWCTRLCON = 0x8c # Flow control confirmation
PARM_SIZE = 0xc0 # Size of the TPDU
PARM_SRCTSAP = 0xc1 # The calling TSAP
PARM_DSTTSAP = 0xc2 # The called TSAP
PARM_CHECKSUM = 0xc3 # Checksum
PARM_VERSION = 0xc4 # Version number
PARM_PROTECTION = 0xc5 # Protection
PARM_OPTIONS = 0xc6 # Additional option selection
PARM_ALTERNATIVE = 0xc7 # Alternative protocol classes
class TPDU:
len = 0
code = 0
def type (self):
"""
Return type hexadecimal type of the TPDU. This function is
common for all TPDUs.
"""
return self.code
def __len__ (self):
"""
Return the calcuclated length of the TPDU. The value is
always WITHOUT the coded type, add 1 to it if in doubt.
"""
return self.len
def __repr__ (self):
"""
Print a representation of the TPDU. Use this method via
`-pair to transfer it over the wire. This will just return
the header data and not the real data!
"""
# Note that the data is not included in the length
return "%c%c" % (2, self.code << 4, self.number)
def __str__ (self):
"""
Return a readable and quite verbose overview of the TPDU instance.
Use this for debugging purposes or if you're just curious.
"""
string = DT_STRING % (self.len, self.number, self.data)
return string

18
tpkt.py Executable file
View File

@@ -0,0 +1,18 @@
#!/usr/bin/python
__author__ = "Daniel Egger"
__date__ = "22 March 2002"
__email__ = "egger@interearth.com"
__version__ = "$Revision: 1.1 $"[11:-2]
class TPKT:
def __init__ (self, len):
self.version = 3
self.reserved = 0
# Also include length of trailer
self.len = len + 4
def __repr__ (self):
return "%c%c%c%c" % (self.version, self.reserved, (self.len >> 8) & 0xff,
self.len & 0xff)

23
utility.py Normal file
View File

@@ -0,0 +1,23 @@
#!/usr/bin/env python2.6
#-*- coding: utf-8 -*-
__author__ = "Michael Rest"
__date__ = "1 August 2010"
__email__ = "michi@rosstein.de"
__version__ = "$Revision: 1.0 $"[11:-2]
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