diff --git a/config.txt b/config.txt index 704758a..e4d1b33 100644 --- a/config.txt +++ b/config.txt @@ -5,6 +5,7 @@ screen.size = medium output.display = True output.serial = False output.i2c = False +output.pwm = False use.logging = False [serial.interface] @@ -20,6 +21,12 @@ right.channel.address = 0x20 output.size = 10 update.period = 0.1 +[pwm.interface] +frequency = 500 +gpio.pin.left = 24 +gpio.pin.right = 25 +update.period = 0.1 + [data.source] type = pipe polling.interval = 0.01 diff --git a/configfileparser.py b/configfileparser.py index 51dbb36..a98fe12 100644 --- a/configfileparser.py +++ b/configfileparser.py @@ -1,4 +1,4 @@ -# Copyright 2016-2018 PeppyMeter peppy.player@gmail.com +# Copyright 2016-2019 PeppyMeter peppy.player@gmail.com # # This file is part of PeppyMeter. # @@ -32,16 +32,25 @@ OUTPUT_DISPLAY = "output.display" OUTPUT_SERIAL = "output.serial" OUTPUT_I2C = "output.i2c" +OUTPUT_PWM = "output.pwm" + SERIAL_INTERFACE = "serial.interface" DEVICE_NAME = "device.name" BAUD_RATE = "baud.rate" INCLUDE_TIME = "include.time" UPDATE_PERIOD = "update.period" + I2C_INTERFACE = "i2c.interface" PORT = "port" LEFT_CHANNEL_ADDRESS = "left.channel.address" RIGHT_CHANNEL_ADDRESS = "right.channel.address" OUTPUT_SIZE = "output.size" + +PWM_INTERFACE = "pwm.interface" +FREQUENCY = "frequency" +GPIO_PIN_LEFT = "gpio.pin.left" +GPIO_PIN_RIGHT = "gpio.pin.right" + USE_LOGGING = "use.logging" USE_VU_METER = "use.vu.meter" METER = "meter" @@ -127,6 +136,7 @@ def __init__(self, base_path): self.meter_config[OUTPUT_DISPLAY] = c.getboolean(CURRENT, OUTPUT_DISPLAY) self.meter_config[OUTPUT_SERIAL] = c.getboolean(CURRENT, OUTPUT_SERIAL) self.meter_config[OUTPUT_I2C] = c.getboolean(CURRENT, OUTPUT_I2C) + self.meter_config[OUTPUT_PWM] = c.getboolean(CURRENT, OUTPUT_PWM) self.meter_config[USE_LOGGING] = c.getboolean(CURRENT, USE_LOGGING) self.meter_config[SERIAL_INTERFACE] = {} @@ -141,6 +151,12 @@ def __init__(self, base_path): self.meter_config[I2C_INTERFACE][RIGHT_CHANNEL_ADDRESS] = int(c.get(I2C_INTERFACE, RIGHT_CHANNEL_ADDRESS), 0) self.meter_config[I2C_INTERFACE][OUTPUT_SIZE] = c.getint(I2C_INTERFACE, OUTPUT_SIZE) self.meter_config[I2C_INTERFACE][UPDATE_PERIOD] = c.getfloat(I2C_INTERFACE, UPDATE_PERIOD) + + self.meter_config[PWM_INTERFACE] = {} + self.meter_config[PWM_INTERFACE][FREQUENCY] = c.getint(PWM_INTERFACE, FREQUENCY) + self.meter_config[PWM_INTERFACE][GPIO_PIN_LEFT] = c.getint(PWM_INTERFACE, GPIO_PIN_LEFT) + self.meter_config[PWM_INTERFACE][GPIO_PIN_RIGHT] = c.getint(PWM_INTERFACE, GPIO_PIN_RIGHT) + self.meter_config[PWM_INTERFACE][UPDATE_PERIOD] = c.getfloat(PWM_INTERFACE, UPDATE_PERIOD) screen_size = c.get(CURRENT, SCREEN_SIZE) self.meter_config[SCREEN_INFO] = {} diff --git a/peppymeter.py b/peppymeter.py index 381b44f..57d874e 100644 --- a/peppymeter.py +++ b/peppymeter.py @@ -1,4 +1,4 @@ -# Copyright 2016-2018 PeppyMeter peppy.player@gmail.com +# Copyright 2016-2019 PeppyMeter peppy.player@gmail.com # # This file is part of PeppyMeter. # @@ -26,9 +26,10 @@ from datasource import DataSource, SOURCE_NOISE, SOURCE_PIPE from serialinterface import SerialInterface from i2cinterface import I2CInterface +from pwminterface import PWMInterface from screensavermeter import ScreensaverMeter from configfileparser import ConfigFileParser, SCREEN_RECT, SCREEN_INFO, WIDTH, HEIGHT, DEPTH, \ - OUTPUT_DISPLAY, OUTPUT_SERIAL, OUTPUT_I2C, DATA_SOURCE, TYPE, USE_LOGGING, USE_VU_METER + OUTPUT_DISPLAY, OUTPUT_SERIAL, OUTPUT_I2C, OUTPUT_PWM, DATA_SOURCE, TYPE, USE_LOGGING, USE_VU_METER class Peppymeter(ScreensaverMeter): """ Peppy Meter class """ @@ -80,6 +81,9 @@ def __init__(self, util=None, standalone=False): if self.util.meter_config[OUTPUT_I2C]: self.outputs[OUTPUT_I2C] = I2CInterface(self.util.meter_config, self.data_source) + + if self.util.meter_config[OUTPUT_PWM]: + self.outputs[OUTPUT_PWM] = PWMInterface(self.util.meter_config, self.data_source) self.start_interface_outputs() @@ -104,6 +108,14 @@ def init_display(self): os.environ["SDL_MOUSEDEV"] = "/dev/input/touchscreen" os.environ["SDL_MOUSEDRV"] = "TSLIB" + if not self.util.meter_config[OUTPUT_DISPLAY]: + os.environ["SDL_VIDEODRIVER"] = "dummy" + os.environ["DISPLAY"] = ":0" + pygame.display.init() + pygame.font.init() + self.util.PYGAME_SCREEN = pygame.display.set_mode((1,1), pygame.DOUBLEBUF, depth) + return + if "win" not in sys.platform: pygame.display.init() pygame.mouse.set_visible(False) @@ -124,6 +136,10 @@ def start_interface_outputs(self): if self.util.meter_config[OUTPUT_I2C]: self.i2c_interface = self.outputs[OUTPUT_I2C] self.i2c_interface.start_writing() + + if self.util.meter_config[OUTPUT_PWM]: + self.pwm_interface = self.outputs[OUTPUT_PWM] + self.pwm_interface.start_writing() def start(self): """ Start VU meter. This method called by Peppy Meter to start meter """ @@ -168,6 +184,8 @@ def exit(self): self.serial_interface.stop_writing() if self.util.meter_config[OUTPUT_I2C]: self.i2c_interface.stop_writing() + if self.util.meter_config[OUTPUT_PWM]: + self.pwm_interface.stop_writing() pygame.quit() os._exit(0) @@ -176,7 +194,9 @@ def exit(self): pm = Peppymeter(standalone=True) if pm.util.meter_config[DATA_SOURCE][TYPE] != SOURCE_PIPE: pm.data_source.start_data_source() + + pm.init_display() + if pm.util.meter_config[OUTPUT_DISPLAY]: - pm.init_display() pm.start_display_output() diff --git a/pwminterface.py b/pwminterface.py new file mode 100644 index 0000000..92c13b0 --- /dev/null +++ b/pwminterface.py @@ -0,0 +1,116 @@ +# Copyright 2019 PeppyMeter peppy.player@gmail.com +# +# This file is part of PeppyMeter. +# +# PeppyMeter is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# PeppyMeter is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with PeppyMeter. If not, see . + +import time +import sys +import logging + +from threading import Thread +from configfileparser import PWM_INTERFACE, FREQUENCY, GPIO_PIN_LEFT, GPIO_PIN_RIGHT, UPDATE_PERIOD + +class DummyPWM(object): + """ Dummy PWM class used for development on Windows platform """ + + def __init__(self): + """ Initializer """ + + pass + + def start(self, value): + """ Dummy start """ + + pass + + def ChangeDutyCycle(self, value): + """ Dummy change duty cycle """ + + pass + + def stop(self, value): + """ Dummy stop """ + + pass + +class PWMInterface(object): + """ PWM interface class. + + Can be used with devices controlled by means of PWM signal e.g. LED, gas tubes etc. + """ + def __init__(self, config, data_source): + """ Initializer """ + + self.data_source = data_source + + self.frequency = config[PWM_INTERFACE][FREQUENCY] + self.gpio_pin_left = config[PWM_INTERFACE][GPIO_PIN_LEFT] + self.gpio_pin_right = config[PWM_INTERFACE][GPIO_PIN_RIGHT] + self.update_period = config[PWM_INTERFACE][UPDATE_PERIOD] + + if "win" in sys.platform: + self.left = DummyPWM() + self.right = DummyPWM() + else: + import RPi.GPIO as gpio + gpio.setmode(gpio.BCM) + gpio.setwarnings(False) + + gpio.setup(self.gpio_pin_left, gpio.OUT) + gpio.setup(self.gpio_pin_right, gpio.OUT) + + self.left = gpio.PWM(self.gpio_pin_left, self.frequency) + self.right = gpio.PWM(self.gpio_pin_right, self.frequency) + + self.logging_template = "PWM left: {0} right: {1}" + + def start_writing(self): + """ Start writing thread """ + + self.running = True + thread = Thread(target = self.write_data) + thread.start() + + def write_data(self): + """ Method of the writing thread """ + + self.left.start(0) + self.right.start(0) + + while self.running: + time.sleep(self.update_period) + + v = self.data_source.get_value() + + if v == 0: + continue + + logging.debug(v) + left = float(int(v[0])) + right = float(int(v[1])) + + logging.debug(self.logging_template.format(left, right)) + + self.left.ChangeDutyCycle(left) + self.right.ChangeDutyCycle(right) + + def stop_writing(self): + """ Stop writing thread and stop PWM """ + + self.running = False + time.sleep(self.update_period) + self.left.stop() + self.right.stop() + \ No newline at end of file diff --git a/serialinterface.py b/serialinterface.py index 9ce0e2b..5e9f8bc 100644 --- a/serialinterface.py +++ b/serialinterface.py @@ -1,4 +1,4 @@ -# Copyright 2016-2018 PeppyMeter peppy.player@gmail.com +# Copyright 2016-2019 PeppyMeter peppy.player@gmail.com # # This file is part of PeppyMeter. # @@ -84,7 +84,7 @@ def write_data(self): time.sleep(self.update_period) def get_data(self, left, right): - """ Prepareata for writing. Include time if enabled. + """ Prepare data for writing. Include time if enabled. :left: data for left channel :right: data for right channel