#!/usr/bin/python3
#
# Simple terminal interface to the uart of the WR core
#
# Depending on the presents of the Xilinx XDMA driver
# 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: 8/4/2020
#

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

syscon_addr = 0x40400
vuart_addr = 0x40500
xmda_user_fd = 0;

parser = argparse.ArgumentParser(description='Terminal interface to the uart of the wr core on the SPEC card')
parser.add_argument('--device', '-d', default='/dev/spec7_bar0', help = 'device path name, default is /dev/spec7')

args = parser.parse_args()

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:
		data = os.pread(xdma_user_fd, 4, vuart_addr + 0x14)
		rx_reg = int.from_bytes(data, "little")
		if (rx_reg & 0x100) != 0:
			return rx_reg & 0xff
		else:
			return -1

def vuart_putc(c):	
	while True:
		data = os.pread(xdma_user_fd, 4, vuart_addr + 0x10)
		if (int.from_bytes(data, "little") & 0x100) != 0:
			break
		time.sleep(0.1)
	os.pwrite(xdma_user_fd, c.to_bytes(4, 'little'), vuart_addr + 0x10)
	
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)
    xdma_user_fd = os.open(args.device, os.O_RDWR)
    while True:
        key = sys.stdin.read(1)
        if (len(key) > 0):
            if key == chr(1):
                break
            else:
                vuart_putc(ord(key))
        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)
