Skip to content
Snippets Groups Projects
Commit 1653316d authored by da1l6's avatar da1l6
Browse files

Checkin Portal client app.

parent 93ffe5e0
No related branches found
No related tags found
No related merge requests found
#!/usr/bin/env ruby
# encoding: utf-8
require 'ncurses'
require 'serialport.rb'
SERIAL_PORT = "/dev/ttyS0"
STATE_FLAG_UNLOCKED = (1 << 0) #01
STATE_FLAG_LOCKED = (1 << 1) #02
STATE_FLAG_OPEN = (1 << 2) #04
STATE_FLAG_ALARM = (1 << 3) #08
STATE_FLAG_SIGNAL = (1 << 4) #10
STATE_FLAG_UNLOCKING = (1 << 5) #20
STATE_FLAG_LOCKING = (1 << 6) #40
STATE_FLAG_AC_ON = (1 << 7) #80
STATE_FLAG_KEYMATIC_POWER_ON = (1 << 8) #100
STATE_FLAG_ALIX_POWER_ON = (1 << 9) #200
KEY_ABORT = 3
KEY_ESC = 27
KEY_DOWN = 258
KEY_UP = 259
class String
def ord
return self[0]
end
end
class Window
def initialize(x, y, width, height, title)
@win = Ncurses::newwin(height, width, y, x)
@client = Ncurses::newwin(height-2, width-2, y+1, x+1)
Ncurses::box(@win, 0, 0)
Ncurses::wmove(@win,0, 2)
Ncurses::waddstr(@win, " " + title[0,width - 6] + " " )
Ncurses::wrefresh(@win)
end
def write(x,y, color, text)
blink = false
Ncurses::wmove(@client, y, x)
Ncurses::wattr_set(@client, blink ? Ncurses::A_BLINK : Ncurses::A_NORMAL, color, nil)
Ncurses::waddstr(@client, text)
end
def refresh()
Ncurses::wrefresh(@client)
end
def width()
Ncurses.getmaxx(@win)
end
def client_width()
Ncurses.getmaxx(@client)
end
def height()
Ncurses.getmaxy(@win)
end
def client_height()
Ncurses.getmaxy(@client)
end
def get_key()
Ncurses::timeout(0)
return Ncurses::wgetch(@win)
end
end
class RootWindow < Window
def initialize(title = nil, titlecolor = 0)
@win = Ncurses::initscr()
Ncurses::raw()
Ncurses::keypad(@win, 1)
Ncurses::noecho()
Ncurses::curs_set(0) # turn cursor off
Ncurses::start_color()
yield(self)
if (title == nil) then
@client = @win
else
@client = Ncurses::newwin(height()-1, width(), 1, 0)
Ncurses::wattr_set(@win, Ncurses::A_BOLD, titlecolor, nil)
Ncurses::waddstr(@win, title + (" " * (width - title.length)))
end
Ncurses::refresh()
end
def define_color(index, fg, bg)
Ncurses::init_pair(index, fg, bg)
end
end
class PowerStateWindow < Window
def initialize()
super(0, 2, 30, 8, "Power Status")
write(1, 1, 0, "Power Source: N/A");
write(1, 2, 0, "Main Battery: N/A")
write(1, 4, 0, "Keymatic Supply: N/A")
write(1, 5, 0, "Keymatic Battery: N/A")
refresh()
end
def update_state(state)
if (state & STATE_FLAG_AC_ON) != 0 then
write(19, 1, 2, " AC ")
else
write(19, 1, 1, "Battery ")
end
if (state & STATE_FLAG_KEYMATIC_POWER_ON) != 0 then
write(19, 4, 2, "External")
else
write(19, 4, 1, "Internal")
end
refresh()
end
def update_voltage(vbatt, vkm)
write(19, 2, 0, "%0.2fV " % vbatt);
write(19, 5, 0, "%0.2fV " % vkm);
refresh()
end
end
class DoorStateWindow < Window
def initialize()
super(31, 2, 29, 8, "Door Status")
write(1, 1, 0, "N/A")
refresh()
end
def update_state(state)
write(1, 1, (state & STATE_FLAG_LOCKED) != 0 ? 1 : 5, " Locked ")
write(1, 2, (state & STATE_FLAG_UNLOCKED) != 0 ? 2 : 5, " Unlocked ")
write(1, 3, (state & STATE_FLAG_OPEN) != 0 ? 2 : 5, " Door Open ")
write(13, 1, (state & STATE_FLAG_LOCKING) != 0 ? 3 : 5, " Locking... ")
write(13, 2, (state & STATE_FLAG_UNLOCKING) != 0 ? 3 : 5, " Unlocking...")
if (state & STATE_FLAG_ALARM) != 0 then
write(1, 5, 1, " Alarm: ")
write(1, 18, 1, "Now ")
else
if (state & STATE_FLAG_SIGNAL) != 0 then
write(1, 5, 3, " Alarm: Recorded ")
else
write(1, 5, 5, " Alarm: None ")
end
end
refresh()
end
end
class CommandsWindow < Window
def initialize()
super(61, 2, 16, 8, "Commands")
write(1,1, 0, "l: Lock")
write(1,2, 0, "u: Unlock")
write(1,3, 0, "q: Quit")
write(1,4, 0, "a: Clr Alarm")
write(1,5, 0, "r: Reset µC")
refresh()
end
end
class LogWindow < Window
MAX_ENTRIES = 50
def initialize()
super(0, 10,77, 8, "Log")
Ncurses::wmove(@win, 0, 74)
Ncurses::waddstr(@win, "^")
Ncurses::wmove(@win, 7, 74)
Ncurses::waddstr(@win, "V")
Ncurses::wrefresh(@win)
@msgs = []
@scrollpos = 0 #number of lines cut from the end
end
def add_msg(text)
@msgs.push(Time.now.strftime("%Y-%m-%d %H:%M:%S ") + text)
@msgs.unshift
update()
end
def scroll(delta)
@scrollpos += delta
@scrollpos = 0 if @scrollpos < 0
update()
end
def update()
width = client_width()
height = client_height()
while (true)
pos = height + @scrollpos
lineswritten = 0
(@msgs.length-1).downto(0){|i|
s = @msgs[i]
h = (s.length + width - 1) / width #number of lines needed (round up divide)
pos -= h
break if pos < 0
next if pos > height
lastlinelength = s.length - (h-1)*width
lineswritten += h
write(0, pos, 0, s + (" " * (width - lastlinelength)))
}
if pos > 0 && @scrollpos > 0 then
@scrollpos -= 1
else
refresh()
return
end
end
end
end
class ControlIO
attr_writer :state_update_event
attr_writer :voltage_update_event
attr_writer :log_update_event
def initialize()
@sp = SerialPort.new(SERIAL_PORT)
@sp.flow_control = SerialPort::NONE
@sp.baud = 38400
@sp.data_bits = 8
@sp.stop_bits = 1
@sp.parity = SerialPort::NONE
# File.open("log", "w"){|f| f.write(@sp.inspect)}
# @sp = File.open("test", "a+")
@line_buffer = ""
end
def proces_events
ret = IO.select([@sp, STDIN], nil,nil,1)
if ret && ret[0] && ret[0].include?(@sp) then
# if (! @sp.eof?) then
begin
b = @sp.getbyte
c = b.chr
rescue => ex
c = "?"
end
if c == "\n" || c == nil then
# File.open("log", "a"){|f| f.write(@line_buffer.inspect)}
case @line_buffer
when /^Status \(([0-9A-Fa-f]+)\)/
@state_update_event.call($1.to_i(16))
@log_update_event.call(@line_buffer.strip)
when /^VBatt: ([0-9]+)mV, VKM: ([0-9]+)mV/
@voltage_update_event.call($1.to_f / 1000.0, $2.to_f / 1000.0)
else
@log_update_event.call(@line_buffer.strip) if @line_buffer.length > 0
end
@line_buffer = ""
else
@line_buffer += c #c.inspect.to_s[1...-1]
end
end
end
def query_status()
@sp.write('s')
end
def unlock()
@sp.write('u')
end
def unlockF()
@sp.write('U')
end
def lock()
@sp.write('l')
end
def lockF()
@sp.write('L')
end
def keymatic_off()
@sp.write('k')
end
def keymatic_on()
@sp.write('K')
end
def reset()
@sp.write('r')
end
def alarm_off()
@sp.write('a')
end
end
begin
rootwin = RootWindow.new("Warpzone Portal Control",8){|rootwin|
rootwin.define_color(1, Ncurses::COLOR_BLACK, Ncurses::COLOR_RED)
rootwin.define_color(2, Ncurses::COLOR_BLACK, Ncurses::COLOR_GREEN)
rootwin.define_color(3, Ncurses::COLOR_BLACK, Ncurses::COLOR_YELLOW)
rootwin.define_color(4, Ncurses::COLOR_WHITE, Ncurses::COLOR_BLACK)
rootwin.define_color(5, Ncurses::COLOR_BLUE, Ncurses::COLOR_BLACK)
rootwin.define_color(8, Ncurses::COLOR_WHITE, Ncurses::COLOR_BLUE)
}
psw = PowerStateWindow.new()
dsw = DoorStateWindow.new()
logw = LogWindow.new()
CommandsWindow.new()
# psw.update_state(0)
# psw.update_voltage(13.534, 4.124)
# dsw.update_state(0)
logw.add_msg("-- Application Startup --")
# logw.add_msg("Welt")
# logw.add_msg("Foobar")
# logw.add_msg("Foobar2")
# logw.add_msg("Foobar3")
# logw.add_msg("012345678901234567890123456789012345678901234567890123456789")
# logw.add_msg("Test")
io = ControlIO.new()
io.state_update_event = Proc.new{|state|
psw.update_state(state)
dsw.update_state(state)
}
io.voltage_update_event = Proc.new{|vbatt,vkm|
psw.update_voltage(vbatt,vkm)
}
io.log_update_event = Proc.new{|msg|
logw.add_msg(msg)
}
io.query_status()
while true
io.proces_events()
ch = rootwin.get_key()
case ch
when KEY_UP; logw.scroll(1)
when KEY_DOWN; logw.scroll(-1)
when KEY_ABORT, KEY_ESC, "q".ord, "Q".ord; break
when "l".ord
io.lock()
when "L".ord
io.lockF()
when "u".ord
io.unlock()
when "U".ord
io.unlockF()
when "r".ord
io.reset()
when "a".ord
io.alarm_off
when "k".ord
io.keymatic_off
when "K".ord
io.keymatic_on
when -1
#no event
else
logw.add_msg("Unbound Key: " + ch.to_s)
end
# psw.update_state(rand(0x100))
# psw.update_voltage(rand()*15, rand()*5)
# dsw.update_state(rand(0x100))
end
ensure
Ncurses::endwin()
end
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment