6
6
* SPDX-License-Identifier: MPL-2.0
7
7
*/
8
8
9
- #include " Wire.h"
9
+ #include " Wire.h"
10
10
11
- // Setting new_address to 0 means that the module will get back its original address
12
- const uint8_t new_address = 0 ;
13
-
14
- uint8_t address;
15
-
16
- void setup () {
17
- Wire1.begin ();
18
- Serial.begin (115200 );
19
- delay (1000 );
20
- if (new_address != 0 && (new_address < 8 || new_address > 0x77 )) {
21
- Serial.println (" Address outside valid range" );
22
- while (1 );
23
- }
24
- // Search for devices and wait for user confirmation
25
- for (int i = 8 ; i < 128 ; i++) {
26
- Wire1.beginTransmission (i);
27
- auto err = Wire1.endTransmission ();
28
- if (err == 0 ) {
29
- Serial.print (" Found device at " );
30
- Serial.println (i);
31
- address = i;
32
- Serial.println (" Press 'c' to configure te new address" );
33
- }
34
- }
35
- }
36
-
37
- String pinstrapToName (uint8_t pinstrap) {
38
- switch (pinstrap) {
39
- case 0x3C :
40
- return " BUZZER" ;
41
- case 0x7C :
42
- return " BUTTONS" ;
43
- case 0x76 :
44
- case 0x74 :
45
- return " ENCODER" ;
46
- case 0x6C :
47
- return " SMARTLEDS" ;
48
- }
49
- return " UNKNOWN" ;
50
- }
51
-
52
- void loop () {
53
- // put your main code here, to run repeatedly:
54
- if (Serial.available ()) {
55
- if (Serial.read () == ' c' ) {
56
- Serial.print (" Assigning new address to " );
57
- Serial.println (address);
58
- uint8_t data[40 ] = { ' C' , ' F' , new_address * 2 };
59
- Wire1.beginTransmission (address);
60
- Wire1.write (data, 40 );
61
- Wire1.endTransmission ();
62
- delay (1000 );
63
- Wire1.requestFrom (new_address, 1 );
64
- Serial.println (" Device type " + pinstrapToName (Wire1.read ()) + " at new address " + String (new_address));
65
- }
66
- }
67
- }
11
+ struct DetectedModulino {
12
+ uint8_t addr;
13
+ String modulinoType;
14
+ String pinstrap;
15
+ String defaultAddr;
16
+ };
17
+
18
+ #define MAX_DEVICES 16
19
+ DetectedModulino rows[MAX_DEVICES];
20
+ int numRows = 0 ;
21
+
22
+
23
+ void setup () {
24
+ Wire1.begin ();
25
+ Serial.begin (115200 );
26
+
27
+ delay (600 );
28
+ discoverDevices ();
29
+ }
30
+
31
+ bool waitingInput = false ;
32
+ void loop () {
33
+ if (numRows == 0 ) return ;
34
+ if (Serial.available () == 0 && waitingInput) return ;
35
+
36
+ if (Serial.available () > 0 ) {
37
+ String hex1 = Serial.readStringUntil (' ' ); // Read until space (or other delimiter)
38
+ String hex2 = Serial.readStringUntil (' \n ' ); // Read until newline
39
+ Serial.println (" > " +hex1+" " +hex2); // Print what the user inserted.
40
+
41
+ int num1 = parseHex (hex1); // Parse the first hex number
42
+ int num2 = parseHex (hex2); // Parse the second hex number
43
+ if (num1 == -1 || num2 == -1 ) {
44
+ Serial.println (" Error: Incomplete or invalid input. Please enter two hexadecimal numbers" );
45
+ return ;
46
+ }
47
+
48
+ bool success = updateI2cAddress (num1, num2);
49
+ if (!success) return ; // If the update failed, skip discovery and messages, and wait for input again.
50
+
51
+ discoverDevices ();
52
+ waitingInput = false ;
53
+ }
54
+
55
+ Serial.println (" Enter the current address, space, and new address (ex. \" 0x20 0x30\" or \" 20 2A\" ):" );
56
+ Serial.println (" - Enter \" <addr> 0\" to reset the device at <addr> to its default address." );
57
+ Serial.println (" - Enter \" 0 0\" to reset all devices to the default address." );
58
+ waitingInput = true ;
59
+ }
60
+
61
+ // Updates the device at current address to new address. Supports broadcasting and setting default address (0).
62
+ // Returns true if the update was successful, false otherwise.
63
+ bool updateI2cAddress (int curAddress, int newAddress) {
64
+ uint8_t data[40 ] = { ' C' , ' F' , newAddress * 2 };
65
+ memset (data + 3 , 0 , sizeof (data) - 3 ); // Zero the rest of the buffer.
66
+
67
+ // Validate the current address, it must match a detected device.
68
+ if (curAddress != 0 && !findRow (curAddress)) {
69
+ Serial.println (" Error: current address 0x" +String (curAddress, HEX)+" not found in the devices list\n " );
70
+ return false ;
71
+ }
72
+
73
+ if (curAddress != 0 && isFixedAddrDevice (curAddress)) {
74
+ Serial.println (" Error: address 0x" +String (curAddress, HEX)+" is a non configurable device\n " );
75
+ return false ;
76
+ }
77
+
78
+ // Validate the new address.
79
+ if (newAddress != 0 && (newAddress < 8 || newAddress > 0x77 )) {
80
+ Serial.println (" Error: new address 0x" +String (newAddress, HEX)+" must be from 0x08 to 0x77\n " );
81
+ return false ;
82
+ }
83
+
84
+ if (curAddress == 0 ) {
85
+ Serial.print (" Updating all devices (broadcast 0x00) to 0x" + String (newAddress, HEX));
86
+ } else {
87
+ Serial.print (" Updating the device address from 0x" + String (curAddress, HEX) + " to 0x" + String (newAddress, HEX));
88
+ }
89
+ if (newAddress == 0 ) Serial.print (" (default address)" );
90
+ Serial.print (" ..." );
91
+
92
+ Wire1.beginTransmission (curAddress);
93
+ Wire1.write (data, 40 );
94
+ Wire1.endTransmission ();
95
+
96
+ delay (500 );
97
+
98
+ if (newAddress == 0 ) {
99
+ Serial.println (" done\n " );
100
+ return true ;
101
+ } else {
102
+ Wire1.requestFrom (newAddress, 1 );
103
+ if (Wire1.available ()) {
104
+ Serial.println (" done\n " );
105
+ return true ;
106
+ }
107
+ else {
108
+ Serial.println (" error\n " );
109
+ return false ;
110
+ }
111
+ }
112
+ }
113
+
114
+ // Function to parse hex number (with or without 0x prefix)
115
+ int parseHex (String hexStr) {
116
+ hexStr.trim ();
117
+
118
+ if (hexStr.length () == 0 ) {
119
+ return -1 ;
120
+ }
121
+
122
+ if (hexStr.startsWith (" 0x" ) || hexStr.startsWith (" 0X" )) {
123
+ hexStr = hexStr.substring (2 ); // Remove the "0x" prefix
124
+ }
125
+
126
+ // Validate that the remaining string contains only valid hexadecimal characters (0-9, A-F, a-f)
127
+ for (int i = 0 ; i < hexStr.length (); i++) {
128
+ if (!isHexDigit (hexStr.charAt (i))) {
129
+ return -1 ;
130
+ }
131
+ }
132
+
133
+ return strtol (hexStr.c_str (), NULL , 16 );
134
+ }
135
+
136
+ bool isHexDigit (char c) {
137
+ return ( (c >= ' 0' && c <= ' 9' ) || (c >= ' A' && c <= ' F' ) || (c >= ' a' && c <= ' f' ) );
138
+ }
139
+
140
+ void discoverDevices () {
141
+ char buffer[64 ];
142
+ Serial.println (" ADDR\t MODULINO\t PINSTRAP\t DEFAULT ADDR" ); // Table heading.
143
+
144
+ numRows = 0 ;
145
+
146
+ // Discover all modulino devices connected to the I2C bus.
147
+ for (int addr = 8 ; addr < 128 ; addr++) {
148
+ Wire1.beginTransmission (addr);
149
+ if (Wire1.endTransmission () != 0 ) continue ;
150
+
151
+ if (numRows >= MAX_DEVICES) {
152
+ Serial.println (" Too many devices connected, maximum supported is" + String (MAX_DEVICES));
153
+ return ;
154
+ }
155
+
156
+ // Some addresses represent non configurable devices (no MCU on it). Handle them as a special case.
157
+ if (isFixedAddrDevice (addr)) {
158
+ snprintf (buffer, 64 , " 0x%02X (cannot change)" , addr);
159
+ addRow (addr, fixedAddrToName (addr), " -" , String (buffer));
160
+
161
+ continue ; // Stop here, do not try to communicate with this device.
162
+ }
163
+
164
+ {
165
+ uint8_t pinstrap = 0 ; // Variable to store the pinstrap (device type)
166
+ Wire1.beginTransmission (addr); // Begin I2C transmission to the current address
167
+ Wire1.write (0x00 ); // Send a request to the device (assuming 0x00 is the register for device type)
168
+ Wire1.endTransmission (); // End transmission
169
+
170
+ delay (50 ); // Delay to allow for the device to respond
171
+
172
+ Wire1.requestFrom (addr, 1 ); // Request 1 byte from the device at the current address
173
+ if (Wire1.available ()) {
174
+ pinstrap = Wire1.read (); // Read the device type (pinstrap)
175
+ } else {
176
+ // If an error happens in the range 0x78 to 0x7F, ignore it.
177
+ if (addr >= 0x78 ) continue ;
178
+ Serial.println (" Failed to read device type at address 0x" + String (addr, HEX));
179
+ }
180
+
181
+ snprintf (buffer, 64 , " 0x%02X" , pinstrap);
182
+ auto hexPinstrap = String (buffer);
183
+
184
+ snprintf (buffer, 64 , " 0x%02X" , pinstrap / 2 ); // Default address is half pinstrap.
185
+ auto defaultAddr = String (buffer);
186
+ if (addr != pinstrap / 2 ) defaultAddr += " *" ; // Mark devices with modified address.
187
+
188
+ addRow (addr, pinstrapToName (pinstrap), hexPinstrap, defaultAddr);
189
+ }
190
+ }
191
+
192
+ // Print the results.
193
+ for (int i = 0 ; i < numRows; i++) {
194
+ char buffer[16 ];
195
+ snprintf (buffer, 16 , " 0x%02X" , rows[i].addr );
196
+
197
+ Serial.print (fixedWidth (buffer, 8 ));
198
+ Serial.print (fixedWidth (rows[i].modulinoType , 16 ));
199
+ Serial.print (fixedWidth (rows[i].pinstrap , 16 ));
200
+ Serial.println (fixedWidth (rows[i].defaultAddr , 12 ));
201
+ }
202
+ }
203
+
204
+ void addRow (uint8_t address, String modulinoType, String pinstrap, String defaultAddr) {
205
+ if (numRows >= MAX_DEVICES) return ;
206
+
207
+ rows[numRows].addr = address;
208
+ rows[numRows].modulinoType = modulinoType;
209
+ rows[numRows].pinstrap = pinstrap;
210
+ rows[numRows].defaultAddr = defaultAddr;
211
+ numRows++; // Increment the row counter
212
+ }
213
+
214
+ bool findRow (uint8_t address) {
215
+ for (int i = 0 ; i < numRows; i++) {
216
+ if (rows[i].addr == address) return true ;
217
+ }
218
+ return false ;
219
+ }
220
+
221
+
222
+ // Function to add padding to the right to ensure each field has a fixed width
223
+ String fixedWidth (String str, int width) {
224
+ for (int i = str.length (); i < width; i++) str += ' ' ;
225
+ return str;
226
+ }
227
+
228
+ String pinstrapToName (uint8_t pinstrap) {
229
+ switch (pinstrap) {
230
+ case 0x3C :
231
+ return " Buzzer" ;
232
+ case 0x7C :
233
+ return " Buttons" ;
234
+ case 0x76 :
235
+ case 0x74 :
236
+ return " Encoder" ;
237
+ case 0x6C :
238
+ return " Smartleds" ;
239
+ }
240
+ return " UNKNOWN" ;
241
+ }
242
+
243
+ String fixedAddrToName (uint8_t address) {
244
+ switch (address) {
245
+ case 0x29 :
246
+ return " Distance" ;
247
+ case 0x44 :
248
+ return " Thermo" ;
249
+ case 0x6A :
250
+ case 0x6B :
251
+ return " Movement" ;
252
+ }
253
+ return " UNKNOWN" ;
254
+ }
255
+
256
+ bool isFixedAddrDevice (uint8_t addr) {
257
+ // List of non-configurable devices, recognized by their fixed I2C address.
258
+ const uint8_t fixedAddr[] = {0x29 , 0x44 , 0x6A , 0x6B };
259
+
260
+ for (int i = 0 ; i < sizeof (fixedAddr) / sizeof (fixedAddr[0 ]); i++) {
261
+ if (addr == fixedAddr[i]) return true ;
262
+ }
263
+ return false ;
264
+ }
265
+
0 commit comments