#!/usr/bin/python3
#
# Simple terminal interface to the second uart of the WR core
#
# Based on the Single AXI4 memory mapped (MM) user interface of the The Xilinx
# DMA/Bridge Subsystem for PCI Express (pg195)
#
# Author: Ton Damen, tond@nikhef.nl
# Date: 23/9/2021
#

import os
import sys
import argparse
import time
import termios
import pdb

vuart_reg_fifo_in = 0x80000
vuart_reg_fifo_out = 0x80004
vuart_reg_status = 0x80008
vuart_reg_control = 0x8000C

status_mask_rx_ready = 1
status_mask_tx_empty = 4

default_device = '/dev/spec7_bar0'

mm_fd = 0;

parser = argparse.ArgumentParser(description='Terminal interface to the second uart of the wr core on the SPEC7 card')
parser.add_argument('--device', '-d', default = default_device, help = 'device path name, default is ' + default_device)
parser.add_argument('--transmit', '-t', default = "", help = 'transmit string') 

args = parser.parse_args()

def get_status():
	return int.from_bytes(os.pread(mm_fd, 4, vuart_reg_status), "little")

def str2int(s):
	try:
		if (len(s) > 0 and s[0:2] == '0x'):
			val = int(s[2:], 16)
		else:
			val = int(s)
		return val
	except ValueError:
		sys.exit('Invalid value: {}'.format(s))

def vuart_getc():
	while True:
		if get_status() & status_mask_rx_ready != 0:
			data = os.pread(mm_fd, 4, vuart_reg_fifo_in)
			return int.from_bytes(data, "little") & 0xff;
		else:
			return -1

def vuart_putc(c):
	cnt = 100	# 10 sec
	while cnt > 0:
		if get_status() & status_mask_tx_empty != 0:
			break
		time.sleep(0.1)
		cnt -= 1
	if cnt == 0:
		print ("write time-out")
		return -1
	os.pwrite(mm_fd, c.to_bytes(4, 'little'), vuart_reg_fifo_out)
	return 0

def vuart_puts(s):
	n = len(s)
	i = 0
	while i < n:
		if vuart_putc(ord(s[i])) < 0:
			return -1
		i += 1 
	return 0
	
stdio_fd = sys.stdin.fileno()
old = termios.tcgetattr(stdio_fd)
new = termios.tcgetattr(stdio_fd)
# [iflag, oflag, cflag, lflag, ispeed, ospeed, cc]
new[0] = termios.IGNPAR
new[1] = 0
new[2] = termios.B9600 | termios.CS8 | termios.CLOCAL | termios.CREAD
new[3] = 0
new[6][termios.VMIN] = 0
new[6][termios.VTIME] = 0


print('Type C-a to exit\n')

try:
    termios.tcsetattr(stdio_fd, termios.TCSADRAIN, new)
    mm_fd = os.open(args.device, os.O_RDWR)

    if args.transmit != "":
        if vuart_puts(args.transmit) > 0:
           sys.exit("Terminated")
    while True:
        key = sys.stdin.read(1)
        if (len(key) > 0):
            if key == chr(1):
                break
            else:
                if vuart_putc(ord(key)) != 0:
                    break
        c = vuart_getc()
        if c > 0:
            sys.stdout.write(chr(c))
            sys.stdout.flush()
		
except OSError as error: 
    sys.exit('Device i/o failed: {}'.format(error))

finally:
    termios.tcsetattr(stdio_fd, termios.TCSADRAIN, old)


