#! /usr/bin/python
# generated by wxGlade 0.3.1 on Fri Oct 03 23:23:45 2003

#from wxPython.wx import *
import wx
import wxSerialConfigDialog
import serial
import threading
import time
#----------------------------------------------------------------------
# Create an own event type, so that GUI updates can be delegated
# this is required as on some platforms only the main thread can
# access the GUI without crashing. wxMutexGuiEnter/wxMutexGuiLeave
# could be used too, but an event is more elegant.

SERIALRX = wx.NewEventType()
# bind to serial data receive events
EVT_SERIALRX = wx.PyEventBinder(SERIALRX, 0)

class SerialRxEvent(wx.PyCommandEvent):
    eventType = SERIALRX
    def __init__(self, windowID, data):
        wx.PyCommandEvent.__init__(self, self.eventType, windowID)
        self.data = data

    def Clone(self):
        self.__class__(self.GetId(), self.data)

#----------------------------------------------------------------------

ID_CLEAR        = wx.NewId()
ID_SAVEAS       = wx.NewId()
ID_SETTINGS     = wx.NewId()
ID_TERM         = wx.NewId()
ID_EXIT         = wx.NewId()

NEWLINE_CR      = 0
NEWLINE_LF      = 1
NEWLINE_CRLF    = 2


################  DOMOTIKA MESSAGES #################
TERMINATOR='\xff'
START_SERIAL_MESSAGE='\x15'

SERIAL_PROTOCOL_VERSION_BYTE1='\x00'
SERIAL_PROTOCOL_VERSION_BYTE2='\x00'
SERIAL_PROTOCOL_VERSION_BYTE3='\x01'


# PROTOCOL COMMANDS
SP_SPECIAL_COMMAND='\x00'
SP_CARD_TYPE='\x01'
SP_PROTOCOL_VERSION='\x02'
SP_SOFTWARE_VERSION='\x03'
SP_IO_STATE='\x04'
SP_IO_SET ='\x06'
SP_INTERRUPT_EVENT='\x07'
SP_IO_FULL_STATUS='\x08'



# Special Commands
SP_SPECIAL_MAGIK='\x00'
SP_SPECIAL_ACKNACK='\x01'
SP_ALARM='\xff\xff\xff\xff'

# Magik words
SP_MGK_REBOOT='\xde\xad'
SP_MGK_BOOTLOADER='\xca\xfe'
SP_MGK_ERASE_EEPROM='\xfa\x11'
SP_MGK_ASK_INITIALIZE='\xb0\x01'
SP_MGK_ASK_READY='\x15\xb0'
SP_MGK_ISREADY='\xb0\xff'

# ACK/NACK and so on
SP_OK='\x00\x00'
SP_KO='\x00\x01'
SP_ACK='\x01\x00'
SP_NACK='\x01\x01'
SP_YES='\x02\x00'
SP_NO='\x02\x01'


# OTHERS
SP_VALUE_DIGITAL0='\x00\x00'
SP_VALUE_DIGITAL1='\xff\xff'
# I/O types
SP_IOTYPE_RELAY1='\xF0'
SP_IOTYPE_RELAY2='\xF1'
SP_IOTYPE_RELAY3='\xF2'
SP_IOTYPE_RELAY4='\xF3'
SP_IOTYPE_RELAY5='\xF4'
SP_IOTYPE_RELAY6='\xF5'
SP_IOTYPE_RELAY7='\xF6'
SP_IOTYPE_RELAY8='\xF7'
SP_IOTYPE_RELAY9='\xF8'
SP_IOTYPE_RELAY10='\xF9'
SP_IOTYPE_RELAY11='\xFA'
SP_IOTYPE_RELAY12='\xFB'

SP_IOTYPE_DIGITAL_INPUT1='\x00'
SP_IOTYPE_DIGITAL_INPUT2='\x01'
SP_IOTYPE_DIGITAL_INPUT3='\x02'
SP_IOTYPE_DIGITAL_INPUT4='\x03'
SP_IOTYPE_DIGITAL_INPUT5='\x04'
SP_IOTYPE_DIGITAL_INPUT6='\x05'
SP_IOTYPE_DIGITAL_INPUT7='\x06'
SP_IOTYPE_DIGITAL_INPUT8='\x07'
SP_IOTYPE_DIGITAL_INPUT9='\x08'
SP_IOTYPE_DIGITAL_INPUT10='\x09'
SP_IOTYPE_DIGITAL_INPUT11='\x0A'
SP_IOTYPE_DIGITAL_INPUT12='\x0B'


# INTERRUPTS
SP_INTERRUPT_EXT_INPUT5='\x05'
SP_INTERRUPT_EXT_INPUT6='\x06'
SP_INTERRUPT_EXT_INPUT7='\x07'
SP_INTERRUPT_EXT_INPUT8='\x08'


####################################################



def hextobit(v):
   return list(bin(int(bytes(v), 16))[2:])


def bittohex(v):
   return hex(int("0b"+"".join(v), 2))

def checksum(b, word):
   # XXX Bisogna migliorare sto checksum, cosi' non ha senso
   a=ord(word[0])+ord(word[1])+ord(word[2])+ord(word[3])
   #print ord(b), [b], a, ord(word[3])
   #c=chr(int(a, 16))
   #print hex(a), ord(b)
   if word[3]==b:
      return True
   # Will be changed!
   return True

def parse(word):
   
   b1=word[0]
   b2=word[1]
   b3=word[2]
   b4=word[3]
   if b1 == SP_SPECIAL_COMMAND:
      if b2 == SP_SPECIAL_MAGIK:
         if b3+b4 == SP_MGK_REBOOT:
            return 'SPECIAL_COMMAND received (MAGICK REBOOT)' 
         elif b3+b4 == SP_MGK_BOOTLOADER:
            return 'SPECIAL COMMAND (MAGICK BOOTLOADER)'
         elif b3+b4 == SP_MGK_ERASE_EEPROM:
            return 'SPECIAL COMMAND (MAGICK ERASE EEPROM)'
         elif b3+b4 == SP_MGK_ASK_INITIALIZE:
            return 'SPECIAL COMMAND (MAGICK ASK INITIALIZE)'
         elif b3+b4 == SP_MGK_ASK_READY:
            return 'SPECIAL COMMAND (MAGICK ASK READY)'
         elif b3+b4 == SP_MGK_ISREADY:
            return 'SPECIAL COMMAND (MAGICK IS READY)'
      elif b2 == SP_SPECIAL_ACKNACK:
         if b3+b4 == SP_ACK:
            return 'SPECIAL COMMAND (MAGICK ACK)'
         elif b3+b4 == SP_NACK:
            return 'SPECIAL COMMAND (MAGICK NACK)'
         elif b3+b4 == SP_YES:
            return 'SPECIAL COMMAND (MAGICK YES)'
         elif b3+b4 == SP_NO:
            return 'SPECIAL COMMAND (MAGICK NO)'
         elif b3+b4 == SP_OK:
            return 'SPECIAL COMMAND (MAGICK OK)'
         elif b3+b4 == SP_KO:
            return 'SPECIAL COMMAND (MAGICK KO)'
   elif b1 == SP_CARD_TYPE:
      return 'CARD TYPE received (%s)' % str([b2, b3, b4])
   elif b1 ==  SP_PROTOCOL_VERSION:
      return 'PROTOCOL VERSION received (%s)' % str([b2, b3, b4])
   elif b1 == SP_IO_STATE:
      if b3+b4 == SP_VALUE_DIGITAL0:
         val = "VALUE: 0"
      else:
         val = "VALUE: 1"
      if b2 == SP_IOTYPE_RELAY1:
         return 'IO STATE received, RELAY1 %s' % val
      elif b2 == SP_IOTYPE_RELAY2:
         return 'IO STATE received, RELAY2 %s' % val
      elif b2 == SP_IOTYPE_RELAY3:
         return 'IO STATE received, RELAY3 %s' % val
      elif b2 == SP_IOTYPE_RELAY4:
         return 'IO STATE received, RELAY4 %s' % val
      elif b2 == SP_IOTYPE_RELAY5:
         return 'IO STATE received, RELAY5 %s' % val
      elif b2 == SP_IOTYPE_RELAY6:
         return 'IO STATE received, RELAY6 %s' % val
      elif b2 == SP_IOTYPE_RELAY7:
         return 'IO STATE received, RELAY7 %s' % val
      elif b2 == SP_IOTYPE_RELAY8:
         return 'IO STATE received, RELAY8 %s' % val
      elif b2 == SP_IOTYPE_RELAY9:
         return 'IO STATE received, RELAY9 %s' % val
      elif b2 == SP_IOTYPE_RELAY10:
         return 'IO STATE received, RELAY10 %s' % val
      elif b2 == SP_IOTYPE_RELAY11:
         return 'IO STATE received, RELAY11 %s' % val
      elif b2 == SP_IOTYPE_RELAY12:
         return 'IO STATE received, RELAY12 %s' % val
      elif b2 == SP_IOTYPE_DIGITAL_INPUT1:
         return 'IO STATE received, INPUT1 %s' % val
      elif b2 == SP_IOTYPE_DIGITAL_INPUT12:
         return 'IO STATE received, INPUT12 %s' % val
      elif b2 == SP_IOTYPE_DIGITAL_INPUT2:
         return 'IO STATE received, INPUT2 %s' % val
      elif b2 == SP_IOTYPE_DIGITAL_INPUT3:
         return 'IO STATE received, INPUT3 %s' % val
      elif b2 == SP_IOTYPE_DIGITAL_INPUT4:
         return 'IO STATE received, INPUT4 %s' % val
      elif b2 == SP_IOTYPE_DIGITAL_INPUT5:
         return 'IO STATE received, INPUT5 %s' % val
      elif b2 == SP_IOTYPE_DIGITAL_INPUT6:
         return 'IO STATE received, INPUT6 %s' % val
      elif b2 == SP_IOTYPE_DIGITAL_INPUT7:
         return 'IO STATE received, INPUT7 %s' % val
      elif b2 == SP_IOTYPE_DIGITAL_INPUT8:
         return 'IO STATE received, INPUT8 %s' % val
      elif b2 == SP_IOTYPE_DIGITAL_INPUT9:
         return 'IO STATE received, INPUT9 %s' % val
      elif b2 == SP_IOTYPE_DIGITAL_INPUT10:
         return 'IO STATE received, INPUT10 %s' % val
      elif b2 == SP_IOTYPE_DIGITAL_INPUT11:
         return 'IO STATE received, INPUT11 %s' % val


   elif b1 == SP_IO_SET:
      if b3+b4 == SP_VALUE_DIGITAL0:
         val = "VALUE: 0"
      else:
         val = "VALUE: 1"
      if b2 == SP_IOTYPE_RELAY1:
         return 'IO SET received, RELAY1 %s' % val
      elif b2 == SP_IOTYPE_RELAY2:
         return 'IO SET received, RELAY2 %s' % val
      elif b2 == SP_IOTYPE_RELAY3:
         return 'IO SET received, RELAY3 %s' % val
      elif b2 == SP_IOTYPE_RELAY4:
         return 'IO SET received, RELAY4 %s' % val
      elif b2 == SP_IOTYPE_RELAY5:
         return 'IO SET received, RELAY5 %s' % val
      elif b2 == SP_IOTYPE_RELAY6:
         return 'IO SET received, RELAY6 %s' % val
      elif b2 == SP_IOTYPE_RELAY7:
         return 'IO SET received, RELAY7 %s' % val
      elif b2 == SP_IOTYPE_RELAY8:
         return 'IO SET received, RELAY8 %s' % val
      elif b2 == SP_IOTYPE_RELAY9:
         return 'IO SET received, RELAY9 %s' % val
      elif b2 == SP_IOTYPE_RELAY10:
         return 'IO SET received, RELAY10 %s' % val
      elif b2 == SP_IOTYPE_RELAY11:
         return 'IO SET received, RELAY11 %s' % val
      elif b2 == SP_IOTYPE_RELAY12:
         return 'IO SET received, RELAY12 %s' % val
      elif b2 == SP_IOTYPE_DIGITAL_INPUT1:
         return 'IO SET received, INPUT1 %s' % val
      elif b2 == SP_IOTYPE_DIGITAL_INPUT12:
         return 'IO SET received, INPUT12 %s' % val
      elif b2 == SP_IOTYPE_DIGITAL_INPUT2:
         return 'IO SET received, INPUT2 %s' % val
      elif b2 == SP_IOTYPE_DIGITAL_INPUT3:
         return 'IO SET received, INPUT3 %s' % val
      elif b2 == SP_IOTYPE_DIGITAL_INPUT4:
         return 'IO SET received, INPUT4 %s' % val
      elif b2 == SP_IOTYPE_DIGITAL_INPUT5:
         return 'IO SET received, INPUT5 %s' % val
      elif b2 == SP_IOTYPE_DIGITAL_INPUT6:
         return 'IO SET received, INPUT6 %s' % val
      elif b2 == SP_IOTYPE_DIGITAL_INPUT7:
         return 'IO SET received, INPUT7 %s' % val
      elif b2 == SP_IOTYPE_DIGITAL_INPUT8:
         return 'IO SET received, INPUT8 %s' % val
      elif b2 == SP_IOTYPE_DIGITAL_INPUT9:
         return 'IO SET received, INPUT9 %s' % val
      elif b2 == SP_IOTYPE_DIGITAL_INPUT10:
         return 'IO SET received, INPUT10 %s' % val
      elif b2 == SP_IOTYPE_DIGITAL_INPUT11:
         return 'IO SET received, INPUT11 %s' % val

   elif b1 == SP_INTERRUPT_EVENT:
      if b2 == SP_INTERRUPT_EXT_INPUT5:
         return 'EXT INTERRUPT INPUT5 received'
      if b2 == SP_INTERRUPT_EXT_INPUT6:
         return 'EXT INTERRUPT INPUT6 received'
      if b2 == SP_INTERRUPT_EXT_INPUT7:
         return 'EXT INTERRUPT INPUT7 received'
      if b2 == SP_INTERRUPT_EXT_INPUT8:
         return 'EXT INTERRUPT INPUT8 received'

   elif b1 == SP_IO_FULL_STATUS:
      #try:
      st=hextobit(hex(ord(b2)))+hextobit(hex(ord(b3)))+hextobit(hex(ord(b4)))
      #except:
      #   print 'ERROR'
      #   st = 'FULL STATUS ERROR'
      return 'FULL STATUS received (%s)' % str(st)
   elif b1+b2+b3+b4 == SP_ALARM:
      return 'ALARM!!!!!!!!'

class TerminalSetup:
    """Placeholder for various terminal settings. Used to pass the
       options to the TerminalSettingsDialog."""
    def __init__(self):
        self.echo = False
        self.unprintable = False
        self.newline = NEWLINE_CRLF

class TerminalSettingsDialog(wx.Dialog):
    """Simple dialog with common terminal settings like echo, newline mode."""
    
    def __init__(self, *args, **kwds):
        self.settings = kwds['settings']
        del kwds['settings']
        # begin wxGlade: TerminalSettingsDialog.__init__
        kwds["style"] = wx.DEFAULT_DIALOG_STYLE
        wx.Dialog.__init__(self, *args, **kwds)
        self.checkbox_echo = wx.CheckBox(self, -1, "Local Echo")
        self.checkbox_unprintable = wx.CheckBox(self, -1, "Show unprintable characters")
        self.radio_box_newline = wx.RadioBox(self, -1, "Newline Handling", choices=["CR only", "LF only", "CR+LF"], majorDimension=0, style=wx.RA_SPECIFY_ROWS)
        self.button_ok = wx.Button(self, -1, "OK")
        self.button_cancel = wx.Button(self, -1, "Cancel")

        self.__set_properties()
        self.__do_layout()
        # end wxGlade
        self.__attach_events()
        self.checkbox_echo.SetValue(self.settings.echo)
        self.checkbox_unprintable.SetValue(self.settings.unprintable)
        self.radio_box_newline.SetSelection(self.settings.newline)

    def __set_properties(self):
        # begin wxGlade: TerminalSettingsDialog.__set_properties
        self.SetTitle("Terminal Settings")
        self.radio_box_newline.SetSelection(0)
        self.button_ok.SetDefault()
        # end wxGlade

    def __do_layout(self):
        # begin wxGlade: TerminalSettingsDialog.__do_layout
        sizer_2 = wx.BoxSizer(wx.VERTICAL)
        sizer_3 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_4 = wx.StaticBoxSizer(wx.StaticBox(self, -1, "Input/Output"), wx.VERTICAL)
        sizer_4.Add(self.checkbox_echo, 0, wx.ALL, 4)
        sizer_4.Add(self.checkbox_unprintable, 0, wx.ALL, 4)
        sizer_4.Add(self.radio_box_newline, 0, 0, 0)
        sizer_2.Add(sizer_4, 0, wx.EXPAND, 0)
        sizer_3.Add(self.button_ok, 0, 0, 0)
        sizer_3.Add(self.button_cancel, 0, 0, 0)
        sizer_2.Add(sizer_3, 0, wx.ALL|wx.ALIGN_RIGHT, 4)
        self.SetAutoLayout(1)
        self.SetSizer(sizer_2)
        sizer_2.Fit(self)
        sizer_2.SetSizeHints(self)
        self.Layout()
        # end wxGlade

    def __attach_events(self):
        self.Bind(wx.EVT_BUTTON, self.OnOK, id = self.button_ok.GetId())
        self.Bind(wx.EVT_BUTTON, self.OnCancel, id = self.button_cancel.GetId())

    def OnOK(self, events):
        """Update data wil new values and close dialog."""
        self.settings.echo = self.checkbox_echo.GetValue()
        self.settings.unprintable = self.checkbox_unprintable.GetValue()
        self.settings.newline = self.radio_box_newline.GetSelection()
        self.EndModal(wx.ID_OK)
    
    def OnCancel(self, events):
        """Do not update data but close dialog."""
        self.EndModal(wx.ID_CANCEL)

# end of class TerminalSettingsDialog


class TerminalFrame(wx.Frame):
    """Simple terminal program for wxPython"""
    
    def __init__(self, *args, **kwds):
        self.serial = serial.Serial()
        self.serial.timeout = 0.5   #make sure that the alive event can be checked from time to time
        self.settings = TerminalSetup() #placeholder for the settings
        self.thread = None
        self.alive = threading.Event()               
        # begin wxGlade: TerminalFrame.__init__
        kwds["style"] = wx.DEFAULT_FRAME_STYLE
        wx.Frame.__init__(self, *args, **kwds)
        self.text_ctrl_output = wx.TextCtrl(self, -1, "", style=wx.TE_MULTILINE|wx.TE_READONLY)
        
        # Menu Bar
        self.frame_terminal_menubar = wx.MenuBar()
        self.SetMenuBar(self.frame_terminal_menubar)
        wxglade_tmp_menu = wx.Menu()
        wxglade_tmp_menu.Append(ID_CLEAR, "&Clear", "", wx.ITEM_NORMAL)
        wxglade_tmp_menu.Append(ID_SAVEAS, "&Save Text As...", "", wx.ITEM_NORMAL)
        wxglade_tmp_menu.AppendSeparator()
        wxglade_tmp_menu.Append(ID_SETTINGS, "&Port Settings...", "", wx.ITEM_NORMAL)
        wxglade_tmp_menu.Append(ID_TERM, "&Terminal Settings...", "", wx.ITEM_NORMAL)
        wxglade_tmp_menu.AppendSeparator()
        wxglade_tmp_menu.Append(ID_EXIT, "&Exit", "", wx.ITEM_NORMAL)
        self.frame_terminal_menubar.Append(wxglade_tmp_menu, "&File")
        # Menu Bar end

        self.button_changeRelay1 = wx.Button(self, -1, "Relay1 (for master)")
        self.button_changeRelay2 = wx.Button(self, -1, "Relay1 (for slave)")
        self.button_changeInput1 = wx.Button(self, -1, "Input1 (for master)")
        self.button_loop = wx.Button(self, -1, "Loop")
        self.__set_properties()
        self.__do_layout()
        # end wxGlade
        self.__attach_events()          #register events
        self.OnPortSettings(None)       #call setup dialog on startup, opens port
        if not self.alive.isSet():
            self.Close()

    def StartThread(self):
        """Start the receiver thread"""        
        self.thread = threading.Thread(target=self.ComPortThread)
        self.thread.setDaemon(1)
        self.alive.set()
        self.thread.start()

    def StopThread(self):
        """Stop the receiver thread, wait util it's finished."""
        if self.thread is not None:
            self.alive.clear()          #clear alive event for thread
            self.thread.join()          #wait until thread has finished
            self.thread = None
        
    def __set_properties(self):
        # begin wxGlade: TerminalFrame.__set_properties
        self.SetTitle("Serial Terminal")
        self.SetSize((546, 383))
        # end wxGlade

    def __do_layout(self):
        # begin wxGlade: TerminalFrame.__do_layout
        sizer_1 = wx.BoxSizer(wx.VERTICAL)
        sizer_2 = wx.BoxSizer(wx.VERTICAL)
        sizer_3 = wx.BoxSizer(wx.HORIZONTAL) 
        sizer_3.Add(self.button_changeRelay1, 1)
        sizer_3.Add(self.button_changeRelay2, 1)
        sizer_4 = wx.BoxSizer(wx.HORIZONTAL)
        sizer_4.Add(self.button_changeInput1, 1)
        sizer_4.Add(self.button_loop, 1)
        sizer_2.Add(sizer_3, 1, wx.EXPAND, 0)
        sizer_2.Add(sizer_4, 1, wx.EXPAND, 0)
        sizer_1.Add(sizer_2, 0, wx.EXPAND, 0)
        sizer_1.Add(self.text_ctrl_output, 1, wx.EXPAND, 0)
        self.SetAutoLayout(1)
        self.SetSizer(sizer_1)
        self.Layout()
        # end wxGlade

    def __attach_events(self):
        #register events at the controls
        self.Bind(wx.EVT_MENU, self.OnClear, id = ID_CLEAR)
        self.Bind(wx.EVT_MENU, self.OnSaveAs, id = ID_SAVEAS)
        self.Bind(wx.EVT_MENU, self.OnExit, id = ID_EXIT)
        self.Bind(wx.EVT_MENU, self.OnPortSettings, id = ID_SETTINGS)
        self.Bind(wx.EVT_MENU, self.OnTermSettings, id = ID_TERM)
        self.text_ctrl_output.Bind(wx.EVT_CHAR, self.OnKey)        
        self.Bind(EVT_SERIALRX, self.OnSerialRead)
        self.Bind(wx.EVT_CLOSE, self.OnClose)
        self.Bind(wx.EVT_BUTTON, self.OnRelay1, id = self.button_changeRelay1.GetId())
        self.Bind(wx.EVT_BUTTON, self.OnRelay2, id = self.button_changeRelay2.GetId())
        self.Bind(wx.EVT_BUTTON, self.OnInput1, id = self.button_changeInput1.GetId())
        self.Bind(wx.EVT_BUTTON, self.OnLoop, id = self.button_loop.GetId())

    def OnLoop(self, events):
        try:
           if self.loop == 0:
              self.loop = 1
           else:
              self.loop = 0
        except:
           self.loop = 0


    def OnRelay1(self, events):
        try:
           if self.relay1 == 0:
              self.sendRelay1_ON()
              self.relay1 = 1
           else:
              self.sendRelay1_OFF()
              self.relay1 = 0
        except:
           self.sendRelay1_OFF()
           self.relay1 = 0
    def OnRelay2(self, events):
        try:
           if self.relay2 == 0:
              self.sendRelay2_ON()
              self.relay2 = 1
           else:
              self.sendRelay2_OFF()
              self.relay2 = 0
        except:
           self.sendRelay2_OFF()
           self.relay2 = 0
    def OnInput1(self, events):
        try:
           if self.input1 == 0:
              self.sendInput1_ON()
              self.input1 = 1
           else:
              self.sendInput1_OFF()
              self.input1 = 0
        except:
           self.sendInput1_OFF()
           self.input1 = 0
  
    def sendCommand(self, cmd):
        cmds = [START_SERIAL_MESSAGE, '\x00', cmd[0], cmd[1], cmd[2], cmd[3], '\x00', TERMINATOR]
        print 'SENT COMMAND: %s' % cmds

        self.serial.write(START_SERIAL_MESSAGE)
        self.serial.write('\x00')
        #self.serial.write(cmd)
        for i in list(cmd):
           self.serial.write(i)
        self.serial.write('\x00')
        self.serial.write(TERMINATOR)


    def sendRelay1_OFF(self):
        self.sendCommand(SP_IO_STATE+SP_IOTYPE_RELAY1+SP_VALUE_DIGITAL0)

    def sendRelay1_ON(self):
        self.sendCommand(SP_IO_STATE+SP_IOTYPE_RELAY1+SP_VALUE_DIGITAL1)

    def sendInput1_OFF(self):
        self.sendCommand(SP_IO_STATE+SP_IOTYPE_DIGITAL_INPUT1+SP_VALUE_DIGITAL0)

    def sendInput1_ON(self):
        self.sendCommand(SP_IO_STATE+SP_IOTYPE_DIGITAL_INPUT1+SP_VALUE_DIGITAL1)

    def sendRelay2_OFF(self):
        self.sendCommand(SP_IO_SET+SP_IOTYPE_RELAY1+SP_VALUE_DIGITAL0)

    def sendRelay2_ON(self):
        self.sendCommand(SP_IO_SET+SP_IOTYPE_RELAY1+SP_VALUE_DIGITAL1)


    def OnExit(self, event):
        """Menu point Exit"""
        self.Close()

    def OnClose(self, event):
        """Called on application shutdown."""
        self.StopThread()               #stop reader thread
        self.serial.close()             #cleanup
        self.Destroy()                  #close windows, exit app

    def OnSaveAs(self, event):
        """Save contents of output window."""
        filename = None
        dlg = wx.FileDialog(None, "Save Text As...", ".", "", "Text File|*.txt|All Files|*",  wx.SAVE)
        if dlg.ShowModal() ==  wx.ID_OK:
            filename = dlg.GetPath()
        dlg.Destroy()
        
        if filename is not None:
            f = file(filename, 'w')
            text = self.text_ctrl_output.GetValue()
            if type(text) == unicode:
                text = text.encode("latin1")    #hm, is that a good asumption?
            f.write(text)
            f.close()
    
    def OnClear(self, event):
        """Clear contents of output window."""
        self.text_ctrl_output.Clear()
    
    def OnPortSettings(self, event=None):
        """Show the portsettings dialog. The reader thread is stopped for the
           settings change."""
        if event is not None:           #will be none when called on startup
            self.StopThread()
            self.serial.close()
        ok = False
        while not ok:
            dialog_serial_cfg = wxSerialConfigDialog.SerialConfigDialog(None, -1, "",
                show=wxSerialConfigDialog.SHOW_BAUDRATE|wxSerialConfigDialog.SHOW_FORMAT|wxSerialConfigDialog.SHOW_FLOW,
                serial=self.serial
            )
            result = dialog_serial_cfg.ShowModal()
            dialog_serial_cfg.Destroy()
            #open port if not called on startup, open it on startup and OK too
            if result == wx.ID_OK or event is not None:
                try:
                    self.serial.open()
                except serial.SerialException, e:
                    dlg = wx.MessageDialog(None, str(e), "Serial Port Error", wx.OK | wx.ICON_ERROR)
                    dlg.ShowModal()
                    dlg.Destroy()
                else:
                    self.StartThread()
                    self.SetTitle("Serial Terminal on %s [%s, %s%s%s%s%s]" % (
                        self.serial.portstr,
                        self.serial.baudrate,
                        self.serial.bytesize,
                        self.serial.parity,
                        self.serial.stopbits,
                        self.serial.rtscts and ' RTS/CTS' or '',
                        self.serial.xonxoff and ' Xon/Xoff' or '',
                        )
                    )
                    ok = True
            else:
                #on startup, dialog aborted
                self.alive.clear()
                ok = True

    def OnTermSettings(self, event):
        """Menu point Terminal Settings. Show the settings dialog
           with the current terminal settings"""
        dialog = TerminalSettingsDialog(None, -1, "", settings=self.settings)
        result = dialog.ShowModal()
        dialog.Destroy()
        
    def OnKey(self, event):
        """Key event handler. if the key is in the ASCII range, write it to the serial port.
           Newline handling and local echo is also done here."""
        code = event.GetKeyCode()
        if code < 256:                          #is it printable?
            if code == 13:                      #is it a newline? (check for CR which is the RETURN key)
                if self.settings.echo:          #do echo if needed
                    self.text_ctrl_output.AppendText('\n')
                if self.settings.newline == NEWLINE_CR:
                    self.serial.write('\r')     #send CR
                elif self.settings.newline == NEWLINE_LF:
                    self.serial.write('\n')     #send LF
                elif self.settings.newline == NEWLINE_CRLF:
                    self.serial.write('\r\n')   #send CR+LF
            else:
                char = chr(code)
                if self.settings.echo:          #do echo if needed
                    self.text_ctrl_output.WriteText(char)
                self.serial.write(char)         #send the charcater
        else:
            print "Extra Key:", code

    def OnSerialRead(self, event):
        """Handle input from the serial port."""
        text = event.data
        if self.settings.unprintable:
            text = ''.join([(c >= ' ') and c or '<%d>' % ord(c)  for c in text])
        self.text_ctrl_output.AppendText(text)

    def ComPortThread(self):
        """Thread that handles the incomming traffic. Does the basic input
           transformation (newlines) and generates an SerialRxEvent"""
        c=0
        while self.alive.isSet():               #loop while alive event is true
            newbyte = self.serial.read(1)          #read one, with timout
            if newbyte:
               print 'RECEIVED BYTE: ', [newbyte]
               try:
                  if self.loop == 1:
                     print 'REWRITING IN LOOP: ', [newbyte]
                     self.serial.write(newbyte)
               except:
                  pass
               if newbyte == START_SERIAL_MESSAGE and c==0:
                  print 'possible start'
                  c=c+1
                  word=[]
               elif c==1:
                  # XXX Not used for the moment.
                  c=c+1
               elif c >= 2 and len(word) < 4:
                  word.append(newbyte)
                  c=c+1
               elif c==6:
                  print 'WORD', word
                  chk=checksum(newbyte, word)
                  if not chk:
                     print 'checksum not valid'
                     c=0
                  else:
                     c=c+1
               elif c==7:
                  if newbyte==TERMINATOR:
                     #print 'terminator received'
                     res=parse(word)
                     if res:
                        event = SerialRxEvent(self.GetId(), str(time.time())+" -> "+res+"\n")
                        self.GetEventHandler().AddPendingEvent(event)
                  else:
                     print 'terminator not valid'
                  #print 'TERMINATOR', ord(TERMINATOR), ord(newbyte)
                  c=0
               else:
                  #print 'FUORI CICLO'
                  c=0

               #print ord(newbyte)
               #print START_SERIAL_MESSAGE
            #newline transformation
            #if self.settings.newline == NEWLINE_CR:
            #    text = text.replace('\r', '\n')
            #elif self.settings.newline == NEWLINE_LF:
            #    pass
            #elif self.settings.newline == NEWLINE_CRLF:
            #    text = text.replace('\r\n', '\n')
            #event = SerialRxEvent(self.GetId(), text)
            #self.GetEventHandler().AddPendingEvent(event)
            #NONO~ self.OnSerialRead(text)         #output text in window
            
# end of class TerminalFrame


class MyApp(wx.App):
    def OnInit(self):
        wx.InitAllImageHandlers()
        frame_terminal = TerminalFrame(None, -1, "")
        self.SetTopWindow(frame_terminal)
        frame_terminal.Show(1)
        return 1

# end of class MyApp

if __name__ == "__main__":
    app = MyApp(0)
    app.MainLoop()