From 73ae207e16b63766beb5a3d3abb9b39881d70963 Mon Sep 17 00:00:00 2001 From: Robert Wolterman Date: Sat, 28 Jan 2017 04:16:12 +0000 Subject: [PATCH] Copied over 2 new pwm functions from @streamnsight to close #46. these 2 functions are untested, which is why i'm not updating the readme at the moment. --- source/c_pwm.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++++- source/c_pwm.h | 3 ++ source/py_pwm.c | 70 ++++++++++++++++++++++++++++++++++ 3 files changed, 171 insertions(+), 1 deletion(-) diff --git a/source/c_pwm.c b/source/c_pwm.c index 4caa1e1..ece5986 100644 --- a/source/c_pwm.c +++ b/source/c_pwm.c @@ -47,7 +47,6 @@ SOFTWARE. // Global variables int pwm_initialized = 0; -//int DEBUG = 0; // pwm devices (future chip pro use) struct pwm_dev @@ -173,6 +172,66 @@ int pwm_set_frequency(const char *key, float freq) { return rtnval; } +int pwm_set_period_ns(const char *key, unsigned long period_ns) { + int len; + int rtnval = -1; + char buffer[80]; + struct pwm_exp *pwm; + + //TODO: ADD CHECK FOR period_ns + + pwm = lookup_exported_pwm(key); + + if (pwm == NULL) { + return rtnval; + } + + if (pwm->enable) { + if (period_ns != pwm->period_ns) { + pwm->period_ns = period_ns; + + len = snprintf(buffer, sizeof(buffer), "%lu", period_ns); BUF2SMALL(buffer); + ssize_t s = write(pwm->period_fd, buffer, len); //ASSRT(s == len); + if (DEBUG) { + printf(" ** pwm_set_period_ns: pwm_initialized = %d\n", pwm_initialized); + printf(" ** pwm_set_period_ns: buffer: %s\n", buffer); + printf(" ** pwm_set_period_ns: s = %d, len = %d\n", s, len); + } + if (s != len) { + rtnval = -1; + } else { + rtnval = 1; + } + } else { + rtnval = 0; + } + } else { + rtnval = 0; + } + + return rtnval; +} + +int pwm_get_period_ns(const char *key, unsigned long *period_ns) { + int rtnval = -1; + struct pwm_exp *pwm; + + pwm = lookup_exported_pwm(key); + + if (pwm == NULL) { + return rtnval; + } + + if (DEBUG) + printf(" ** pwm_get_period_ns: %lu **\n",pwm->period_ns); + + // Set period_ns to what we have in the struct + *period_ns = pwm->period_ns; + + rtnval = 0; + return rtnval; +} + int pwm_set_polarity(const char *key, int polarity) { int len; int rtnval = -1; @@ -252,6 +311,44 @@ int pwm_set_duty_cycle(const char *key, float duty) { return rtnval; } +int pwm_set_pulse_width_ns(const char *key, unsigned long pulse_width_ns) { + int len; + int rtnval = -1; + char buffer[80]; + struct pwm_exp *pwm; + + pwm = lookup_exported_pwm(key); + + if (pwm == NULL) { + return rtnval; + } + + if (pulse_width_ns < 0 || pulse_width_ns > pwm->period_ns) + return rtnval; + + pwm->duty = pulse_width_ns / pwm->period_ns; + + if (pwm->enable) { + len = snprintf(buffer, sizeof(buffer), "%lu", pwm->duty); BUF2SMALL(buffer); + ssize_t s = write(pwm->duty_fd, buffer, len); //ASSRT(s == len); + if (DEBUG) { + printf(" ** pwm_set_pulse_width_ns: pwm_initialized = %d\n", pwm_initialized); + printf(" ** pwm_set_pulse_width_ns: buffer: %s\n", buffer); + printf(" ** pwm_set_pulse_width_ns: s = %d, len = %d\n", s, len); + } + if (s != len) { + rtnval = -1; + } else { + rtnval = 1; + } + } else { + rtnval = 0; + } + + return rtnval; + +} + int pwm_set_enable(const char *key, int enable) { int len; diff --git a/source/c_pwm.h b/source/c_pwm.h index 77e6f56..9790b14 100644 --- a/source/c_pwm.h +++ b/source/c_pwm.h @@ -32,6 +32,9 @@ SOFTWARE. int pwm_start(const char *key, float duty, float freq, int polarity); int pwm_disable(const char *key); int pwm_set_frequency(const char *key, float freq); +int pwm_set_period_ns(const char *key, unsigned long period_ns); +int pwm_get_period_ns(const char *key, unsigned long *period_ns); int pwm_set_duty_cycle(const char *key, float duty); +int pwm_set_pulse_width_ns(const char *key, unsigned long pulse_width_ns); int pwm_set_enable(const char *key, int enable); void pwm_cleanup(void); diff --git a/source/py_pwm.c b/source/py_pwm.c index 066d1aa..e783277 100644 --- a/source/py_pwm.c +++ b/source/py_pwm.c @@ -143,6 +143,45 @@ static PyObject *py_set_duty_cycle(PyObject *self, PyObject *args, PyObject *kwa Py_RETURN_NONE; } +// python method PWM.set_pulse_width(channel, pulse_width_ns) +static PyObject *py_set_pulse_width_ns(PyObject *self, PyObject *args, PyObject *kwargs) +{ + char key[8]; + char *channel; + unsigned long pulse_width_ns = 0.0; + unsigned long period_ns; + static char *kwlist[] = {"channel", "pulse_width_ns", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|k", kwlist, &channel, &pulse_width_ns)) + return NULL; + + if (!get_pwm_key(channel, key)) { + PyErr_SetString(PyExc_ValueError, "Invalid PWM key or name."); + return NULL; + } + + // Get the period out of the data struct + int rtn = pwm_get_period_ns(key, &period_ns); + if (rtn == -1) + { + PyErr_SetString(PyExc_ValueError, "period unable to be obtained"); + return NULL; + } + + if (pulse_width_ns < 0.0 || pulse_width_ns > period_ns) + { + PyErr_SetString(PyExc_ValueError, "pulse width must have a value from 0 to period"); + return NULL; + } + + if (pwm_set_pulse_width_ns(key, pulse_width_ns) == -1) { + PyErr_SetString(PyExc_RuntimeError, "You must start() the PWM channel first"); + return NULL; + } + + Py_RETURN_NONE; +} + // python method PWM.set_frequency(channel, frequency) static PyObject *py_set_frequency(PyObject *self, PyObject *args, PyObject *kwargs) { @@ -173,6 +212,35 @@ static PyObject *py_set_frequency(PyObject *self, PyObject *args, PyObject *kwar Py_RETURN_NONE; } +// python method PWM.set_period_ns(channel, period_ns) +static PyObject *py_set_period_ns(PyObject *self, PyObject *args, PyObject *kwargs) +{ + char key[8]; + char *channel; + unsigned long period_ns = 2e6; + static char *kwlist[] = {"channel", "period_ns", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|k", kwlist, &channel, &period_ns)) + return NULL; + + if (period_ns <= 0) + { + PyErr_SetString(PyExc_ValueError, "period must be greater than 0ns"); + return NULL; + } + + if (!get_pwm_key(channel, key)) { + PyErr_SetString(PyExc_ValueError, "Invalid PWM key or name."); + return NULL; + } + + if (pwm_set_period_ns(key, period_ns) == -1) { + PyErr_SetString(PyExc_RuntimeError, "You must start() the PWM channel first"); + return NULL; + } + + Py_RETURN_NONE; +} static const char moduledocstring[] = "Hardware PWM functionality of a CHIP using Python"; @@ -181,6 +249,8 @@ PyMethodDef pwm_methods[] = { {"stop", (PyCFunction)py_stop_channel, METH_VARARGS | METH_KEYWORDS, "Stop the PWM channel. channel can be in the form of 'PWM0', or 'U13_18'"}, {"set_duty_cycle", (PyCFunction)py_set_duty_cycle, METH_VARARGS, "Change the duty cycle\ndutycycle - between 0.0 and 100.0" }, {"set_frequency", (PyCFunction)py_set_frequency, METH_VARARGS, "Change the frequency\nfrequency - frequency in Hz (freq > 0.0)" }, + {"set_period_ns", (PyCFunction)py_set_period_ns, METH_VARARGS, "Change the period\nperiod_ns - period in nanoseconds" }, + {"set_pulse_width_ns", (PyCFunction)py_set_pulse_width_ns, METH_VARARGS, "Change the period\npulse_width_ns - pulse width in nanoseconds" }, {"cleanup", py_cleanup, METH_VARARGS, "Clean up by resetting all GPIO channels that have been used by this program to INPUT with no pullup/pulldown and no event detection"}, {"toggle_debug", py_toggle_debug, METH_VARARGS, "Toggles the enabling/disabling of Debug print output"}, {NULL, NULL, 0, NULL}