# -*- coding: utf-8 -*-
# (c) 2015 Tuomas Airaksinen
#
# This file is part of automate-rpio.
#
# automate-rpio 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.
#
# automate-rpio 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 automate-rpio. If not, see <http://www.gnu.org/licenses/>.
from __future__ import unicode_literals
from traits.api import CInt, CBool, Instance, Any, CFloat, Property
from automate.service import AbstractSystemService
from automate.statusobject import AbstractActuator
[docs]class RpioActuator(AbstractActuator):
"""
Boolean-valued actuator for setting Raspberry Pi GPIO port statuses (on/off).
"""
_status = CBool(transient=True)
#: GPIO port id
port = CInt
#: Set to True to have inversed status value
inverted = CBool(False)
_hw_service = Instance(AbstractSystemService, transient=True)
view = AbstractActuator.view + ["port"]
def setup(self):
self._hw_service = self.system.request_service('RpioService')
self._hw_service.enable_output_port(self.port)
def _port_changed(self, old, new):
if not self._hw_service:
return
if old:
self._hw_service.disable_output_port(old)
self._hw_service.enable_output_port(new)
def _status_changed(self):
self.logger.debug("%s gpio actuator status changed %s", self.name, repr(self._status))
self._hw_service.set_output_port_status(self.port, self._status if not self.inverted else not self._status)
[docs]class RpioPWMActuator(AbstractActuator):
"""
Actuator to control PWM (pulse-width-modulation) ports on Raspberry pi GPIO.
Status range 0...1
This is not recommended to be used because RPIO PWM implementation is not very well behaving.
I recommend to use ArduinoPWMActuator with an Arduino loaded with StandardFirmata. It's much more
stable and robust solution.
"""
_status = CFloat(transient=True)
#: GPIO port number
port = CInt
#: RPIO PWM DMA channel
dma_channel = CInt(0)
#: PWM frequency (Hz)
frequency = CFloat(50.)
_subcycle = Property(trait=CInt, transient=True)
view = AbstractActuator.view + ["port"]
_pwm = Any(transient=True)
_hw_service = Instance(AbstractSystemService, transient=True)
def _get__subcycle(self):
return int(1. / self.frequency * 1e6)
def setup(self):
self._hw_service = self.system.request_service('RpioService')
self._pwm = self._hw_service.get_pwm_module()
self._port_changed(None, self.port)
def _port_changed(self, old, new):
if not self._hw_service:
return
if old:
self._pwm.clear_channel_gpio(self.dma_channel, old)
self._pwm.init_channel(self.dma_channel, self._subcycle)
new = min(0.999, max(0., self._status))
self._pwm.add_channel_pulse(self.dma_channel, self.port, 0, int(round(new * self._subcycle / 10.)))
def _frequency_changed(self):
self._port_changed(self.port, self.port)
def _status_changed(self):
self.logger.debug("PWMActuator %s change %s", self, self._status)
PWM = self._pwm
PWM.clear_channel_gpio(self.dma_channel, self.port)
new = min(0.999, max(0., self._status))
PWM.add_channel_pulse(self.dma_channel, self.port, 0, int(round(new * self._subcycle / 10.)))