功能点:
1.调用动态库函数作为命令。如:get_portState,slot_present等。
2.调用可执行程序作为命令。如:iio-info,cpld-upgrade
3.满足tab键补全和上键补全历史记录
难点:
1.进程和线程同时使用stdin,需要加锁。本示例中锁为 stop_thread
2.实现命令的方式有三种,三种方式各不相同
- 直接写
- 调用动态库函数------lib = ctypes.CDLL(‘/usr/lib/libfpga.so’) ; lib.fpga_is_slot_present.[argtypes|restype]
- 调用可执行文件------subprocess.Popen,采用这种方式,实现可执行文件实时的打印及输入
3.获取数据后对数据的解析
import click
import subprocess
import sys
import ctypes
import time
import threading
import shlex
import re
import os
import readline
stop_thread = threading.Event()
'''
c struct
typedef struct PORTSTATUSINFO
{
char portName[64];
uint16_t linkStatus;
}T_PORTSTATUSINFO;
'''
class T_PORTSTATUSINFO(ctypes.Structure):
_fields_ = [
("portName",ctypes.c_char *64),
("linkStatus",ctypes.c_uint16)
]
lib = ctypes.CDLL('/usr/lib/libfpga.so')
@click.group()
def cli():
pass
history_index = 0
history = []
def custom_completer(text,state):
commands = cli.commands
options = [cmd.name for cmd in commands.values() if cmd.name.startswith(text)]
if state < len(options):
return options[state]
else:
return None
readline.set_completer_delims('\t\n;')
readline.set_completer(custom_completer)
readline.parse_and_bind('tab: complete')
def get_user_input(user_input):
global history_index
char = user_input[0]
if char == '\x1b':
sequence = user_input[1]
if sequence == '[A':
if history_index > 0:
history_index -= 1
return history[history_index] if history else ''
elif sequence == '[B':
if history_index < len(history) - 1 :
history_index += 1
return history[history_index] if history else ''
elif sequence == '[C':
pass
elif sequence == '[D':
pass
else:
return sequence
elif char == '\n':
history.append(readline.get_line_buffer())
history.append(input)
history_index = len(history)
return user_input
elif char == '\t':
readline.insert_text(readline.get_completer().complete(readline.get_line_buffer()))
readline.redisplay()
else:
readline.insert_text(user_input)
return user_input
@cli.command()
@click.argument('input_file', type=click.Path(exists=True))
@click.argument('output_file', type=click.Path())
@click.option('--block-size', '-b', default=1024, help='Block size in bytes')
@click.option('--count', '-c', default=1, help='Number of blocks to copy')
def dd(input_file, output_file, block_size,count):
"""EMCC, SD read and write test commands."""
if count < 0:
count_arg = ''
else:
count_arg = 'count=' + str(count)
cmd = ['dd', 'if=' + input_file, 'of=' + output_file, 'bs=' + str(block_size), count_arg,'status=progress']
subprocess.run(cmd)
@cli.command()
@click.argument('help', default='')
def interrupt_count(help):
""" Interrupt count query command"""
try:
if help == "help":
click.echo("please input command [interrupt-count]")
else:
result = subprocess.run(['cat','/proc/interrupts'] , capture_output=True, text=True, check=True)
click.echo(result.stdout)
except subprocess.CalledProcessError as e:
click.echo(f"Error:{e}", err=True)
@cli.command()
@click.argument('hd', type=str,default='')
@click.option('--name','-n',type=str,help='port name value:[PORT_NMS1,PORT_NMS1,PORT_ETH1,...]')
def get_portState(hd,name):
'''EXI Ethernet Port Status Query Command'''
try:
if hd == 'help':
click.echo('=========================get-portstate=========================\n')
click.echo('Options:\n')
click.echo('\t -n,\t--name\t\t\tport name\n')
click.echo('Example:\n')
click.echo('get-portstate -n name\n')
click.echo('name = PORT_NMS ,PORT_NMS1 ,PORT_NMS2 ,PORT_ETH ,PORT_ETH1 ,PORT_ETH2\n')
else:
data = T_PORTSTATUSINFO()
data.portName = name.encode('utf-8')
data.linkStatus = 0xff
lib.get_portState.argtypes = [ctypes.POINTER(T_PORTSTATUSINFO)]
lib.get_portState.restype = ctypes.c_int
result = lib.get_portState(ctypes.byref(data))
if result != 0:
click.echo(f"Error: get-portState failed with error code {result}")
else:
if data.linkStatus == 0:
click.echo(f"port {name} port status is link down")
elif data.linkStatus == 1:
click.echo(f"port {name} port status is link up")
except Exception as e:
click.echo(f"Error:{e}")
@cli.command()
@click.argument('hd', type=str,default='')
@click.option('--id','-i',type=int,help='port name value:[1~8]')
def slot_present(hd,id):
'''Command to query the status of each board in place'''
try:
present =ctypes.c_bool()
present_ptr = ctypes.pointer(present)
if hd == 'help':
click.echo('=========================slot_present=======================\n')
click.echo('Options:\n')
click.echo('\t -i,\t--id\t\t\slot id\n')
click.echo('Example:\n')
click.echo('slot-present -i id\n')
click.echo('id = 1~8\n')
else:
lib.fpga_is_slot_present.argtypes = [ctypes.c_int,ctypes.POINTER(ctypes.c_bool)]
lib.fpga_is_slot_present.restype = ctypes.c_int
result = lib.fpga_is_slot_present(id,present_ptr)
if result != 0:
click.echo(f"Error: slot_present failed with error code {result}")
else:
if present:
click.echo(f"slot{id} is ON\n")
else:
click.echo(f"slot{id} is DOWN\n")
except Exception as e:
click.echo(f"Error:{e}")
def get_cu_temp(id):
'''get_cu_temp '''
try:
temp =ctypes.c_float()
temp_ptr = ctypes.pointer(temp)
lib.get_cu_temp.argtypes = [ctypes.c_int,ctypes.POINTER(ctypes.c_float)]
lib.get_cu_temp.restype = ctypes.c_int
result = lib.get_cu_temp(id,temp_ptr)
if result != 0:
click.echo(f"Error: get_cu_temp failed with error code {result}")
else:
pass
click.echo(f"cu temperature :" + str(temp.value) + "℃")
except Exception as e:
click.echo(f"Error:{e}")
def get_panel_temp():
'''get_panel_temp '''
try:
lib.cpld_enable_panel_temperature_output.argtypes = [ctypes.c_int]
lib.cpld_enable_panel_temperature_output.restype = ctypes.c_int
result = lib.cpld_enable_panel_temperature_output(1)
if result != 0:
click.echo(f"Error: get_panel_temp failed with error code {result}")
else:
pass
temp =ctypes.c_float()
temp_ptr = ctypes.pointer(temp)
lib.cpld_get_panel_board_temperature.argtypes = [ctypes.POINTER(ctypes.c_float)]
lib.cpld_get_panel_board_temperature.restype = ctypes.c_int
result = lib.cpld_get_panel_board_temperature(temp_ptr)
if result != 0:
click.echo(f"Error: get_panel_temp failed with error code {result}")
else:
pass
click.echo(f"panel temperature :" + str(temp.value) + "℃")
except Exception as e:
click.echo(f"Error:{e}")
def get_fan_temp(index):
'''get_fan_temp '''
try:
lib.cpld_enable_fan_temperature_output.argtypes = [ctypes.c_int]
lib.cpld_enable_fan_temperature_output.restype = ctypes.c_int
result = lib.cpld_enable_fan_temperature_output(1)
if result != 0:
click.echo(f"Error: get_fan_temp failed with error code {result}")
else:
pass
temp =ctypes.c_float()
temp_ptr = ctypes.pointer(temp)
lib.cpld_get_fan_board_temperature.argtypes = [ctypes.c_int,ctypes.POINTER(ctypes.c_float)]
lib.cpld_get_fan_board_temperature.restype = ctypes.c_int
result = lib.cpld_get_fan_board_temperature(index,temp_ptr)
if result != 0:
click.echo(f"Error: get_fan_temp failed with error code {result}")
else:
pass
click.echo(f"fan tempeture :" + str(temp.value) + "℃")
except Exception as e:
click.echo(f"Error:{e}")
@cli.command()
@click.argument('card', type=str,default='')
@click.option('--id','-i',type=int,help='cu_41 : -i 0 ; cu_42 : -i 1')
def get_temp(card,id):
'''Temperature query command'''
try:
if card == 'help':
click.echo('=========================get_cu_temp=========================\n')
click.echo('Options:\n')
click.echo('\t -i,\t--id\t\t\tcu/fan/psu id\n')
click.echo('Example:\n')
click.echo('panel temp: get-temp panel \n')
click.echo('cu41 temp: get-temp cu -i 0 \n')
click.echo('cu42 temp: get-temp cu -i 1 \n')
click.echo('fan#1 temp: get-temp fan -i 1 \n')
click.echo('fan#2 temp: get-temp fan -i 2 \n')
click.echo('fan#3 temp: get-temp fan -i 3 \n')
click.echo('psu#1 temp: get-temp psu -i 1 \n')
click.echo('psu#2 temp: get-temp psu -i 2 \n')
elif card == 'panel':
get_panel_temp()
elif card == 'fan':
if id > 0 and id < 4:
get_fan_temp(id)
else:
click.echo('id :1~3')
elif card == 'cu':
if id == 0 or id == 1 :
get_cu_temp(id)
else:
click.echo('id :0~2')
elif card == 'psu':
if id == 1 or id == 2 :
ctx = click.get_current_context()
ctx.invoke(psu, iardtype=str(id), temperature='-t')
else:
click.echo('id :1~2')
else:
click.echo('Please input [panel,cu ,fan, psu]')
except Exception as e:
click.echo(f"Error:{e}")
@cli.command()
@click.argument('bus', type=str,default='')
@click.argument('obj', type=str,default='')
@click.argument('objfront', type=str,default='')
@click.argument('objbehind', type=str,default='')
@click.argument('opfront', type=str,default='')
@click.argument('opmiddle', type=str,default='')
@click.argument('opbehind', type=str,default='')
def mdio(bus,obj,objfront,objbehind,opfront,opmiddle,opbehind):
'''SMI read and write commands'''
try:
command=['/usr/bin/mdio']
if bus == 'help':
result = subprocess.run(['/usr/bin/mdio','-h'],capture_output=True, text=True, check=True)
else:
if bus != '':
command.append(bus)
if obj != '':
command.append(obj)
if objfront != '':
command.append(objfront)
if objbehind != '':
command.append(objbehind)
if opfront != '':
command.append(opfront)
if opmiddle != '':
command.append(opmiddle)
if opbehind != '':
command.append(opbehind)
result = subprocess.run(command,capture_output=True, text=True, check=True)
click.echo(result.stdout.strip())
except subprocess.CalledProcessError as e:
click.echo(f'Error: {e}')
@cli.command()
@click.argument('hd', type=str,default='')
@click.option('--version','-v','version', type=str, help='bus id',flag_value='-v')
@click.option('--iardtype','-i', type=str, help='device address',default='3')
@click.option('--ktype','-k', type=str, help='register address',default='3')
@click.option('--protect','-p','protect', type=str, help='num of register',flag_value='-p')
@click.option('--temperature','-t', 'temperature',type=str, help='register address bandwith',flag_value='-t')
@click.option('--file','-f','file', type=str, help='value',flag_value='-f')
@click.option('--alarm','-a','alarm', type=str, help='value',flag_value='-a')
@click.option('--manufacture','-m','manufacture', type=str, help='value',flag_value='-m')
@click.option('--read','-r','read', type=str, help='value',flag_value='-r')
def psu(hd,version,iardtype,ktype,protect,temperature,file,alarm,manufacture,read):
''' psu'''
try:
command=['/usr/bin/psu']
if version == '-v':
command.append('-v')
if iardtype != '3':
command.append('-i')
command.append(iardtype)
if ktype != '3':
command.append('-k')
command.append(ktype)
if protect == '-p':
command.append('-p')
if temperature == '-t':
command.append('-t')
if file == '-f':
command.append('-f')
if alarm == '-a':
command.append('-a')
if manufacture == '-m':
command.append('-m')
if read == '-r':
command.append('-r')
if hd == 'help':
result = subprocess.run(['/usr/bin/psu','--help'],capture_output=True, text=True, check=True)
else:
result = subprocess.run(command,capture_output=True, text=True, check=True)
click.echo(result.stdout.strip())
except subprocess.CalledProcessError as e:
click.echo(f'Error: {e}')
@cli.command()
@click.argument('hd', type=str,default='')
@click.option('-w', 'opera', flag_value='-w')
@click.option('-r', 'opera', flag_value='-r')
@click.option('-g', 'opera', flag_value='-g')
@click.option('--slot','-s', type=str,help='slot id')
@click.option('--file','-f', type=click.Path(exists=True),help='filename')
@click.option('--offset','-o', type=str,help='offset')
@click.option('--length','-l', type=str,help='lenght')
def inventory(hd,opera,slot,file,offset,length):
'''EEPROM read and write commands. {panel|fan|cu|exi|psu}'''
try:
if hd == 'help':
result = subprocess.run(['/usr/bin/inventory', '--help'],capture_output=True, text=True, check=True)
click.echo(result.stdout.strip())
elif opera.lower() == '-w':
if slot in ['cu41','cu42']:
result = subprocess.run(['/usr/bin/fpga_tool', str('-w'), str('-a'),str('0x18') ,str('-v'), str('0x0')], capture_output=True, text=True, check=True)
result = subprocess.run(['/usr/bin/inventory', str('-w'), str('-s'),slot, str('-f'), file], capture_output=True, text=True, check=True)
result = subprocess.run(['/usr/bin/fpga_tool', str('-w'), str('-a'), str('0x18'), str('-v') ,str('0x1')], capture_output=True, text=True, check=True)
elif slot == 'slot40' or slot == 'fan31' or slot == 'fan32' or slot == 'fan33':
address = '0x0c'
value = '0x1'
bus = '0x3'
if slot == 'slot40':
device = '0x60'
address = '0x04'
value = '0x10'
bus = '0x2'
elif slot == 'fan31':
device = '0x64'
elif slot == 'fan32':
device = '0x65'
elif slot == 'fan33':
device = '0x66'
result = subprocess.run(['/usr/bin/fpga_i2c', str('-w'), str('-b'), bus, str('-d'), device, str('-a'), address, str('-p'), str('2'), str('-v'), str('0x0')], capture_output=True, text=True, check=True)
result = subprocess.run(['/usr/bin/inventory', str('-w'), str('-s'), slot ,str('-f'), file], capture_output=True, text=True, check=True)
result = subprocess.run(['/usr/bin/fpga_i2c', str('-w'), str('-b'), bus, str('-d'), device ,str('-a') ,address, str('-p') ,str('2') ,str('-v'), value], capture_output=True, text=True, check=True)
elif slot == 'slot1~8':
'''line card, cpld_tool'''
pass
elif slot == 'slot0' or slot == 'psu21' or slot == 'psu22' or slot == 'mux1' or slot == 'mux2' or slot == 'mux3' or slot == 'mux4':
result = subprocess.run(['/usr/bin/inventory',str('-w'), str('-s'), slot ,str('-f'), file], capture_output=True, text=True, check=True)
elif opera.lower() == '-g':
result = subprocess.run(['/usr/bin/inventory',str('-g'),str('-s'), slot],capture_output=True, text=True, check=True)
click.echo(result.stdout.strip())
elif opera.lower() == '-r':
result = subprocess.run(['/usr/bin/inventory',str('-r'),str('-s'), slot,str('-o'), offset,str('-l'),length],capture_output=True, text=True, check=True)
click.echo(result.stdout.strip())
except subprocess.CalledProcessError as e:
click.echo(f'Error: {e}')
@cli.command()
@click.argument('hd', type=str,default='')
@click.option('--bus','-b', type=str, help='bus id',default='')
@click.option('--device','-d', type=str, help='device address')
@click.option('--address','-a', type=str, help='register address')
@click.option('--num','-n', type=str, help='num of register',default='')
@click.option('--bandwidth','-p', type=str, help='register address bandwith',default='')
@click.option('-w', 'opera', flag_value='-w')
@click.option('-r', 'opera', flag_value='-r')
@click.option('--value','-v', type=str,multiple=True, help='value',default='')
def fpga_i2c(hd,bus,device,address,num,bandwidth,opera,value):
'''I2C read and write commands'''
try:
value_list = list(value)
command=['/usr/bin/fpga_i2c',str('-b'), bus, str('-d') ,device ,str('-a'), address ,str('-n'), num ,str('-p'), bandwidth, str(opera)]
if hd == 'help':
result = subprocess.run(['/usr/bin/fpga_i2c', str('--help')],capture_output=True, text=True, check=True)
elif opera == '-w':
for i in range(int(num)):
command += [str('-v'),value_list[int(i)]]
result = subprocess.run(command,capture_output=True, text=True, check=True)
elif opera == '-r':
result = subprocess.run(['/usr/bin/fpga_i2c',str('-b'), bus, str('-d') ,device ,str('-a'), address ,str('-n'), num ,str('-p'), bandwidth, str(opera)],capture_output=True, text=True, check=True)
click.echo(result.stdout.strip())
except subprocess.CalledProcessError as e:
click.echo(f'Error: {e}')
@cli.command()
@click.argument('hd', type=str,default='')
@click.option('--fan','-f', type=str, help='fan1 | fan2 | fan3',default='')
@click.option('--opera','-o', type=str, help='read/low/middle/height',default='')
def fan_speed(hd,fan,opera):
'''fan-speed'''
fan_address = ['0x64','0x65','0x66']
fan_id = ['fan1','fan2','fan3']
ctx = click.get_current_context()
if opera == 'read' :
ctx.invoke(fpga_i2c, bus='3',device=fan_address[fan_id.index(fan)], address='0x80' , num='4', bandwidth='2', opera='-r')
elif opera == 'middle':
ctx.invoke(fpga_i2c, bus='3',device=fan_address[fan_id.index(fan)], address='0x80' , num='4', bandwidth='2', opera='-w',value=('0x5b', '0x8f', '0xcc', '0xcc'))
elif opera == 'low':
ctx.invoke(fpga_i2c, bus='3',device=fan_address[fan_id.index(fan)], address='0x80' , num='4', bandwidth='2', opera='-w',value=('0x70', '0x3d', '0xcc', '0xcc'))
elif opera == 'height':
ctx.invoke(fpga_i2c, bus='3',device=fan_address[fan_id.index(fan)], address='0x80' , num='4', bandwidth='2', opera='-w',value=('0xcc', '0xcc', '0xcc', '0xcc'))
if hd == 'help':
click.echo('please input fan-speed -f [fan1 | fan2 | fan3] -o [read | low | middle | height]')
@cli.command()
@click.argument('hd', type=str,default='')
@click.option('-w', 'opera', flag_value='-w')
@click.option('-r', 'opera', flag_value='-r')
@click.option('--address','-a', type=str, help='address')
@click.option('--num','-n', type=str, help='num of register',default='')
@click.option('--value','-v', type=str, help='value',default='')
def fpga_tool(hd,opera,address,num,value):
''' reset sub card, CU main/backup, board in place'''
try:
if hd == 'help':
result = subprocess.run(['/usr/bin/fpga_tool', str('--help')],capture_output=True, text=True, check=True)
else:
result = subprocess.run(['/usr/bin/fpga_tool', str('-a') ,address, opera ,str('-n'),num,str('-v'),value],capture_output=True, text=True, check=True)
print(hd)
click.echo(result.stdout.strip())
except subprocess.CalledProcessError as e:
click.echo(f'Error: {e}')
@cli.command()
@click.argument('opera', type=str, default='')
def get_id(opera):
'''get_id'''
if opera == 'help':
click.echo("please input command : get-id\n")
else:
ctx = click.get_current_context()
ctx.invoke(fpga_tool, opera='-r', address='0x13',num='5')
@cli.command()
@click.argument('opera', type=str, default='')
def watch_dog(opera):
'''cu ? fan watch_dog'''
ctx = click.get_current_context()
if opera == 'read' :
ctx.invoke(fpga_tool, opera='-r', address='0x0d')
elif opera == 'enable':
ctx.invoke(fpga_tool, opera='-w', address='0x0d',value='1')
elif opera == 'disabled':
ctx.invoke(fpga_tool, opera='-w', address='0x0d',value='0')
else:
click.echo('please input watch-dog [read | enable | disabled ]')
@cli.command()
@click.argument('hd', type=str,default='')
@click.option('--slot','-s', type=str, help='slot1~slot8',default='')
@click.option('--opera','-o', type=str, help='put on/off',default='')
def card_power(hd,slot,opera):
'''card_power'''
slot_id = ['slot1','slot2','slot3','slot4','slot5','slot6','slot7','slot8']
slot_address = ['0x61','0x62','0x63','0x64','0x65','0x66','0x67','0x68']
ctx = click.get_current_context()
if opera == 'on' :
ctx.invoke(fpga_tool, opera='-w', address=slot_address[slot_id.index(slot)],value='0x10')
ctx.invoke(fpga_tool, opera='-w', address=slot_address[slot_id.index(slot)],value='0x50')
ctx.invoke(fpga_tool, opera='-w', address=slot_address[slot_id.index(slot)],value='0x18')
ctx.invoke(fpga_tool, opera='-w', address=slot_address[slot_id.index(slot)],value='0x50')
ctx.invoke(fpga_tool, opera='-r', address=slot_address[slot_id.index(slot)],num='1')
elif opera == 'off':
ctx.invoke(fpga_tool, opera='-w', address=slot_address[slot_id.index(slot)],value='0x14')
ctx.invoke(fpga_tool, opera='-w', address=slot_address[slot_id.index(slot)],value='0x50')
ctx.invoke(fpga_tool, opera='-w', address=slot_address[slot_id.index(slot)],value='0x1c')
ctx.invoke(fpga_tool, opera='-w', address=slot_address[slot_id.index(slot)],value='0x50')
ctx.invoke(fpga_tool, opera='-r', address=slot_address[slot_id.index(slot)],num='1')
if hd == 'help':
click.echo('please input command: card-power -s [slot1~slot8] -o [on | off ]')
@cli.command()
@click.argument('opera', type=str, default='')
def master_backup(opera):
'''master_backup'''
ctx = click.get_current_context()
if opera == 'read' :
ctx.invoke(fpga_tool, opera='-r', address='0x0f')
elif opera == 'master':
ctx.invoke(fpga_tool, opera='-w', address='0x10',value='0x6')
elif opera == 'backup':
ctx.invoke(fpga_tool, opera='-w', address='0x10',value='0x5')
else:
click.echo('please input command: master-backup [read | master | backup ]')
@cli.command()
@click.argument('opera', type=str, default='')
def reset_fan(opera):
'''reset_fan'''
if opera =='':
ctx = click.get_current_context()
ctx.invoke(fpga_tool, opera='-w', address='0x1f',value='0xa55a')
ctx.invoke(fpga_tool, opera='-w', address='0x05',value='0x0')
else:
click.echo(' Execute command: [reset-fan] will reset three fans ')
@cli.command()
def exit():
"""Exit from current program."""
@cli.command()
def help():
"""Show help for all commands."""
commands = cli.commands
max_length = max(len(command.help) for command in commands.values())
click.echo(f"\nCommands available:\n")
for command in commands.values():
click.echo(f"{command.name.ljust(20)}\t\t\t{command.help.ljust(max_length)}")
def iio_result(process):
adc = []
ads = []
i=0
while True:
output = process.stdout.readline()
#click.echo(output)
if output == '' and process.poll() is not None:
break
if 'raw value:' in output:
pattern = re.compile(r'raw value:\s*(\d+)')
num = pattern.findall(output)
if i<8:
adc.append(num[0])
else:
ads.append(num[0])
i += 1
click.echo("analysis result:\r\n")
click.echo("rk3568 adc\r\n")
i=0
adc_result = [int(item)*1.8/1023 for item in adc]
for num in adc_result:
click.echo(f"channels[{i}] {num:.3f}V\r\n")
i+=1
if os.path.exists('/sys/class/gpio/gpio23'):
result = subprocess.run(['sudo cat /sys/class/gpio/gpio23/value'],shell = True,stdout=subprocess.PIPE)
num = result.stdout.decode().strip()
click.echo(f"ads7959 {num}\r\n")
else:
click.echo("ads7959\r\n")
i=0
ads_result = [int(item)*2.5/255 for item in ads]
for num in ads_result:
click.echo(f'channels[{i}] {num:.3f}V\r\n')
i+=1
def gpio_switch(id):
result = subprocess.run(['sudo echo 23 > /sys/class/gpio/export'],shell = True,stdout=subprocess.PIPE)
result = subprocess.run(['sudo echo out > /sys/class/gpio/gpio23/direction'],shell = True,stdout=subprocess.PIPE)
result = subprocess.run([f'sudo echo {id} > /sys/class/gpio/gpio23/value'],shell = True,stdout=subprocess.PIPE)
#result = subprocess.run(['sudo cat /sys/class/gpio/gpio23/value'],shell = True,stdout=subprocess.PIPE)
def iio_output(process):
try:
iio_result(process)
if os.path.exists('/sys/class/gpio/gpio23'):
result = subprocess.run(['sudo echo 23 > /sys/class/gpio/unexport'],shell = True,stdout=subprocess.PIPE)
#click.echo(f"select value: {result}\r\n")
stop_thread.set()
#time.sleep(0.1)
except KeyboardInterrupt:
click.echo('Process interrupted by user')
stop_thread.set()
def direct_output(process):
try:
while not stop_thread.is_set():
output = process.stdout.readline()
if output == '' and process.poll() is not None:
stop_thread.set()
if 'error' in output.lower():
stop_thread.set()
if output:
click.echo(output, nl=False)
if 'input' in output:
usr_input = click.prompt("Input your selection ",type=str).strip()
process.stdin.write(usr_input + '\n')
process.stdin.flush()
sys.stdout.flush()
#time.sleep(0.1)
except KeyboardInterrupt:
click.echo('Process interrupted by user')
stop_thread.set()
@cli.command()
def iio_info():
"""Voltage measurement result query command."""
click.echo('\n')
@cli.command()
def cpld_upgrade():
"""CPLD Upgrade Command."""
click.echo('\n')
def extract_and_convert_numbers(s):
hex_numbers = re.findall(r'0x([0-9a-fA-F]+)', s)
numbers = []
for hex_num in hex_numbers:
try:
number = int(hex_num, 16)
numbers.append(number)
except ValueError:
print(f"Unable to convert hexadecimal numbers: {hex_num}")
return numbers
def update_reault(result):
#click.echo(result + "\n")
slot_address = ['0x61','0x62','0x63','0x64','0x65','0x66','0x67','0x68']
index = result.lower().find("successfully")
if index != -1:
if any(slot in result for slot in slot_address) or '0x10' in result \
or '0x80' in result or '0xd' in result:
pass
elif '0x5' in result:
click.echo("reset fan successfully\n")
else:
click.echo(result[index+len("successfully"):])
elif result.find("====") != -1 and result.find("temperature:") != -1:
result = result.replace("\n", "℃\n")
click.echo(result[index+len("====="):])
#click.echo("℃\n")
elif 'Read' in result :
if any(slot in result for slot in slot_address):
if '0x80' in result:
number = extract_and_convert_numbers(result)
speed =''
if number[6] == 91:
speed ='middle'
elif number[6] == 112:
speed ='low'
elif number[6] == 204:
speed ='height'
else:
speed = 'default'
click.echo(f"fan speed is {speed} \n")
else:
number = extract_and_convert_numbers(result)
click.echo(f"slot power status is {'on' if number[1] == 466 else 'off'}\n")
elif '0xd' in result:
number = extract_and_convert_numbers(result)
click.echo(f"watch dog is {'enable' if number[1] == 1 else 'disabled'} \n")
elif '0x13' in result:
name_id =['CU-SLOT-ID','SHELF-ID','HARDWARE-ID','PCB-ID','BOM-ID']
number = extract_and_convert_numbers(result)
max_length = max(len(str(index)) for index in number)
for index in range(5):
click.echo('\n\t' + name_id[index].ljust(15) + f':\t{str(hex(number[index+1])).ljust(max_length)}' +'\n')
elif '0xf' in result:
if 'mdio' in result:
click.echo(result)
else:
number = extract_and_convert_numbers(result)
click.echo(f"cu status is {'master' if number[1] == 1 else 'backup'} \n")
elif 'exit' in result:
click.echo(result)
else:
click.echo(result)
def execute_command(command_string):
from click.testing import CliRunner
runner = CliRunner()
result = runner.invoke(cli, command_string.split())
#click.echo(command_string.split())
if result.exit_code == 0:
#click.echo(result.output)
update_reault(result.output)
else:
click.echo(f'Error: {result.output}')
def run_command(command_args):
try:
if "cpld-upgrade" in command_args or \
"iio-info" in command_args:
stop_thread.clear()
if 'cpld-upgrade' in command_args:
replaced_string = command_args.replace("cpld-upgrade", "/usr/bin/cpld_upgrade")
elif 'iio-info' in command_args:
if 'ads7959' in command_args:
gpio_switch(command_args[17])
command_args = command_args.replace(f"ads7959 {command_args[17]}","")
replaced_string = command_args.replace("iio-info", "/usr/bin/iio_info")
if 'help' in replaced_string:
replaced_string = replaced_string.replace("help", "--help")
command_args = shlex.split(replaced_string)
process = subprocess.Popen(
command_args,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
stdin=subprocess.PIPE,
text=True,
bufsize=1,
universal_newlines=True,
)
if '/usr/bin/iio_info' in process.args and '--help' not in process.args :
output_thread = threading.Thread(target=iio_output, args=(process,))
output_thread.start()
else:
output_thread = threading.Thread(target=direct_output, args=(process,))
output_thread.start()
if stop_thread.is_set():
output_thread.join()
if process.poll() is None:
process.terminate()
try:
process.wait(timeout=5)
except subprocess.TimeoutExpired:
click.echo('Child process timed out, forced termination.')
process.kill()
process.stdout.close()
process.stderr.close()
process.stdin.close()
process.communicate()
click.echo('\r\n')
elif command_args == '':
pass
else:
execute_command(command_args)
except Exception as e:
click.echo(f'Exception: {str(e)}')
def interactive_mode():
stop_thread.set()
user_input = ''
while True:
while stop_thread.is_set():
user_input = input('>>>: ')
if user_input.lower() == 'exit':
click.echo('Exiting Interactive CLI. Goodbye!')
break
else:
run_command(user_input)
if user_input.lower() == 'exit':
break
if __name__ == '__main__':
interactive_mode()