maa: change complex C++ write calls to CamelCase for spi & i2c
[contrib/mraa.git] / src / pwm / pwm.c
1 /*
2  * Author: Thomas Ingleby <thomas.c.ingleby@intel.com>
3  * Copyright (c) 2014 Intel Corporation.
4  *
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:
12  *
13  * The above copyright notice and this permission notice shall be
14  * included in all copies or substantial portions of the Software.
15  *
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.
23  */
24
25 #include <stdlib.h>
26 #include <sys/stat.h>
27 #include <unistd.h>
28
29 #include "pwm.h"
30 #include "maa_internal.h"
31
32 #define MAX_SIZE 64
33 #define SYSFS_PWM "/sys/class/pwm"
34
35 /**
36  * A structure representing a PWM pin
37  */
38 struct _pwm {
39     /*@{*/
40     int pin; /**< the pin number, as known to the os. */
41     int chipid; /**< the chip id, which the pwm resides */
42     int duty_fp; /**< File pointer to duty file */
43     maa_boolean_t owner; /**< Owner of pwm context*/
44     /*@}*/
45 };
46
47 static int
48 maa_pwm_setup_duty_fp(maa_pwm_context dev)
49 {
50     char bu[MAX_SIZE];
51     snprintf(bu,MAX_SIZE, "/sys/class/pwm/pwmchip%d/pwm%d/duty_cycle", dev->chipid, dev->pin);
52
53     dev->duty_fp = open(bu, O_RDWR);
54     if (dev->duty_fp == -1) {
55         return 1;
56     }
57     return 0;
58 }
59
60 static maa_result_t
61 maa_pwm_write_period(maa_pwm_context dev, int period)
62 {
63     char bu[MAX_SIZE];
64     snprintf(bu,MAX_SIZE ,"/sys/class/pwm/pwmchip%d/pwm%d/period", dev->chipid, dev->pin);
65
66     int period_f = open(bu, O_RDWR);
67     if (period_f == -1) {
68         fprintf(stderr, "Failed to open period for writing!\n");
69         return MAA_ERROR_INVALID_RESOURCE;
70     }
71     char out[MAX_SIZE];
72     int length = snprintf(out, MAX_SIZE, "%d", period);
73     if (write(period_f, out, length*sizeof(char)) == -1) {
74         close(period_f);
75         return MAA_ERROR_INVALID_RESOURCE;
76     }
77
78     close(period_f);
79     return MAA_SUCCESS;
80 }
81
82 static maa_result_t
83 maa_pwm_write_duty(maa_pwm_context dev, int duty)
84 {
85     if (dev->duty_fp == -1) {
86         maa_pwm_setup_duty_fp(dev);
87     }
88     char bu[64];
89     int length = sprintf(bu, "%d", duty);
90     if (write(dev->duty_fp, bu, length * sizeof(char)) == -1)
91         return MAA_ERROR_INVALID_RESOURCE;
92     return MAA_SUCCESS;
93 }
94
95 static int
96 maa_pwm_get_period(maa_pwm_context dev)
97 {
98     char bu[MAX_SIZE];
99     char output[MAX_SIZE];
100     snprintf(bu,MAX_SIZE, "/sys/class/pwm/pwmchip%d/pwm%d/period", dev->chipid, dev->pin);
101
102     int period_f = open(bu, O_RDWR);
103     if (period_f == -1) {
104         fprintf(stderr, "Failed to open period for reading!\n");
105         return 0;
106     }
107     off_t size = lseek(period_f, 0, SEEK_END);
108     lseek(period_f, 0, SEEK_SET);
109
110     read(period_f, output, size + 1);
111     close(period_f);
112     int ret = strtol(output, NULL, 10);
113
114     return ret;
115 }
116
117 static int
118 maa_pwm_get_duty(maa_pwm_context dev)
119 {
120     if (dev->duty_fp == -1) {
121         maa_pwm_setup_duty_fp(dev);
122     } else {
123         lseek(dev->duty_fp, 0, SEEK_SET);
124     }
125     off_t size = lseek(dev->duty_fp, 0, SEEK_END);
126     lseek(dev->duty_fp, 0, SEEK_SET);
127     char output[MAX_SIZE];
128     read(dev->duty_fp, output, size+1);
129
130     int ret = strtol(output, NULL, 10);
131     return ret;
132 }
133
134 maa_pwm_context
135 maa_pwm_init(int pin) {
136     maa_pin_t* pinm = maa_setup_pwm(pin);
137     if (pinm == NULL)
138         return NULL;
139     int chip = pinm->parent_id;
140     int pinn = pinm->pinmap;
141     free(pinm);
142     return maa_pwm_init_raw(chip,pinn);
143 }
144
145 maa_pwm_context
146 maa_pwm_init_raw(int chipin, int pin)
147 {
148     maa_pwm_context dev = (maa_pwm_context) malloc(sizeof(struct _pwm));
149     if (dev == NULL)
150         return NULL;
151     dev->duty_fp = -1;
152     dev->chipid = chipin;
153     dev->pin = pin;
154
155     char directory[MAX_SIZE];
156     snprintf(directory, MAX_SIZE, SYSFS_PWM "/pwmchip%d/pwm%d", dev->chipid, dev->pin);
157     struct stat dir;
158     if (stat(directory, &dir) == 0 && S_ISDIR(dir.st_mode)) {
159         fprintf(stderr, "PWM Pin already exporting, continuing.\n");
160         dev->owner = 0; // Not Owner
161     } else {
162         char buffer[MAX_SIZE];
163         snprintf(buffer, MAX_SIZE, "/sys/class/pwm/pwmchip%d/export", dev->chipid);
164         int export_f = open(buffer, O_WRONLY);
165         if (export_f == -1) {
166             fprintf(stderr, "Failed to open export for writing!\n");
167             free(dev);
168             return NULL;
169         }
170
171         char out[MAX_SIZE];
172         int size = snprintf(out, MAX_SIZE, "%d", dev->pin);
173         if (write(export_f, out, size*sizeof(char)) == -1) {
174             fprintf(stderr, "Failed to write to export! Potentially already enabled\n");
175             close(export_f);
176             return NULL;
177         }
178         dev->owner = 1;
179         close(export_f);
180     }
181     maa_pwm_setup_duty_fp(dev);
182     return dev;
183 }
184
185 maa_result_t
186 maa_pwm_write(maa_pwm_context dev, float percentage)
187 {
188     return maa_pwm_write_duty(dev, percentage * maa_pwm_get_period(dev));
189 }
190
191 float
192 maa_pwm_read(maa_pwm_context dev)
193 {
194     float output = maa_pwm_get_duty(dev) / (float) maa_pwm_get_period(dev);
195     return output;
196 }
197
198 maa_result_t
199 maa_pwm_period(maa_pwm_context dev, float seconds)
200 {
201     return maa_pwm_period_ms(dev, seconds*1000);
202 }
203
204 maa_result_t
205 maa_pwm_period_ms(maa_pwm_context dev, int ms)
206 {
207     return maa_pwm_period_us(dev, ms*1000);
208 }
209
210 maa_result_t
211 maa_pwm_period_us(maa_pwm_context dev, int us)
212 {
213     return maa_pwm_write_period(dev, us*1000);
214 }
215
216 maa_result_t
217 maa_pwm_pulsewidth(maa_pwm_context dev, float seconds)
218 {
219     return maa_pwm_pulsewidth_ms(dev, seconds*1000);
220 }
221
222 maa_result_t
223 maa_pwm_pulsewidth_ms(maa_pwm_context dev, int ms)
224 {
225     return maa_pwm_pulsewidth_us(dev, ms*1000);
226 }
227
228 maa_result_t
229 maa_pwm_pulsewidth_us(maa_pwm_context dev, int us)
230 {
231     return maa_pwm_write_duty(dev, us*1000);
232 }
233
234 maa_result_t
235 maa_pwm_enable(maa_pwm_context dev, int enable)
236 {
237     int status;
238     if (enable != 0) {
239         status = 1;
240     } else {
241         status = enable;
242     }
243     char bu[MAX_SIZE];
244     snprintf(bu,MAX_SIZE, "/sys/class/pwm/pwmchip%d/pwm%d/enable", dev->chipid, dev->pin);
245
246     int enable_f = open(bu, O_RDWR);
247
248     if (enable_f == -1) {
249         fprintf(stderr, "Failed to open enable for writing!\n");
250         return MAA_ERROR_INVALID_RESOURCE;
251     }
252     char out[2];
253     int size = snprintf(out, sizeof(out), "%d", enable);
254     if (write(enable_f, out, size * sizeof(char)) == -1) {
255         fprintf(stderr, "Failed to write to enable!\n");
256         close(enable_f);
257         return MAA_ERROR_INVALID_RESOURCE;
258     }
259     close(enable_f);
260     return MAA_SUCCESS;
261 }
262
263 maa_result_t
264 maa_pwm_unexport_force(maa_pwm_context dev)
265 {
266     char filepath[MAX_SIZE];
267     snprintf(filepath, MAX_SIZE, "/sys/class/pwm/pwmchip%d/unexport", dev->chipid);
268
269     int unexport_f = open(filepath, O_WRONLY);
270     if (unexport_f == -1) {
271         fprintf(stderr, "Failed to open unexport for writing!\n");
272         return MAA_ERROR_INVALID_RESOURCE;
273     }
274
275     char out[MAX_SIZE];
276     int size = snprintf(out, MAX_SIZE, "%d", dev->pin);
277     if (write(unexport_f, out, size*sizeof(char)) == -1) {
278         fprintf(stderr, "Failed to write to unexport!\n");
279         close(unexport_f);
280         return MAA_ERROR_INVALID_RESOURCE;
281     }
282
283     close(unexport_f);
284     return MAA_SUCCESS;
285 }
286
287 maa_result_t
288 maa_pwm_unexport(maa_pwm_context dev)
289 {
290     maa_pwm_enable(dev, 0);
291     if (dev->owner) {
292         return maa_pwm_unexport_force(dev);
293     }
294     return MAA_ERROR_INVALID_RESOURCE;
295 }
296
297 maa_result_t
298 maa_pwm_close(maa_pwm_context dev)
299 {
300     maa_pwm_unexport(dev);
301     free(dev);
302     return MAA_SUCCESS;
303 }
304
305 maa_result_t
306 maa_pwm_owner(maa_pwm_context dev, maa_boolean_t owner_new)
307 {
308     if (dev == NULL)
309         return MAA_ERROR_INVALID_RESOURCE;
310     dev->owner = owner_new;
311     return MAA_SUCCESS;
312 }