2 * Author: Thomas Ingleby <thomas.c.ingleby@intel.com>
3 * Copyright (c) 2014 Intel Corporation.
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
13 * The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 #include "mraa_internal.h"
34 #define SYSFS_PWM "/sys/class/pwm"
37 mraa_pwm_setup_duty_fp(mraa_pwm_context dev)
40 snprintf(bu,MAX_SIZE, "/sys/class/pwm/pwmchip%d/pwm%d/duty_cycle", dev->chipid, dev->pin);
42 dev->duty_fp = open(bu, O_RDWR);
43 if (dev->duty_fp == -1) {
50 mraa_pwm_write_period(mraa_pwm_context dev, int period)
52 if (advance_func->pwm_period_replace != NULL) {
53 mraa_result_t result = advance_func->pwm_period_replace(dev,period);
54 if (result == MRAA_SUCCESS) {
60 snprintf(bu,MAX_SIZE ,"/sys/class/pwm/pwmchip%d/pwm%d/period", dev->chipid, dev->pin);
62 int period_f = open(bu, O_RDWR);
64 syslog(LOG_ERR, "pwm: Failed to open period for writing");
65 return MRAA_ERROR_INVALID_RESOURCE;
68 int length = snprintf(out, MAX_SIZE, "%d", period);
69 if (write(period_f, out, length*sizeof(char)) == -1) {
71 return MRAA_ERROR_INVALID_RESOURCE;
80 mraa_pwm_write_duty(mraa_pwm_context dev, int duty)
82 if (dev->duty_fp == -1) {
83 if (mraa_pwm_setup_duty_fp(dev) == 1) {
84 return MRAA_ERROR_INVALID_HANDLE;
88 int length = sprintf(bu, "%d", duty);
89 if (write(dev->duty_fp, bu, length * sizeof(char)) == -1)
90 return MRAA_ERROR_INVALID_RESOURCE;
95 mraa_pwm_read_period(mraa_pwm_context dev)
98 char output[MAX_SIZE];
99 snprintf(bu,MAX_SIZE, "/sys/class/pwm/pwmchip%d/pwm%d/period", dev->chipid, dev->pin);
101 int period_f = open(bu, O_RDWR);
102 if (period_f == -1) {
103 syslog(LOG_ERR, "pwm: Failed to open period for reading");
106 off_t size = lseek(period_f, 0, SEEK_END);
107 lseek(period_f, 0, SEEK_SET);
109 ssize_t rb = read(period_f, output, size + 1);
113 syslog(LOG_ERR, "pwm: Error in reading period");
118 long int ret = strtol(output, &endptr, 10);
119 if ('\0' != *endptr && '\n' != *endptr) {
120 syslog(LOG_ERR, "pwm: Error in string conversion");
123 else if (ret > INT_MAX || ret < INT_MIN) {
124 syslog(LOG_ERR, "pwm: Number is invalid");
127 dev->period = (int)ret;
132 mraa_pwm_read_duty(mraa_pwm_context dev)
134 if (dev->duty_fp == -1) {
135 if (mraa_pwm_setup_duty_fp(dev) == 1) {
136 return MRAA_ERROR_INVALID_HANDLE;
139 lseek(dev->duty_fp, 0, SEEK_SET);
141 off_t size = lseek(dev->duty_fp, 0, SEEK_END);
142 lseek(dev->duty_fp, 0, SEEK_SET);
143 char output[MAX_SIZE];
144 ssize_t rb = read(dev->duty_fp, output, size+1);
146 syslog(LOG_ERR, "pwm: Error in reading duty");
151 long int ret = strtol(output, &endptr, 10);
152 if ('\0' != *endptr && '\n' != *endptr) {
153 syslog(LOG_ERR, "pwm: Error in string converstion");
156 else if (ret > INT_MAX || ret < INT_MIN) {
157 syslog(LOG_ERR, "pwm: Number is invalid");
164 mraa_pwm_init(int pin)
166 if (advance_func->pwm_init_pre != NULL) {
167 if (advance_func->pwm_init_pre(pin) != MRAA_SUCCESS)
171 syslog(LOG_ERR, "pwm: Platform Not Initialised");
174 if (plat->pins[pin].capabilites.pwm != 1) {
175 syslog(LOG_ERR, "pwm: pin not capable of pwm");
179 if (plat->pins[pin].capabilites.gpio == 1) {
180 // This deserves more investigation
181 mraa_gpio_context mux_i;
182 mux_i = mraa_gpio_init_raw(plat->pins[pin].gpio.pinmap);
184 syslog(LOG_ERR, "pwm: error in gpio->pwm transition");
187 if (mraa_gpio_dir(mux_i, MRAA_GPIO_OUT) != MRAA_SUCCESS) {
188 syslog(LOG_ERR, "pwm: error in gpio->pwm transition");
191 if (mraa_gpio_write(mux_i, 1) != MRAA_SUCCESS) {
192 syslog(LOG_ERR, "pwm: error in gpio->pwm transition");
195 if (mraa_gpio_close(mux_i) != MRAA_SUCCESS) {
196 syslog(LOG_ERR, "pwm: error in gpio->pwm transition");
201 if (plat->pins[pin].pwm.mux_total > 0) {
202 if (mraa_setup_mux_mapped(plat->pins[pin].pwm) != MRAA_SUCCESS) {
203 syslog(LOG_ERR, "pwm: Failed to set-up multiplexer");
208 int chip = plat->pins[pin].pwm.parent_id;
209 int pinn = plat->pins[pin].pwm.pinmap;
211 if (advance_func->pwm_init_post != NULL) {
212 mraa_pwm_context pret = mraa_pwm_init_raw(chip,pinn);
213 mraa_result_t ret = advance_func->pwm_init_post(pret);
214 if (ret != MRAA_SUCCESS) {
220 return mraa_pwm_init_raw(chip,pinn);
224 mraa_pwm_init_raw(int chipin, int pin)
226 mraa_pwm_context dev = (mraa_pwm_context) malloc(sizeof(struct _pwm));
230 dev->chipid = chipin;
234 char directory[MAX_SIZE];
235 snprintf(directory, MAX_SIZE, SYSFS_PWM "/pwmchip%d/pwm%d", dev->chipid, dev->pin);
237 if (stat(directory, &dir) == 0 && S_ISDIR(dir.st_mode)) {
238 syslog(LOG_NOTICE, "pwm: Pin already exported, continuing");
239 dev->owner = 0; // Not Owner
241 char buffer[MAX_SIZE];
242 snprintf(buffer, MAX_SIZE, "/sys/class/pwm/pwmchip%d/export", dev->chipid);
243 int export_f = open(buffer, O_WRONLY);
244 if (export_f == -1) {
245 syslog(LOG_ERR, "pwm: Failed to open export for writing");
251 int size = snprintf(out, MAX_SIZE, "%d", dev->pin);
252 if (write(export_f, out, size*sizeof(char)) == -1) {
253 syslog(LOG_WARNING, "pwm: Failed to write to export! Potentially already enabled");
259 mraa_pwm_period_us(dev, plat->pwm_default_period);
262 mraa_pwm_setup_duty_fp(dev);
267 mraa_pwm_write(mraa_pwm_context dev, float percentage)
269 if (dev->period == -1) {
270 if (mraa_pwm_read_period(dev) <= 0)
271 return MRAA_ERROR_NO_DATA_AVAILABLE;
274 if (percentage >= 1.0f) {
275 return mraa_pwm_write_duty(dev, dev->period);
277 return mraa_pwm_write_duty(dev, percentage * dev->period);
281 mraa_pwm_read(mraa_pwm_context dev)
283 int period = mraa_pwm_read_period(dev);
285 return (mraa_pwm_read_duty(dev) / (float) period);
291 mraa_pwm_period(mraa_pwm_context dev, float seconds)
293 return mraa_pwm_period_ms(dev, seconds*1000);
297 mraa_pwm_period_ms(mraa_pwm_context dev, int ms)
299 return mraa_pwm_period_us(dev, ms*1000);
303 mraa_pwm_period_us(mraa_pwm_context dev, int us)
305 if (us < plat->pwm_min_period ||
306 us > plat->pwm_max_period) {
307 syslog(LOG_ERR, "pwm: period value outside platform range");
308 return MRAA_ERROR_INVALID_PARAMETER;
310 return mraa_pwm_write_period(dev, us*1000);
314 mraa_pwm_pulsewidth(mraa_pwm_context dev, float seconds)
316 return mraa_pwm_pulsewidth_ms(dev, seconds*1000);
320 mraa_pwm_pulsewidth_ms(mraa_pwm_context dev, int ms)
322 return mraa_pwm_pulsewidth_us(dev, ms*1000);
326 mraa_pwm_pulsewidth_us(mraa_pwm_context dev, int us)
328 return mraa_pwm_write_duty(dev, us*1000);
332 mraa_pwm_enable(mraa_pwm_context dev, int enable)
341 snprintf(bu,MAX_SIZE, "/sys/class/pwm/pwmchip%d/pwm%d/enable", dev->chipid, dev->pin);
343 int enable_f = open(bu, O_RDWR);
345 if (enable_f == -1) {
346 syslog(LOG_ERR, "pwm: Failed to open enable for writing");
347 return MRAA_ERROR_INVALID_RESOURCE;
350 int size = snprintf(out, sizeof(out), "%d", enable);
351 if (write(enable_f, out, size * sizeof(char)) == -1) {
352 syslog(LOG_ERR, "pwm: Failed to write to enable");
354 return MRAA_ERROR_INVALID_RESOURCE;
361 mraa_pwm_unexport_force(mraa_pwm_context dev)
363 char filepath[MAX_SIZE];
364 snprintf(filepath, MAX_SIZE, "/sys/class/pwm/pwmchip%d/unexport", dev->chipid);
366 int unexport_f = open(filepath, O_WRONLY);
367 if (unexport_f == -1) {
368 syslog(LOG_ERR, "pwm: Failed to open unexport for writing");
369 return MRAA_ERROR_INVALID_RESOURCE;
373 int size = snprintf(out, MAX_SIZE, "%d", dev->pin);
374 if (write(unexport_f, out, size*sizeof(char)) == -1) {
375 syslog(LOG_ERR, "pwm: Failed to write to unexport");
377 return MRAA_ERROR_INVALID_RESOURCE;
385 mraa_pwm_unexport(mraa_pwm_context dev)
387 mraa_pwm_enable(dev, 0);
389 return mraa_pwm_unexport_force(dev);
391 return MRAA_ERROR_INVALID_RESOURCE;
395 mraa_pwm_close(mraa_pwm_context dev)
397 mraa_pwm_unexport(dev);
403 mraa_pwm_owner(mraa_pwm_context dev, mraa_boolean_t owner_new)
406 return MRAA_ERROR_INVALID_RESOURCE;
407 dev->owner = owner_new;
412 mraa_pwm_config_ms(mraa_pwm_context dev, int ms ,float ms_float)
414 int old_dutycycle, old_period, status;
415 old_dutycycle = mraa_pwm_read_duty(dev);
416 old_period = mraa_pwm_read_period(dev);
417 status = mraa_pwm_period_us(dev, ms*1000);
418 if (status != MRAA_SUCCESS) {
419 mraa_pwm_write_duty(dev, old_dutycycle);
422 status = mraa_pwm_write_duty(dev, 0);
423 if (status != MRAA_SUCCESS) {
426 status = mraa_pwm_pulsewidth_us(dev, ms_float*1000);
427 if (status != MRAA_SUCCESS) {
428 mraa_pwm_write_duty(dev, old_dutycycle);
429 mraa_pwm_write_period(dev, old_period);
436 mraa_pwm_config_percent(mraa_pwm_context dev, int ms ,float percentage)
438 int old_dutycycle, old_period, status;
439 old_dutycycle = mraa_pwm_read_duty(dev);
440 old_period = mraa_pwm_read_period(dev);
441 status = mraa_pwm_period_us(dev, ms*1000);
442 if (status != MRAA_SUCCESS) {
443 mraa_pwm_write_duty(dev, old_dutycycle);
446 status = mraa_pwm_write_duty(dev, 0);
447 if (status != MRAA_SUCCESS) {
450 status = mraa_pwm_pulsewidth_us(dev, (ms*1000)*percentage);
451 if (status != MRAA_SUCCESS) {
452 mraa_pwm_write_duty(dev, old_dutycycle);
453 mraa_pwm_write_period(dev, old_period);