Skip to content

Commit 0efe42f

Browse files
committed
[PCA9685] Add range checks and memory optimization
1 parent 8feb444 commit 0efe42f

File tree

1 file changed

+105
-58
lines changed

1 file changed

+105
-58
lines changed

src/_P022_PCA9685.ino

Lines changed: 105 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -13,25 +13,58 @@
1313
#define PLUGIN_VALUENAME1_022 "PWM"
1414

1515
#define PLUGIN_022_PCA9685_MODE1 0x00 // location for Mode1 register address
16-
#define PCA9685_MODE2 0x01 // location for Mode2 register address
17-
#define PCA9685_MODE2_VALUES 0x20
18-
#define PCA9685_LED0 0x06 // location for start of LED0 registers
19-
#define PCA9685_ADDRESS 0x40 // I2C address
20-
#define PCA9685_MAX_ADDRESS 0x7F
21-
#define PCA9685_NUMS_ADDRESS PCA9685_MAX_ADDRESS - PCA9685_ADDRESS
22-
#define PCA9685_MAX_PINS 15
23-
#define PCA9685_MAX_PWM 4095
24-
#define PCA9685_MIN_FREQUENCY 23.0 // Min possible PWM cycle frequency
25-
#define PCA9685_MAX_FREQUENCY 1500.0 // Max possible PWM cycle frequency
26-
#define PCA9685_ALLLED_REG (byte)0xFA
27-
28-
/*
29-
is bit flag any bit rapresent the initialization state of PCA9685
30-
es: bit 3 is set 1 PCA9685 with address 0X40 + 0x03 is intin
31-
*/
32-
#define IS_INIT(state, bit) ((bit >= 0) && (bit < 32) && ((state & (1 << bit)) != 0))
33-
#define SET_INIT(state, bit) (state |= (1 << bit))
34-
long long initializeState; //
16+
#define PCA9685_MODE2 0x01 // location for Mode2 register address
17+
#define PCA9685_MODE2_VALUES 0x20
18+
#define PCA9685_LED0 0x06 // location for start of LED0 registers
19+
#define PCA9685_ADDRESS 0x40 // I2C address
20+
#define PCA9685_MAX_ADDRESS 0x7F
21+
#define PCA9685_NUMS_ADDRESS (PCA9685_MAX_ADDRESS - PCA9685_ADDRESS)
22+
#define PCA9685_MAX_PINS 15
23+
#define PCA9685_MAX_PWM 4095
24+
#define PCA9685_MIN_FREQUENCY 23.0 // Min possible PWM cycle frequency
25+
#define PCA9685_MAX_FREQUENCY 1500.0 // Max possible PWM cycle frequency
26+
#define PCA9685_ALLLED_REG (byte)0xFA
27+
28+
29+
// Bit mask to keep track of addresses initialized.
30+
static uint32_t initializeState_lo = 0;
31+
static uint32_t initializeState_hi = 0;
32+
33+
bool p022_is_init(uint8_t address) {
34+
if ((address < PCA9685_ADDRESS) || (address > PCA9685_MAX_ADDRESS)) { return false; }
35+
uint32_t address_offset = address - PCA9685_ADDRESS;
36+
37+
if (address_offset < 32) {
38+
return initializeState_lo & (1 << address_offset);
39+
} else {
40+
return initializeState_hi & (1 << (address_offset - 32));
41+
}
42+
}
43+
44+
bool p022_set_init(uint8_t address) {
45+
if ((address < PCA9685_ADDRESS) || (address > PCA9685_MAX_ADDRESS)) { return false; }
46+
uint32_t address_offset = address - PCA9685_ADDRESS;
47+
48+
if (address_offset < 32) {
49+
initializeState_lo |= (1 << address_offset);
50+
} else {
51+
initializeState_hi |= (1 << (address_offset - 32));
52+
}
53+
return true;
54+
}
55+
56+
bool p022_clear_init(uint8_t address) {
57+
if ((address < PCA9685_ADDRESS) || (address > PCA9685_MAX_ADDRESS)) { return false; }
58+
uint32_t address_offset = address - PCA9685_ADDRESS;
59+
60+
if (address_offset < 32) {
61+
initializeState_lo &= ~(1 << address_offset);
62+
} else {
63+
initializeState_hi &= ~(1 << (address_offset - 32));
64+
}
65+
return true;
66+
}
67+
3568

3669
boolean Plugin_022(byte function, struct EventStruct *event, String& string)
3770
{
@@ -49,6 +82,10 @@ boolean Plugin_022(byte function, struct EventStruct *event, String& string)
4982
range = PCONFIG(2);
5083
}
5184

85+
if ((address < PCA9685_ADDRESS) || (address > PCA9685_MAX_ADDRESS)) {
86+
address = PCA9685_ADDRESS;
87+
}
88+
5289
if (freq == 0) {
5390
freq = PCA9685_MAX_FREQUENCY;
5491
}
@@ -88,56 +125,66 @@ boolean Plugin_022(byte function, struct EventStruct *event, String& string)
88125

89126
case PLUGIN_WEBFORM_LOAD:
90127
{
91-
int optionValues[PCA9685_NUMS_ADDRESS];
92-
93-
for (int i = 0; i < PCA9685_NUMS_ADDRESS; i++)
128+
// The options lists are quite long.
129+
// To prevent stack overflow issues, each selection has its own scope.
94130
{
95-
optionValues[i] = PCA9685_ADDRESS + i;
96-
}
97-
addFormSelectorI2C(F("i2c_addr"), PCA9685_NUMS_ADDRESS, optionValues, address);
131+
int optionValues[PCA9685_NUMS_ADDRESS];
98132

99-
String m2Options[PCA9685_MODE2_VALUES];
100-
int m2Values[PCA9685_MODE2_VALUES];
101-
102-
for (int i = 0; i < PCA9685_MODE2_VALUES; i++)
133+
for (int i = 0; i < PCA9685_NUMS_ADDRESS; i++)
134+
{
135+
optionValues[i] = PCA9685_ADDRESS + i;
136+
}
137+
addFormSelectorI2C(F("i2c_addr"), PCA9685_NUMS_ADDRESS, optionValues, address);
138+
}
103139
{
104-
m2Values[i] = i;
105-
m2Options[i] = formatToHex_decimal(i);
140+
String m2Options[PCA9685_MODE2_VALUES];
141+
int m2Values[PCA9685_MODE2_VALUES];
106142

107-
if (i == 0x10) {
108-
m2Options[i] += F(" - (default)");
143+
for (int i = 0; i < PCA9685_MODE2_VALUES; i++)
144+
{
145+
m2Values[i] = i;
146+
m2Options[i] = formatToHex_decimal(i);
147+
148+
if (i == 0x10) {
149+
m2Options[i] += F(" - (default)");
150+
}
109151
}
152+
addFormSelector(F("MODE2"), F("p022_mode2"), PCA9685_MODE2_VALUES, m2Options, m2Values, mode2);
153+
}
154+
{
155+
String freqString = F("Frequency (");
156+
freqString += PCA9685_MIN_FREQUENCY;
157+
freqString += '-';
158+
freqString += PCA9685_MAX_FREQUENCY;
159+
freqString += ')';
160+
addFormNumericBox(freqString, F("p022_freq"), freq, PCA9685_MIN_FREQUENCY, PCA9685_MAX_FREQUENCY);
161+
}
162+
{
163+
String funitString = F("default ");
164+
funitString += PCA9685_MAX_FREQUENCY;
165+
addUnit(funitString);
166+
}
167+
{
168+
addFormNumericBox(F("Range (1-10000)"), F("p022_range"), range, 1, 10000);
169+
String runitString = F("default ");
170+
runitString += PCA9685_MAX_PWM;
171+
addUnit(runitString);
110172
}
111-
addFormSelector(F("MODE2"), F("p022_mode2"), PCA9685_MODE2_VALUES, m2Options, m2Values, mode2);
112-
113-
String freqString = F("Frequency (");
114-
freqString += PCA9685_MIN_FREQUENCY;
115-
freqString += '-';
116-
freqString += PCA9685_MAX_FREQUENCY;
117-
freqString += ')';
118-
addFormNumericBox(freqString, F("p022_freq"), freq, PCA9685_MIN_FREQUENCY, PCA9685_MAX_FREQUENCY);
119-
String funitString = F("default ");
120-
funitString += PCA9685_MAX_FREQUENCY;
121-
addUnit(funitString);
122-
123-
addFormNumericBox(F("Range (1-10000)"), F("p022_range"), range, 1, 10000);
124-
String runitString = F("default ");
125-
runitString += PCA9685_MAX_PWM;
126-
addUnit(runitString);
127-
128173
success = true;
129174
break;
130175
}
131176

132177
case PLUGIN_WEBFORM_SAVE:
133178
{
179+
p022_clear_init(CONFIG_PORT);
134180
CONFIG_PORT = getFormItemInt(F("i2c_addr"));
135181
PCONFIG(0) = getFormItemInt(F("p022_mode2"));
136182
PCONFIG(1) = getFormItemInt(F("p022_freq"));
137183
PCONFIG(2) = getFormItemInt(F("p022_range"));
138184

139-
if (!IS_INIT(initializeState, (CONFIG_PORT - PCA9685_ADDRESS)))
185+
if (!p022_is_init(CONFIG_PORT))
140186
{
187+
Plugin_022_initialize(address);
141188
if (PCONFIG(0) != mode2) {
142189
Plugin_022_writeRegister(address, PCA9685_MODE2, PCONFIG(0));
143190
}
@@ -186,7 +233,7 @@ boolean Plugin_022(byte function, struct EventStruct *event, String& string)
186233
{
187234
if ((event->Par2 >= 0) && (event->Par2 <= range))
188235
{
189-
if (!IS_INIT(initializeState, (address - PCA9685_ADDRESS)))
236+
if (!p022_is_init(address))
190237
{
191238
Plugin_022_initialize(address);
192239
Plugin_022_writeRegister(address, PCA9685_MODE2, mode2);
@@ -225,7 +272,7 @@ boolean Plugin_022(byte function, struct EventStruct *event, String& string)
225272

226273
if ((event->Par1 >= PCA9685_MIN_FREQUENCY) && (event->Par1 <= PCA9685_MAX_FREQUENCY))
227274
{
228-
if (!IS_INIT(initializeState, (address - PCA9685_ADDRESS)))
275+
if (!p022_is_init(address))
229276
{
230277
Plugin_022_initialize(address);
231278
Plugin_022_writeRegister(address, PCA9685_MODE2, mode2);
@@ -262,7 +309,7 @@ boolean Plugin_022(byte function, struct EventStruct *event, String& string)
262309

263310
if ((event->Par1 >= 0) && (event->Par1 < PCA9685_MODE2_VALUES))
264311
{
265-
if (!IS_INIT(initializeState, (address - PCA9685_ADDRESS)))
312+
if (!p022_is_init(address))
266313
{
267314
Plugin_022_initialize(address);
268315
Plugin_022_Frequency(address, freq);
@@ -282,7 +329,7 @@ boolean Plugin_022(byte function, struct EventStruct *event, String& string)
282329
{
283330
if (parseString(line, 2) == F("pca"))
284331
{
285-
if (!IS_INIT(initializeState, (address - PCA9685_ADDRESS)))
332+
if (!p022_is_init(address))
286333
{
287334
Plugin_022_initialize(address);
288335
Plugin_022_writeRegister(address, PCA9685_MODE2, mode2);
@@ -302,7 +349,7 @@ boolean Plugin_022(byte function, struct EventStruct *event, String& string)
302349

303350
if ((event->Par1 >= 0) && (event->Par1 <= PCA9685_MAX_PINS))
304351
{
305-
if (!IS_INIT(initializeState, (address - PCA9685_ADDRESS)))
352+
if (!p022_is_init(address))
306353
{
307354
Plugin_022_initialize(address);
308355
Plugin_022_writeRegister(address, PCA9685_MODE2, mode2);
@@ -358,7 +405,7 @@ boolean Plugin_022(byte function, struct EventStruct *event, String& string)
358405

359406
if ((event->Par1 >= 0) && (event->Par1 <= PCA9685_MAX_PINS))
360407
{
361-
if (!IS_INIT(initializeState, (address - PCA9685_ADDRESS)))
408+
if (!p022_is_init(address))
362409
{
363410
Plugin_022_initialize(address);
364411
Plugin_022_writeRegister(address, PCA9685_MODE2, mode2);
@@ -561,7 +608,7 @@ void Plugin_022_initialize(int address)
561608
delay(1);
562609
Plugin_022_writeRegister(i2cAddress, PLUGIN_022_PCA9685_MODE1, (byte)B10100000); // set up for auto increment
563610
// Plugin_022_writeRegister(i2cAddress, PCA9685_MODE2, (byte)0x10); // set to output
564-
SET_INIT(initializeState, (address - PCA9685_ADDRESS));
611+
p022_set_init(address);
565612
}
566613

567614
#endif // USES_P022

0 commit comments

Comments
 (0)