class PlottingDataMonitor(QMainWindow):
    def __init__(self, parent=None):
        super(PlottingDataMonitor, self).__init__(parent)

        self.monitor_active = False
        self.com_monitor = None
        self.livefeed = LiveDataFeed()
        self.temperature_samples = []
        self.timer = QTimer()

        # menu
        #
        self.file_menu = self.menuBar().addMenu("&File")
        selectport_action = QAction('Select TTY &Port...', self)
        selectport_action.triggered.connect(self.on_select_port)
        self.file_menu.addAction(selectport_action)

        self.start_action = QAction('&Start monitor')
        self.start_action.triggered.connect(self.on_start)
        self.start_action.setEnabled(False)
        self.file_menu.addAction(self.start_action)

        self.stop_action = QAction('&Stop monitor')
        self.stop_action.triggered.connect(self.on_stop)

        # main widget
        #
        # port
        portname_label = QLabel('tty port:')
        self.portname = QLineEdit()
        self.portname.setEnabled(False)
        self.portname.setFrame(False)
        portname_layout = QHBoxLayout()
        portname_layout.addWidget(portname_label)
        portname_layout.addWidget(self.portname, 0)
        portname_layout.addStretch(1)
        portname_groupbox = QGroupBox('Port')
        portname_groupbox.setLayout(portname_layout)

        # plot widget
        self.plot = qwt.QwtPlot(self)
        self.plot.setCanvasBackground(Qt.black)
        self.plot.setAxisTitle(qwt.QwtPlot.xBottom, 'Time')
        self.plot.setAxisScale(qwt.QwtPlot.xBottom, 0, 10, 1)
        self.plot.setAxisTitle(qwt.QwtPlot.yLeft, 'Temperature')
        self.plot.setAxisScale(qwt.QwtPlot.yLeft, 0, 250, 40)
        self.plot.replot()

        # curve widget
        self.curve = qwt.QwtPlotCurve('')
        self.curve.setRenderHint(qwt.QwtPlotItem.RenderAntialiased)
        pen = QPen(QColor('limegreen'))
        pen.setWidth(2)
        self.curve.setPen(pen)
        self.curve.attach(self.plot)

        # dial
        #
        self.dial = QDial()
        self.dial.setNotchesVisible(True)
        self.dial.setRange(0, 20)
        self.dial.setValue(10)
        self.dial.valueChanged.connect(self.on_dial_change)

        self.dial_label = QLabel('Update speed = %s (Hz)' % self.dial.value())
        self.dial_label.setAlignment(Qt.AlignTop | Qt.AlignHCenter)
        dial_layout = QVBoxLayout()
        dial_layout.addWidget(self.dial)
        dial_layout.addWidget(self.dial_label)

        # plot layout
        plot_layout = QVBoxLayout()
        plot_layout.addWidget(self.plot)
        plot_layout.addLayout(dial_layout)

        plot_groupbox = QGroupBox('Temperature')
        plot_groupbox.setLayout(plot_layout)

        # main
        self.main_frame = QWidget()
        main_layout = QVBoxLayout()
        main_layout.addWidget(portname_groupbox)
        main_layout.addWidget(plot_groupbox)
        main_layout.addStretch(1)
        self.main_frame.setLayout(main_layout)

        self.setCentralWidget(self.main_frame)

        # status
        #
        self.status_text = QLabel('Monitor idle')
        self.statusBar().addWidget(self.status_text, 1)

    def set_actions_enable_state(self):
        if self.portname.text() == '':
            start_enable = stop_enable = False
        else:
            start_enable = not self.monitor_active
            stop_enable = self.monitor_active

        self.start_action.setEnabled(start_enable)
        self.stop_action.setEnabled(stop_enable)

    def read_serial_data(self):
        '''Called periodically be the update timer to read data from the
serial port.

        '''
        qdata = list(get_all_from_queue(self.data_q))
        if len(qdata) > 0:
            # print(len(qdata))

            data = dict(timestamp=qdata[-1][1], temperature=ord(qdata[-1][0]))
            # print(data)
            self.livefeed.add_data(data)
        else:
            print('no data')

    def update_monitor(self):
        '''Updates the state of the monitor window with new data. The
livefeed is used to dind out whether new data was received since last
update. If not, nothing is updated.

        '''
        if self.livefeed.has_new_data:
            data = self.livefeed.read_data()
            # print(data)
            self.temperature_samples.append(
                (data['timestamp'], data['temperature']))
            if len(self.temperature_samples) > 100:
                self.temperature_samples.pop(0)

            xdata = [s[0] for s in self.temperature_samples]
            ydata = [s[1] for s in self.temperature_samples]

            avg = sum(ydata) / float(len(ydata))

            self.plot.setAxisScale(qwt.QwtPlot.xBottom, xdata[0],
                                   max(20, xdata[-1]))
            self.curve.setData(xdata, ydata)
            self.plot.replot()

    # slots
    def on_select_port(self):
        text, ok = QInputDialog.getText(self, 'Port Name', 'Enter tty:')
        if ok:
            self.portname.setText(str(text))
            self.set_actions_enable_state()

    def on_start(self):
        '''Start the monitor: com_monitor thread and the update timer'''
        if self.com_monitor is not None or self.portname.text() == '':
            return

        self.data_q = Queue()
        self.error_q = Queue()
        self.com_monitor = ComMonitorThread(self.data_q, self.error_q,
                                            self.portname.text(), 38400)
        self.com_monitor.start()
        com_error = None
        try:
            com_error = self.error_q.get(True, 0.01)
        except Empty:
            pass
        if com_error is not None:
            QMessageBox.critical(self, 'ComMonitorThread error', com_error)
            self.com_monitor = None

        self.monitor_active = True
        self.set_actions_enable_state()

        self.timer = QTimer()
        self.timer.timeout.connect(self.on_timer)

        update_freq = self.dial.value()
        if update_freq > 0:
            self.timer.start(1000 / update_freq)

        self.status_text.setText('Monitor running')

    def on_stop(self):
        '''Stop the monitor'''
        if self.com_monitor is not None:
            self.com_monitor.join(0.01)
            self.com_monitor = None

        self.monitor_actibe = False
        self.timer.stop()
        self.set_actions_enable_state()

        self.status_text.setText('Monitor idle')

    def on_timer(self):
        '''Executed periodically when the monitor update timer is fired.'''
        self.read_serial_data()
        self.update_monitor()

    def on_dial_change(self):
        '''When the dial is rotated, it sets the update interval of the
timer'''
        update_freq = self.dial.value()
        self.dial_label.setText('Update speed = %s (Hz)' % self.dial.value())

        if self.timer.isActive():
            update_freq = max(0.01, update_freq)
            self.timer.setInterval(1000 / update_freq)
class PlottingDataMonitor(QMainWindow):
    def __init__(self, parent=None):
        super(PlottingDataMonitor, self).__init__(parent)

        self.setWindowTitle('ADXL345 Realtime Monitor')
        self.resize(800, 600)
        
        self.port           = ""
        self.baudrate       = 9600
        self.monitor_active = False                 # on/off monitor state
        self.com_monitor    = None                  # monitor reception thread
        self.com_data_q     = None
        self.com_error_q    = None
        self.livefeed       = LiveDataFeed()
        self.timer          = QTimer()
        self.g_samples      = [[], [], []]
        self.curve          = [None]*3
        self.gcurveOn       = [1]*3                 # by default all curve are plotted
        self.csvdata        = []
        
        self.create_menu()
        self.create_main_frame()
        self.create_status_bar()

        # Activate start-stop button connections
        self.connect(self.button_Connect, SIGNAL("clicked()"),
                    self.OnStart)
        self.connect(self.button_Disconnect, SIGNAL("clicked()"),
                    self.OnStop)
    #----------------------------------------------------------


    def create_com_box(self):
        """
        Purpose:   create the serial com groupbox
        Return:    return a layout of the serial com
        """
        self.com_box = QGroupBox("COM Configuration")

        com_layout = QGridLayout()

        self.radio115200    =    QRadioButton("115200")
        self.radio115200.setChecked(1)
        self.radio19200    =    QRadioButton("19200")
        self.radio9600     =    QRadioButton("9600")
        self.Com_ComboBox  =    QComboBox()

        com_layout.addWidget(self.Com_ComboBox,0,0,1,3)
        com_layout.addWidget(self.radio115200,1,0)
        com_layout.addWidget(self.radio19200,1,1)
        com_layout.addWidget(self.radio9600,1,2)
        self.fill_ports_combobox()

        self.button_Connect      =   QPushButton("Start")
        self.button_Disconnect   =   QPushButton("Stop")
        self.button_Disconnect.setEnabled(False)

        com_layout.addWidget(self.button_Connect,0,3)
        com_layout.addWidget(self.button_Disconnect,1,3)

        return com_layout
    #---------------------------------------------------------------------


    def create_plot(self):
        """ 
        Purpose:   create the pyqwt plot
        Return:    return a list containing the plot and the list of the curves
        """
        plot = Qwt.QwtPlot(self)
        plot.setCanvasBackground(Qt.black)
        plot.setAxisTitle(Qwt.QwtPlot.xBottom, 'Time')
        plot.setAxisScale(Qwt.QwtPlot.xBottom, 0, 10, 1)
        plot.setAxisTitle(Qwt.QwtPlot.yLeft, 'Acceleration')
        plot.setAxisScale(Qwt.QwtPlot.yLeft, YMIN, YMAX, (YMAX-YMIN)/10)
        plot.replot()
        
        curve = [None]*3
        pen = [QPen(QColor('limegreen')), QPen(QColor('red')) ,QPen(QColor('yellow')) ]
        for i in range(3):
            curve[i] =  Qwt.QwtPlotCurve('')
            curve[i].setRenderHint(Qwt.QwtPlotItem.RenderAntialiased)
            pen[i].setWidth(2)
            curve[i].setPen(pen[i])
            curve[i].attach(plot)

        return plot, curve
    #---------------------------------------------------


    def create_knob(self):
        """ 
        Purpose:   create a knob
        Return:    return a the knob widget
        """
        knob = Qwt.QwtKnob(self)
        knob.setRange(0, 180, 0, 1)
        knob.setScaleMaxMajor(10)
        knob.setKnobWidth(50)
        knob.setValue(180)
        return knob
    #---------------------------------------------------


    def create_status_bar(self):
        self.status_text = QLabel('Monitor idle')
        self.statusBar().addWidget(self.status_text, 1)
    #---------------------------------------------------


    def create_checkbox(self, label, color, connect_fn, connect_param):
        """
        Purpose:    create a personalized checkbox
        Input:      the label, color, activated function and the transmitted parameter
        Return:     return a checkbox widget
        """
        checkBox = QCheckBox(label)
        checkBox.setChecked(1)
        checkBox.setFont( QFont("Arial", pointSize=12, weight=QFont.Bold ) )
        green = QPalette()
        green.setColor(QPalette.Foreground, color)
        checkBox.setPalette(green)
        self.connect(checkBox, SIGNAL("clicked()"), partial(connect_fn,connect_param))
        return checkBox
        #---------------------------------------------------


    def create_main_frame(self):
        """
        Purpose:    create the main frame Qt widget
        """
        # Serial communication combo box
        portname_layout = self.create_com_box()
        self.com_box.setLayout(portname_layout)
        
        # Update speed knob
        self.updatespeed_knob = self.create_knob()
        self.connect(self.updatespeed_knob, SIGNAL('valueChanged(double)'),
            self.on_knob_change)
        self.knob_l = QLabel('Update speed = %s (Hz)' % self.updatespeed_knob.value())
        self.knob_l.setAlignment(Qt.AlignTop | Qt.AlignHCenter)

        # Create the plot and curves
        self.plot, self.curve = self.create_plot()

        # Create the configuration horizontal panel
        self.max_spin    = QSpinBox()
        self.max_spin.setMaximum(10000)
        self.max_spin.setValue(10000)
        spins_hbox      = QHBoxLayout()
        spins_hbox.addWidget(QLabel('Save every'))
        spins_hbox.addWidget(self.max_spin)
        spins_hbox.addWidget( QLabel('Lines'))
        #spins_hbox.addStretch(1)

        self.gCheckBox   =  [   self.create_checkbox("Acceleration(x)", Qt.green, self.activate_curve, 0),
                                self.create_checkbox("Acceleration(y)", Qt.red, self.activate_curve, 1),
                                self.create_checkbox("Acceleration(z)", Qt.yellow, self.activate_curve, 2)
                            ]

        self.button_clear      =   QPushButton("Clear screen")

        self.connect(self.button_clear, SIGNAL("clicked()"),
                    self.clear_screen)

        # Place the horizontal panel widget
        plot_layout = QGridLayout()
        plot_layout.addWidget(self.plot,0,0,8,7)
        plot_layout.addWidget(self.gCheckBox[0],0,8)
        plot_layout.addWidget(self.gCheckBox[1],1,8)
        plot_layout.addWidget(self.gCheckBox[2],2,8)
        plot_layout.addWidget(self.button_clear,3,8)
        plot_layout.addLayout(spins_hbox,4,8)
        plot_layout.addWidget(self.updatespeed_knob,5,8)
        plot_layout.addWidget(self.knob_l,6,8)
        
        plot_groupbox = QGroupBox('Acceleration')
        plot_groupbox.setLayout(plot_layout)
        
        # Place the main frame and layout
        self.main_frame = QWidget()
        main_layout 	= QVBoxLayout()
        main_layout.addWidget(self.com_box)
        main_layout.addWidget(plot_groupbox)
        main_layout.addStretch(1)
        self.main_frame.setLayout(main_layout)
        
        self.setCentralWidget(self.main_frame)
    #----------------------------------------------------------------------


    def clear_screen(self):
        self.g_samples = [[], [], []]
        self.plot.setAxisScale(Qwt.QwtPlot.xBottom, 0, 10)
        for i in range(3):
            self.curve[i].setData([], [])
        self.plot.replot()
    #-----------------------------


    def activate_curve(self, axe):
        if self.gCheckBox[axe].isChecked():
            self.gcurveOn[axe]  = 1
        else:
            self.gcurveOn[axe]  = 0
    #---------------------------------------


    def create_menu(self):
        self.file_menu = self.menuBar().addMenu("&File")
        
        selectport_action = self.create_action("Select COM &Port...",
            shortcut="Ctrl+P", slot=self.on_select_port, tip="Select a COM port")
        self.start_action = self.create_action("&Start monitor",
            shortcut="Ctrl+M", slot=self.OnStart, tip="Start the data monitor")
        self.stop_action = self.create_action("&Stop monitor",
            shortcut="Ctrl+T", slot=self.OnStop, tip="Stop the data monitor")
        exit_action = self.create_action("E&xit", slot=self.close, 
            shortcut="Ctrl+X", tip="Exit the application")
        
        self.start_action.setEnabled(False)
        self.stop_action.setEnabled(False)
        
        self.add_actions(self.file_menu, 
            (   selectport_action, self.start_action, self.stop_action,
                None, exit_action))
            
        self.help_menu = self.menuBar().addMenu("&Help")
        about_action = self.create_action("&About",
            shortcut='F1', slot=self.on_about,
            tip='About the monitor')
        
        self.add_actions(self.help_menu, (about_action,))
    #----------------------------------------------------------------------


    def set_actions_enable_state(self):
        if self.portname.text() == '':
            start_enable = stop_enable = False
        else:
            start_enable = not self.monitor_active
            stop_enable = self.monitor_active
        
        self.start_action.setEnabled(start_enable)
        self.stop_action.setEnabled(stop_enable)
    #-----------------------------------------------


    def on_about(self):
        msg = __doc__
        QMessageBox.about(self, "About the demo", msg.strip())
    #-----------------------------------------------


    def on_select_port(self):
        
        ports = enumerate_serial_ports()
        
        if len(ports) == 0:
            QMessageBox.critical(self, 'No ports',
                'No serial ports found')
            return
        
        item, ok = QInputDialog.getItem(self, 'Select a port',
                    'Serial port:', ports, 0, False)
        
        if ok and not item.isEmpty():
            self.portname.setText(item)
            self.set_actions_enable_state()
    #-----------------------------------------------


    def fill_ports_combobox(self):
        """ Purpose: rescan the serial port com and update the combobox
        """
        vNbCombo = ""
        self.Com_ComboBox.clear()
        self.AvailablePorts = enumerate_serial_ports()
        for value in self.AvailablePorts:
            self.Com_ComboBox.addItem(value)
            vNbCombo += value + " - "
        vNbCombo = vNbCombo[:-3]

        debug(("--> Les ports series disponibles sont: %s " % (vNbCombo)))
    #----------------------------------------------------------------------


    def OnStart(self):
        """ Start the monitor: com_monitor thread and the update timer
        """
        if self.radio115200.isChecked():
            self.baudrate = 115200
            print "--> baudrate is 115200 bps"
        if self.radio19200.isChecked():
            self.baudrate = 19200
            print "--> baudrate is 19200 bps"
        if self.radio9600.isChecked():
            self.baudrate = 9600
            print "--> baudrate is 9600 bps"

        vNbCombo    = self.Com_ComboBox.currentIndex()
        self.port   = self.AvailablePorts[vNbCombo]

        self.button_Connect.setEnabled(False)
        self.button_Disconnect.setEnabled(True)
        self.Com_ComboBox.setEnabled(False)

        self.data_q      =  Queue.Queue()
        self.error_q     =  Queue.Queue()
        self.com_monitor =  ComMonitorThread(
                                            self.data_q,
                                            self.error_q,
                                            self.port,
                                            self.baudrate)
        
        self.com_monitor.start()

        com_error = get_item_from_queue(self.error_q)
        if com_error is not None:
            QMessageBox.critical(self, 'ComMonitorThread error',
                com_error)
            self.com_monitor = None  

        self.monitor_active = True

        self.connect(self.timer, SIGNAL('timeout()'), self.on_timer)
        
        update_freq = self.updatespeed_knob.value()
        if update_freq > 0:
            self.timer.start(1000.0 / update_freq)
        
        self.status_text.setText('Monitor running')
        debug('--> Monitor running')
    #------------------------------------------------------------


    def OnStop(self):
        """ Stop the monitor
        """
        if self.com_monitor is not None:
            self.com_monitor.join(1000)
            self.com_monitor = None

        self.monitor_active = False
        self.button_Connect.setEnabled(True)
        self.button_Disconnect.setEnabled(False)
        self.Com_ComboBox.setEnabled(True)
        self.timer.stop()
        self.status_text.setText('Monitor idle')
        debug('--> Monitor idle')
    #-----------------------------------------------


    def on_timer(self):
        """ Executed periodically when the monitor update timer
            is fired.
        """
        self.read_serial_data()
        self.update_monitor()
    #-----------------------------------------------


    def on_knob_change(self):
        """ When the knob is rotated, it sets the update interval
            of the timer.
        """
        update_freq = self.updatespeed_knob.value()
        self.knob_l.setText('Update speed = %s (Hz)' % self.updatespeed_knob.value())

        if self.timer.isActive():
            update_freq = max(0.01, update_freq)
            self.timer.setInterval(1000.0 / update_freq)
    #-----------------------------------------------


    def update_monitor(self):
        """ Updates the state of the monitor window with new 
            data. The livefeed is used to find out whether new
            data was received since the last update. If not, 
            nothing is updated.
        """
        if self.livefeed.has_new_data:
            data = self.livefeed.read_data()

            self.csvdata.append([data['timestamp'], data['gx'], data['gy'], data['gz']] )
            if len(self.csvdata) > self.max_spin.value():
                f = open(time.strftime("%H%M%S")+".csv", 'wt')
                try:
                    writer = csv.writer(f)
                    for i in range(self.max_spin.value()):
                        writer.writerow( self.csvdata[i] )
                    print 'transfer data to csv after 10000 samples'
                finally:
                    f.close()
                self.csvdata = []

            self.g_samples[0].append(
                (data['timestamp'], data['gx']))
            if len(self.g_samples[0]) > 1000:
                self.g_samples[0].pop(0)

            self.g_samples[1].append(
                (data['timestamp'], data['gy']))
            if len(self.g_samples[1]) > 1000:
                self.g_samples[1].pop(0)

            self.g_samples[2].append(
                (data['timestamp'], data['gz']))
            if len(self.g_samples[2]) > 1000:
                self.g_samples[2].pop(0)

            tdata = [s[0] for s in self.g_samples[2]]

            for i in range(3):
                data[i] = [s[1] for s in self.g_samples[i]]
                if self.gcurveOn[i]:
                    self.curve[i].setData(tdata, data[i])

            """
            debug("xdata", data[0])
            debug("ydata", data[1])
            debug("tdata", data[2])
            """

            #self.plot.setAxisScale(Qwt.QwtPlot.xBottom, tdata[0], max(10, tdata[-1]) )

            self.plot.replot()
    #-----------------------------------------------


    def read_serial_data(self):
        """ Called periodically by the update timer to read data
            from the serial port.
        """
        qdata = list(get_all_from_queue(self.data_q))
        # get just the most recent data, others are lost
        #print "qdata" , qdata
        if len(qdata) > 0:
            data = dict(timestamp=qdata[-1][1], 
                        gx=qdata[-1][0][0],
                        gy=qdata[-1][0][1],
                        gz=qdata[-1][0][2]
                        )
            self.livefeed.add_data(data)
    #-----------------------------------------------


    # The following two methods are utilities for simpler creation
    # and assignment of actions
    #
    def add_actions(self, target, actions):
        for action in actions:
            if action is None:
                target.addSeparator()
            else:
                target.addAction(action)
    #-----------------------------------------------


    def create_action(  self, text, slot=None, shortcut=None, 
                        icon=None, tip=None, checkable=False, 
                        signal="triggered()"):
        action = QAction(text, self)
        if icon is not None:
            action.setIcon(QIcon(":/%s.png" % icon))
        if shortcut is not None:
            action.setShortcut(shortcut)
        if tip is not None:
            action.setToolTip(tip)
            action.setStatusTip(tip)
        if slot is not None:
            self.connect(action, SIGNAL(signal), slot)
        if checkable:
            action.setCheckable(True)
        return action
class PlottingDataMonitor(QMainWindow):
    def __init__(self, parent=None):
        super(PlottingDataMonitor, self).__init__(parent)

        self.setWindowTitle('ADXL345 Realtime Monitor')
        self.resize(800, 600)
        
        self.port           = ""
        self.baudrate       = 9600
        self.monitor_active = False                 # on/off monitor state
        self.com_monitor    = None                  # monitor reception thread
        self.com_data_q     = None
        self.com_error_q    = None
        self.livefeed       = LiveDataFeed()
        self.timer          = QTimer()
        self.g_samples      = [[], [], []]
        self.curve          = [None]*3
        self.gcurveOn       = [1]*3                 # by default all curve are plotted
        self.csvdata        = []    
        
        self.create_menu()
        self.create_main_frame()
        self.create_status_bar()

        # Activate start-stop button connections
        self.connect(self.button_Connect, SIGNAL("clicked()"),
                    self.OnStart)
        self.connect(self.button_Disconnect, SIGNAL("clicked()"),
                    self.OnStop)
    #----------------------------------------------------------


    def create_com_box(self):
        """ 
        Purpose:   create the serial com groupbox
        Return:    return a layout of the serial com
        """
        self.com_box = QGroupBox("COM Configuration")

        com_layout = QGridLayout()

        self.radio9600     =    QRadioButton("9600")
        self.radio9600.setChecked(1)
        self.radio19200    =    QRadioButton("19200")
        self.Com_ComboBox  =    QComboBox()

        com_layout.addWidget(self.Com_ComboBox,0,0,1,2)
        com_layout.addWidget(self.radio9600,1,0)
        com_layout.addWidget(self.radio19200,1,1)
        self.fill_ports_combobox()

        self.button_Connect      =   QPushButton("Start")
        self.button_Disconnect   =   QPushButton("Stop")
        self.button_Disconnect.setEnabled(False)

        com_layout.addWidget(self.button_Connect,0,2)
        com_layout.addWidget(self.button_Disconnect,1,2)        

        return com_layout
    #---------------------------------------------------------------------
   

    def create_plot(self):
        """ 
        Purpose:   create the pyqwt plot
        Return:    return a list containing the plot and the list of the curves
        """
        plot = Qwt.QwtPlot(self)
        plot.setCanvasBackground(Qt.black)
        plot.setAxisTitle(Qwt.QwtPlot.xBottom, 'Time')
        plot.setAxisScale(Qwt.QwtPlot.xBottom, 0, 10, 1)
        plot.setAxisTitle(Qwt.QwtPlot.yLeft, 'Acceleration')
        plot.setAxisScale(Qwt.QwtPlot.yLeft, YMIN, YMAX, (YMAX-YMIN)/10)
        plot.replot()
        
        curve = [None]*3
        pen = [QPen(QColor('limegreen')), QPen(QColor('red')) ,QPen(QColor('yellow')) ]
        for i in range(3):
            curve[i] =  Qwt.QwtPlotCurve('')
            curve[i].setRenderHint(Qwt.QwtPlotItem.RenderAntialiased)
            pen[i].setWidth(2)
            curve[i].setPen(pen[i])
            curve[i].attach(plot)

        return plot, curve
    #---------------------------------------------------


    def create_knob(self):
        """ 
        Purpose:   create a knob
        Return:    return a the knob widget
        """
        knob = Qwt.QwtKnob(self)
        knob.setRange(0, 180, 0, 1)
        knob.setScaleMaxMajor(10)
        knob.setKnobWidth(50)
        knob.setValue(10)
        return knob
    #---------------------------------------------------


    def create_status_bar(self):
        self.status_text = QLabel('Monitor idle')
        self.statusBar().addWidget(self.status_text, 1)
    #---------------------------------------------------


    def create_checkbox(self, label, color, connect_fn, connect_param):
        """ 
        Purpose:    create a personalized checkbox
        Input:      the label, color, activated function and the transmitted parameter
        Return:     return a checkbox widget
        """
        checkBox = QCheckBox(label)
        checkBox.setChecked(1)
        checkBox.setFont( QFont("Arial", pointSize=12, weight=QFont.Bold ) )
        green = QPalette()
        green.setColor(QPalette.Foreground, color)
        checkBox.setPalette(green)
        self.connect(checkBox, SIGNAL("clicked()"), partial(connect_fn,connect_param))
        return checkBox
        #---------------------------------------------------


    def create_main_frame(self):
        """ 
        Purpose:    create the main frame Qt widget
        """
        # Serial communication combo box
        portname_layout = self.create_com_box()
        self.com_box.setLayout(portname_layout)
        
        # Update speed knob
        self.updatespeed_knob = self.create_knob()
        self.connect(self.updatespeed_knob, SIGNAL('valueChanged(double)'),
            self.on_knob_change)
        self.knob_l = QLabel('Update speed = %s (Hz)' % self.updatespeed_knob.value())
        self.knob_l.setAlignment(Qt.AlignTop | Qt.AlignHCenter)

        # Create the plot and curves
        self.plot, self.curve = self.create_plot()

        # Create the configuration horizontal panel
        self.max_spin    = QSpinBox()
        self.max_spin.setMaximum(1000)
        self.max_spin.setValue(1000)
        spins_hbox      = QHBoxLayout()
        spins_hbox.addWidget(QLabel('Save every'))
        spins_hbox.addWidget(self.max_spin)
        spins_hbox.addWidget( QLabel('Lines'))
        #spins_hbox.addStretch(1)

        self.gCheckBox   =  [   self.create_checkbox("Acceleration(x)", Qt.green, self.activate_curve, 0),
                                self.create_checkbox("Acceleration(y)", Qt.red, self.activate_curve, 1),
                                self.create_checkbox("Acceleration(z)", Qt.yellow, self.activate_curve, 2)
                            ]

        self.button_clear      =   QPushButton("Clear screen")

        self.connect(self.button_clear, SIGNAL("clicked()"),
                    self.clear_screen)
        
        # Place the horizontal panel widget
        plot_layout = QGridLayout()
        plot_layout.addWidget(self.plot,0,0,8,7)
        plot_layout.addWidget(self.gCheckBox[0],0,8)
        plot_layout.addWidget(self.gCheckBox[1],1,8)
        plot_layout.addWidget(self.gCheckBox[2],2,8)
        plot_layout.addWidget(self.button_clear,3,8)
        plot_layout.addLayout(spins_hbox,4,8)
        plot_layout.addWidget(self.updatespeed_knob,5,8)
        plot_layout.addWidget(self.knob_l,6,8)
        
        plot_groupbox = QGroupBox('Acceleration')
        plot_groupbox.setLayout(plot_layout)
        
        # Place the main frame and layout
        self.main_frame = QWidget()
        main_layout 	= QVBoxLayout()
        main_layout.addWidget(self.com_box)
        main_layout.addWidget(plot_groupbox)
        main_layout.addStretch(1)
        self.main_frame.setLayout(main_layout)
        
        self.setCentralWidget(self.main_frame)
    #----------------------------------------------------------------------


    def clear_screen(self):
        g_samples[0] = []
    #-----------------------------
        

    def activate_curve(self, axe):
        if self.gCheckBox[axe].isChecked():
            self.gcurveOn[axe]  = 1
        else:
            self.gcurveOn[axe]  = 0
    #---------------------------------------


    def create_menu(self):
        self.file_menu = self.menuBar().addMenu("&File")
        
        selectport_action = self.create_action("Select COM &Port...",
            shortcut="Ctrl+P", slot=self.on_select_port, tip="Select a COM port")
        self.start_action = self.create_action("&Start monitor",
            shortcut="Ctrl+M", slot=self.OnStart, tip="Start the data monitor")
        self.stop_action = self.create_action("&Stop monitor",
            shortcut="Ctrl+T", slot=self.OnStop, tip="Stop the data monitor")
        exit_action = self.create_action("E&xit", slot=self.close, 
            shortcut="Ctrl+X", tip="Exit the application")
        
        self.start_action.setEnabled(False)
        self.stop_action.setEnabled(False)
        
        self.add_actions(self.file_menu, 
            (   selectport_action, self.start_action, self.stop_action,
                None, exit_action))
            
        self.help_menu = self.menuBar().addMenu("&Help")
        about_action = self.create_action("&About", 
            shortcut='F1', slot=self.on_about, 
            tip='About the monitor')
        
        self.add_actions(self.help_menu, (about_action,))
    #----------------------------------------------------------------------


    def set_actions_enable_state(self):
        if self.portname.text() == '':
            start_enable = stop_enable = False
        else:
            start_enable = not self.monitor_active
            stop_enable = self.monitor_active
        
        self.start_action.setEnabled(start_enable)
        self.stop_action.setEnabled(stop_enable)
    #-----------------------------------------------


    def on_about(self):
        msg = __doc__
        QMessageBox.about(self, "About the demo", msg.strip())
    #-----------------------------------------------

    

    def on_select_port(self):
        
        ports = enumerate_serial_ports()
        
        if len(ports) == 0:
            QMessageBox.critical(self, 'No ports',
                'No serial ports found')
            return
        
        item, ok = QInputDialog.getItem(self, 'Select a port',
                    'Serial port:', ports, 0, False)
        
        if ok and not item.isEmpty():
            self.portname.setText(item)            
            self.set_actions_enable_state()
    #-----------------------------------------------


    def fill_ports_combobox(self):
        """ Purpose: rescan the serial port com and update the combobox
        """
        vNbCombo = ""
        self.Com_ComboBox.clear()
        self.AvailablePorts = enumerate_serial_ports()
        for value in self.AvailablePorts:
            self.Com_ComboBox.addItem(value)
            vNbCombo += value + " - "
        vNbCombo = vNbCombo[:-3] 

        debug(("--> Les ports series disponibles sont: %s " % (vNbCombo)))
    #----------------------------------------------------------------------


    def OnStart(self):
        """ Start the monitor: com_monitor thread and the update timer     
        """
        if self.radio19200.isChecked():
            self.baudrate = 19200
            print "--> baudrate is 19200 bps"
        if self.radio9600.isChecked():
            self.baudrate = 9600
            print "--> baudrate is 9600 bps"  

        vNbCombo    = self.Com_ComboBox.currentIndex()
        self.port   = self.AvailablePorts[vNbCombo]

        self.button_Connect.setEnabled(False)
        self.button_Disconnect.setEnabled(True)
        self.Com_ComboBox.setEnabled(False)

        self.data_q      =  Queue.Queue()
        self.error_q     =  Queue.Queue()
        self.com_monitor =  ComMonitorThread(
                                            self.data_q,
                                            self.error_q,
                                            self.port,
                                            self.baudrate)
        
        self.com_monitor.start()  

        com_error = get_item_from_queue(self.error_q)
        if com_error is not None:
            QMessageBox.critical(self, 'ComMonitorThread error',
                com_error)
            self.com_monitor = None  

        self.monitor_active = True

        self.connect(self.timer, SIGNAL('timeout()'), self.on_timer)
        
        update_freq = self.updatespeed_knob.value()
        if update_freq > 0:
            self.timer.start(1000.0 / update_freq)
        
        self.status_text.setText('Monitor running')
        debug('--> Monitor running')
    #------------------------------------------------------------


    def OnStop(self):
        """ Stop the monitor
        """
        if self.com_monitor is not None:
            self.com_monitor.join(1000)
            self.com_monitor = None

        self.monitor_active = False
        self.button_Connect.setEnabled(True)
        self.button_Disconnect.setEnabled(False)
        self.Com_ComboBox.setEnabled(True)
        self.timer.stop()
        self.status_text.setText('Monitor idle')
        debug('--> Monitor idle')
    #-----------------------------------------------


    def on_timer(self):
        """ Executed periodically when the monitor update timer
            is fired.
        """
        self.read_serial_data()
        self.update_monitor()
	#-----------------------------------------------


    def on_knob_change(self):
        """ When the knob is rotated, it sets the update interval
            of the timer.
        """
        update_freq = self.updatespeed_knob.value()
        self.knob_l.setText('Update speed = %s (Hz)' % self.updatespeed_knob.value())

        if self.timer.isActive():
            update_freq = max(0.01, update_freq)
            self.timer.setInterval(1000.0 / update_freq)
    #-----------------------------------------------


    def update_monitor(self):
        """ Updates the state of the monitor window with new 
            data. The livefeed is used to find out whether new
            data was received since the last update. If not, 
            nothing is updated.
        """
        if self.livefeed.has_new_data:
            data = self.livefeed.read_data()

            self.csvdata.append([data['timestamp'], data['gx'], data['gy'], data['gz']] )
            if len(self.csvdata) > self.max_spin.value():
                f = open(time.strftime("%H%M%S")+".csv", 'wt')
                try:
                    writer = csv.writer(f)
                    for i in range(self.max_spin.value()):
                        writer.writerow( self.csvdata[i] )
                    print 'transfert data to csv after 1000 samples'
                finally:
                    f.close()
                self.csvdata = []
            
            self.g_samples[0].append(
                (data['timestamp'], data['gx']))
            if len(self.g_samples[0]) > 100:
                self.g_samples[0].pop(0)

            self.g_samples[1].append(
                (data['timestamp'], data['gy']))
            if len(self.g_samples[1]) > 100:
                self.g_samples[1].pop(0)

            self.g_samples[2].append(
                (data['timestamp'], data['gz']))
            if len(self.g_samples[2]) > 100:
                self.g_samples[2].pop(0)

            tdata = [s[0] for s in self.g_samples[2]]

            for i in range(3):
                data[i] = [s[1] for s in self.g_samples[i]]
                if self.gcurveOn[i]:
                    self.curve[i].setData(tdata, data[i])

            """
            debug("xdata", data[0])
            debug("ydata", data[1])
            debug("tdata", data[2])
            """

            self.plot.setAxisScale(Qwt.QwtPlot.xBottom, tdata[0], max(5, tdata[-1]) )        
            
            self.plot.replot()
    #-----------------------------------------------
            
            
    def read_serial_data(self):
        """ Called periodically by the update timer to read data
            from the serial port.
        """
        qdata = list(get_all_from_queue(self.data_q))
        # get just the most recent data, others are lost
        #print "qdata" , qdata
        if len(qdata) > 0:
            data = dict(timestamp=qdata[-1][1], 
                        gx=qdata[-1][0][0],
                        gy=qdata[-1][0][1],
                        gz=qdata[-1][0][2]
                        )
            self.livefeed.add_data(data)
    #-----------------------------------------------


    
    # The following two methods are utilities for simpler creation
    # and assignment of actions
    #
    def add_actions(self, target, actions):
        for action in actions:
            if action is None:
                target.addSeparator()
            else:
                target.addAction(action)
    #-----------------------------------------------


    def create_action(  self, text, slot=None, shortcut=None, 
                        icon=None, tip=None, checkable=False, 
                        signal="triggered()"):
        action = QAction(text, self)
        if icon is not None:
            action.setIcon(QIcon(":/%s.png" % icon))
        if shortcut is not None:
            action.setShortcut(shortcut)
        if tip is not None:
            action.setToolTip(tip)
            action.setStatusTip(tip)
        if slot is not None:
            self.connect(action, SIGNAL(signal), slot)
        if checkable:
            action.setCheckable(True)
        return action