#!/usr/bin/python
#licence GPL
import time
import serial
import os
import sys

wait_between_strokes=0
serial_port='/dev/ttyS0'
serial_baudrate=19200

# This program reads a file, ignores all non-printable characters except ENTER and TAB,
# converts characters to ps2 keyboard scancodes (US keymap) and sends them via /dev/ttyS0
# serial line out. It needs to have permission to write to ttyS0 or run as root.
#
# The baud rate is 19200 and it MUST use 8-bit because scancodes are 8-bit.
#
# The other side should run this as root:
# inputattach --baud 19200 --ps2serkbd /dev/ttyUSB0
# You can notice, that serial port over USB works.
#
# The hardware needed is simple - just null modem cable
#
# It would run via bluetooth probably, but there is no encryption, therefore it isn't 
# wise in most scenarios.

#The relevant set seems to be Scan Code Set 2 
keyboard=[[0, 0], #0
          [0, 0],
          [0, 0],
          [0, 0],
          [0, 0],
          [0, 0],
          [0, 0],
          [0, 0],
          [0, 0],
          [0x0d, 0], #tab
          [0, 0], #10
          [0, 0],
          [0, 0],
          [0x5a, 0],
          [0, 0],
          [0, 0],
          [0, 0],
          [0, 0],
          [0, 0],
          [0, 0],
          [0, 0], #20
          [0, 0],
          [0, 0],
          [0, 0],
          [0, 0],
          [0, 0],
          [0, 0],
          [0, 0],
          [0, 0],
          [0, 0],
          [0, 0], #30
          [0, 0],
          [0x29, 0], #space #?
          [0x12, 0x16], #!
          [0x12, 0x52], #"
          [0x12, 0x26], ##
          [0x12, 0x25], #$
          [0x12, 0x2e], #%
          [0x12, 0x3d], #&
          [0x52, 0], #'
          [0x12, 0x46], #( #40
          [0x12, 0x45], #)
          [0x12, 0x3e], #*
          [0x12, 0x55], #+ #?
          [0x41, 0x41], #,
          [0x4e, 0], #-
          [0x49, 0], #.
          [0x4a, 0], #/
          [0x45, 0], #0
          [0x16, 0], #1
          [0x1e, 0], #2 #50
          [0x26, 0], #3
          [0x25, 0], #4
          [0x2E, 0], #5
          [0x36, 0], #6
          [0x3d, 0], #7
          [0x3e, 0], #8
          [0x46, 0], #9
          [0x12, 0x4c], #:
          [0x4c, 0], #;
          [0x12, 0x41], #<
          [0x55, 0], #= 
          [0x12, 0x49], #>
          [0x12, 0x4a], #?
          [0x12, 0x1e], #@
          [0x12, 0x1c], #A
          [0x12, 0x32], #B
          [0x12, 0x21], #C
          [0x12, 0x23], #D
          [0x12, 0x24], #E
          [0x12, 0x2b], #F
          [0x12, 0x34], #G
          [0x12, 0x33], #H
          [0x12, 0x43], #I
          [0x12, 0x3b], #J
          [0x12, 0x42], #K
          [0x12, 0x4b], #L
          [0x12, 0x3a], #M
          [0x12, 0x31], #N
          [0x12, 0x44], #O
          [0x12, 0x4d], #P
          [0x12, 0x15], #Q
          [0x12, 0x2d], #R
          [0x12, 0x1b], #S
          [0x12, 0x2c], #T
          [0x12, 0x3c], #U
          [0x12, 0x2a], #V
          [0x12, 0x1d], #W
          [0x12, 0x22], #X
          [0x12, 0x35], #Y
          [0x12, 0x1a], #Z
          [0x54, 0], #[
          [0x5d, 0], #\
          [0x5b, 0], #]
          [0x12, 0x36], #^
          [0x12, 0x4e], #_
          [0x0e, 0], #`
          [0x1c, 0], #a
          [0x32, 0], #b
          [0x21, 0], #c
          [0x23, 0], #d
          [0x24, 0], #e
          [0x2b, 0], #f
          [0x34, 0], #g
          [0x33, 0], #h
          [0x43, 0], #i
          [0x3b, 0], #j
          [0x42, 0], #k
          [0x4b, 0], #l
          [0x3a, 0], #m
          [0x31, 0], #n
          [0x44, 0], #o
          [0x4d, 0], #p
          [0x15, 0], #q
          [0x2d, 0], #r
          [0x1b, 0], #s
          [0x2c, 0], #t
          [0x3c, 0], #u
          [0x2a, 0], #v
          [0x1d, 0], #w
          [0x22, 0], #x
          [0x35, 0], #y
          [0x1a, 0], #z
          [0x12, 0x54], #{
          [0x12, 0x5d], #|
          [0x12, 0x5b], #}
          [0x12, 0x0e]] #~

#use UCW Czech keyboard or Right-Alt switched us/cz keymap for Czech symbols

if len(sys.argv) < 2:
	print 'Usage: serialkbd.py filename'
	sys.exit(1)
else:
        filename=str(sys.argv[1])
	file_to_push=open(filename, 'r')
          

# configure the serial connections
ser = serial.Serial(
	#port='/dev/ttyS0',
	port=serial_port,   
	#baudrate=19200,
	baudrate=serial_baudrate,
	parity=serial.PARITY_ODD,
	stopbits=serial.STOPBITS_TWO,
	bytesize=serial.EIGHTBITS
)

ser.isOpen()

for line in file_to_push:
	#print 'Line: ', line,
	for i in range(0, len(line)):
		#print line[i], ' :', 
		ascii=ord(line[i])
		if (ascii == 9) or (ascii == 13) or ((ascii >= 32) and (ascii <=126)):
			if (keyboard[ascii][0] != 0):
				ser.write(chr(keyboard[ascii][0]))
				#print keyboard[ascii][0], ' ',
				if (keyboard[ascii][1] != 0):
					ser.write(chr(keyboard[ascii][1]))
					#print keyboard[ascii][1], ' ',
					ser.write(chr(0xf0))
					#print 0xf0, ' ',
					ser.write(chr(keyboard[ascii][1]))
					#print keyboard[ascii][1], ' ',
				ser.write(chr(0xf0))
				#print 0xf0, ' ',
				ser.write(chr(keyboard[ascii][0]))		
				#print keyboard[ascii][0], ' '
				if (wait_between_strokes!=0): 
					time.sleep(wait_between_strokes)
	
	ser.write(chr(0x5a))
	ser.write(chr(0xf0))
	ser.write(chr(0x5a))
	if (wait_between_strokes!=0): 
		time.sleep(wait_between_strokes)
