class LibgseWrapper (object): ''' Wrapper for the libgse library. Example usage:- gse = LibgseWrapper() # create PDU pdu_label = [0xAB, 0xCD, 0xEF, 0x01, 0x23, 0x45] pdu_protocol = 0x1234 pdu_bytes = [0xA5]*60 # encapsulate into very small GSE packets gse.encap_push_pdu(pdu_bytes, label=pdu_label, protocol=pdu_protocol) gse_pkt1 = gse.encap_pop_gse(max_bytes=50) gse_pkt2 = gse.encap_pop_gse(max_bytes=50) # decapsulate back into PDU gse.decap_push_gse(gse_pkt1) gse.decap_push_gse(gse_pkt2) pdu = gse.decap_pop_pdu() rx_pdu_label = pdu[0] rx_pdu_protocol = pdu[1] rx_pdu_bytes = pdu[2] ''' def __init__(self, num_channels=1, fifo_size=1024, libgse_path=None): self.num_channels = num_channels self.fifo_size = fifo_size if libgse_path: self.libgse_path = libgse_path else: self.libgse_path = find_library("gse") self.libgse = CDLL(self.libgse_path) # Initialize libgse interface self.libgse.gse_create_vfrag_with_data.argtypes = [POINTER(c_void_p), c_size_t, c_size_t, c_size_t, POINTER(c_ubyte), c_size_t] self.libgse.gse_create_vfrag_with_data.restype = c_ushort self.libgse.gse_get_vfrag_start.argtypes = [c_void_p] self.libgse.gse_get_vfrag_start.restype = POINTER(c_ubyte) self.libgse.gse_get_vfrag_length.argtypes = [c_void_p] self.libgse.gse_get_vfrag_length.restype = c_size_t self.libgse.gse_free_vfrag.argtypes = [POINTER(c_void_p)] self.libgse.gse_free_vfrag.restype = c_ushort self.libgse.gse_encap_init.argtypes = [c_ubyte, c_size_t, POINTER(c_void_p)] self.libgse.gse_encap_init.restype = c_ushort self.libgse.gse_encap_receive_pdu.argtypes = [c_void_p, c_void_p, c_ubyte*6, c_ubyte, c_ushort, c_ubyte] self.libgse.gse_encap_receive_pdu.restype = c_ushort self.libgse.gse_encap_get_packet_copy.argtypes = [POINTER(c_void_p), c_void_p, c_size_t, c_ubyte] self.libgse.gse_encap_get_packet_copy.restype = c_ushort self.libgse.gse_encap_get_packet_copy.argtypes = [POINTER(c_void_p), c_void_p, c_size_t, c_ubyte] self.libgse.gse_encap_get_packet_copy.restype = c_ushort self.libgse.gse_encap_release.argtypes = [c_void_p] self.libgse.gse_encap_release.restype = c_ushort self.libgse.gse_deencap_init.argtypes = [c_ubyte, POINTER(c_void_p)] self.libgse.gse_deencap_init.restype = c_ushort self.libgse.gse_deencap_packet.argtypes = [c_void_p, c_void_p, POINTER(c_ubyte), c_ubyte*6, POINTER(c_ushort), POINTER(c_void_p), POINTER(c_ushort)] self.libgse.gse_deencap_packet.restype = c_ushort self.libgse.gse_deencap_release.argtypes = [c_void_p] self.libgse.gse_deencap_release.restype = c_ushort # Allocate C data storage self.c_encap_state = c_void_p() self.c_deencap_state = c_void_p() self.c_pdu_vfrag = c_void_p() self.c_gse_vfrag = c_void_p() self.c_data = (c_ubyte*65536)() self.c_label = (c_ubyte*6)() self.c_labeltype = c_ubyte() self.c_protocol = c_ushort() self.c_len = c_ushort() # Initialize Rx PDU queues self.rx_pdus = [[]]*num_channels # Initialize encapsulator and deencapsulator status = self.libgse.gse_encap_init(self.num_channels, self.fifo_size, byref(self.c_encap_state)) if status != 0: raise LibgseWrapperError('libgse/gse_encap_init: {}'.format(hex(status))) status = self.libgse.gse_deencap_init(self.num_channels, byref(self.c_deencap_state)) if status != 0: self.libgse.gse_encap_release(self.c_encap_state) raise LibgseWrapperError('libgse/gse_deencap_init: {}'.format(hex(status))) def __del__(self): self.libgse.gse_encap_release(self.c_encap_state) self.libgse.gse_deencap_release(self.c_deencap_state) def encap_push_pdu(self, pdu_bytes, channel=0, label=[1,2,3,4,5,6], protocol=0x0800): ''' Push a PDU into the Tx packet buffer The contents of the PDU, pdu_bytes, should be a sequence of bytes. ''' if channel < 0 or channel >= self.num_channels: raise LibgseWrapperError('Channel number out of range: {}'.format(channel)) if len(label) != 6: raise LibgseWrapperError('Only 6-byte labels supported: {}'.format(label)) num_bytes = min(len(pdu_bytes), 65536) for n in range(num_bytes): self.c_data[n] = pdu_bytes[n] for n in range(6): self.c_label[n] = label[n] self.c_labeltype = c_ubyte(0) self.c_protocol = c_ushort(protocol) status = self.libgse.gse_create_vfrag_with_data(byref(self.c_pdu_vfrag), num_bytes, gse_max_header_length, gse_max_trailer_length, self.c_data, num_bytes) if status != 0: raise LibgseWrapperError('libgse/gse_create_vfrag_with_data: {}'.format(hex(status))) status = self.libgse.gse_encap_receive_pdu(self.c_pdu_vfrag, self.c_encap_state, self.c_label, self.c_labeltype, self.c_protocol, channel) if status != 0: raise LibgseWrapperError('libgse/gse_encap_receive_pdu: {}'.format(hex(status))) def encap_pop_gse(self, max_bytes=4096, channel=0): ''' Pop a GSE packet no bigger than max_bytes from the Tx packet buffer. Returns a list of byte values if the buffer is non-empty, otherwise an empty list. ''' if channel < 0 or channel >= self.num_channels: raise LibgseWrapperError('Channel number out of range: {}'.format(channel)) status = self.libgse.gse_encap_get_packet_copy(byref(self.c_gse_vfrag), self.c_encap_state, max_bytes, channel) if status == 0x0302: # buffer empty return [] elif status != 0: raise LibgseWrapperError('libgse/gse_encap_get_packet_copy: {}'.format(hex(status))) buf = self.libgse.gse_get_vfrag_start(self.c_gse_vfrag) lng = self.libgse.gse_get_vfrag_length(self.c_gse_vfrag) pkt = [0]*lng for n in range(lng): pkt[n] = buf[n] # remove unnecessary padding bytes added by libgse gse_len = (pkt[0] % 16)*256 + pkt[1] gse_pkt = pkt[0:gse_len+2] status = self.libgse.gse_free_vfrag(self.c_gse_vfrag) if status != 0: raise LibgseWrapperError('libgse/gse_free_vfrag: {}'.format(hex(status))) return gse_pkt def decap_push_gse(self, pkt, channel=0): ''' Push a GSE packet (sequence of byte values) into the Rx packet buffer. ''' if channel < 0 or channel >= self.num_channels: raise LibgseWrapperError('Channel number out of range: {}'.format(channel)) num_bytes = min(len(pkt), 65536) for n in range(num_bytes): self.c_data[n] = pkt[n] status = self.libgse.gse_create_vfrag_with_data(self.c_gse_vfrag, num_bytes, 0, 0, self.c_data, num_bytes) if status != 0: raise LibgseWrapperError('libgse/gse_create_vfrag_with_data: {}'.format(hex(status))) status = self.libgse.gse_deencap_packet(self.c_gse_vfrag, self.c_deencap_state, byref(self.c_labeltype), self.c_label, byref(self.c_protocol), byref(self.c_pdu_vfrag), byref(self.c_len)) if status == 0x0901: # PDU completed buf = self.libgse.gse_get_vfrag_start(self.c_pdu_vfrag) lng = self.libgse.gse_get_vfrag_length(self.c_pdu_vfrag) label = [0]*6 for n in range(6): label[n] = self.c_label[n] protocol = self.c_protocol.value pdu_bytes = [0]*lng for n in range(lng): pdu_bytes[n] = buf[n] self.rx_pdus[channel].append([label, protocol, pdu_bytes]) elif status != 0: raise LibgseWrapperError('libgse/gse_deencap_packet: {}'.format(hex(status))) def decap_pop_pdu(self, channel=0): ''' Pop a PDU from the Rx packet buffer. Returns a list of three items: a 6-element list of label byte values, an integer representing the protocol type, and another list of byte values representing the contents of the PDU. If the buffer is empty (no PDUs available), then returns an empty list. ''' if channel < 0 or channel >= self.num_channels: raise LibgseWrapperError('Channel number out of range: {}'.format(channel)) if len(self.rx_pdus[channel]) > 0: return self.rx_pdus[channel].pop() else: return []