Skip to content

Commit f560e79

Browse files
authored
Merge pull request #11641 from hugueskamba/hk-fix-deepsleep-pwmout
PmwOut: Add method to enable/disable PWM
2 parents f59d71f + b8bcc7f commit f560e79

File tree

8 files changed

+444
-9
lines changed

8 files changed

+444
-9
lines changed
Lines changed: 258 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,258 @@
1+
/*
2+
* Copyright (c) 2019 Arm Limited and affiliates.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
#include "gtest/gtest.h"
19+
#include "gmock/gmock.h"
20+
#include "drivers/PwmOut.h"
21+
22+
using namespace mbed;
23+
24+
class MbedPowerMgmtInterface {
25+
public:
26+
virtual ~MbedPowerMgmtInterface() {}
27+
virtual void sleep_manager_unlock_deep_sleep_internal() = 0;
28+
virtual void sleep_manager_lock_deep_sleep_internal() = 0;
29+
};
30+
31+
32+
class MockMbedPowerMgmt : public MbedPowerMgmtInterface {
33+
public:
34+
virtual ~MockMbedPowerMgmt() {}
35+
36+
MOCK_METHOD0(sleep_manager_unlock_deep_sleep_internal, void());
37+
MOCK_METHOD0(sleep_manager_lock_deep_sleep_internal, void());
38+
39+
static MockMbedPowerMgmt *get_instance()
40+
{
41+
if (_instance == nullptr) {
42+
_instance = new MockMbedPowerMgmt();
43+
}
44+
45+
++_ref_counter;
46+
47+
return _instance;
48+
}
49+
50+
static void release_instance()
51+
{
52+
--_ref_counter;
53+
54+
if ((_instance != nullptr) && (_ref_counter == 0)) {
55+
delete _instance;
56+
_instance = nullptr;
57+
}
58+
}
59+
60+
static void sleep_manager_unlock_deep_sleep()
61+
{
62+
// Do not increment the call count unless it's done by a test
63+
// case.
64+
if (_instance) {
65+
_instance->sleep_manager_unlock_deep_sleep_internal();
66+
}
67+
}
68+
69+
static void sleep_manager_lock_deep_sleep()
70+
{
71+
// Do not increment the call count unless it's done by a test
72+
// case.
73+
if (_instance) {
74+
_instance->sleep_manager_lock_deep_sleep_internal();
75+
}
76+
}
77+
78+
MockMbedPowerMgmt(MockMbedPowerMgmt const &) = delete;
79+
void operator=(MockMbedPowerMgmt const &) = delete;
80+
private:
81+
MockMbedPowerMgmt() {}
82+
static MockMbedPowerMgmt *_instance;
83+
static int _ref_counter;
84+
};
85+
MockMbedPowerMgmt *MockMbedPowerMgmt::_instance = nullptr;
86+
int MockMbedPowerMgmt::_ref_counter = 0;
87+
88+
89+
void sleep_manager_unlock_deep_sleep(void)
90+
{
91+
MockMbedPowerMgmt::sleep_manager_unlock_deep_sleep();
92+
}
93+
94+
95+
void sleep_manager_lock_deep_sleep(void)
96+
{
97+
MockMbedPowerMgmt::sleep_manager_lock_deep_sleep();
98+
}
99+
100+
101+
class TestPwmOut : public testing::Test {
102+
protected:
103+
PwmOut *pwm_obj;
104+
MockMbedPowerMgmt *mbed_mgmt_mock;
105+
106+
void SetUp()
107+
{
108+
pwm_obj = new PwmOut(PTC1);
109+
// Create a mock object singleton after the PwmOut object
110+
// instantiation so the sleep_manager_lock_deep_sleep call by the
111+
// constructor does not increment the call count.
112+
// Now it is ok because a test case is about to start.
113+
mbed_mgmt_mock = MockMbedPowerMgmt::get_instance();
114+
}
115+
116+
void TearDown()
117+
{
118+
// Destroy the mock object singleton before the PwmOut destruction
119+
// because it will increment the sleep_manager_unlock_deep_sleep call
120+
// count.
121+
MockMbedPowerMgmt::release_instance();
122+
delete pwm_obj;
123+
}
124+
};
125+
// *INDENT-ON*
126+
127+
128+
/** Test if the constructor locks deepsleep
129+
Given an instantiated Pmw
130+
When the constructor is called
131+
Then the deep sleep lock is acquired
132+
*/
133+
TEST_F(TestPwmOut, test_constructor)
134+
{
135+
using ::testing::Mock;
136+
137+
EXPECT_CALL(
138+
*mbed_mgmt_mock, sleep_manager_lock_deep_sleep_internal()
139+
).Times(1);
140+
141+
PwmOut pmw(PTC1);
142+
143+
// Force gMock to verify a mock object singleton before it is destructed
144+
// by the teardown
145+
Mock::VerifyAndClearExpectations(mbed_mgmt_mock);
146+
// Suppress the memory leak error. The mock singleton will be released and
147+
// deleted in the TearDown call.
148+
Mock::AllowLeak(mbed_mgmt_mock);
149+
}
150+
151+
152+
/** Test if the destructor unlocks deepsleep
153+
Given an instantiated Pmw
154+
When the destructor is called
155+
Then the deep sleep lock is released
156+
*/
157+
TEST_F(TestPwmOut, test_destructor)
158+
{
159+
using ::testing::Mock;
160+
161+
EXPECT_CALL(
162+
*mbed_mgmt_mock, sleep_manager_unlock_deep_sleep_internal()
163+
).Times(1);
164+
165+
PwmOut *pmw = new PwmOut(PTC1);
166+
delete pmw;
167+
168+
// Force gMock to verify a mock object singleton before it is destructed
169+
// by the teardown
170+
Mock::VerifyAndClearExpectations(mbed_mgmt_mock);
171+
// Suppress the memory leak error. The mock singleton will be released and
172+
// deleted in the TearDown call.
173+
Mock::AllowLeak(mbed_mgmt_mock);
174+
}
175+
176+
177+
/** Test if `suspend` unlocks deepsleep
178+
179+
Given an initialised Pmw with a deep sleep lock
180+
When the instance is suspended
181+
Then the deep sleep lock is released once
182+
*/
183+
TEST_F(TestPwmOut, test_suspend)
184+
{
185+
using ::testing::Mock;
186+
187+
EXPECT_CALL(
188+
*mbed_mgmt_mock, sleep_manager_unlock_deep_sleep_internal()
189+
).Times(1);
190+
pwm_obj->suspend();
191+
pwm_obj->suspend();
192+
193+
// Force gMock to verify a mock object singleton before it is destructed
194+
// by the teardown
195+
Mock::VerifyAndClearExpectations(mbed_mgmt_mock);
196+
// Suppress the memory leak error. The mock singleton will be released and
197+
// deleted in the TearDown call.
198+
Mock::AllowLeak(mbed_mgmt_mock);
199+
}
200+
201+
202+
/** Test if `resume` lock deepsleep
203+
204+
Given an initialised Pmw in a suspended state
205+
When the instance is resumed
206+
Then the deep sleep lock is re-acquired once
207+
*/
208+
TEST_F(TestPwmOut, test_resume)
209+
{
210+
using ::testing::Mock;
211+
212+
EXPECT_CALL(
213+
*mbed_mgmt_mock, sleep_manager_lock_deep_sleep_internal()
214+
).Times(1);
215+
216+
pwm_obj->suspend();
217+
pwm_obj->resume();
218+
pwm_obj->resume();
219+
220+
// Force gMock to verify a mock object singleton before it is destructed
221+
// by the teardown
222+
Mock::VerifyAndClearExpectations(mbed_mgmt_mock);
223+
// Suppress the memory leak error. The mock singleton will be released and
224+
// deleted in the TearDown call.
225+
Mock::AllowLeak(mbed_mgmt_mock);
226+
}
227+
228+
/** Test if `suspend`/`resume` unlock/lock deepsleep multiple times
229+
230+
Given an initialised Pmw
231+
When the instance is suspended and then resumed
232+
Then the deep sleep lock can be unlocked and then locked again and again
233+
*/
234+
TEST_F(TestPwmOut, test_multiple_suspend_resume)
235+
{
236+
using ::testing::Mock;
237+
238+
const int suspend_resume_max_cycle = 3;
239+
240+
EXPECT_CALL(
241+
*mbed_mgmt_mock, sleep_manager_unlock_deep_sleep_internal()
242+
).Times(suspend_resume_max_cycle);
243+
EXPECT_CALL(
244+
*mbed_mgmt_mock, sleep_manager_lock_deep_sleep_internal()
245+
).Times(suspend_resume_max_cycle);
246+
247+
for (int i = 0; i < suspend_resume_max_cycle; i++) {
248+
pwm_obj->suspend();
249+
pwm_obj->resume();
250+
}
251+
252+
// Force gMock to verify a mock object singleton before it is destructed
253+
// by the teardown
254+
Mock::VerifyAndClearExpectations(mbed_mgmt_mock);
255+
// Suppress the memory leak error. The mock singleton will be released and
256+
// deleted in the TearDown call.
257+
Mock::AllowLeak(mbed_mgmt_mock);
258+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
2+
####################
3+
# UNIT TESTS
4+
####################
5+
set(TEST_SUITE_NAME "PwmOut")
6+
7+
# Add test specific include paths
8+
set(unittest-includes ${unittest-includes}
9+
.
10+
../hal
11+
)
12+
13+
# Source files
14+
set(unittest-sources
15+
../drivers/source/PwmOut.cpp
16+
)
17+
18+
# Test files
19+
set(unittest-test-sources
20+
drivers/PwmOut/test_pwmout.cpp
21+
stubs/mbed_critical_stub.c
22+
stubs/mbed_assert_stub.c
23+
stubs/pwmout_api_stub.c
24+
)
25+
26+
# defines
27+
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DDEVICE_PWMOUT")
28+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDEVICE_PWMOUT")

UNITTESTS/stubs/pwmout_api_stub.c

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* Copyright (c) 2019 Arm Limited and affiliates.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
#include "hal/pwmout_api.h"
17+
18+
#if DEVICE_PWMOUT
19+
20+
void pwmout_init(pwmout_t *obj, PinName pin)
21+
{
22+
}
23+
24+
void pwmout_free(pwmout_t *obj)
25+
{
26+
}
27+
28+
void pwmout_write(pwmout_t *obj, float percent)
29+
{
30+
}
31+
32+
float pwmout_read(pwmout_t *obj)
33+
{
34+
return 0;
35+
}
36+
37+
void pwmout_period(pwmout_t *obj, float seconds)
38+
{
39+
}
40+
41+
void pwmout_period_ms(pwmout_t *obj, int ms)
42+
{
43+
}
44+
45+
void pwmout_period_us(pwmout_t *obj, int us)
46+
{
47+
}
48+
49+
void pwmout_pulsewidth(pwmout_t *obj, float seconds)
50+
{
51+
}
52+
53+
void pwmout_pulsewidth_ms(pwmout_t *obj, int ms)
54+
{
55+
}
56+
57+
void pwmout_pulsewidth_us(pwmout_t *obj, int us)
58+
{
59+
}
60+
61+
#endif // DEVICE_PWMOUT

UNITTESTS/target_h/PinNames.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ typedef enum {
3434
} PinName;
3535

3636
typedef enum {
37+
PullNone = 0,
38+
PullDown = 1,
39+
PullUp = 2,
40+
PullDefault = PullUp
3741
} PinMode;
3842

3943
#ifdef __cplusplus

UNITTESTS/target_h/objects.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#ifndef MBED_OBJECTS_H
1919
#define MBED_OBJECTS_H
2020

21+
#include <stdint.h>
2122
#include "PeripheralNames.h"
2223
#include "PinNames.h"
2324

@@ -33,6 +34,12 @@ struct serial_s {
3334
int x;
3435
};
3536

37+
struct pwmout_s {
38+
int pwm_name;
39+
};
40+
41+
42+
3643
#include "gpio_object.h"
3744

3845
#ifdef __cplusplus

UNITTESTS/target_h/platform/mbed_power_mgmt.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,17 @@
2121
*/
2222
#ifndef MBED_POWER_MGMT_H
2323
#define MBED_POWER_MGMT_H
24+
2425
extern void mock_system_reset();
2526

2627
MBED_NORETURN static inline void system_reset(void)
2728
{
2829
mock_system_reset();
2930
}
3031

32+
void sleep_manager_unlock_deep_sleep(void);
33+
34+
void sleep_manager_lock_deep_sleep(void);
35+
3136
#endif
3237

0 commit comments

Comments
 (0)