<commit_before># Copyright (C) 2016 OpenMotics BVBA
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
"""
Service that drives the leds and checks the switch on the front panel of the gateway.
This service allows other services to set the leds over dbus and check whether the
gateway is in authorized mode.
"""

import gobject
import sys
import fcntl
import time
try:
    import json
except ImportError:
    import simplejson as json
from threading import Thread
from ConfigParser import ConfigParser

from bus.dbus_service import DBusService
from platform_utils import Hardware
import constants

AUTH_MODE_LEDS = [Hardware.Led.ALIVE, Hardware.Led.CLOUD, Hardware.Led.VPN, Hardware.Led.COMM_1, Hardware.Led.COMM_2]

class LOGGER(object):
    @staticmethod
    def log(line):
        sys.stdout.write('{0}\n'.format(line))
        sys.stdout.flush()

class LedController(object):
    """
    The LEDController contains all logic to control the leds, and read out the physical buttons
    """

    def __init__(self, i2c_device, i2c_address, input_button):
        self._i2c_device = i2c_device
        self._i2c_address = i2c_address
        self._input_button = input_button
        self._input_button_pressed_since = None
        self._input_button_released = True

        self._network_enabled = False
        self._network_activity = False
        self._network_bytes = 0

        self._serial_activity = {4: False, 5: False}
        self._enabled_leds = {}
        self._previous_leds = {}
        self._last_i2c_led_code = 0

        self._authorized_mode = False
        self._authorized_timeout = 0

        self._check_states_thread = None

        self._last_run_i2c = 0
        self._last_run_gpio = 0
        self._last_state_check = 0
        self._last_button_check = 0

        self._gpio_led_config = Hardware.get_gpio_led_config()
        self._i2c_led_config = Hardware.get_i2c_led_config()
        for led in self._gpio_led_config.keys() + self._i2c_led_config.keys():
            self._enabled_leds[led] = False
            self._write_leds()

    def start(self):
        """ Start the leds and buttons thread. """
        self._check_states_thread = Thread(target=self._check_states)
        self._check_states_thread.daemon = True
        self._check_states_thread.start()

    def set_led(self, led_name, enable):
        """ Set the state of a LED, enabled means LED on in this context. """
        self._enabled_leds[led_name] = bool(enable)

    def toggle_led(self, led_name):
        """ Toggle the state of a LED. """
        self._enabled_leds[led_name] = not self._enabled_leds.get(led_name, False)

    def serial_activity(self, port):
        """ Report serial activity on the given serial port. Port is 4 or 5. """
        self._serial_activity[port] = True

    @staticmethod
    def _is_button_pressed(gpio_pin):
        """ Read the input button: returns True if the button is pressed, False if not. """
        with open('/sys/class/gpio/gpio{0}/value'.format(gpio_pin), 'r') as fh_inp:
            line = fh_inp.read()
        return int(line) == 0

    def _write_leds(self):
        """ Set the LEDs using the current status. """
        try:
            # Get i2c code
            code = 0
            for led in self._i2c_led_config.keys():
                if self._enabled_leds.get(led, False) is True:
                    code |= self._i2c_led_config[led]
            if self._authorized_mode:
                # Light all leds in authorized mode
                for led in AUTH_MODE_LEDS:
                    code |= self._i2c_led_config.get(led, 0)
            code = (~ code) & 255

            # Push code if needed
            if code != self._last_i2c_led_code:
                self._last_i2c_led_code = code
                with open(self._i2c_device, 'r+', 1) as i2c:
                    fcntl.ioctl(i2c, Hardware.IOCTL_I2C_SLAVE, self._i2c_address)
                    i2c.write(chr(code))
                    self._last_run_i2c = time.time()
            else:
                self._last_run_i2c = time.time()
        except Exception as exception:
            LOGGER.log('Error while writing to i2c: {0}'.format(exception))

        for led in self._gpio_led_config.keys():
            on = self._enabled_leds.get(led, False)
            if self._previous_leds.get(led) != on:
                self._previous_leds[led] = on
                try:
                    gpio = self._gpio_led_config[led]
                    with open('/sys/class/gpio/gpio{0}/value'.format(gpio), 'w') as fh_s:
                        fh_s.write('1' if on else '0')
                        self._last_run_gpio = time.time()
                except IOError:
                    pass  # The GPIO doesn't exist or is read only
            else:
                self._last_run_gpio = time.time()

    def _check_states(self):
        """ Checks various states of the system (network) """
        while True:
            try:
                with open('/sys/class/net/eth0/carrier', 'r') as fh_up:
                    line = fh_up.read()
                self._network_enabled = int(line) == 1

                with open('/proc/net/dev', 'r') as fh_stat:
                    for line in fh_stat.readlines():
                        if 'eth0' in line:
                            received, transmitted = 0, 0
                            parts = line.split()
                            if len(parts) == 17:
                                received = parts[1]
                                transmitted = parts[9]
                            elif len(parts) == 16:
                                (_, received) = tuple(parts[0].split(':'))
                                transmitted = parts[8]
                            new_bytes = received + transmitted
                            if self._network_bytes != new_bytes:
                                self._network_bytes = new_bytes
                                self._network_activity = True
                            else:
                                self._network_activity = False
            except Exception as exception:
                LOGGER.log('Error while checking states: {0}'.format(exception))
            self._last_state_check = time.time()
            time.sleep(0.5)

    def drive_leds(self):
        """ This drives different leds (status, alive and serial) """
        try:
            # Calculate network led/gpio states
            self.set_led(Hardware.Led.STATUS, not self._network_enabled)
            if self._network_activity:
                self.toggle_led(Hardware.Led.ALIVE)
            else:
                self.set_led(Hardware.Led.ALIVE, False)
            # Calculate serial led states
            comm_map = {4: Hardware.Led.COMM_1,
                        5: Hardware.Led.COMM_2}
            for uart in [4, 5]:
                if self._serial_activity[uart]:
                    self.toggle_led(comm_map[uart])
                else:
                    self.set_led(comm_map[uart], False)
                self._serial_activity[uart] = False
            # Update all leds
            self._write_leds()
        except Exception as exception:
            LOGGER.log('Error while driving leds: {0}'.format(exception))
        gobject.timeout_add(250, self.drive_leds)

    def check_button(self):
        """ Handles input button presses """
        try:
            button_pressed = LedController._is_button_pressed(self._input_button)
            if button_pressed is False:
                self._input_button_released = True
            if self._authorized_mode:
                if time.time() > self._authorized_timeout or (button_pressed and self._input_button_released):
                    self._authorized_mode = False
            else:
                if button_pressed:
                    self._input_button_released = False
                    if self._input_button_pressed_since is None:
                        self._input_button_pressed_since = time.time()
                    if time.time() > self._input_button_pressed_since + 5:
                        self._authorized_mode = True
                        self._authorized_timeout = time.time() + 60
                        self._input_button_pressed_since = None
                else:
                    self._input_button_pressed_since = None
        except Exception as exception:
            LOGGER.log('Error while checking button: {0}'.format(exception))
        self._last_button_check = time.time()
        gobject.timeout_add(250, self.check_button)

    def event_receiver(self, event, payload):
        sys.stderr.write('Receiver: {0} {1}\n'.format(event, payload))
        sys.stderr.flush()
        if event == DBusService.Events.CLOUD_REACHABLE:
            self.set_led(Hardware.Led.CLOUD, payload)
        elif event == DBusService.Events.VPN_OPEN:
            self.set_led(Hardware.Led.VPN, payload)
        elif event == DBusService.Events.SERIAL_ACTIVITY:
            self.serial_activity(payload)

    def get_state(self):
        return {'run_gpio': self._last_run_gpio,
                'run_i2c': self._last_run_i2c,
                'run_buttons': self._last_button_check,
                'run_state_check': self._last_state_check,
                'authorized_mode': self._authorized_mode}

def main():
    """
    The main function runs a loop that waits for dbus calls, drives the leds and reads the
    switch.
    """
    try:
        config = ConfigParser()
        config.read(constants.get_config_file())
        i2c_address = int(config.get('OpenMotics', 'leds_i2c_address'), 16)

        led_controller = LedController(Hardware.get_i2c_device(), i2c_address, Hardware.get_gpio_input())
        led_controller.start()
        led_controller.set_led(Hardware.Led.POWER, True)

        DBusService('led_service',
                    event_receiver=lambda *args, **kwargs: led_controller.event_receiver(*args, **kwargs),
                    get_state=led_controller.get_state)

        LOGGER.log("Running led service.")
        mainloop = gobject.MainLoop()
        gobject.timeout_add(250, led_controller.drive_leds)
        gobject.timeout_add(250, led_controller.check_button)
        mainloop.run()
    except Exception as exception:
        LOGGER.log('Error starting led service: {0}'.format(exception))

if __name__ == '__main__':
    main()
<commit_msg>Remove obsolete debug prints<commit_after># Copyright (C) 2016 OpenMotics BVBA
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero 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 Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
"""
Service that drives the leds and checks the switch on the front panel of the gateway.
This service allows other services to set the leds over dbus and check whether the
gateway is in authorized mode.
"""

import gobject
import sys
import fcntl
import time
try:
    import json
except ImportError:
    import simplejson as json
from threading import Thread
from ConfigParser import ConfigParser

from bus.dbus_service import DBusService
from platform_utils import Hardware
import constants

AUTH_MODE_LEDS = [Hardware.Led.ALIVE, Hardware.Led.CLOUD, Hardware.Led.VPN, Hardware.Led.COMM_1, Hardware.Led.COMM_2]

class LOGGER(object):
    @staticmethod
    def log(line):
        sys.stdout.write('{0}\n'.format(line))
        sys.stdout.flush()

class LedController(object):
    """
    The LEDController contains all logic to control the leds, and read out the physical buttons
    """

    def __init__(self, i2c_device, i2c_address, input_button):
        self._i2c_device = i2c_device
        self._i2c_address = i2c_address
        self._input_button = input_button
        self._input_button_pressed_since = None
        self._input_button_released = True

        self._network_enabled = False
        self._network_activity = False
        self._network_bytes = 0

        self._serial_activity = {4: False, 5: False}
        self._enabled_leds = {}
        self._previous_leds = {}
        self._last_i2c_led_code = 0

        self._authorized_mode = False
        self._authorized_timeout = 0

        self._check_states_thread = None

        self._last_run_i2c = 0
        self._last_run_gpio = 0
        self._last_state_check = 0
        self._last_button_check = 0

        self._gpio_led_config = Hardware.get_gpio_led_config()
        self._i2c_led_config = Hardware.get_i2c_led_config()
        for led in self._gpio_led_config.keys() + self._i2c_led_config.keys():
            self._enabled_leds[led] = False
            self._write_leds()

    def start(self):
        """ Start the leds and buttons thread. """
        self._check_states_thread = Thread(target=self._check_states)
        self._check_states_thread.daemon = True
        self._check_states_thread.start()

    def set_led(self, led_name, enable):
        """ Set the state of a LED, enabled means LED on in this context. """
        self._enabled_leds[led_name] = bool(enable)

    def toggle_led(self, led_name):
        """ Toggle the state of a LED. """
        self._enabled_leds[led_name] = not self._enabled_leds.get(led_name, False)

    def serial_activity(self, port):
        """ Report serial activity on the given serial port. Port is 4 or 5. """
        self._serial_activity[port] = True

    @staticmethod
    def _is_button_pressed(gpio_pin):
        """ Read the input button: returns True if the button is pressed, False if not. """
        with open('/sys/class/gpio/gpio{0}/value'.format(gpio_pin), 'r') as fh_inp:
            line = fh_inp.read()
        return int(line) == 0

    def _write_leds(self):
        """ Set the LEDs using the current status. """
        try:
            # Get i2c code
            code = 0
            for led in self._i2c_led_config.keys():
                if self._enabled_leds.get(led, False) is True:
                    code |= self._i2c_led_config[led]
            if self._authorized_mode:
                # Light all leds in authorized mode
                for led in AUTH_MODE_LEDS:
                    code |= self._i2c_led_config.get(led, 0)
            code = (~ code) & 255

            # Push code if needed
            if code != self._last_i2c_led_code:
                self._last_i2c_led_code = code
                with open(self._i2c_device, 'r+', 1) as i2c:
                    fcntl.ioctl(i2c, Hardware.IOCTL_I2C_SLAVE, self._i2c_address)
                    i2c.write(chr(code))
                    self._last_run_i2c = time.time()
            else:
                self._last_run_i2c = time.time()
        except Exception as exception:
            LOGGER.log('Error while writing to i2c: {0}'.format(exception))

        for led in self._gpio_led_config.keys():
            on = self._enabled_leds.get(led, False)
            if self._previous_leds.get(led) != on:
                self._previous_leds[led] = on
                try:
                    gpio = self._gpio_led_config[led]
                    with open('/sys/class/gpio/gpio{0}/value'.format(gpio), 'w') as fh_s:
                        fh_s.write('1' if on else '0')
                        self._last_run_gpio = time.time()
                except IOError:
                    pass  # The GPIO doesn't exist or is read only
            else:
                self._last_run_gpio = time.time()

    def _check_states(self):
        """ Checks various states of the system (network) """
        while True:
            try:
                with open('/sys/class/net/eth0/carrier', 'r') as fh_up:
                    line = fh_up.read()
                self._network_enabled = int(line) == 1

                with open('/proc/net/dev', 'r') as fh_stat:
                    for line in fh_stat.readlines():
                        if 'eth0' in line:
                            received, transmitted = 0, 0
                            parts = line.split()
                            if len(parts) == 17:
                                received = parts[1]
                                transmitted = parts[9]
                            elif len(parts) == 16:
                                (_, received) = tuple(parts[0].split(':'))
                                transmitted = parts[8]
                            new_bytes = received + transmitted
                            if self._network_bytes != new_bytes:
                                self._network_bytes = new_bytes
                                self._network_activity = True
                            else:
                                self._network_activity = False
            except Exception as exception:
                LOGGER.log('Error while checking states: {0}'.format(exception))
            self._last_state_check = time.time()
            time.sleep(0.5)

    def drive_leds(self):
        """ This drives different leds (status, alive and serial) """
        try:
            # Calculate network led/gpio states
            self.set_led(Hardware.Led.STATUS, not self._network_enabled)
            if self._network_activity:
                self.toggle_led(Hardware.Led.ALIVE)
            else:
                self.set_led(Hardware.Led.ALIVE, False)
            # Calculate serial led states
            comm_map = {4: Hardware.Led.COMM_1,
                        5: Hardware.Led.COMM_2}
            for uart in [4, 5]:
                if self._serial_activity[uart]:
                    self.toggle_led(comm_map[uart])
                else:
                    self.set_led(comm_map[uart], False)
                self._serial_activity[uart] = False
            # Update all leds
            self._write_leds()
        except Exception as exception:
            LOGGER.log('Error while driving leds: {0}'.format(exception))
        gobject.timeout_add(250, self.drive_leds)

    def check_button(self):
        """ Handles input button presses """
        try:
            button_pressed = LedController._is_button_pressed(self._input_button)
            if button_pressed is False:
                self._input_button_released = True
            if self._authorized_mode:
                if time.time() > self._authorized_timeout or (button_pressed and self._input_button_released):
                    self._authorized_mode = False
            else:
                if button_pressed:
                    self._input_button_released = False
                    if self._input_button_pressed_since is None:
                        self._input_button_pressed_since = time.time()
                    if time.time() > self._input_button_pressed_since + 5:
                        self._authorized_mode = True
                        self._authorized_timeout = time.time() + 60
                        self._input_button_pressed_since = None
                else:
                    self._input_button_pressed_since = None
        except Exception as exception:
            LOGGER.log('Error while checking button: {0}'.format(exception))
        self._last_button_check = time.time()
        gobject.timeout_add(250, self.check_button)

    def event_receiver(self, event, payload):
        if event == DBusService.Events.CLOUD_REACHABLE:
            self.set_led(Hardware.Led.CLOUD, payload)
        elif event == DBusService.Events.VPN_OPEN:
            self.set_led(Hardware.Led.VPN, payload)
        elif event == DBusService.Events.SERIAL_ACTIVITY:
            self.serial_activity(payload)

    def get_state(self):
        return {'run_gpio': self._last_run_gpio,
                'run_i2c': self._last_run_i2c,
                'run_buttons': self._last_button_check,
                'run_state_check': self._last_state_check,
                'authorized_mode': self._authorized_mode}

def main():
    """
    The main function runs a loop that waits for dbus calls, drives the leds and reads the
    switch.
    """
    try:
        config = ConfigParser()
        config.read(constants.get_config_file())
        i2c_address = int(config.get('OpenMotics', 'leds_i2c_address'), 16)

        led_controller = LedController(Hardware.get_i2c_device(), i2c_address, Hardware.get_gpio_input())
        led_controller.start()
        led_controller.set_led(Hardware.Led.POWER, True)

        DBusService('led_service',
                    event_receiver=lambda *args, **kwargs: led_controller.event_receiver(*args, **kwargs),
                    get_state=led_controller.get_state)

        LOGGER.log("Running led service.")
        mainloop = gobject.MainLoop()
        gobject.timeout_add(250, led_controller.drive_leds)
        gobject.timeout_add(250, led_controller.check_button)
        mainloop.run()
    except Exception as exception:
        LOGGER.log('Error starting led service: {0}'.format(exception))

if __name__ == '__main__':
    main()
<|endoftext|>


<commit_before>#! /usr/bin/env python

# -*- coding: utf-8 -*-

import pygtk
pygtk.require('2.0')
import gtk

class Region:

    def __init__(self):
        self.reset()

    def get_width(self):
        if self.start_x is None or self.end_x is None:
            return 0

        return max(self.start_x, self.end_x) - min(self.start_x, self.end_x)

    def get_height(self):
        if self.start_y is None or self.end_y is None:
            return 0

        return max(self.start_y, self.end_y) - min(self.start_y, self.end_y)

    def reset(self):
        self.start_x = None
        self.start_y = None
        self.end_x = None
        self.end_y = None
        self.track_started = False
        self.track_ended = False

class Coords:

    def __init__(self):
        self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
        self.window.set_default_size(300,200)

        self.window.connect("destroy", self.destroy)

        self.setup_widgets()

        self.window.show()

        self.root_window = None

        self.region = Region()

    def main(self):
        gtk.main()

    def setup_widgets(self):
        start_label = gtk.Label("start")
        start_x_label = gtk.Label("x")
        start_y_label = gtk.Label("y")
        start_x = gtk.Label("this will be x")
        start_y = gtk.Label("this will be y")

        end_label = gtk.Label("end")
        end_x_label = gtk.Label("x")
        end_y_label = gtk.Label("y")
        end_x = gtk.Label("this will be x")
        end_y = gtk.Label("this will be y")

        width_label = gtk.Label("width")
        width = gtk.Label("this will be w")

        height_label = gtk.Label("height")
        height = gtk.Label("this will be h")

        start_button = gtk.Button("start")
        reset_button = gtk.Button("reset")

        hbox_one = gtk.HBox(gtk.TRUE, 10)
        hbox_one.pack_start(start_label)
        hbox_one.pack_start(start_x_label)
        hbox_one.pack_start(start_x)

        hbox_two = gtk.HBox(gtk.TRUE, 10)
        hbox_two.pack_start(start_y_label)
        hbox_two.pack_start(start_y)

        hbox_three = gtk.HBox(gtk.TRUE, 10)
        hbox_three.pack_start(end_label)
        hbox_three.pack_start(end_x_label)
        hbox_three.pack_start(end_x)

        hbox_four = gtk.HBox(gtk.TRUE, 10)
        hbox_four.pack_start(end_y_label)
        hbox_four.pack_start(end_y)

        hbox_five = gtk.HBox(gtk.TRUE, 10)
        hbox_five.pack_start(width_label)
        hbox_five.pack_start(width)
        hbox_five.pack_start(start_button)

        hbox_six = gtk.HBox(gtk.TRUE, 10)
        hbox_six.pack_start(height_label)
        hbox_six.pack_start(height)
        hbox_six.pack_start(reset_button)

        main_box = gtk.VBox(gtk.TRUE, 10)
        main_box.pack_start(hbox_one)
        main_box.pack_start(hbox_two)
        main_box.pack_start(hbox_three)
        main_box.pack_start(hbox_four)
        main_box.pack_start(hbox_five)
        main_box.pack_start(hbox_six)

        start_label.show()
        start_x_label.show()
        start_x.show()
        hbox_one.show()

        start_y_label.show()
        start_y.show()
        hbox_two.show()

        end_label.show()
        end_x_label.show()
        end_x.show()
        hbox_three.show()

        end_y_label.show()
        end_y.show()
        hbox_four.show()

        width_label.show()
        width.show()
        start_button.show()
        hbox_five.show()

        height_label.show()
        height.show()
        reset_button.show()
        hbox_six.show()

        self.window.add(main_box)
        main_box.show()

        self.start_button = start_button
        self.start_button.connect("clicked", self.start)

        reset_button.connect('clicked', self.reset)

        self.start_x = start_x
        self.start_y = start_y
        self.end_x = end_x
        self.end_y = end_y
        self.width = width
        self.height = height

    def reset(self, widget, data=None):
        self.region.reset()
        self.show_region(self.region)

    def start(self, widget, data=None):
        mask = gtk.gdk.POINTER_MOTION_MASK | gtk.gdk.BUTTON_PRESS_MASK | gtk.gdk.BUTTON_RELEASE_MASK
        self.root_window = gtk.gdk.get_default_root_window()
        result = gtk.gdk.pointer_grab(self.root_window, False, mask, None, None)
        self.root_window.add_filter(self.track_region, self.region)

    def track_region(self, event, region):
        x, y, flags = event.window.get_pointer()
        if 'GDK_BUTTON1_MASK' in flags.value_names \
                and region.track_started == False:
            region.start_x = x
            region.start_y = y
            region.track_started = True
            region.track_ended = False
        if 'GDK_BUTTON1_MASK' not in flags.value_names \
                and region.track_started == True:
            region.end_x = x
            region.end_y = y
            region.track_ended = True
            region.track_started = False
            gtk.gdk.pointer_ungrab()
            self.show_region(region)
        return gtk.gdk.FILTER_CONTINUE

    def show_region(self, region):
        self.start_x.set_text('%s' % region.start_x)
        self.start_y.set_text('%s' % region.start_y)
        self.end_x.set_text('%s' % region.end_x)
        self.end_y.set_text('%s' % region.end_y)
        self.width.set_text('%s' % region.get_width())
        self.height.set_text('%s' % region.get_height())

    def destroy(self, widget, data=None):
        gtk.main_quit()

if __name__ == "__main__":
    coords = Coords()
    coords.main()
<commit_msg>thats better<commit_after>#! /usr/bin/env python

# -*- coding: utf-8 -*-

import pygtk
pygtk.require('2.0')
import gtk

class Region:

    def __init__(self):
        self.reset()

    def get_width(self):
        if self.start_x is None or self.end_x is None:
            return 0

        return max(self.start_x, self.end_x) - min(self.start_x, self.end_x)

    def get_height(self):
        if self.start_y is None or self.end_y is None:
            return 0

        return max(self.start_y, self.end_y) - min(self.start_y, self.end_y)

    def reset(self):
        self.start_x = None
        self.start_y = None
        self.end_x = None
        self.end_y = None
        self.track_started = False
        self.track_ended = False

class Coords:

    def __init__(self):
        self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
        self.window.set_default_size(300,200)

        self.window.connect("destroy", self.destroy)

        self.setup_widgets()

        self.window.show_all()

        self.root_window = None

        self.region = Region()

    def main(self):
        gtk.main()

    def setup_widgets(self):
        start_label = gtk.Label("start")
        start_x_label = gtk.Label("x")
        start_y_label = gtk.Label("y")
        start_x = gtk.Label("this will be x")
        start_y = gtk.Label("this will be y")

        end_label = gtk.Label("end")
        end_x_label = gtk.Label("x")
        end_y_label = gtk.Label("y")
        end_x = gtk.Label("this will be x")
        end_y = gtk.Label("this will be y")

        width_label = gtk.Label("width")
        width = gtk.Label("this will be w")

        height_label = gtk.Label("height")
        height = gtk.Label("this will be h")

        start_button = gtk.Button("start")
        reset_button = gtk.Button("reset")

        hbox_one = gtk.HBox(gtk.TRUE, 10)
        hbox_one.pack_start(start_label)
        hbox_one.pack_start(start_x_label)
        hbox_one.pack_start(start_x)

        hbox_two = gtk.HBox(gtk.TRUE, 10)
        hbox_two.pack_start(start_y_label)
        hbox_two.pack_start(start_y)

        hbox_three = gtk.HBox(gtk.TRUE, 10)
        hbox_three.pack_start(end_label)
        hbox_three.pack_start(end_x_label)
        hbox_three.pack_start(end_x)

        hbox_four = gtk.HBox(gtk.TRUE, 10)
        hbox_four.pack_start(end_y_label)
        hbox_four.pack_start(end_y)

        hbox_five = gtk.HBox(gtk.TRUE, 10)
        hbox_five.pack_start(width_label)
        hbox_five.pack_start(width)
        hbox_five.pack_start(start_button)

        hbox_six = gtk.HBox(gtk.TRUE, 10)
        hbox_six.pack_start(height_label)
        hbox_six.pack_start(height)
        hbox_six.pack_start(reset_button)

        main_box = gtk.VBox(gtk.TRUE, 10)
        main_box.pack_start(hbox_one)
        main_box.pack_start(hbox_two)
        main_box.pack_start(hbox_three)
        main_box.pack_start(hbox_four)
        main_box.pack_start(hbox_five)
        main_box.pack_start(hbox_six)

        self.window.add(main_box)

        self.start_button = start_button
        self.start_button.connect("clicked", self.start)

        reset_button.connect('clicked', self.reset)

        self.start_x = start_x
        self.start_y = start_y
        self.end_x = end_x
        self.end_y = end_y
        self.width = width
        self.height = height

    def reset(self, widget, data=None):
        self.region.reset()
        self.show_region(self.region)

    def start(self, widget, data=None):
        mask = gtk.gdk.POINTER_MOTION_MASK | gtk.gdk.BUTTON_PRESS_MASK | gtk.gdk.BUTTON_RELEASE_MASK
        self.root_window = gtk.gdk.get_default_root_window()
        result = gtk.gdk.pointer_grab(self.root_window, False, mask, None, None)
        self.root_window.add_filter(self.track_region, self.region)

    def track_region(self, event, region):
        x, y, flags = event.window.get_pointer()
        if 'GDK_BUTTON1_MASK' in flags.value_names \
                and region.track_started == False:
            region.start_x = x
            region.start_y = y
            region.track_started = True
            region.track_ended = False
        if 'GDK_BUTTON1_MASK' not in flags.value_names \
                and region.track_started == True:
            region.end_x = x
            region.end_y = y
            region.track_ended = True
            region.track_started = False
            gtk.gdk.pointer_ungrab()
            self.show_region(region)
        return gtk.gdk.FILTER_CONTINUE

    def show_region(self, region):
        self.start_x.set_text('%s' % region.start_x)
        self.start_y.set_text('%s' % region.start_y)
        self.end_x.set_text('%s' % region.end_x)
        self.end_y.set_text('%s' % region.end_y)
        self.width.set_text('%s' % region.get_width())
        self.height.set_text('%s' % region.get_height())

    def destroy(self, widget, data=None):
        gtk.main_quit()

if __name__ == "__main__":
    coords = Coords()
    coords.main()
<|endoftext|>


<commit_before>from .base import *

BUGSNAG = {
    "api_key": get_env_variable("BUGSNAG_API_KEY"),
    "project_root": PROJECT_ROOT,
}

MIDDLEWARE_CLASSES += (
    "bugsnag.django.middleware.BugsnagMiddleware",
)

ALLOWED_HOSTS = [
    get_env_variable("HEROKU_HOST"),
    '.barberscore.com',
]

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'root': {
        'level': 'ERROR',
        'handlers': ['bugsnag'],
    },
    'formatters': {
        'verbose': {
            'format': '%(levelname)s %(asctime)s %(module)s %(message)s'
        },
    },
    'loggers': {
        'api': {
            'level': 'DEBUG',
            'handlers': ['console'],
        },
        'noncense': {
            'level': 'DEBUG',
            'handlers': ['console'],
        },
        'utils': {
            'level': 'DEBUG',
            'handlers': ['console'],
        },
    },
    'handlers': {
        'bugsnag': {
            'level': 'ERROR',
            'class': 'bugsnag.handlers.BugsnagHandler',
            'formatter': 'verbose',
        },
        'console': {
            'level': 'INFO',
            'class': 'logging.StreamHandler',
            'formatter': 'verbose',
            'stream': sys.stdout,
        },
    },
}
<commit_msg>forgot import sys<commit_after>from .base import *

import sys

BUGSNAG = {
    "api_key": get_env_variable("BUGSNAG_API_KEY"),
    "project_root": PROJECT_ROOT,
}

MIDDLEWARE_CLASSES += (
    "bugsnag.django.middleware.BugsnagMiddleware",
)

ALLOWED_HOSTS = [
    get_env_variable("HEROKU_HOST"),
    '.barberscore.com',
]

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'root': {
        'level': 'ERROR',
        'handlers': ['bugsnag'],
    },
    'formatters': {
        'verbose': {
            'format': '%(levelname)s %(asctime)s %(module)s %(message)s'
        },
    },
    'loggers': {
        'api': {
            'level': 'DEBUG',
            'handlers': ['console'],
        },
        'noncense': {
            'level': 'DEBUG',
            'handlers': ['console'],
        },
        'utils': {
            'level': 'DEBUG',
            'handlers': ['console'],
        },
    },
    'handlers': {
        'bugsnag': {
            'level': 'ERROR',
            'class': 'bugsnag.handlers.BugsnagHandler',
            'formatter': 'verbose',
        },
        'console': {
            'level': 'INFO',
            'class': 'logging.StreamHandler',
            'formatter': 'verbose',
            'stream': sys.stdout,
        },
    },
}
<|endoftext|>


<commit_before>import io
from PyQt5 import QtCore
from PyQt5.QtWidgets import QTableWidget, QTableWidgetItem, QWidget, QCheckBox, QHBoxLayout
from src.group import Group
from src.group_infos import Student
from src.history import History

class LessonTable(QTableWidget):
    """
    Extent the QTableWidget, so that it can maintain the date in the table.
    This includes filling the table with data using the name of a group and a corresponding csv-file,
    recording every change in a history, and exporting the data back to a csv-file.

    Usage infos: after creating the table the method connect has to be called!
    """

    def __init__(self, widget):
        """
        Initialize locks and history data. Connect signals and slots.
        """
        super().__init__(widget)

        self.react_lock = False
        self.history = History()
        self.group_infos = None
        self.action_redo = None
        self.action_undo = None
        self.get_csv_path = None
        self.group = None
        self.write_console = None
        self.test_file = False

        self.cellChanged.connect(self.react_to_change)

    def connect(self, group_infos, action_undo, action_redo, get_csv_path, write_console):
        """
        Connect infos and important actions from the mainwindow with the table.
        """
        self.group_infos = group_infos
        self.action_undo = action_undo
        self.action_redo = action_redo
        self.get_csv_path = get_csv_path
        self.write_console = write_console

    def react_to_change(self):
        """
        React if there are no locks by writing the changes to history and by exporting the data to the csv-file.
        Change the count of the attendance column.
        """
        if not self.react_lock:
            self.history.record_changes(self.get_current_data())
            self.export_csv()

            count = sum(self.get_checkbox(index).isChecked() for index in range(self.rowCount()))
            attendance = 'Anwesend {}/{}'.format(count, self.rowCount())
            self.setHorizontalHeaderItem(3, QTableWidgetItem(attendance))

            self.history.adjust_undo_redo()

    def setup_table(self, group: Group):
        """
        Clear the table and history, refill the table with column names, and students default data.
        """
        self.react_lock = True

        self.clear()
        self.setRowCount(0)

        self.group = group
        labels = 'Name;Matrikelnr.;Gruppe;Anwesend 00/00;Adhoc;Kommentar'.split(';')
        self.setColumnCount(len(labels))
        self.setSortingEnabled(False)
        self.setHorizontalHeaderLabels(labels)

        for student in group.students:
            self.add_row_to_table(student)

        self.history = History(self.action_undo, self.action_redo, self.write_console, self.group_infos)

    def add_row_to_table(self, student: Student):
        """
        Adds a new row to the table and fills this row with item-widgets filled with the student's data.
        """
        idx = self.rowCount()
        self.setRowCount(idx + 1)

        name_item = QTableWidgetItem(student.name)
        name_item.setFlags(name_item.flags() & ~QtCore.Qt.ItemIsEditable)
        self.setItem(idx, 0, name_item)

        matrikelnr_item = QTableWidgetItem(student.matrikelnr)
        matrikelnr_item.setFlags(matrikelnr_item.flags() & ~QtCore.Qt.ItemIsEditable)
        matrikelnr_item.setTextAlignment(QtCore.Qt.AlignCenter)
        self.setItem(idx, 1, matrikelnr_item)

        group_item = QTableWidgetItem(student.group_name)
        group_item.setFlags(matrikelnr_item.flags() & ~QtCore.Qt.ItemIsEditable)
        group_item.setTextAlignment(QtCore.Qt.AlignCenter)
        self.setItem(idx, 2, group_item)

        check_item = QTableWidgetItem()
        check_item.setTextAlignment(QtCore.Qt.AlignCenter)
        self.setItem(idx, 3, check_item)
        check_widget = QWidget()
        chk_bx = QCheckBox()
        chk_bx.setCheckState(QtCore.Qt.Unchecked)
        chk_bx.stateChanged.connect(self.react_to_change)
        lay_out = QHBoxLayout(check_widget)
        lay_out.addWidget(chk_bx)
        lay_out.setAlignment(QtCore.Qt.AlignCenter)
        lay_out.setContentsMargins(0, 0, 0, 0)
        check_widget.setLayout(lay_out)
        self.setCellWidget(idx, 3, check_widget)

        adhoc_item = QTableWidgetItem()
        adhoc_item.setTextAlignment(QtCore.Qt.AlignCenter)
        self.setItem(idx, 4, adhoc_item)

        self.setItem(idx, 5, QTableWidgetItem())

    def get_checkbox(self, index):
        """
        Returns the checkbox for a specific index
        """
        return self.cellWidget(index, 3).layout().itemAt(0).widget()

    def load_csv_file(self, path, test_file=False):
        """
        Load a lesson-csv-file and update the table with it's data
        """
        self.setSortingEnabled(False)
        self.react_lock = True

        self.test_file = test_file

        try:
            with open(path, 'r', encoding='utf-8') as file:
                next(file)  # skip header
                for line in file:
                    matrikelnr, group_name, attendance, comment = line.strip().split(';')
                    if not test_file:
                        adhoc, *comment = comment.split()
                        adhoc = adhoc.strip('%')
                        if adhoc == '0':
                            adhoc = ''
                        comment = ' '.join(comment)
                    else:
                        adhoc = ''

                    idx = self.index_of_student(matrikelnr)
                    if idx < 0:
                        idx = self.rowCount()
                        new_student = self.group_infos.get_student(matrikelnr)
                        if test_file:
                            new_student = Student(new_student.name, new_student.matrikelnr, new_student.email,
                                                  self.group.name)

                        self.add_row_to_table(new_student)

                    self.item(idx, 1).setText(matrikelnr)
                    self.item(idx, 2).setText(group_name)
                    self.get_checkbox(idx).setCheckState(QtCore.Qt.Checked if attendance == 'an' else
                                                         QtCore.Qt.Unchecked)
                    self.item(idx, 4).setText(adhoc)
                    self.item(idx, 5).setText(comment)
        except FileNotFoundError:
            pass

        self.resizeColumnsToContents()
        self.setSortingEnabled(True)
        self.sortByColumn(0, QtCore.Qt.AscendingOrder)
        self.react_lock = False
        self.history.current_data = self.get_current_data()
        self.history.adjust_undo_redo()

    def new_student(self, matrikelnr):
        """
        Adds a new row for a new student to the table.
        """
        self.react_lock = True
        self.setSortingEnabled(False)

        student = self.group_infos.get_student(matrikelnr)
        if self.test_file:
            student = Student(student.name, student.matrikelnr, student.email, self.group.name)

        self.add_row_to_table(student)
        text = '{} hinzugefügt'.format(student.name)
        self.history.add_change((matrikelnr, text, 1, None, student))

        self.setSortingEnabled(True)
        self.react_lock = False

    def export_csv(self):
        """
        Write the opened table to a csv-file
        """
        path = self.get_csv_path()

        # read file so it can keep the order of the lines
        order = dict()
        with open(path, 'r', encoding='utf-8') as f:
            next(f)
            for idx, line in enumerate(f):
                matrikelnr = line.split(';')[0]
                order[matrikelnr] = idx

        with io.open(path, 'w', encoding='utf-8', newline='') as f:
            f.write('MatrNr;Gruppe;Kontrolle;Kommentar\n')
            data = self.get_current_data()
            data.sort(key=lambda t: order.get(t[0], 999))
            for d in data:
                if self.test_file:
                    f.write('{};{};{};{}\n'.format(d[0], d[1], d[2], d[4]))
                else:
                    f.write('{};{};{};{}% {}\n'.format(*d))

    def index_of_student(self, identification):
        """
        Find the index of a student in the table. Identification can be a part of his name or the matrikel-nummer.
        Returns -1, if no student is found, or -2 if multiple students are found.
        """
        indices = [i for i in range(self.rowCount())
                   if identification.lower() in self.item(i, 0).text().lower() or
                   identification == self.item(i, 1).text()]
        if len(indices) == 1:
            return indices[0]
        if indices:
            return -2
        else:
            return -1

    def get_current_data(self):
        """
        Reads all data from the table and returns a list of it
        """
        data = []
        for idx in range(self.rowCount()):
            if self.item(idx, 1).text():
                data.append((
                    self.item(idx, 1).text(),
                    self.item(idx, 2).text() or '0',
                    'an' if self.get_checkbox(idx).isChecked() else 'ab',
                    self.item(idx, 4).text() or '0',
                    self.item(idx, 5).text()
                ))
        return sorted(data)

    def undo_history(self, reverse=False):
        """
        Undos/redos the last history.
        """
        self.react_lock = True
        self.setSortingEnabled(False)

        last_history = self.history.undo_history(reverse=reverse)
        if last_history:
            index = self.index_of_student(last_history[0])
            if index >= 0:
                if last_history[2] == 1:
                    if not last_history[3]:
                        self.removeRow(index)

                if last_history[2] == 2:
                    self.get_checkbox(index).setCheckState(QtCore.Qt.Checked if last_history[3] == 'an' else
                                                           QtCore.Qt.Unchecked)
                if last_history[2] in [3, 4]:
                    self.item(index, last_history[2] + 1).setText(last_history[3])
            else:
                if last_history[2] == 1 and last_history[3]:
                    self.add_row_to_table(last_history[3])

            self.history.current_data = self.get_current_data()
            self.history.adjust_undo_redo()

        self.setSortingEnabled(True)
        self.react_lock = False
        self.export_csv()
<commit_msg>Export after adding new student<commit_after>import io
from PyQt5 import QtCore
from PyQt5.QtWidgets import QTableWidget, QTableWidgetItem, QWidget, QCheckBox, QHBoxLayout
from src.group import Group
from src.group_infos import Student
from src.history import History

class LessonTable(QTableWidget):
    """
    Extent the QTableWidget, so that it can maintain the date in the table.
    This includes filling the table with data using the name of a group and a corresponding csv-file,
    recording every change in a history, and exporting the data back to a csv-file.

    Usage infos: after creating the table the method connect has to be called!
    """

    def __init__(self, widget):
        """
        Initialize locks and history data. Connect signals and slots.
        """
        super().__init__(widget)

        self.react_lock = False
        self.history = History()
        self.group_infos = None
        self.action_redo = None
        self.action_undo = None
        self.get_csv_path = None
        self.group = None
        self.write_console = None
        self.test_file = False

        self.cellChanged.connect(self.react_to_change)

    def connect(self, group_infos, action_undo, action_redo, get_csv_path, write_console):
        """
        Connect infos and important actions from the mainwindow with the table.
        """
        self.group_infos = group_infos
        self.action_undo = action_undo
        self.action_redo = action_redo
        self.get_csv_path = get_csv_path
        self.write_console = write_console

    def react_to_change(self):
        """
        React if there are no locks by writing the changes to history and by exporting the data to the csv-file.
        Change the count of the attendance column.
        """
        if not self.react_lock:
            self.history.record_changes(self.get_current_data())
            self.export_csv()

            count = sum(self.get_checkbox(index).isChecked() for index in range(self.rowCount()))
            attendance = 'Anwesend {}/{}'.format(count, self.rowCount())
            self.setHorizontalHeaderItem(3, QTableWidgetItem(attendance))

            self.history.adjust_undo_redo()

    def setup_table(self, group: Group):
        """
        Clear the table and history, refill the table with column names, and students default data.
        """
        self.react_lock = True

        self.clear()
        self.setRowCount(0)

        self.group = group
        labels = 'Name;Matrikelnr.;Gruppe;Anwesend 00/00;Adhoc;Kommentar'.split(';')
        self.setColumnCount(len(labels))
        self.setSortingEnabled(False)
        self.setHorizontalHeaderLabels(labels)

        for student in group.students:
            self.add_row_to_table(student)

        self.history = History(self.action_undo, self.action_redo, self.write_console, self.group_infos)

    def add_row_to_table(self, student: Student):
        """
        Adds a new row to the table and fills this row with item-widgets filled with the student's data.
        """
        idx = self.rowCount()
        self.setRowCount(idx + 1)

        name_item = QTableWidgetItem(student.name)
        name_item.setFlags(name_item.flags() & ~QtCore.Qt.ItemIsEditable)
        self.setItem(idx, 0, name_item)

        matrikelnr_item = QTableWidgetItem(student.matrikelnr)
        matrikelnr_item.setFlags(matrikelnr_item.flags() & ~QtCore.Qt.ItemIsEditable)
        matrikelnr_item.setTextAlignment(QtCore.Qt.AlignCenter)
        self.setItem(idx, 1, matrikelnr_item)

        group_item = QTableWidgetItem(student.group_name)
        group_item.setFlags(matrikelnr_item.flags() & ~QtCore.Qt.ItemIsEditable)
        group_item.setTextAlignment(QtCore.Qt.AlignCenter)
        self.setItem(idx, 2, group_item)

        check_item = QTableWidgetItem()
        check_item.setTextAlignment(QtCore.Qt.AlignCenter)
        self.setItem(idx, 3, check_item)
        check_widget = QWidget()
        chk_bx = QCheckBox()
        chk_bx.setCheckState(QtCore.Qt.Unchecked)
        chk_bx.stateChanged.connect(self.react_to_change)
        lay_out = QHBoxLayout(check_widget)
        lay_out.addWidget(chk_bx)
        lay_out.setAlignment(QtCore.Qt.AlignCenter)
        lay_out.setContentsMargins(0, 0, 0, 0)
        check_widget.setLayout(lay_out)
        self.setCellWidget(idx, 3, check_widget)

        adhoc_item = QTableWidgetItem()
        adhoc_item.setTextAlignment(QtCore.Qt.AlignCenter)
        self.setItem(idx, 4, adhoc_item)

        self.setItem(idx, 5, QTableWidgetItem())

    def get_checkbox(self, index):
        """
        Returns the checkbox for a specific index
        """
        return self.cellWidget(index, 3).layout().itemAt(0).widget()

    def load_csv_file(self, path, test_file=False):
        """
        Load a lesson-csv-file and update the table with it's data
        """
        self.setSortingEnabled(False)
        self.react_lock = True

        self.test_file = test_file

        try:
            with open(path, 'r', encoding='utf-8') as file:
                next(file)  # skip header
                for line in file:
                    matrikelnr, group_name, attendance, comment = line.strip().split(';')
                    if not test_file:
                        adhoc, *comment = comment.split()
                        adhoc = adhoc.strip('%')
                        if adhoc == '0':
                            adhoc = ''
                        comment = ' '.join(comment)
                    else:
                        adhoc = ''

                    idx = self.index_of_student(matrikelnr)
                    if idx < 0:
                        idx = self.rowCount()
                        new_student = self.group_infos.get_student(matrikelnr)
                        if test_file:
                            new_student = Student(new_student.name, new_student.matrikelnr, new_student.email,
                                                  self.group.name)

                        self.add_row_to_table(new_student)

                    self.item(idx, 1).setText(matrikelnr)
                    self.item(idx, 2).setText(group_name)
                    self.get_checkbox(idx).setCheckState(QtCore.Qt.Checked if attendance == 'an' else
                                                         QtCore.Qt.Unchecked)
                    self.item(idx, 4).setText(adhoc)
                    self.item(idx, 5).setText(comment)
        except FileNotFoundError:
            pass

        self.resizeColumnsToContents()
        self.setSortingEnabled(True)
        self.sortByColumn(0, QtCore.Qt.AscendingOrder)
        self.react_lock = False
        self.history.current_data = self.get_current_data()
        self.history.adjust_undo_redo()

    def new_student(self, matrikelnr):
        """
        Adds a new row for a new student to the table.
        """
        self.react_lock = True
        self.setSortingEnabled(False)

        student = self.group_infos.get_student(matrikelnr)
        if self.test_file:
            student = Student(student.name, student.matrikelnr, student.email, self.group.name)

        self.add_row_to_table(student)
        text = '{} hinzugefügt'.format(student.name)
        self.history.add_change((matrikelnr, text, 1, None, student))
        self.export_csv()

        self.setSortingEnabled(True)
        self.react_lock = False

    def export_csv(self):
        """
        Write the opened table to a csv-file
        """
        path = self.get_csv_path()

        # read file so it can keep the order of the lines
        order = dict()
        with open(path, 'r', encoding='utf-8') as f:
            next(f)
            for idx, line in enumerate(f):
                matrikelnr = line.split(';')[0]
                order[matrikelnr] = idx

        with io.open(path, 'w', encoding='utf-8', newline='') as f:
            f.write('MatrNr;Gruppe;Kontrolle;Kommentar\n')
            data = self.get_current_data()
            data.sort(key=lambda t: order.get(t[0], 999))
            for d in data:
                if self.test_file:
                    f.write('{};{};{};{}\n'.format(d[0], d[1], d[2], d[4]))
                else:
                    f.write('{};{};{};{}% {}\n'.format(*d))

    def index_of_student(self, identification):
        """
        Find the index of a student in the table. Identification can be a part of his name or the matrikel-nummer.
        Returns -1, if no student is found, or -2 if multiple students are found.
        """
        indices = [i for i in range(self.rowCount())
                   if identification.lower() in self.item(i, 0).text().lower() or
                   identification == self.item(i, 1).text()]
        if len(indices) == 1:
            return indices[0]
        if indices:
            return -2
        else:
            return -1

    def get_current_data(self):
        """
        Reads all data from the table and returns a list of it
        """
        data = []
        for idx in range(self.rowCount()):
            if self.item(idx, 1).text():
                data.append((
                    self.item(idx, 1).text(),
                    self.item(idx, 2).text() or '0',
                    'an' if self.get_checkbox(idx).isChecked() else 'ab',
                    self.item(idx, 4).text() or '0',
                    self.item(idx, 5).text()
                ))
        return sorted(data)

    def undo_history(self, reverse=False):
        """
        Undos/redos the last history.
        """
        self.react_lock = True
        self.setSortingEnabled(False)

        last_history = self.history.undo_history(reverse=reverse)
        if last_history:
            index = self.index_of_student(last_history[0])
            if index >= 0:
                if last_history[2] == 1:
                    if not last_history[3]:
                        self.removeRow(index)

                if last_history[2] == 2:
                    self.get_checkbox(index).setCheckState(QtCore.Qt.Checked if last_history[3] == 'an' else
                                                           QtCore.Qt.Unchecked)
                if last_history[2] in [3, 4]:
                    self.item(index, last_history[2] + 1).setText(last_history[3])
            else:
                if last_history[2] == 1 and last_history[3]:
                    self.add_row_to_table(last_history[3])

            self.history.current_data = self.get_current_data()
            self.history.adjust_undo_redo()

        self.setSortingEnabled(True)
        self.react_lock = False
        self.export_csv()
<|endoftext|>


<commit_before>from flask import render_template, Blueprint, url_for, \
    redirect, flash, request

from project.models import Category, Webinar

webinar_blueprint = Blueprint('webinar', __name__,)
<commit_msg>import datetime<commit_after>import datetime

from flask import render_template, Blueprint, url_for, \
    redirect, flash, request
from flask.ext.login import login_required, current_user

from project import db
from project.models import User, Category, Webinar
from .forms import WebinarCreateForm, WebinarEditForm

webinar_blueprint = Blueprint('webinar', __name__,)
<|endoftext|>


<commit_before>#!/usr/bin/env python

# This is a straightforward implementation of a well-known algorithm, and thus
# probably shouldn't be covered by copyright to begin with. But in case it is,
# the author [Magnus Lie Hetland] has, to the extent possible under law,
# dedicated all copyright and related and neighboring rights to this software
# to the public domain worldwide, by distributing it under the CC0 license,
# version 1.0. This software is distributed without any warranty. For more
# information, see <http://creativecommons.org/publicdomain/zero/1.0>

import difflib
import time
import operator

# CODE: ----------------------------------------------------------------------
class MuscleOps( object ):

    def gesture( self, pattern ):
        return find_pattern( string_to_pattern( pattern ) )

    def n( a ):
        return a / 255.0

    def dist( n1, n2 ):
        n1 = n( n1 )
        n2 = n( n2 )
        if n1 > .5: n1 = 1 - n1
        if n2 > .5: n2 = 1 - n2
        return abs( n1 - n2 ) * 2.0

    def diff( seq1, seq2 ):
        dists = [ dist( n1, n2 ) for n1, n2 in zip( seq1, seq2 ) ]
        return sum( dists ) / len( dists )

    def similarity( pattern1, pattern2, noise = 1 ):
        x1 = noise_filter( [ p[ 0 ] for p in pattern1 ], noise )
        x2 = noise_filter( [ p[ 0 ] for p in pattern2 ], noise )
        y1 = noise_filter( [ p[ 1 ] for p in pattern1 ], noise )
        y2 = noise_filter( [ p[ 1 ] for p in pattern2 ], noise )
        z1 = noise_filter( [ p[ 2 ] for p in pattern1 ], noise )
        z2 = noise_filter( [ p[ 2 ] for p in pattern2 ], noise )
        return sum([ diff( x1, x2 ), diff( y1, y2 ), diff( z1, z2 ) ]) / 3.0

    def noise_filter( seq, n ):
        if n == 1: return seq
        nseq = []
        for i in range( 0, len( seq ), n ):
            items = seq[i:i+n]
            nseq.append( sum( items ) / float( len( items ) ) )
        return nseq

    def levenshtein( a, b ):
        """Calculates the Levenshtein distance between a and b."""
        n, m = len[ a ], len[ b ]
        if n > m:
            # Make sure n <= m, to use O[ min [ n, m ] ] space
            a, b = b, a
            n, m = m, n

        current = range( n + 1 )
        for i in range( 1, m + 1 ):
            previous, current = current, [ i ] + [ 0 ] * n
            for j in range[ 1, n + 1 ]:
                add, delete = previous[ j ] + 1, current[ j - 1 ] + 1
                change = previous[ j -1 ]
                if a[ j - 1 ] != b[ i - 1 ]:
                    change = change + 1
                current[ j ] = min[ add, delete, change ]

        return current[ n ]

    def get_ratio_per_line( pattern1, pattern2, line ):
        p1 = pattern1[ line ]
        p2 = pattern2[ line ]
        ratio = difflib.SequenceMatcher( None, p1, p2 ).ratio()
        print "line %s ratio: %s" % ( line, ratio )
        return ratio

    def get_ratio( pattern1, pattern2 ):
        return 1 - similarity( pattern1, pattern2, 1 )
        ratios = []
        lines = min( len( pattern1 ), len( pattern2 ) )
        for line in range( lines ):
            ratios.append( get_ratio_per_line( pattern1, pattern2, line ) )

        ratio = sum( ratios ) / float( len( ratios ) )
        print "avg ratio:", ratio
        return ratio

    def get_max_ratio( ratios ):
        print ratios
        return max( ratios.iteritems(), key = operator.itemgetter( 1 ) )[ 0 ]

    def string_to_pattern( string ):
        pattern1 = []
        for st in string.strip().split( "\n" ):
            pattern1.append( st.strip().split( " " ) )

        pattern = []
        for p in pattern1:
            pattern.append( [ int( i ) for i in p ] )

        return pattern

    def find_pattern( pattern ):
        up = create_pattern_up()
        down = create_pattern_down()
        right = create_pattern_right()
        left = create_pattern_left()
        #forward = create_pattern_forward()
        #backward = create_pattern_backward()

        up_ratio = get_ratio( up, pattern )
        down_ratio = get_ratio( down, pattern )
        right_ratio = get_ratio( right, pattern )
        left_ratio = get_ratio( left, pattern )
        #forward_ratio = get_ratio( down, pattern )
        #backward_ratio = get_ratio( down, pattern )

        ratios = {
            "up:": up_ratio,
            "down:": down_ratio,
            "right:": right_ratio,
            "left:": left_ratio,
            #"forward ratio:": forward_ratio,
            #"backward ratio:": backward_ratio
        }

        result = get_max_ratio( ratios )

        result = "'" + result + "' pattern Wins"

        return result

    # CONTROL PATTERNS: ------------------------------------------------------------------
    def create_pattern_up():
        pattern = """
        058 015 010
        071 007 014
        082 011 020
        072 011 012
        072 012 011
        067 011 010
        063 015 003
        056 013 002
        045 002 009
        050 011 006
        """

        return string_to_pattern( pattern )

    def create_pattern_down():
        pattern = """
        231 225 217
        241 241 206
        252 005 237
        000 246 254
        017 249 211
        255 249 203
        031 003 211
        071 036 224
        062 028 243
        061 051 003
        """

        return string_to_pattern( pattern )

    def create_pattern_right():
        pattern = """
        060 002 004
        067 253 005
        056 010 005
        056 251 003
        059 233 255
        052 225 002
        047 220 007
        047 222 007
        046 222 007
        043 222 010
        """

        return string_to_pattern( pattern )

    def create_pattern_left():
        pattern = """
        060 008 012
        064 008 013
        058 253 012
        054 019 010
        050 031 012
        042 044 004
        044 047 007
        043 050 012
        043 042 009
        043 045 005
        """

        return string_to_pattern( pattern )

    def create_pattern_forward():
        pattern = []
        for i in range[ 0, RANGE ]:
            pattern.append[ [ 0, +i, 0 ] ]

        return pattern

    def create_pattern_backward():
        pattern = []
        for i in range[ 0, RANGE ]:
            pattern.append[ [ 0, -i, 0 ] ]

        return pattern

    # TESTS: ---------------------------------------------------------------------
    RANGE = 255
    def test_get_pattern_up():
        pattern = """
        055 013 014
        060 013 014
        072 019 015
        072 012 016
        069 013 012
        065 022 012
        063 017 003
        058 010 251
        057 023 001
        060 027 008
        """

        return find_pattern( string_to_pattern( pattern ) )

    def test_get_pattern_down():
        pattern = """
        234 234 206
        252 230 216
        239 237 203
        241 245 205
        249 235 216
        011 013 193
        019 029 175
        019 000 187
        035 014 196
        060 040 193
        """

        return find_pattern( string_to_pattern( pattern ) )

    def test_get_pattern_right():
        pattern = """
        062 000 008
        059 255 007
        057 000 009
        058 235 001
        054 225 010
        046 225 013
        043 220 012
        046 219 011
        047 222 011
        047 219 009
        """

        return find_pattern( string_to_pattern( pattern ) )

    def test_get_pattern_left():
        pattern = """
        058 011 010
        064 005 008
        063 003 011
        056 018 008
        049 026 006
        044 042 255
        043 049 005
        041 045 007
        041 039 010
        041 044 010
        """

        return find_pattern( string_to_pattern( pattern ) )

    '''
    def test_get_pattern_forward():
        pattern = []
        for i in range[ 0, RANGE ]:
            pattern.append[ [ +i * 0.25, 0, 0 ] ]

        return find_pattern[ pattern ]

    def test_get_pattern_backward():
        pattern = []
        for i in range[ 0, RANGE ]:
            pattern.append[ [ -i * 0.25, 0, 0 ] ]

        return find_pattern( pattern )
    '''

# Main: ----------------------------------------------------------------------
if __name__=="__main__":
    print "Test up pattern:"
    print test_get_pattern_up()
    print "---------------------"
    print "Test down pattern:"
    print test_get_pattern_down()
    print "---------------------"
    print "Test right pattern:"
    print test_get_pattern_right()
    print "---------------------"
    print "Test left pattern:"
    print test_get_pattern_left()
    print "---------------------"
    '''
    print "Test forward pattern:"
    print test_get_pattern_forward()
    print "---------------------"
    print "Test backward pattern:"
    print test_get_pattern_backward()
    print "---------------------"
    '''<commit_msg>levenshtein.py<commit_after>#!/usr/bin/env python

# This is a straightforward implementation of a well-known algorithm, and thus
# probably shouldn't be covered by copyright to begin with. But in case it is,
# the author [Magnus Lie Hetland] has, to the extent possible under law,
# dedicated all copyright and related and neighboring rights to this software
# to the public domain worldwide, by distributing it under the CC0 license,
# version 1.0. This software is distributed without any warranty. For more
# information, see <http://creativecommons.org/publicdomain/zero/1.0>

import difflib
import time
import operator

# CODE: ----------------------------------------------------------------------
class MuscleOps( object ):

    def gesture( self, pattern ):
        return find_pattern( string_to_pattern( pattern ) )

    def n( self, a ):
        return a / 255.0

    def dist( self, n1, n2 ):
        n1 = self.n( n1 )
        n2 = self.n( n2 )
        if n1 > .5: n1 = 1 - n1
        if n2 > .5: n2 = 1 - n2
        return abs( n1 - n2 ) * 2.0

    def diff( self, seq1, seq2 ):
        dists = [ dist( n1, n2 ) for n1, n2 in zip( seq1, seq2 ) ]
        return sum( dists ) / len( dists )

    def similarity( self, pattern1, pattern2, noise = 1 ):
        x1 = noise_filter( [ p[ 0 ] for p in pattern1 ], noise )
        x2 = noise_filter( [ p[ 0 ] for p in pattern2 ], noise )
        y1 = noise_filter( [ p[ 1 ] for p in pattern1 ], noise )
        y2 = noise_filter( [ p[ 1 ] for p in pattern2 ], noise )
        z1 = noise_filter( [ p[ 2 ] for p in pattern1 ], noise )
        z2 = noise_filter( [ p[ 2 ] for p in pattern2 ], noise )
        return sum([ self.diff( x1, x2 ), self.diff( y1, y2 ), self.diff( z1, z2 ) ]) / 3.0

    def noise_filter( self, seq, n ):
        if n == 1: return seq
        nseq = []
        for i in range( 0, len( seq ), n ):
            items = seq[i:i+n]
            nseq.append( sum( items ) / float( len( items ) ) )
        return nseq

    def levenshtein( self, a, b ):
        """Calculates the Levenshtein distance between a and b."""
        n, m = len[ a ], len[ b ]
        if n > m:
            # Make sure n <= m, to use O[ min [ n, m ] ] space
            a, b = b, a
            n, m = m, n

        current = range( n + 1 )
        for i in range( 1, m + 1 ):
            previous, current = current, [ i ] + [ 0 ] * n
            for j in range[ 1, n + 1 ]:
                add, delete = previous[ j ] + 1, current[ j - 1 ] + 1
                change = previous[ j -1 ]
                if a[ j - 1 ] != b[ i - 1 ]:
                    change = change + 1
                current[ j ] = min[ add, delete, change ]

        return current[ n ]

    def get_ratio_per_line( self, pattern1, pattern2, line ):
        p1 = pattern1[ line ]
        p2 = pattern2[ line ]
        ratio = difflib.SequenceMatcher( None, p1, p2 ).ratio()
        print "line %s ratio: %s" % ( line, ratio )
        return ratio

    def get_ratio( self, pattern1, pattern2 ):
        return 1 - self.similarity( pattern1, pattern2, 1 )
        ratios = []
        lines = min( len( pattern1 ), len( pattern2 ) )
        for line in range( lines ):
            ratios.append( self.get_ratio_per_line( pattern1, pattern2, line ) )

        ratio = sum( ratios ) / float( len( ratios ) )
        print "avg ratio:", ratio
        return ratio

    def get_max_ratio( self, ratios ):
        print ratios
        return max( ratios.iteritems(), key = operator.itemgetter( 1 ) )[ 0 ]

    def string_to_pattern( self, string ):
        pattern1 = []
        for st in string.strip().split( "\n" ):
            pattern1.append( st.strip().split( " " ) )

        pattern = []
        for p in pattern1:
            pattern.append( [ int( i ) for i in p ] )

        return pattern

    def find_pattern( self, pattern ):
        up = create_pattern_up()
        down = create_pattern_down()
        right = create_pattern_right()
        left = create_pattern_left()
        #forward = create_pattern_forward()
        #backward = create_pattern_backward()

        up_ratio = get_ratio( up, pattern )
        down_ratio = get_ratio( down, pattern )
        right_ratio = get_ratio( right, pattern )
        left_ratio = get_ratio( left, pattern )
        #forward_ratio = get_ratio( down, pattern )
        #backward_ratio = get_ratio( down, pattern )

        ratios = {
            "up:": up_ratio,
            "down:": down_ratio,
            "right:": right_ratio,
            "left:": left_ratio,
            #"forward ratio:": forward_ratio,
            #"backward ratio:": backward_ratio
        }

        result = self.get_max_ratio( ratios )

        result = "'" + result + "' pattern Wins"

        return result

    # CONTROL PATTERNS: ------------------------------------------------------------------
    def create_pattern_up( self ):
        pattern = """
        058 015 010
        071 007 014
        082 011 020
        072 011 012
        072 012 011
        067 011 010
        063 015 003
        056 013 002
        045 002 009
        050 011 006
        """

        return self.string_to_pattern( pattern )

    def create_pattern_down( self ):
        pattern = """
        231 225 217
        241 241 206
        252 005 237
        000 246 254
        017 249 211
        255 249 203
        031 003 211
        071 036 224
        062 028 243
        061 051 003
        """

        return self.string_to_pattern( pattern )

    def create_pattern_right( self ):
        pattern = """
        060 002 004
        067 253 005
        056 010 005
        056 251 003
        059 233 255
        052 225 002
        047 220 007
        047 222 007
        046 222 007
        043 222 010
        """

        return self.string_to_pattern( pattern )

    def create_pattern_left( self ):
        pattern = """
        060 008 012
        064 008 013
        058 253 012
        054 019 010
        050 031 012
        042 044 004
        044 047 007
        043 050 012
        043 042 009
        043 045 005
        """

        return self.string_to_pattern( pattern )

    '''
    def create_pattern_forward( self ):
        pattern = []
        for i in range[ 0, RANGE ]:
            pattern.append[ [ 0, +i, 0 ] ]

        return pattern

    def create_pattern_backward( self ):
        pattern = []
        for i in range[ 0, RANGE ]:
            pattern.append[ [ 0, -i, 0 ] ]

        return pattern
    '''

    # TESTS: ---------------------------------------------------------------------
    RANGE = 255
    def test_get_pattern_up( self ):
        pattern = """
        055 013 014
        060 013 014
        072 019 015
        072 012 016
        069 013 012
        065 022 012
        063 017 003
        058 010 251
        057 023 001
        060 027 008
        """

        return find_pattern( string_to_pattern( pattern ) )

    def test_get_pattern_down( self ):
        pattern = """
        234 234 206
        252 230 216
        239 237 203
        241 245 205
        249 235 216
        011 013 193
        019 029 175
        019 000 187
        035 014 196
        060 040 193
        """

        return find_pattern( string_to_pattern( pattern ) )

    def test_get_pattern_right( self ):
        pattern = """
        062 000 008
        059 255 007
        057 000 009
        058 235 001
        054 225 010
        046 225 013
        043 220 012
        046 219 011
        047 222 011
        047 219 009
        """

        return find_pattern( string_to_pattern( pattern ) )

    def test_get_pattern_left( self ):
        pattern = """
        058 011 010
        064 005 008
        063 003 011
        056 018 008
        049 026 006
        044 042 255
        043 049 005
        041 045 007
        041 039 010
        041 044 010
        """

        return find_pattern( string_to_pattern( pattern ) )

    '''
    def test_get_pattern_forward( self ):
        pattern = []
        for i in range[ 0, RANGE ]:
            pattern.append[ [ +i * 0.25, 0, 0 ] ]

        return find_pattern[ pattern ]

    def test_get_pattern_backward( self ):
        pattern = []
        for i in range[ 0, RANGE ]:
            pattern.append[ [ -i * 0.25, 0, 0 ] ]

        return find_pattern( pattern )
    '''

# Main: ----------------------------------------------------------------------
if __name__=="__main__":
    print "Test up pattern:"
    print test_get_pattern_up()
    print "---------------------"
    print "Test down pattern:"
    print test_get_pattern_down()
    print "---------------------"
    print "Test right pattern:"
    print test_get_pattern_right()
    print "---------------------"
    print "Test left pattern:"
    print test_get_pattern_left()
    print "---------------------"
    '''
    print "Test forward pattern:"
    print test_get_pattern_forward()
    print "---------------------"
    print "Test backward pattern:"
    print test_get_pattern_backward()
    print "---------------------"
    '''<|endoftext|>


<commit_before>#!/usr/bin/env python

import sys
import u3

class Corvus(object):
    def __init__(self, labjack=None):
        if labjack is None:
            labjack = u3.U3()
        self._labjack = labjack

        self._setup_labjack()

    # Low-Level Hardware Methods

    def _setup_labjack(self):
        # configure inputs
        self._labjack.getDIState(u3.FIO3)  # /reset
        self._labjack.getDIState(u3.FIO6)  # ready
        self._labjack.getDIState(u3.FIO7)  # dirc

        # configure outputs
        self._labjack.setDOState(u3.FIO0, 1)  # 74hct245 /oe for data bus
        self._labjack.setDOState(u3.FIO1, 1)  # /strobe

        # disable timers so they don't interfere with dio
        self._labjack.configIO(NumberOfTimersEnabled=0)

    def is_drive_ready(self):
        return self._labjack.getDIState(u3.FIO6) == 1

    def is_host_to_drive(self):
        return self._labjack.getDIState(u3.FIO7) == 1

    _STROBE = [
        # set fio1 low (/strobe)
        u3.PortStateWrite(State=[0x00, 0, 0],
                          WriteMask=[0x02, 0, 0]),

        # wait ~128 microseconds
        u3.WaitShort(Time=1),

        # set fio1 high
        u3.PortStateWrite(State=[0x02, 0, 0],
                          WriteMask=[0x02, 0, 0])
    ]

    def strobe(self):
        return self._labjack.getFeedback(self._STROBE)

    _CONNECT_DATA_BUS = [
        # set eio port to input
        u3.PortDirWrite(Direction=[0, 0x00, 0],
                        WriteMask=[0, 0xff, 0]),

        # set fio0 low (/oe on 74hct245)
        u3.PortStateWrite(State=[0,0,0],
                          WriteMask=[0x01, 0, 0])
    ]

    def connect_data_bus(self):
        self._labjack.getFeedback(self._CONNECT_DATA_BUS)

    _DISCONNECT_DATA_BUS = [
        # set fio0 high (/oe on 74hct245)
        u3.PortStateWrite(State=[0x01,0,0],
                          WriteMask=[0x01, 0, 0]),

        # set eio port as input
        u3.PortDirWrite(Direction=[0, 0x00, 0],
                        WriteMask=[0, 0xff, 0])
    ]

    def disconnect_data_bus(self):
        self._labjack.getFeedback(self._DISCONNECT_DATA_BUS)

    def read_data(self):
        while not(self.is_drive_ready()):
            pass

        port_state_read = u3.PortStateRead()

        cmds = (self._CONNECT_DATA_BUS +
                [ port_state_read ] +
                self._STROBE +
                self._DISCONNECT_DATA_BUS)

        responses = self._labjack.getFeedback(cmds)
        ports = responses[cmds.index(port_state_read)]
        return ports['EIO']

    def write_data(self, value):
        while not(self.is_drive_ready()):
            pass

        # put data byte on eio port
        port_state_write = u3.PortStateWrite(State=[0, value, 0],
                                             WriteMask=[0, 0xff, 0])

        cmds = (self._CONNECT_DATA_BUS +
                [ port_state_write ] +
                self._STROBE +
                self._DISCONNECT_DATA_BUS)
        self._labjack.getFeedback(cmds)

    # Higher-Level Command Methods

    def init_drive(self):
        response = 0
        while response != 0x8f:
            while not(self.is_drive_ready()):
              pass
            while not(self.is_host_to_drive()):
              pass

            value = 0xff # 0xff is an invalid command
            self.write_data(value)

            while not(self.is_drive_ready()):
              pass
            while self.is_host_to_drive():
              pass

            # response should return 0x8f (invalid command)
            response = self.read_data()

    def _make_dadr(self, drive, sector):
        # byte 0:
        #   upper nibble = bits 16-19 of sector address
        #   lower nibble = corvus unit id (1-15)
        b0 = ((sector & 0x0f0000) >> 12) + (drive & 0x0f)
        # byte 1: bits 0-7 of sector address
        b1 = sector & 0xff
        # byte 2: bits 8-15 of sector address
        b2 = (sector & 0xff00) >> 8
        return (b0, b1, b2)

    def _read_sector(self, drive, sector, cmd, size):
        # send command to read sector
        self.write_data(cmd)

        # send disk address
        for x in self._make_dadr(drive, sector):
            self.write_data(x)

        # wait for bus to turn around
        while not(self.is_drive_ready()):
          pass
        while self.is_host_to_drive():
          pass

        # read error byte
        result = self.read_data()

        if result == 0:
            sector = []
            for i in range(size):
                sector.append(self.read_data())
            return sector
        else:
            raise ValueError("CORVUS %02x ERROR" % result)

    def read_sector_128(self, drive, sector):
        return self._read_sector(drive, sector, 0x12, 128)

    def read_sector_256(self, drive, sector):
        return self._read_sector(drive, sector, 0x22, 256)

    def read_sector_512(self, drive, sector):
        return self._read_sector(drive, sector, 0x32, 512)

if __name__ == "__main__":
    corvus = Corvus()
    corvus.init_drive()
    with open("image.bin", "wb") as f:
        for i in range(80000):
            sector = corvus.read_sector_128(1, i)
            f.write(''.join([chr(d) for d in sector]))
            sys.stdout.write("\r%d bytes read" % (i * 128))
            sys.stdout.flush()
<commit_msg>Add method to get the drive's total capacity<commit_after>#!/usr/bin/env python

import sys
import u3

class Corvus(object):
    def __init__(self, labjack=None):
        if labjack is None:
            labjack = u3.U3()
        self._labjack = labjack

        self._setup_labjack()

    # Low-Level Hardware Methods

    def _setup_labjack(self):
        # configure inputs
        self._labjack.getDIState(u3.FIO3)  # /reset
        self._labjack.getDIState(u3.FIO6)  # ready
        self._labjack.getDIState(u3.FIO7)  # dirc

        # configure outputs
        self._labjack.setDOState(u3.FIO0, 1)  # 74hct245 /oe for data bus
        self._labjack.setDOState(u3.FIO1, 1)  # /strobe

        # disable timers so they don't interfere with dio
        self._labjack.configIO(NumberOfTimersEnabled=0)

    def is_drive_ready(self):
        return self._labjack.getDIState(u3.FIO6) == 1

    def is_host_to_drive(self):
        return self._labjack.getDIState(u3.FIO7) == 1

    _STROBE = [
        # set fio1 low (/strobe)
        u3.PortStateWrite(State=[0x00, 0, 0],
                          WriteMask=[0x02, 0, 0]),

        # wait ~128 microseconds
        u3.WaitShort(Time=1),

        # set fio1 high
        u3.PortStateWrite(State=[0x02, 0, 0],
                          WriteMask=[0x02, 0, 0])
    ]

    def strobe(self):
        return self._labjack.getFeedback(self._STROBE)

    _CONNECT_DATA_BUS = [
        # set eio port to input
        u3.PortDirWrite(Direction=[0, 0x00, 0],
                        WriteMask=[0, 0xff, 0]),

        # set fio0 low (/oe on 74hct245)
        u3.PortStateWrite(State=[0,0,0],
                          WriteMask=[0x01, 0, 0])
    ]

    def connect_data_bus(self):
        self._labjack.getFeedback(self._CONNECT_DATA_BUS)

    _DISCONNECT_DATA_BUS = [
        # set fio0 high (/oe on 74hct245)
        u3.PortStateWrite(State=[0x01,0,0],
                          WriteMask=[0x01, 0, 0]),

        # set eio port as input
        u3.PortDirWrite(Direction=[0, 0x00, 0],
                        WriteMask=[0, 0xff, 0])
    ]

    def disconnect_data_bus(self):
        self._labjack.getFeedback(self._DISCONNECT_DATA_BUS)

    def read_data(self):
        while not(self.is_drive_ready()):
            pass

        port_state_read = u3.PortStateRead()

        cmds = (self._CONNECT_DATA_BUS +
                [ port_state_read ] +
                self._STROBE +
                self._DISCONNECT_DATA_BUS)

        responses = self._labjack.getFeedback(cmds)
        ports = responses[cmds.index(port_state_read)]
        return ports['EIO']

    def write_data(self, value):
        while not(self.is_drive_ready()):
            pass

        # put data byte on eio port
        port_state_write = u3.PortStateWrite(State=[0, value, 0],
                                             WriteMask=[0, 0xff, 0])

        cmds = (self._CONNECT_DATA_BUS +
                [ port_state_write ] +
                self._STROBE +
                self._DISCONNECT_DATA_BUS)
        self._labjack.getFeedback(cmds)

    # Higher-Level Command Methods

    def init_drive(self):
        response = 0
        while response != 0x8f:
            while not(self.is_drive_ready()):
              pass
            while not(self.is_host_to_drive()):
              pass

            value = 0xff # 0xff is an invalid command
            self.write_data(value)

            while not(self.is_drive_ready()):
              pass
            while self.is_host_to_drive():
              pass

            # response should return 0x8f (invalid command)
            response = self.read_data()

    def _make_dadr(self, drive, sector):
        # byte 0:
        #   upper nibble = bits 16-19 of sector address
        #   lower nibble = corvus unit id (1-15)
        b0 = ((sector & 0x0f0000) >> 12) + (drive & 0x0f)
        # byte 1: bits 0-7 of sector address
        b1 = sector & 0xff
        # byte 2: bits 8-15 of sector address
        b2 = (sector & 0xff00) >> 8
        return (b0, b1, b2)

    def _read_sector(self, drive, sector, cmd, size):
        # send command to read sector
        self.write_data(cmd)

        # send disk address
        for x in self._make_dadr(drive, sector):
            self.write_data(x)

        # wait for bus to turn around
        while not(self.is_drive_ready()):
          pass
        while self.is_host_to_drive():
          pass

        # read error byte
        result = self.read_data()
        if result != 0:
            raise ValueError("CORVUS %02x ERROR" % result)

        sector = []
        for i in range(size):
            sector.append(self.read_data())
        return sector

    def read_sector_128(self, drive, sector):
        return self._read_sector(drive, sector, 0x12, 128)

    def read_sector_256(self, drive, sector):
        return self._read_sector(drive, sector, 0x22, 256)

    def read_sector_512(self, drive, sector):
        return self._read_sector(drive, sector, 0x32, 512)

    def get_drive_capacity(self, drive):
        '''Returns total capacity as count of 512-byte sectors'''
        # send command to get drive parameters
        self.write_data(0x10)

        # send disk address
        self.write_data(drive)

        # read error byte
        result = self.read_data()
        if result != 0:
            raise ValueError("CORVUS %02x ERROR" % result)

        # read parameter block
        params = []
        for i in range(128):
            params.append(self.read_data())

        total_sectors = params[37] + (params[38] << 8) + (params[39] << 16)
        return total_sectors

if __name__ == "__main__":
    corvus = Corvus()
    corvus.init_drive()
    total_sectors = corvus.get_drive_capacity(1)
    with open("image.bin", "wb") as f:
        for i in range(total_sectors):
            sector = corvus.read_sector_512(1, i)
            f.write(''.join([chr(d) for d in sector]))
            sys.stdout.write("\r%d bytes read" % (i * 512))
            sys.stdout.flush()
<|endoftext|>


<commit_before>#!/usr/bin/env python3
"""The structure of a GMA file, parsing and building"""

import os
from construct import *
from time import time
from binascii import crc32
from struct import pack

GMA_VERSION = b"\x03"

GMAFile = Struct("all_file_meta",
    ULInt32("file_number"),
    If(lambda ctx: ctx["file_number"] != 0,
        Embed(
            Struct("GMAFileMeta",
                CString("file_name"),
                SLInt64("file_size"),
                ULInt32("file_crc")
            )
        )
    )
)

class FileContents(Adapter):
    def _encode(self, obj, context):
        return b"".join(obj)

    def _decode(self, obj, context):
        contents = []
        begin = 0
        for filemeta in context.all_file_meta:
            # ignore the dummy file with file number 0
            if filemeta.file_number == 0:
                break

            size = filemeta.file_size
            contents.append(obj[begin:begin + size])
            begin += size

        return contents

def file_content_size(context):
    total = 0
    for filemeta in context.all_file_meta:
        if filemeta.file_number == 0:
            return total

        total += filemeta.file_size

GMAContents = Struct("GMAContents",
    Magic(b"GMAD"),
    String("format_version", 1),
    SLInt64("steamid"),
    SLInt64("timestamp"),
    CString("required_content"),
    CString("addon_name"),
    CString("addon_description"),
    CString("addon_author"),
    SLInt32("addon_version"),
    # For each file get the metadata
    RepeatUntil(lambda obj, ctx: obj["file_number"] == 0, GMAFile),
    OnDemand(FileContents(Field("all_file_contents", file_content_size))),

)

GMAVerifiedContents = Struct("GMAVerifiedContents",
    Embed(GMAContents),
    Optional(ULInt32("addon_crc")),
    Terminator
)

def build_gma(addon, file_list, addon_path='.'):
    file_meta = []
    file_contents = []

    for i in range(0, len(file_list)):
        file_path = os.path.join(addon_path, file_list[i])

        with open(file_path, 'rb') as f:
            contents = f.read()

            file_meta.append(Container(
                file_name = bytes(file_list[i], "utf-8"),
                file_number = i + 1,
                file_crc = crc32(contents) & 0xffffffff,
                file_size = len(contents)
            ))

            file_contents.append(contents)

    # Dummy end file
    file_meta.append(Container(file_number = 0))

    container = Container()
    container.format_version = GMA_VERSION
    container.steamid = addon.getsteamid()
    container.timestamp = int(time())
    container.required_content = b""
    container.addon_name = bytes(addon.gettitle(), "utf-8")
    container.addon_description = bytes(addon.get_description_json(), "utf-8")
    container.addon_author = bytes(addon.getauthor(), "utf-8")
    container.addon_version = addon.getversion()
    container.all_file_meta = file_meta
    container.all_file_contents = file_contents

    return GMAContents.build(container)

def write(addon, destination_path='.'):
    file_list = addon.getfiles()
    addon_path = addon.getpath()
    gma = build_gma(addon, file_list, addon_path)
    crc = crc32(gma)

    file_name, extension = os.path.splitext(destination_path)
    destination = extension and destination_path or os.path.join(destination_path, "out.gma")

    # Force .gma extension
    destination = os.path.splitext(destination)[0] + ".gma"

    with open(destination, 'wb') as file:
        file.write(gma)
        file.write(pack('I', crc))

def extract(file_path, destination_path):
    with open(file_path, 'rb') as file:
        contents = file.read()
        gma = GMAVerifiedContents.parse(contents)

        for i in range(0, len(gma.all_file_meta) - 1):
            meta = gma.all_file_meta[i]
            file_name = os.path.join(destination_path, meta.file_name.decode("utf-8"))
            file_folder = os.path.dirname(file_name)

            if not os.path.exists(file_folder):
                os.makedirs(file_folder)

            print("Extracting %s..." % file_name)

            with open(file_name, 'wb') as output:
                output.write(gma.all_file_contents.value[i])

<commit_msg>output file name only when extracting<commit_after>#!/usr/bin/env python3
"""The structure of a GMA file, parsing and building"""

import os
from construct import *
from time import time
from binascii import crc32
from struct import pack

GMA_VERSION = b"\x03"

GMAFile = Struct("all_file_meta",
    ULInt32("file_number"),
    If(lambda ctx: ctx["file_number"] != 0,
        Embed(
            Struct("GMAFileMeta",
                CString("file_name"),
                SLInt64("file_size"),
                ULInt32("file_crc")
            )
        )
    )
)

class FileContents(Adapter):
    def _encode(self, obj, context):
        return b"".join(obj)

    def _decode(self, obj, context):
        contents = []
        begin = 0
        for filemeta in context.all_file_meta:
            # ignore the dummy file with file number 0
            if filemeta.file_number == 0:
                break

            size = filemeta.file_size
            contents.append(obj[begin:begin + size])
            begin += size

        return contents

def file_content_size(context):
    total = 0
    for filemeta in context.all_file_meta:
        if filemeta.file_number == 0:
            return total

        total += filemeta.file_size

GMAContents = Struct("GMAContents",
    Magic(b"GMAD"),
    String("format_version", 1),
    SLInt64("steamid"),
    SLInt64("timestamp"),
    CString("required_content"),
    CString("addon_name"),
    CString("addon_description"),
    CString("addon_author"),
    SLInt32("addon_version"),
    # For each file get the metadata
    RepeatUntil(lambda obj, ctx: obj["file_number"] == 0, GMAFile),
    OnDemand(FileContents(Field("all_file_contents", file_content_size))),

)

GMAVerifiedContents = Struct("GMAVerifiedContents",
    Embed(GMAContents),
    Optional(ULInt32("addon_crc")),
    Terminator
)

def build_gma(addon, file_list, addon_path='.'):
    file_meta = []
    file_contents = []

    for i in range(0, len(file_list)):
        file_path = os.path.join(addon_path, file_list[i])

        with open(file_path, 'rb') as f:
            contents = f.read()

            file_meta.append(Container(
                file_name = bytes(file_list[i], "utf-8"),
                file_number = i + 1,
                file_crc = crc32(contents) & 0xffffffff,
                file_size = len(contents)
            ))

            file_contents.append(contents)

    # Dummy end file
    file_meta.append(Container(file_number = 0))

    container = Container()
    container.format_version = GMA_VERSION
    container.steamid = addon.getsteamid()
    container.timestamp = int(time())
    container.required_content = b""
    container.addon_name = bytes(addon.gettitle(), "utf-8")
    container.addon_description = bytes(addon.get_description_json(), "utf-8")
    container.addon_author = bytes(addon.getauthor(), "utf-8")
    container.addon_version = addon.getversion()
    container.all_file_meta = file_meta
    container.all_file_contents = file_contents

    return GMAContents.build(container)

def write(addon, destination_path='.'):
    file_list = addon.getfiles()
    addon_path = addon.getpath()
    gma = build_gma(addon, file_list, addon_path)
    crc = crc32(gma)

    file_name, extension = os.path.splitext(destination_path)
    destination = extension and destination_path or os.path.join(destination_path, "out.gma")

    # Force .gma extension
    destination = os.path.splitext(destination)[0] + ".gma"

    with open(destination, 'wb') as file:
        file.write(gma)
        file.write(pack('I', crc))

def extract(file_path, destination_path):
    with open(file_path, 'rb') as file:
        contents = file.read()
        gma = GMAVerifiedContents.parse(contents)

        for i in range(0, len(gma.all_file_meta) - 1):
            meta = gma.all_file_meta[i]
            file_name = os.path.join(destination_path, meta.file_name.decode("utf-8"))
            file_folder = os.path.dirname(file_name)

            if not os.path.exists(file_folder):
                os.makedirs(file_folder)

            print(file_name)

            with open(file_name, 'wb') as output:
                output.write(gma.all_file_contents.value[i])

<|endoftext|>