Cole Walker 916f9da112 [PTP] Update cgu parser for Logan Beach NIC
Intel Logan Beach NICs have additional fields in the cgu output,
resulting in failures when converting it into a dict. Updated the logic
for cgu_output_to_dict() to find the start and end of the "input" table.
Once the start and end lines of the table are identified, then the other
required fields can be located based on the known offset from the table.

This also allows any future lines added to the table to handled without
requiring additional code changes.

Updated the unit tests to cover both the Logan Beach and Westport Channel
cgu output formats.

Test plan:
PASS: Unit tests passing
PASS: Build notificationservice-base image and test on both NIC
types.

Story: 2010270
Task: 46870

Signed-off-by: Cole Walker <cole.walker@windriver.com>
Change-Id: Ib6716f38ea3c64a68e7162bb5d4f2154fa399a8c
2022-11-17 16:33:33 -05:00

138 lines
5.1 KiB
Python

#
# Copyright (c) 2022 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
import logging
import os
import re
from trackingfunctionsdk.common.helpers import constants
from trackingfunctionsdk.common.helpers import log_helper
LOG = logging.getLogger(__name__)
log_helper.config_logger(LOG)
class CguHandler:
def __init__(self, config_file, nmea_serialport=None, pci_addr=None,
cgu_path=None):
self.config_file = config_file
self.nmea_serialport = nmea_serialport
self.pci_addr = pci_addr
self.cgu_path = cgu_path
self.cgu_output_raw = ""
self.cgu_output_parsed = {}
def get_gnss_nmea_serialport_from_ts2phc_config(self):
# Read a tstphc config file and return the ts2phc.nmea_serialport
nmea_serialport = None
try:
with open(self.config_file, 'r') as infile:
for line in infile:
if constants.NMEA_SERIALPORT in line:
nmea_serialport = line.split(' ')[1].strip('\n')
break
self.nmea_serialport = nmea_serialport
return
except (FileNotFoundError, PermissionError) as err:
LOG.error(err)
raise
def convert_nmea_serialport_to_pci_addr(self, log_file="/logs/kern.log"):
# Parse the nmea_serialport value into a PCI address so that we can
# later find the cgu
# Returns the address or None
pci_addr = None
# Get only the ttyGNSS_1800_0 portion of the path
nmea_serialport = self.nmea_serialport.split('/')[2]
LOG.debug("Looking for nmea_serialport value: %s" % nmea_serialport)
with open(log_file, 'r') as file:
for line in file:
if nmea_serialport in line:
# Regex split to make any number of spaces the delimiter
# Eg.: ... ice 0000:18:00.0: ttyGNSS_1800_0 registered
# Becomes: 0000:18:00.0
pci_addr = re.split(' +', line)[7].strip(':')
LOG.debug("Found with PCI addr: %s" % pci_addr)
break
self.pci_addr = pci_addr
def get_cgu_path_from_pci_addr(self):
# Search for a cgu file using the given pci address
cgu_path = "/ice/" + self.pci_addr + "/cgu"
if os.path.exists(cgu_path):
LOG.debug("PCI address %s has cgu path %s" %
(self.pci_addr, cgu_path))
self.cgu_path = cgu_path
return
else:
LOG.error("Could not find cgu path for PCI address %s" %
self.pci_addr)
raise FileNotFoundError
def read_cgu(self):
# Read a given cgu path and return the output in a parseable structure
cgu_output = None
if os.path.exists(self.cgu_path):
with open(self.cgu_path, 'r') as infile:
cgu_output = infile.read()
self.cgu_output_raw = cgu_output
def cgu_output_to_dict(self):
# Take raw cgu output and parse it into a dict
cgu_output = self.cgu_output_raw.splitlines()
cgu_dict = {'input': {},
'EEC DPLL': {
'Current reference': '',
'Status': ''
},
'PPS DPLL': {
'Current reference': '',
'Status': '',
'Phase offset': ''
}
}
# Get the input state table start and end lines
# Can vary in length depending on NIC types
for index, line in enumerate(cgu_output):
if "input (idx)" in line:
table_start = index + 2
if "EEC DPLL:" in line:
dpll_start = index
table_end = index - 1
for line in cgu_output[table_start:table_end]:
# Build a dict out of the table
dict_to_insert = {
re.split(' +', line)[1]: {
'state': re.split(' +', line)[4],
'priority': {
'EEC': re.split(' +', line)[6],
'PPS': re.split(' +', line)[8]
}
}
}
cgu_dict['input'].update(dict_to_insert)
# Add the DPLL data below the table
# Set the line offsets for each item we want
eec_current_ref = dpll_start + 1
eec_status = dpll_start + 2
pps_current_ref = dpll_start + 5
pps_status = dpll_start + 6
pps_phase_offset = dpll_start + 7
cgu_dict['EEC DPLL']['Current reference'] = \
re.split('[ \t]+', cgu_output[eec_current_ref])[-1]
cgu_dict['EEC DPLL']['Status'] = re.split('[ \t]+', cgu_output[eec_status])[-1]
cgu_dict['PPS DPLL']['Current reference'] = \
re.split('[ \t]+', cgu_output[pps_current_ref])[-1]
cgu_dict['PPS DPLL']['Status'] = re.split('[ \t]+', cgu_output[pps_status])[-1]
cgu_dict['PPS DPLL']['Phase offset'] = \
re.split('[ \t]+', cgu_output[pps_phase_offset])[-1]
self.cgu_output_parsed = cgu_dict