#!/usr/bin/env python2
# -*- coding: utf-8 -*-
#
# Copyright 2012-2017 Frédéric Magniette, Miguel Rubio-Roy, LLR
#
import random,fcntl,socket,struct,time
import pools
gdcc_pool = pools.pool("gdcc")
#********************* internal GDCC functions ********************************
def gener_pktid():
# generate a random packet id for gdcc packets
return random.randrange(100,53260,1)
def getHwAddr(ifname):
# get the hardware address of the acq PC the code is running on
s=socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
info=fcntl.ioctl(s.fileno(),0x8927,struct.pack('256s',ifname[:15]))
return ''.join(['%02x:' % ord(char) for char in info[18:24]])[:-1]
def split_short(value):
value2=value&0xff
value1=(value&0xff00)>>8
return "%d,%d"%(value1,value2)
def split_int(value):
value4=value&0xff
value3=(value&0xff00)>>8
value2=(value&0xff0000)>>16
value1=(value&0xff000000)>>24
data="%d,%d,%d,%d" % (value1,value2,value3,value4)
return data
def int2bin(n, count=16):
# convert integer to binary
return "".join([str((n >> y) & 1) for y in range(count-1, -1, -1)])
#pc_dev and mac_addr and data are string
#gdcctype, modifier, pktid, datalen are short integer
def send_gdccpkt(pc_dev,macaddr,gdcctype,modifier,pktid,datalen,data):
packet=split_short(gdcctype)+","+split_short(modifier)+","+split_short(pktid)+","+split_short(datalen)+","+data
retcode,res=submod_execcmd("send_packet@raweth",pc_dev,macaddr,"0x810",packet)
if retcode==0:
return 0,"cant send gdcc pkt <- %s"%(res)
return 1,"ok"
def even_parity(abyte):
rbyte=abyte&0xff;
p=0;
for i in range(8):
if i==0:
p=rbyte&1;
else:
p=p^(rbyte&1)
rbyte=rbyte>>1
return p
def calc_gdcc_parity(cmdw,modifier,comma,data):
result=even_parity(cmdw&0xff)
result=result|(even_parity((cmdw>>8)&0xff)<<1)
result=result|(even_parity((modifier)&0xff)<<2)
result=result|(even_parity((modifier>>8)&0xff)<<3)
result=result|(even_parity(comma)<<4)
result=result|(even_parity(data)<<5)
return result
def send_fcpkt(pc_dev,macaddr,mask,data):
packet=split_short(0xfa57)+","+split_short(mask)+",0x7c,"+str(data)+","+split_short(calc_gdcc_parity(0xfa57,mask,0x7c,data))
retcode,res=submod_execcmd("send_packet@raweth",pc_dev,macaddr,"0x809",packet)
if retcode==0:
return 0,"cant send fast command <- %s"%(res)
return 1,"ok"
#############################################
def get_register(gdcc_id,reg_addr):
# get the value of a register of a gdcc
try:
gdcc = gdcc_pool.get(gdcc_id)
except Exception as e:
return 0,str(e)
#format the register address
data=split_short(reg_addr)+",0,0,0,0"
datalen=1
pktid=gener_pktid()
#send the packet
retcode,res=send_gdccpkt(gdcc["pc_dev"],gdcc["mac_addr"],2,0,pktid,datalen,data)
if retcode==0:
return 0,res
#getting the question
retcode,res=submod_execcmd("get_cpkt_byid@acq","ecal_dif",str(pktid),"0","0","0")
#getting the answer
retcode,res=submod_execcmd("get_cpkt_byid@acq","ecal_dif",str(pktid),"0","0","0")
if retcode==0:
return 0,"cant get register %x <- %s"%(reg_addr,res)
return 1,"%s" % res
def set_register(gdcc_id,reg_addr,value):
# set the value of a register of a gdcc
try:
gdcc = gdcc_pool.get(gdcc_id)
except Exception as e:
return 0,str(e)
#format the packet
data=split_short(reg_addr)+","+split_int(value)
pktid=gener_pktid()
#send the packet
retcode,res=send_gdccpkt(gdcc["pc_dev"],gdcc["mac_addr"],1,0,pktid,1,data)
if retcode==0:
return 0,res
return 1,"register set packet sent"
#############################################
[docs]def set_pktid_gdcc(gdcc_id,value):
"""set the packet id of data packets"""
#TODO unify int and hexa
retcode,res=set_register(gdcc_id,0x400c,iohtoi(value))
if retcode==0:
return 0,"cant set packet id: %s"%(res)
return 1,"ok"
#############################################
[docs]def rst_lnks_gdcc(gdcc_id,mask):
"""reset the links of an gdcc"""
# reset the links of a gdcc without any check
try:
gdcc = gdcc_pool.get(gdcc_id)
except Exception as e:
return 0,str(e)
pktid=gener_pktid()
data="0x10,2,0,0,"+split_short(int(mask))+",0x10,0,0,0,"+split_short(int(mask))+",0x10,8,0,0,"+split_short(int(mask))+",0x40,0x6,0,0,0xff,0xff,0x40,0x7,0,0,0xff,0xff,0x40,0x8,0,0,0xff,0xff"
datalen=6
retcode,res=send_gdccpkt(gdcc["pc_dev"],gdcc["mac_addr"],1,0,pktid,datalen,data)
if retcode==0:
return 0,res
return 1,"gdcc reset packet sent"
#############################################
def get_status_word(gdcc_id):
# get the status word of a gdcc
retcode,res1=get_register(gdcc_id,0x100a)
if retcode==0:
return 0,"cant get status: %s"%(res1)
retcode,res2=get_register(gdcc_id,0x100b)
if retcode==0:
return 0,"cant get status: %s"%(res2)
rawbin="%s%s"%(int2bin(int(res1[48:56],16)),int2bin(int(res2[48:56],16)))
return 1,rawbin
def get_status_chan(rawbin,channel):
if channel<=5:
j=channel-1
return rawbin[(4-j)*3+1:(4-j)*3+4]
else:
j=channel-6
return rawbin[16+(4-j)*3+1:16+(4-j)*3+4]
#############################################
[docs]def reset_n_check_gdcc(gdcc_id):
"""reset and check an gdcc and its channels"""
# reset the active ports of an gdcc, synchronize them and verify their locking
try:
gdcc = gdcc_pool.get(gdcc_id)
except Exception as e:
return 0,str(e)
#compute the mask for reset
mask=0
for p in range(gdcc["dif_nb"]):
port=int(gdcc["dif%d_port"%(p)])
print("adding %d to mask"%(port))
lmask=1<<(port-1)
mask+=lmask
print("new mask=%d"%(mask))
#resetting the links
retcode,res=rst_lnks_gdcc(gdcc_id,str(mask))
if retcode==0:
return 0,"cant reset the port %d: %s"%(port,res)
time.sleep(0.5)
#get the links status
retcode,res=get_status_word(gdcc_id)
if retcode==0:
return 0,"cant get the link status: %s"%(res)
#check every channel
statw=res
for p in range(gdcc["dif_nb"]):
port=int(gdcc["dif%d_port"%(p)])
status=get_status_chan(statw,port)
#print("status=%s"%(status))
if status!="101":
return 0,"link %d is not locked: %s"%(port,status)
return 1,"ok"
#############################################
[docs]def get_macdest_gdcc(gdcc_id):
"""get the unicast mac address of a gdcc"""
# get the mac address from a gdcc
retcode,res1=get_register(gdcc_id,0x4006)
if retcode==0:
return 0,res1
retcode,res2=get_register(gdcc_id,0x4007)
if retcode==0:
return 0,res2
retcode,res3=get_register(gdcc_id,0x4008)
if retcode==0:
return 0,res3
return 1,"%s:%s:%s:%s:%s:%s"%(res3[52:54],res3[54:56],res2[52:54],res2[54:56],res1[52:54],res1[54:56])
#############################################
[docs]def set_macdest_gdcc(gdcc_id,macaddr):
"""set the unicast mac address of a gdcc"""
# set the mac address used by a gdcc for unicast communication
try:
gdcc = gdcc_pool.get(gdcc_id)
except Exception as e:
return 0,str(e)
#split the mac address
smac=macaddr.split(":")
#set the first two bytes
retcode,res=set_register(gdcc_id,0x4006,int("0x%s%s"%(smac[4],smac[5]),16))
if retcode==0:
return 0,"cant set macdest part 1: %s" % (res)
#set the second two bytes
retcode,res=set_register(gdcc_id,0x4007,int("0x%s%s"%(smac[2],smac[3]),16))
if retcode==0:
return 0,"cant set macdest part 2: %s" % (res)
#set the third two bytes
retcode,res=set_register(gdcc_id,0x4008,int("0x%s%s"%(smac[0],smac[1]),16))
if retcode==0:
return 0,"cant set macdest part 3: %s" % (res)
#return result
return 1,"macdest set"
#############################################
[docs]def get_version_gdcc(gdcc_id):
"""get the version number of a gdcc"""
# get the version number of a gdcc
retcode,res1=get_register(gdcc_id,0x300f)
if retcode==0:
return 0,"cant get version: %s"%(res1)
retcode,res2=get_register(gdcc_id,0x300e)
if retcode==0:
return 0,"cant get version: %s"%(res2)
return 1,"%x:%x"%(int(res1[48:56],16),int(res2[48:56],16))
#*********************** CALICOES FUNCTIONS **********************************
[docs]def init_gdcc(gdcc_id,mac_addr,pc_dev,simul):
"""initialize a gdcc"""
gdcc_pool.new(gdcc_id,{"name":gdcc_id,
"mac_addr":mac_addr,
"pc_dev":pc_dev,
"trans_delay":"0",
"simul":simul,
"dif_nb":0})
return 1,"ok"
[docs]def init_fin_gdcc(gdcc_id):
"""Finalize initialization of gdcc"""
try:
gdcc = gdcc_pool.get(gdcc_id)
except Exception as e:
return 0,str(e)
retcode,res=submod_execcmd("get_name_sublist@cmod","dif",gdcc_id)
if retcode==0:
return 0,"error while getting DIFs of GDCC %s <- %s"%(gdcc["name"],res)
difs=res.split(",")
for dif_id in difs:
retcode,res=submod_execcmd("get_param@cmod",dif_id,"gdcc_port")
if retcode==0:
return 0,"error while getting gdcc_port of dif_id %s <- %s"%(dif_id,res)
gdcc["dif%d_port"%(gdcc["dif_nb"])]=res
gdcc["dif_nb"]+=1
return 1,"ok"
#############################################
[docs]def deinit_gdcc(gdcc_id):
"""deinitialize the gdcc"""
try:
gdcc = gdcc_pool.get(gdcc_id)
except Exception as e:
return 1,str(e)
gdcc_pool.remove(gdcc_id)
return 1,"ok"
#############################################
def config_once(gdcc_id,trans_delay):
# real configuration of a gdcc
try:
gdcc = gdcc_pool.get(gdcc_id)
except Exception as e:
return 0,str(e)
#getting the version number of the gdcc, just to be sure that communication is possible
retcode,res=get_version_gdcc(gdcc_id)
if retcode==0:
return 0,"%s: no connectivity: %s"%(gdcc["name"],res)
#set transmission delay
set_trans_delay_gdcc(gdcc_id,trans_delay)
#reset the links of the gdcc
retcode,res=reset_n_check_gdcc(gdcc_id)
if retcode==0:
return 0,"%s: cant reset links: %s"%(gdcc["name"],res)
time.sleep(0.5)
#set the unicast mac address
mac_addr=getHwAddr(gdcc["pc_dev"])
retcode,res=set_macdest_gdcc(gdcc_id,mac_addr);
if retcode==0:
return 0,"%s: cant set_macdest: %s" % (gdcc["name"],res)
#get back the unicast address to verify the setting
retcode,res=get_macdest_gdcc(gdcc_id)
if retcode==0:
return 0,"%s: cant get_macdest: %s" % (gdcc["name"],res)
if res!=mac_addr:
return 0,"%s: mac_addr is not correct register=%s,expected=%s"%(gdcc["name"],res,mac_addr)
return 1,"ok"
[docs]def config_gdcc(gdcc_id,trans_delay):
"""configure an gdcc"""
try:
gdcc = gdcc_pool.get(gdcc_id)
except Exception as e:
return 0,str(e)
#adapt the resilience to the config mode
retcode,res=submod_execcmd("getvar@varmod","varmod","ecal","config_mode")
if retcode==0:
print("cant get config_mode from varmod: going to debug mode")
nbtry=1
if res=="debug":
nbtry=1
else:
nbtry=3
#call configuration multiple times if necessary
if gdcc["simul"]=="0":
for _ in range(nbtry):
retcode,res=config_once(gdcc_id,trans_delay)
if retcode!=0:
break;
if retcode==0:
return 0,"%s"%(res)
return 1,res
#############################################
[docs]def dump_all_gdcc():
"""display details about registered gdccs"""
print("%d gdccs"%(gdcc_pool.length))
for _,gdcc in gdcc_pool.get_all():
print("mac addr of gdcc %s (%d) is %s"%(gdcc["name"],gdcc["id"],gdcc["mac_addr"]))
return 1,"ok"
#************************* DIF functions
[docs]def send_difpkt_gdcc(gdcc_id,difport,data):
"""send a data packet to a dif"""
try:
gdcc = gdcc_pool.get(gdcc_id)
except Exception as e:
return 0,str(e)
datalen=len(data.split(","))
packetid=0
retcode,res=send_gdccpkt(gdcc["pc_dev"],gdcc["mac_addr"],0x102,int(difport),packetid,datalen,data)
if retcode==0:
return 0,"%s"%(res)
return 1,"pkt sended"
[docs]def send_diffc_gdcc(gdcc_id,mask,data):
"""send a fast command to a dif"""
try:
gdcc = gdcc_pool.get(gdcc_id)
except Exception as e:
return 0,str(e)
retcode,res=send_fcpkt(gdcc["pc_dev"],gdcc["mac_addr"],int(mask),int(data))
if retcode==0:
return 0,"%s"%(res)
return 1,"dif fast command sended"
#********************* LINKS FUNCTIONS **************************
[docs]def get_lnks_locked_gdcc(gdcc_id):
"""get the links locked of a gdcc"""
try:
gdcc = gdcc_pool.get(gdcc_id)
except Exception as e:
return 0,str(e)
retcode,res=get_register(gdcc_id,0x1022)
if retcode==0:
return 0,"cant lock links: %s"%(res)
return 1,"%d"%(int(res[48:56],16))
#********************** STATUS FUNCTIONS ***************************
[docs]def get_status_gdcc(gdcc_id):
"""get the status of every gdcc channel"""
retcode,res=get_status_word(gdcc_id)
if retcode==0:
return 0,"%s"%(res)
rawbin=res
fineres=""
for channel in range(1,11,1):
fineres+="%d:%s|"%(channel,get_status_chan(rawbin,channel))
return 1,fineres
#parser par bloc de 3 bits pour obtenir l'etat de chaque lien avec le codage:
# "000" = starting up
# "001" = sending_idle_stream
# "010" = sending loopback command. Waiting for loopback to ack.
# "011" = sending random data. Shows Remote is looped.
# "100" = sending link start.
# "101" = Link is up
# "111" = Has all gone wrong.
#************** TRANSMISSION DELAY FUNCTIONS ***********************
[docs]def get_trans_delay_gdcc(gdcc_id):
"""get the transmission delay value of a gdcc"""
# get the transmission delay value of a gdcc
retcode,res=get_register(gdcc_id,0x4002)
if retcode==0:
return 0,"cant get transmission delay: %s"%(res)
return 1,"%d"%(int(res[48:56],16))
[docs]def set_trans_delay_gdcc(gdcc_id,delay):
"""set the transmission delay value of a gdcc"""
# set the transmission delay value of a gdcc
try:
gdcc = gdcc_pool.get(gdcc_id)
except Exception as e:
return 0,str(e)
retcode,res=set_register(gdcc_id,0x4002,int(delay))
if retcode==0:
return 0,"cant set transmission delay: %s"%(res)
gdcc["trans_delay"]=delay
return 1,"delay set"
#********************** OTHER FUNCTIONS ***************************
[docs]def get_difnb_gdcc(gdcc_id):
"""returns the number of dif attached to a gdcc"""
try:
gdcc = gdcc_pool.get(gdcc_id)
except Exception as e:
return 0,str(e)
return 1,str(gdcc["dif_nb"])
#*******************************************************************
#************************ Global GDCC reset ************************
#*********************** from enable register bit #7 **************
[docs]def set_global_reset_gdcc(gdcc_id):
"""set global reset"""
#set bit 7 of enable register
retcode,res=set_register(gdcc_id,0x4000,int(128))
if retcode==0:
return 0,"cant set bit 7 of enable register: %s"%(res)
#return result
return 1,"global reset set"
#************************* Pattern generator *************************
#*********************************************************************
#************************** Enable random pakt generator *************
[docs]def set_pktgen_enable_gdcc(gdcc_id,enablepktgen):
"""set value of enable register for gdcc pkt generator"""
#set enable gdcc pkt generator
retcode,res=set_register(gdcc_id,0x4000,int(enablepktgen))
if retcode==0:
return 0,"cant enable pkt generator: %s" % (res)
return 1,"enable gdcc pkt generator setted"
#*************************** control register configuration ***********
[docs]def set_pktgen_control_gdcc(gdcc_id,control):
"""set value of control register for the gdcc pkt generator"""
#set the bytes register control
retcode,res=set_register(gdcc_id,0x4010,int(control))
if retcode==0:
return 0,"cant set controller register: %s"%(res)
return 1,"controller register setted"
#*****************read control register **********************************
[docs]def get_register_control_gdcc(gdcc_id):
"""get the register control value"""
# get the register control value
retcode,res1=get_register(gdcc_id,0x4010)
if retcode==0:
return 0,"cant get control register: %s" % (res1)
return 1,"%x"%(int(res1[48:56],16))
#************** register parameters for pkt generator ********************
[docs]def set_pktgen_parameter_gdcc(gdcc_id,pkt_size,pkt_nbr,delay_btwpkt,pkt_seed):
"""set the parameters for gdcc pkt generator"""
#set the packet size
retcode,res=set_register(gdcc_id,0x4011,int(pkt_size))
if retcode==0:
return 0,"cant set pktgen pkt size: %s"%(res)
#set the number of packets
retcode,res=set_register(gdcc_id,0x4012,int(pkt_nbr))
if retcode==0:
return 0,"cant set pkygen pkt number: %s"%(res)
#set the delay between packet
retcode,res=set_register(gdcc_id,0x4013,int(delay_btwpkt))
if retcode==0:
return 0,"cant set pktgen delay between paket: %s"%(res)
#set the random seed
retcode,res=set_register(gdcc_id,0x4014,int(pkt_seed))
if retcode==0:
return 0,"cant set pktgen random seed: %s"%(res)
#return result
return 1,"pktgen set"