
#
#	Plussy Display
#	Copyright (C) 2017  Christian Carlowitz <chca@cmesh.de>
#
#	This program is free software: you can redistribute it and/or modify
#	it under the terms of the GNU General Public License as published by
#	the Free Software Foundation, either version 3 of the License, or
#	(at your option) any later version.
#
#	This program is distributed in the hope that it will be useful,
#	but WITHOUT ANY WARRANTY; without even the implied warranty of
#	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#	GNU General Public License for more details.
#
#	You should have received a copy of the GNU General Public License
#	along with this program.  If not, see <http://www.gnu.org/licenses/>.
#

import freedomgfx as fgfx
import time
import appglue
import network
import wifi
import usocket
import badge
import uos

fgfx.init()
wifi.init()

dispW = 296
dispH = 128

# intro
introDone = False
def btn_continue(tgl):
	global introDone
	introDone = True

fgfx.string(15,5,
	"Welcome to the world of Free Software!\n \n"+
	"Free Software gives every user the essential\nfour freedoms:\n"+
	"(0) run the program for any purpose\n"+
	"(1) study and change it in source code form\n"+
	"(2) redistribute exact copies\n"+
	"(3) distribute modified versions\n \n"
	"A: Continue"
	,"default",fgfx.BLACK)
fgfx.flush()

fgfx.input_init()
fgfx.input_attach(fgfx.BTN_A, btn_continue)
while not introDone:
	time.sleep(0.1)
	fgfx.poll()
fgfx.area(0,0,dispW,dispH,fgfx.WHITE)

# draw plussy
pW = 30
pL = 12
pGap = 7
pPos = (10,10) # top left pos
pEnd = (pPos[0]+(pW+pGap)*3, pPos[1]+(pW+pGap)*3) # bottom right end
fgfx.area(pPos[0]+pW+pGap,pPos[1],pW,pW,fgfx.BLACK)
fgfx.area(pPos[0]+pW+pGap,pPos[1]+pW+pGap,pW,pW,fgfx.BLACK)
fgfx.area(pPos[0],pPos[1]+pW+pGap,pW,pW,fgfx.BLACK)
fgfx.area(pPos[0]+(pW+pGap)*2,pPos[1]+pW+pGap,pW,pW,fgfx.BLACK)
fgfx.area(pPos[0]+pW+pGap,pPos[1]+(pW+pGap)*2,pL,pW,fgfx.BLACK)
fgfx.area(pPos[0]+2*pW-pL+pGap,pPos[1]+(pW+pGap)*2,pL,pW,fgfx.BLACK)

# draw welcome text
xoff = pEnd[0]
fgfx.string(xoff+10,10,
	"Welcome to Plussy Control!\n"+
	"Find the Plussy at FSFE\n"+
	"Village or Koeniglich\n"+
	"Bayrisches Amtsvillage.\n"+
	"A: Connect, B: Back Home\n"+
	"Joy: LED, Select: Color."
	,"default",fgfx.BLACK)

fgfx.flush()

# helper
def led_set(v,r=0,g=1,b=0):
	data = []
	for k in range(0,6):
		if v & (1<<k):
			data.extend([int(0xff*g),int(0xff*r),int(0xff*b),0]) # G,R,B,W
		else:
			data.extend([0,0,0,0])
	badge.leds_send_data(bytes(data))

# keyboard
quitReq = False

def btn_quit(tgl):
	global quitReq
	quitReq = True

com_socket = None

def btn_connect(tgl):
	yoffs = 90
	fgfx.area(xoff+10,yoffs,296-xoff-10,128-yoffs,fgfx.WHITE)
	fgfx.string(xoff+10,yoffs,"Connecting WLAN ...","default",fgfx.BLACK)
	fgfx.flush()
	sta_if = network.WLAN(network.STA_IF)
	sta_if.connect("FrankenFellowshipFSFE")
	cnt = 0
	while cnt < 30 and not wifi.sta_if.isconnected():
		time.sleep(0.1)
	if wifi.sta_if.isconnected():
		try:
			fgfx.area(xoff+10,yoffs,296-xoff-10,128-yoffs,fgfx.WHITE)
			fgfx.string(xoff+10,yoffs,"Connecting WLAN ... Done.","default",fgfx.BLACK)
			fgfx.flush()
			
			listen_socket = usocket.socket(usocket.AF_INET, usocket.SOCK_DGRAM)
			listen_socket.settimeout(3)
			udp_addr = ("255.255.255.255", 60000)
			listen_socket.bind(udp_addr)
			cnt = 0
			server_addr = ""
			while cnt < 3:
				data, addr = listen_socket.recvfrom(2048)
				if "plussyDisplay" in data.decode():
					server_addr = addr[0]
					break
			listen_socket.close()

			fgfx.string(xoff+10,yoffs+12,"Plussy at %s" % server_addr,"default",fgfx.BLACK)
			fgfx.flush()
			
			global com_socket
			com_socket = usocket.socket(usocket.AF_INET, usocket.SOCK_STREAM)
			com_socket.settimeout(3)
			com_socket.connect((server_addr, 60000))
			com_socket.sendall("e\n")
			ans = com_socket.readline()
			if ans.decode().strip()[0] != "E":
				raise OSError()

			# show welcome led stream
			badge.leds_init()
			led_set(0)
			v = 1
			for k in range(0,6):
				led_set(v)
				v <<= 1
				time.sleep(0.1)
			led_set(1,1,0,0)
			
		except OSError as e:
			fgfx.string(xoff+10,yoffs+24,"Network Error","default",fgfx.BLACK)
			fgfx.flush()
			comm_socket = None
			raise e
			

	else:
		fgfx.area(xoff+10,yoffs,296-xoff-10,128-yoffs,fgfx.WHITE)
		fgfx.string(xoff+10,yoffs,"Connecting ... Failed.","default",fgfx.BLACK)
		fgfx.flush()

def plussy_set(idxs,col):
	global com_socket
	if com_socket != None:
		try:
			for i in idxs:
				cmd = "m%02x%02x%02x%02x\n" % (int(i),int(255*col[0]),int(255*col[1]),int(255*col[2]))
				com_socket.sendall(cmd)
				ans = com_socket.readline()
		except OSError:
			print("plussy set failed")
			yoffs = 90
			fgfx.string(xoff+10,yoffs+24,"Network Error","default",fgfx.BLACK)
			fgfx.flush()
			com_socket = None

def btn_joyUp():
	global colors, cur_col
	c = colors[cur_col][1]
	led_set(0x3f,c[0],c[1],c[2])
	plussy_set([16,17,18,19], c)
	led_set(0x1,c[0],c[1],c[2])
def btn_joyLeft():
	global colors, cur_col
	c = colors[cur_col][1]
	led_set(0x3f,c[0],c[1],c[2])
	plussy_set([4,5,14,15], c)
	led_set(0x1,c[0],c[1],c[2])
def btn_joyDown():
	global colors, cur_col
	c = colors[cur_col][1]
	led_set(0x3f,c[0],c[1],c[2])
	plussy_set([0,1,2,3], c)
	led_set(0x1,c[0],c[1],c[2])
def btn_joyRight():
	global colors, cur_col
	c = colors[cur_col][1]
	led_set(0x3f,c[0],c[1],c[2])
	plussy_set([8,9,10,11], c)
	led_set(0x1,c[0],c[1],c[2])
def btn_start():
	global colors, cur_col
	c = colors[cur_col][1]
	led_set(0x3f,c[0],c[1],c[2])
	plussy_set([6,7,12,13], c)
	led_set(0x1,c[0],c[1],c[2])

	
colors = (
	("red",(1,0,0)),
	("green",(0,1,0)),
	("blue",(0,0,1)),
	("pink",(1,0,1)),
	("yellow",(1,1,0)),
	("cyan",(0,1,1)),
	("white",(1,1,1)),
)
cur_col = 0

def btn_sel():
	global cur_col, colors
	cur_col = (cur_col + 1)%len(colors)
	c = colors[cur_col][1]
	led_set(1,c[0],c[1],c[2])
	
	
fgfx.input_attach(fgfx.BTN_B, btn_quit)
fgfx.input_attach(fgfx.BTN_A, btn_connect)
fgfx.input_attach(fgfx.JOY_UP, lambda tgl: btn_joyUp())
fgfx.input_attach(fgfx.JOY_DOWN, lambda tgl: btn_joyDown())
fgfx.input_attach(fgfx.JOY_LEFT, lambda tgl: btn_joyLeft())
fgfx.input_attach(fgfx.JOY_RIGHT, lambda tgl: btn_joyRight())
fgfx.input_attach(fgfx.BTN_SELECT, lambda tgl: btn_sel())
fgfx.input_attach(fgfx.BTN_START, lambda tgl: btn_start())

# main loop
while not quitReq:
	time.sleep(0.1)
	fgfx.poll()
	
fgfx.deinit()
badge.leds_disable()
print("done")
appglue.home()
