ApraLinuxUtils 1.0.0
C++ utility library for embedded Linux systems
 
Loading...
Searching...
No Matches
PWM.cpp
Go to the documentation of this file.
1/*
2 * PWM.cpp
3 *
4 * Copyright (c) 2024 Apra Labs
5 *
6 * This file is part of ApraUtils.
7 *
8 * Licensed under the MIT License.
9 * See LICENSE file in the project root for full license information.
10 */
11
12#include <stddef.h>
13#include <stdio.h>
14#include <stdexcept>
15#include <unistd.h>
16#include <fcntl.h>
17#include <utils/PWM.h>
18#include <inttypes.h>
19#include "ApraUtils.h"
20
21#define PWM_TOUT_USEC 10000
22#define PWM_EXPORT "export"
23#define PWM_UNEXPORT "unexport"
24#define PWM_PERIOD "period"
25#define PWM_DUTYCYCLE "duty_cycle"
26#define PWM_ENABLE "enable"
27
28using namespace std;
29namespace apra
30{
31
32PWM::PWM(uint32_t pwmChipNo, uint32_t pwmPinNo, bool shouldPrint) :
33 m_shouldPrint(shouldPrint), m_chipNo(pwmChipNo), m_pinNo(pwmPinNo), m_nSecPeriod(
34 0), m_nSecDutyCycle(0), m_chipPath(SYS_PWM_PATH), m_isSetupComplete(
35 false), m_isPWMRunning(false)
36{
37 m_chipPath += "/pwmchip" + to_string(m_chipNo);
38 if (!Utils::directoryExists(m_chipPath))
39 {
40 string error = "PWM Chip number is invalid: " + to_string(m_chipNo);
41 printf("%s\n", error.c_str());
42 throw std::invalid_argument(error);
43 }
44}
45
47{
48 destroy();
49}
50
51bool PWM::setup(uint64_t nSecPeriod, uint64_t nSecDutyCycle)
52{
53 if (nSecDutyCycle > nSecPeriod)
54 {
55 throw std::invalid_argument(
56 "Duty cycle time cannot be more than period");
57 return false;
58 }
59 m_nSecPeriod = nSecPeriod;
60 m_nSecDutyCycle = nSecDutyCycle;
61 bool didFail = false;
62 if (m_isPWMRunning)
63 {
64 didFail = stop();
65 if (m_shouldPrint && didFail)
66 {
67 printf("stop failed\n");
68 }
69 }
70 if (m_isSetupComplete && !didFail)
71 {
72 didFail = !updatePWMParams(0, PWM_DUTYCYCLE);
73 if (m_shouldPrint && didFail)
74 {
75 printf("set duty cycle failed\n");
76 }
77 if (!didFail)
78 {
79 didFail = !updatePWMParams(0, PWM_PERIOD);
80 if (m_shouldPrint && didFail)
81 {
82 printf("set period failed\n");
83 }
84 }
85 }
86 if (!m_isSetupComplete && !didFail)
87 {
88 didFail = !Export();
89 if (m_shouldPrint && didFail)
90 {
91 printf("export failed\n");
92 }
93 }
94 if (!didFail)
95 {
96 didFail = !updatePWMParams(nSecPeriod, PWM_PERIOD);
97 if (m_shouldPrint && didFail)
98 {
99 printf("set period failed\n");
100 }
101 }
102 if (!didFail)
103 {
104 didFail = !updatePWMParams(nSecDutyCycle, PWM_DUTYCYCLE);
105 if (m_shouldPrint && didFail)
106 {
107 printf("set duty cycle failed\n");
108 }
109 }
110 m_isSetupComplete = !didFail;
111 if (!m_isSetupComplete)
112 {
113 bool didSucceed = UnExport();
114 if (!didSucceed && m_shouldPrint)
115 {
116 printf("unexport failed\n");
117 }
118 }
119 return !didFail;
120}
121
123{
124 bool didFail = false;
125 if (m_isPWMRunning)
126 {
127 didFail = !stop();
128 m_isPWMRunning = didFail;
129 }
130 if (m_isSetupComplete)
131 {
132 didFail = !UnExport();
133 m_isSetupComplete = didFail;
134 }
135 return !didFail;
136}
137
139{
140 bool didFail = false;
141 if (m_isSetupComplete)
142 {
143 didFail = !updatePWMParams(1, PWM_ENABLE);
144 m_isPWMRunning = !didFail;
145 }
146 return !didFail;
147}
148
150{
151 bool didFail = false;
152 if (m_isSetupComplete && m_isPWMRunning)
153 {
154 didFail = !updatePWMParams(0, PWM_ENABLE);
155 m_isPWMRunning = didFail;
156 }
157 return !didFail;
158}
159
160bool PWM::updateDutyCycle(uint64_t nSecDutyCycle)
161{
162 m_nSecDutyCycle = nSecDutyCycle;
163 m_percentDutyCycle = (m_nSecDutyCycle / m_nSecPeriod) * 100;
164 return updatePWMParams(nSecDutyCycle, PWM_DUTYCYCLE);
165}
166
167bool PWM::changeDutyCycle(uint32_t percent)
168{
169 uint64_t dutyCycle = (m_nSecPeriod * percent) / 100;
170 m_nSecDutyCycle = dutyCycle;
171 return updatePWMParams(dutyCycle, PWM_DUTYCYCLE);
172}
173
175{
176 return m_percentDutyCycle;
177}
178
180{
181 return m_nSecDutyCycle;
182}
183
184std::string PWM::getPWMPinPath()
185{
186 return m_chipPath + "/pwm" + to_string(m_pinNo);
187}
188
189bool PWM::updatePWMParams(uint64_t value, std::string params)
190{
191 string pwmPinPath = getPWMPinPath();
192 if (!Utils::directoryExists(pwmPinPath))
193 {
194 if (m_shouldPrint)
195 {
196 printf("%s doesnt exist\n", pwmPinPath.c_str());
197 }
198 string log(
199 "Seems like the pwm(" + to_string(m_pinNo)
200 + ") setup is not done properly.");
201 printf("%s\n", log.c_str());
202 return false;
203 }
204 int fd, length;
205 char buff[64] = { 0 };
206
207 fd = open((pwmPinPath + "/" + params).c_str(), O_WRONLY);
208 if (fd < 0)
209 {
210 printf("unable to open %s to set %" PRIu64 "\n", params.c_str(), value);
211 return false;
212 }
213
214 length = snprintf(buff, sizeof(buff), "%" PRIu64 "", value);
215 if (write(fd, buff, length) != length)
216 {
217 close(fd);
218 printf("unable to write %" PRIu64 " on %s\n", value, params.c_str());
219 return false;
220 }
221 close(fd);
222 usleep(PWM_TOUT_USEC);
223 return true;
224}
225
226bool PWM::Export()
227{
228 int fd, length;
229 char buff[64] = { 0 };
230 string pwmPath = m_chipPath + "/" + PWM_EXPORT;
231 if (m_shouldPrint)
232 {
233 printf("export path %s\n", pwmPath.c_str());
234 }
235 if (!Utils::fileExists(pwmPath))
236 {
237 printf("%s not found\n", pwmPath.c_str());
238 return false;
239 }
240 fd = open(pwmPath.c_str(), O_WRONLY);
241 if (fd < 0)
242 {
243 printf("unable to open %s for pwm %" PRIu32 "\n", pwmPath.c_str(),
244 m_pinNo);
245 return false;
246 }
247
248 length = snprintf(buff, sizeof(buff), "%" PRIu32 "", m_pinNo);
249 if (m_shouldPrint)
250 {
251 printf("write on export %s length %d\n", buff, length);
252 }
253 if (write(fd, buff, length) != length)
254 {
255 close(fd);
256 printf("unable to init pwm %" PRIu32 "\n", m_pinNo);
257 return false;
258 }
259 close(fd);
260 usleep(PWM_TOUT_USEC);
261 if (m_shouldPrint)
262 {
263 printf("export write succeed\n");
264 }
265 if (!Utils::directoryExists(getPWMPinPath()))
266 {
267 printf("unable to access pwm %" PRIu32 "\n", m_pinNo);
268 return false;
269 }
270 return true;
271}
272
273bool PWM::UnExport()
274{
275 int fd, length;
276 char buff[64] = { 0 };
277
278 fd = open((m_chipPath + "/" + PWM_UNEXPORT).c_str(), O_WRONLY);
279 if (fd < 0)
280 {
281 printf("unable to open pwm %" PRIu32 " for %s\n", m_pinNo,
283 return false;
284 }
285
286 length = snprintf(buff, sizeof(buff), "%" PRIu32 "", m_pinNo);
287 if (write(fd, buff, length) != length)
288 {
289 close(fd);
290 printf("unable to %s gpio %" PRIu32 "\n", PWM_UNEXPORT, m_pinNo);
291 return false;
292 }
293 close(fd);
294 if (Utils::directoryExists(getPWMPinPath()))
295 {
296 printf("unable to close pwm %" PRIu32 "\n", m_pinNo);
297 return false;
298 }
299 return true;
300}
301
302} /* namespace apra */
#define PWM_UNEXPORT
Definition PWM.cpp:23
#define PWM_PERIOD
Definition PWM.cpp:24
#define PWM_TOUT_USEC
Definition PWM.cpp:21
#define PWM_DUTYCYCLE
Definition PWM.cpp:25
#define PWM_ENABLE
Definition PWM.cpp:26
#define PWM_EXPORT
Definition PWM.cpp:22
#define SYS_PWM_PATH
Definition PWM.h:18
virtual ~PWM()
Definition PWM.cpp:46
bool changeDutyCycle(uint32_t percent)
Definition PWM.cpp:167
bool stop()
Definition PWM.cpp:149
bool updateDutyCycle(uint64_t nSecDutyCycle)
Definition PWM.cpp:160
PWM(uint32_t pwmChipNo, uint32_t pwmPinNo, bool shouldPrint)
Definition PWM.cpp:32
bool destroy()
Definition PWM.cpp:122
uint32_t getDutyCyclePercent()
Definition PWM.cpp:174
bool setup(uint64_t nSecPeriod, uint64_t nSecDutyCycle)
Definition PWM.cpp:51
bool start()
Definition PWM.cpp:138
uint64_t getDutyCycleInNSec()
Definition PWM.cpp:179
static bool fileExists(const std::string &path)
Definition Utils.cpp:128
static bool directoryExists(const std::string &path)
Definition Utils.cpp:113