Skip to content

Commit f96283e

Browse files
committed
Refactor of the arduino protocol
The firmware code has been converted into a Arduino Library. The new design simplifies the interface and create the abstraction for manage different types of connection (In theory, any type of serial interface that extends from Stream class should work well). Also, the new design allows the final user to add new code to be executed in the board (this features can affect the protocol performance, so should be used with caution). Issue #22
1 parent eb9f37d commit f96283e

File tree

4 files changed

+432
-308
lines changed

4 files changed

+432
-308
lines changed

MLC/arduino/Firmware/Firmware.ino

Lines changed: 6 additions & 308 deletions
Original file line numberDiff line numberDiff line change
@@ -1,277 +1,7 @@
11

2-
#define DEBUG 1
3-
#if DEBUG
4-
#define LOG(x,y) Serial.print(x); Serial.println(y);
5-
#else
6-
#define LOG(x,y)
7-
#endif
8-
9-
// defines ahorran ROM... aunque nos sobra de eso XD -- Verificar que los const vayan a la rom!
10-
const uint8_t ANALOG_PRECISION_CMD = 0x01;
11-
const uint8_t ADD_INPUT_PIN_CMD = 0x02;
12-
const uint8_t ADD_OUTPUT_PIN_CMD = 0x03;
13-
const uint8_t SET_PIN_MODE_CMD = 0x04;
14-
const uint8_t SET_REPORT_MODE_CMD = 0x05;
15-
const uint8_t ANALOG_WRITE = 0x06;
16-
const uint8_t ACTUATE_CMD = 0xF0;
17-
const uint8_t RESET_PINS = 0xFE;
18-
19-
// Commands executor caller -- one vector position == one command
20-
int (*executor[255])(const char*);
21-
22-
int not_implemented(const char* data)
23-
{
24-
//nothing to do...
25-
return 1;
26-
}
27-
28-
typedef enum ReportModes {average, bulk, rt};
29-
30-
/** ---------------------------------------------------------- **/
31-
/** GLOBAL CONFIG **/
32-
33-
uint8_t REPORT_READ_COUNT = 0;
34-
uint8_t REPORT_READ_DELAY = 0;
35-
ReportModes REPORT_MODE = average;
36-
uint8_t INPUT_PORTS[129]; // Port count in first position
37-
uint8_t ANALOG_PINS_COUNT = 0;
38-
uint8_t DIGITAL_PINS_COUNT = 0;
39-
40-
/** ---------------------------------------------------------- **/
41-
42-
const char* ACK = "\xFF\x00";
43-
44-
/**
45-
* ANALOG_WRITE: 0x06 0x03 [PIN] [H_VALUE][L_VALUE]
46-
*/
47-
int analog_write(const char* data)
48-
{
49-
uint16_t data = (data[3] << 8) + data[4];
50-
analogWrite(data[2], data[3]);
51-
return 5;
52-
}
53-
54-
/**
55-
ANALOG_PRECISION: 0x01 0x01 [BITS]
56-
*/
57-
int set_analog_precision(const char* data)
58-
{
59-
int i = byte(data[2]);
60-
// Tal vez conviene separar estas funciones ya que hay boards con resoluciones distintas...
61-
// Igual, así funciona bien con el due (y con todos, ya que no hay problema en superar el máximo de la resolución)
62-
analogWriteResolution(i);
63-
analogReadResolution(i);
64-
65-
LOG("Resolution changed to: ", i);
66-
67-
return 3; // Command of 3 bytes
68-
}
69-
70-
/**
71-
PIN_MODE: 0x04 0x02 [PIN] [MODE]
72-
*/
73-
int set_pin_mode(const char* data)
74-
{
75-
pinMode(data[2], data[3]);
76-
LOG("Changed pin mode on pin ", uint8_t(data[2]));
77-
LOG("Mode set to ", uint8_t(data[3]));
78-
79-
return 4; // Command of 4 bytes
80-
}
81-
82-
/**
83-
REPORT_MODE: 0x05 0x03 [MODE] [READ_COUNT] [READ_DELAY]
84-
*/
85-
int set_report_mode(const char* data)
86-
{
87-
REPORT_MODE = (ReportModes)(data[2]);
88-
REPORT_READ_COUNT = byte(data[3]);
89-
REPORT_READ_DELAY = byte(data[4]);
90-
LOG("Report mode changed on port ", byte(data[3]));
91-
92-
return 5; // Command of 5 bytes
93-
}
94-
95-
/**
96-
ANALOG_INPUT: 0x02 0x01 [PORT]
97-
*/
98-
int set_analog_input(const char* data)
99-
{
100-
INPUT_PORTS[0] += 1;
101-
INPUT_PORTS[INPUT_PORTS[0]] = byte(data[2]);
102-
103-
if ( INPUT_PORTS[INPUT_PORTS[0]] >= A0 )
104-
{
105-
ANALOG_PINS_COUNT++;
106-
LOG("New analog input: ", byte(data[2]));
107-
} else
108-
{
109-
DIGITAL_PINS_COUNT++;
110-
LOG("New digital input: ", byte(data[2]));
111-
}
112-
113-
return 3; // Command of 3 bytes
114-
}
115-
/**
116-
RESET: 0xFF
117-
*/
118-
int reset(const char* data)
119-
{
120-
for ( int i = 1; i <= byte(INPUT_PORTS[0]); i++)
121-
{
122-
pinMode(INPUT_PORTS[i], OUTPUT);
123-
}
124-
125-
INPUT_PORTS[0] = 0;
126-
ANALOG_PINS_COUNT = 0;
127-
DIGITAL_PINS_COUNT = 0;
128-
129-
LOG("System reset executed", "");
2+
#include "GenericArduinoController.h"
1303

131-
return 1;
132-
}
133-
134-
/**
135-
ANALOG_OUTPUT: 0x03 0x01 [PORT]
136-
*/
137-
int set_analog_output(const char* data)
138-
{
139-
// No se si vale la pena guardar registro de pines de salida...
140-
141-
return 3; // Command of 3 bytes
142-
}
143-
144-
/**
145-
ACTUATE: 0xF0 [DATA_LEN] [PIN_A] [VALUE_PIN_A] ... [PIN_N] [VALUE_PIN_N]
146-
*/
147-
int actuate(const char* data)
148-
{
149-
int offset = 0;
150-
int byte_count = byte(data[1]); // Un byte puede llegar a limitar la cantidad de salidas... creo
151-
152-
uint8_t digital_input_buffer[DIGITAL_PINS_COUNT][REPORT_READ_COUNT / 8 + 2]; // 255 lectures of 1 bit for every digital pin -- 1 extra byte for the port address
153-
uint8_t analog_input_buffer[ANALOG_PINS_COUNT][(2 * REPORT_READ_COUNT) + 3]; // 255 lectures of 2 bytes for every analog pin -- 1 extra byte for the port address
154-
155-
LOG("Actutating over payload of size: ", byte_count);
156-
157-
// ACTUATION ZONE
158-
while (offset < byte_count)
159-
{
160-
//Se aplica la acción a cada puerto indicado
161-
int port = byte(data[2 + offset]);
162-
163-
//Detects an analog port
164-
if ( port >= A0 )
165-
{
166-
int value = (data[3 + offset] << 8) + data[4 + offset];
167-
analogWrite(port, value);
168-
offset += 3;
169-
170-
LOG("Analog pin written", port);
171-
} else
172-
{
173-
int value = data[3 + offset] > 0 ? HIGH : LOW; // Creo que da igual si pongo el entero directamente
174-
digitalWrite(port, value);
175-
offset += 2;
176-
177-
LOG("Digital pin written ", port);
178-
}
179-
}
180-
181-
delayMicroseconds(REPORT_READ_DELAY); // FIXME: Usamos variable de 8 bits cuando la precisión de esta función llega a 16 bits.
182-
183-
char response[130];
184-
response[0] = '\xF1';
185-
uint16_t len = 0; // Inicia en 1 para evitar pisar el id de comando
186-
187-
// Resets of digital buffers (required due the buffering strategy for digital pins)
188-
memset(digital_input_buffer, 0, DIGITAL_PINS_COUNT * (REPORT_READ_COUNT / 8 + 2));
189-
190-
for (int i = 0; i < DIGITAL_PINS_COUNT; i++)
191-
{
192-
for (int j = 0; j < REPORT_READ_COUNT / 8 + 1; j++)
193-
{
194-
Serial.print(digital_input_buffer[i][j], HEX);
195-
}
196-
Serial.println("");
197-
}
198-
199-
// Tracks count of digital and analog ports
200-
LOG("Number of lectures to report: ", REPORT_READ_COUNT);
201-
for (int lecture = 0; lecture <= REPORT_READ_COUNT; lecture++)
202-
{
203-
uint8_t current_digital = 0;
204-
uint8_t current_analog = 0;
205-
for (int i = 1; i <= byte(INPUT_PORTS[0]); i++)
206-
{
207-
//response[len + 1] = INPUT_PORTS[i];
208-
if ( INPUT_PORTS[i] >= A0 )
209-
{
210-
LOG("Reading analog port A", INPUT_PORTS[i] - A0);
211-
int data = analogRead(INPUT_PORTS[i] - A0);
212-
//response[len + 2] = byte((data & 0xFF00) >> 8); // Se guarda el msb en el buffer
213-
//response[len + 3] = byte(data & 0xFF); // Se guarda el lsb en el buffer
214-
analog_input_buffer[current_analog][0] = INPUT_PORTS[i];
215-
analog_input_buffer[current_analog][(lecture * 2) + 1] = byte((data & 0xFF00) >> 8);
216-
analog_input_buffer[current_analog][(lecture * 2) + 2] = byte(data & 0xFF);
217-
218-
//len += 3; // Cada lectura de un recurso analógico ocupa dos bytes. FIXME: se puede optimizar con bajas resoluciones
219-
LOG("=====================================", "");
220-
LOG("Analog pin read: ", INPUT_PORTS[i]);
221-
LOG("Analog read value: ", data);
222-
223-
current_analog++;
224-
} else
225-
{
226-
int data = digitalRead(INPUT_PORTS[i]);
227-
//response[len + 2] = byte(data);
228-
digital_input_buffer[current_digital][0] = INPUT_PORTS[i];
229-
digital_input_buffer[current_digital][(lecture / 8) + 1] += (byte(data) & 0x01) << (lecture % 8); // Just keep first bit
230-
current_digital++;
231-
//len += 2;
232-
LOG("=====================================", "");
233-
LOG("Digital pin read: ", INPUT_PORTS[i]);
234-
LOG("Raw read: ", data);
235-
LOG("Lecture: ", lecture);
236-
LOG("Filtered read: ", (byte(data) & 0x01));
237-
LOG("Left padding: ", (lecture % 8));
238-
LOG("Added: ", (byte(data) & 0x01) << (lecture % 8));
239-
LOG("Digital read value: ", digital_input_buffer[current_digital - 1][(lecture / 8) + 1]);
240-
}
241-
};
242-
}
243-
244-
// Every analog output will be in the buffer as
245-
if (ANALOG_PINS_COUNT > 0)
246-
{
247-
len += ANALOG_PINS_COUNT + ((REPORT_READ_COUNT + 1) * 2 * ANALOG_PINS_COUNT);
248-
}
249-
250-
if (DIGITAL_PINS_COUNT > 0)
251-
{
252-
len += DIGITAL_PINS_COUNT + (((REPORT_READ_COUNT + 1) / 8 ) + 1) * DIGITAL_PINS_COUNT;
253-
}
254-
255-
LOG("Reporting actuate results ", len - 1);
256-
response[1] = len;
257-
SerialUSB.write(response, 2); // 2 bytes extras por el id de comando y la longitud y -1 por el padding
258-
259-
//response[len + 1] = INPUT_PORTS[i];
260-
if ( ANALOG_PINS_COUNT > 0)
261-
{
262-
SerialUSB.write(analog_input_buffer[0], ANALOG_PINS_COUNT + ((REPORT_READ_COUNT + 1) * 2 * ANALOG_PINS_COUNT));
263-
//SerialUSB.write(INPUT_PORTS[i]);
264-
//SerialUSB.write(analog_input_buffer[INPUT_PORTS[i] - A0], (REPORT_READ_COUNT + 1) * 2);
265-
LOG("Reported an analog port with a read count len of: ", ANALOG_PINS_COUNT + (REPORT_READ_COUNT + 1) * 2 * ANALOG_PINS_COUNT);
266-
}
267-
268-
if ( DIGITAL_PINS_COUNT > 0) {
269-
SerialUSB.write(digital_input_buffer[0], DIGITAL_PINS_COUNT + (((REPORT_READ_COUNT + 1) / 8 ) + 1) * DIGITAL_PINS_COUNT );
270-
LOG("Reported an digital port with a read count len of: ", DIGITAL_PINS_COUNT + (((REPORT_READ_COUNT + 1) / 8 ) + 1) * DIGITAL_PINS_COUNT );
271-
}
272-
273-
return len + 2;
274-
}
4+
GenericArduinoController controller(SerialUSB);
2755

2766
void setup() {
2777
SerialUSB.begin(115200);
@@ -280,44 +10,12 @@ void setup() {
28010
Serial.begin(115200);
28111
#endif
28212

283-
for (int i = 0; i < 255; i++)
284-
{
285-
executor[i] = &not_implemented;
286-
}
287-
288-
INPUT_PORTS[0] = 0;
289-
290-
/** Commands Callbacks **/
291-
executor[ANALOG_PRECISION_CMD] = &set_analog_precision;
292-
executor[ADD_INPUT_PIN_CMD] = &set_analog_input;
293-
executor[ADD_OUTPUT_PIN_CMD] = &set_analog_output;
294-
executor[SET_PIN_MODE_CMD] = &set_pin_mode;
295-
executor[SET_REPORT_MODE_CMD] = &set_report_mode;
296-
executor[ACTUATE_CMD] = &actuate;
297-
executor[RESET_PINS] = &reset;
29813
}
29914

30015
void loop() {
16+
controller.handle_commands();
30117

302-
if (SerialUSB.available() > 0)
303-
{
304-
LOG("USB serial data available ", SerialUSB.available());
305-
char input[64]; // Esto se reserva en el stack, tal vez hacerlo global consume menos recursos...
306-
307-
byte b_read = 0;
308-
byte b_pos = 0;
309-
310-
while (SerialUSB.available() > 0)
311-
{
312-
b_read += SerialUSB.readBytes(input, SerialUSB.available());
313-
}
314-
315-
// Loop to process all commands received in the buffer
316-
while (b_pos < b_read)
317-
{
318-
LOG("Executing command: ", int(input[b_pos]));
319-
b_pos += executor[input[b_pos]](&input[b_pos]); // Does the callback for the command
320-
LOG("b_pos ", b_pos);
321-
}
322-
}
18+
/**
19+
* HERE the user can insert any command
20+
*/
32321
}

0 commit comments

Comments
 (0)