Skip to content

Commit 6ff348f

Browse files
committed
Added support to multiple reads in arduino controller
The arduino controller can return N readings of a pin (configured using the set_mode function of the protocol).
1 parent bbe4d38 commit 6ff348f

File tree

3 files changed

+170
-43
lines changed

3 files changed

+170
-43
lines changed

MLC/arduino/Firmware/Firmware.ino

Lines changed: 151 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11

2-
#define DEBUG 0
2+
#define DEBUG 1
33
#if DEBUG
44
#define LOG(x,y) Serial.print(x); Serial.println(y);
55
#else
@@ -8,19 +8,20 @@
88

99
// defines ahorran ROM... aunque nos sobra de eso XD -- Verificar que los const vayan a la rom!
1010
const uint8_t ANALOG_PRECISION_CMD = 0x01;
11-
const uint8_t ADD_INPUT_PORT_CMD = 0x02;
12-
const uint8_t ADD_OUTPUT_PORT_CMD = 0x03;
11+
const uint8_t ADD_INPUT_PIN_CMD = 0x02;
12+
const uint8_t ADD_OUTPUT_PIN_CMD = 0x03;
1313
const uint8_t SET_PIN_MODE_CMD = 0x04;
1414
const uint8_t SET_REPORT_MODE_CMD = 0x05;
1515
const uint8_t ACTUATE_CMD = 0xF0;
16+
const uint8_t RESET_PINS = 0xFE;
1617

1718
// Commands executor caller -- one vector position == one command
1819
int (*executor[255])(const char*);
1920

2021
int not_implemented(const char* data)
2122
{
2223
//nothing to do...
23-
return 0;
24+
return 1;
2425
}
2526

2627
typedef enum ReportModes {average, bulk, rt};
@@ -32,6 +33,8 @@ uint8_t REPORT_READ_COUNT = 0;
3233
uint8_t REPORT_READ_DELAY = 0;
3334
ReportModes REPORT_MODE = average;
3435
uint8_t INPUT_PORTS[129]; // Port count in first position
36+
uint8_t ANALOG_PINS_COUNT = 0;
37+
uint8_t DIGITAL_PINS_COUNT = 0;
3538

3639
/** ---------------------------------------------------------- **/
3740

@@ -85,14 +88,41 @@ int set_analog_input(const char* data)
8588
{
8689
INPUT_PORTS[0] += 1;
8790
INPUT_PORTS[INPUT_PORTS[0]] = byte(data[2]);
88-
LOG("New analog input: ", byte(data[2]));
91+
92+
if ( INPUT_PORTS[INPUT_PORTS[0]] >= A0 )
93+
{
94+
ANALOG_PINS_COUNT++;
95+
LOG("New analog input: ", byte(data[2]));
96+
} else
97+
{
98+
DIGITAL_PINS_COUNT++;
99+
LOG("New digital input: ", byte(data[2]));
100+
}
89101

90102
return 3; // Command of 3 bytes
91103
}
104+
/**
105+
RESET: 0xFF
106+
*/
107+
int reset(const char* data)
108+
{
109+
for ( int i = 1; i <= byte(INPUT_PORTS[0]); i++)
110+
{
111+
pinMode(INPUT_PORTS[i], OUTPUT);
112+
}
113+
114+
INPUT_PORTS[0] = 0;
115+
ANALOG_PINS_COUNT = 0;
116+
DIGITAL_PINS_COUNT = 0;
117+
118+
LOG("System reset executed", "");
119+
120+
return 1;
121+
}
92122

93123
/**
94-
* ANALOG_OUTPUT: 0x03 0x01 [PORT]
95-
*/
124+
ANALOG_OUTPUT: 0x03 0x01 [PORT]
125+
*/
96126
int set_analog_output(const char* data)
97127
{
98128
// No se si vale la pena guardar registro de pines de salida...
@@ -101,13 +131,16 @@ int set_analog_output(const char* data)
101131
}
102132

103133
/**
104-
* ACTUATE: 0xF0 [DATA_LEN] [PIN_A] [VALUE_PIN_A] ... [PIN_N] [VALUE_PIN_N]
105-
*/
134+
ACTUATE: 0xF0 [DATA_LEN] [PIN_A] [VALUE_PIN_A] ... [PIN_N] [VALUE_PIN_N]
135+
*/
106136
int actuate(const char* data)
107137
{
108138
int offset = 0;
109139
int byte_count = byte(data[1]); // Un byte puede llegar a limitar la cantidad de salidas... creo
110140

141+
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
142+
uint8_t analog_input_buffer[ANALOG_PINS_COUNT][(2 * REPORT_READ_COUNT) + 2]; // 255 lectures of 2 bytes for every analog pin -- 1 extra byte for the port address
143+
111144
LOG("Actutating over payload of size: ", byte_count);
112145

113146
// ACTUATION ZONE
@@ -138,42 +171,104 @@ int actuate(const char* data)
138171

139172
char response[130];
140173
response[0] = '\xF1';
141-
byte len = 1; // Inicia en 1 para evitar pisar el id de comando
142-
for (int i = 1; i <= byte(INPUT_PORTS[0]); i++)
174+
uint16_t len = 0; // Inicia en 1 para evitar pisar el id de comando
175+
176+
// Resets of digital buffers (required due the buffering strategy for digital pins)
177+
memset(digital_input_buffer, 0, DIGITAL_PINS_COUNT * (REPORT_READ_COUNT / 8 + 2));
178+
179+
for (int i = 0; i < DIGITAL_PINS_COUNT; i++)
143180
{
144-
response[len + 1] = INPUT_PORTS[i];
145-
if ( INPUT_PORTS[i] >= A0 )
181+
for (int j = 0; j < REPORT_READ_COUNT / 8 + 1; j++)
146182
{
147-
int data = analogRead(INPUT_PORTS[i]-A0);
148-
response[len + 2] = byte((data & 0xFF00) >> 8); // Se guarda el msb en el buffer
149-
response[len + 3] = byte(data & 0xFF); // Se guarda el lsb en el buffer
183+
Serial.print(digital_input_buffer[i][j], HEX);
184+
}
185+
Serial.println("");
186+
}
150187

151-
len += 3; // Cada lectura de un recurso analógico ocupa dos bytes. FIXME: se puede optimizar con bajas resoluciones
152-
LOG("Analog pin read: ", INPUT_PORTS[i]);
153-
} else
188+
// Tracks count of digital and analog ports
189+
LOG("Number of lectures to report: ", REPORT_READ_COUNT);
190+
for (int lecture = 0; lecture <= REPORT_READ_COUNT; lecture++)
191+
{
192+
uint8_t current_digital = 0;
193+
uint8_t current_analog = 0;
194+
for (int i = 1; i <= byte(INPUT_PORTS[0]); i++)
154195
{
155-
int data = digitalRead(INPUT_PORTS[i]);
156-
response[len + 2] = byte(data);
157-
len += 2;
158-
LOG("Digital pin read: ", INPUT_PORTS[i]);
159-
}
160-
};
196+
//response[len + 1] = INPUT_PORTS[i];
197+
if ( INPUT_PORTS[i] >= A0 )
198+
{
199+
LOG("Reading analog port A", INPUT_PORTS[i] - A0);
200+
int data = analogRead(INPUT_PORTS[i] - A0);
201+
//response[len + 2] = byte((data & 0xFF00) >> 8); // Se guarda el msb en el buffer
202+
//response[len + 3] = byte(data & 0xFF); // Se guarda el lsb en el buffer
203+
analog_input_buffer[current_analog][0] = INPUT_PORTS[i];
204+
analog_input_buffer[current_analog][lecture + 1] = byte((data & 0xFF00) >> 8);
205+
analog_input_buffer[current_analog][lecture + 2] = byte(data & 0xFF);
206+
207+
current_analog++;
208+
209+
//len += 3; // Cada lectura de un recurso analógico ocupa dos bytes. FIXME: se puede optimizar con bajas resoluciones
210+
LOG("=====================================", "");
211+
LOG("Analog pin read: ", INPUT_PORTS[i]);
212+
LOG("Analog read value: ", data);
213+
} else
214+
{
215+
int data = digitalRead(INPUT_PORTS[i]);
216+
//response[len + 2] = byte(data);
217+
digital_input_buffer[current_digital][0] = INPUT_PORTS[i];
218+
digital_input_buffer[current_digital][(lecture / 8) + 1] += (byte(data) & 0x01) << (lecture % 8); // Just keep first bit
219+
current_digital++;
220+
//len += 2;
221+
LOG("=====================================", "");
222+
LOG("Digital pin read: ", INPUT_PORTS[i]);
223+
LOG("Raw read: ", data);
224+
LOG("Lecture: ", lecture);
225+
LOG("Filtered read: ", (byte(data) & 0x01));
226+
LOG("Left padding: ", (lecture % 8));
227+
LOG("Added: ", (byte(data) & 0x01) << (lecture % 8));
228+
LOG("Digital read value: ", digital_input_buffer[current_digital - 1][(lecture / 8) + 1]);
229+
}
230+
};
231+
}
161232

233+
// Every analog output will be in the buffer as
234+
if (ANALOG_PINS_COUNT > 0)
235+
{
236+
len += ANALOG_PINS_COUNT + ( (REPORT_READ_COUNT + 1) * 2);
237+
}
238+
239+
if (DIGITAL_PINS_COUNT > 0)
240+
{
241+
len += DIGITAL_PINS_COUNT + (((REPORT_READ_COUNT + 1) / 8 ) + 1);
242+
}
162243

163244
LOG("Reporting actuate results ", len - 1);
164-
response[1] = len - 1;
165-
SerialUSB.write(response, len + 1); // 2 bytes extras por el id de comando y la longitud y -1 por el padding
245+
response[1] = len;
246+
SerialUSB.write(response, 2); // 2 bytes extras por el id de comando y la longitud y -1 por el padding
247+
248+
//response[len + 1] = INPUT_PORTS[i];
249+
if ( ANALOG_PINS_COUNT > 0)
250+
{
251+
SerialUSB.write(analog_input_buffer[0], ANALOG_PINS_COUNT + ((REPORT_READ_COUNT + 1) * 2 * ANALOG_PINS_COUNT));
252+
//SerialUSB.write(INPUT_PORTS[i]);
253+
//SerialUSB.write(analog_input_buffer[INPUT_PORTS[i] - A0], (REPORT_READ_COUNT + 1) * 2);
254+
LOG("Reported an analog port with a read count len of: ", (REPORT_READ_COUNT + 1) * 2 + 1);
255+
}
256+
257+
if ( DIGITAL_PINS_COUNT > 0) {
258+
SerialUSB.write(digital_input_buffer[0], DIGITAL_PINS_COUNT + (((REPORT_READ_COUNT + 1) / 8 ) + 1) * DIGITAL_PINS_COUNT );
259+
LOG("Reported an digital port with a read count len of: ", DIGITAL_PINS_COUNT + (((REPORT_READ_COUNT + 1) / 8 ) + 1) * DIGITAL_PINS_COUNT );
260+
}
166261

167-
return offset + 2;
262+
return len + 2;
168263
}
169264

170265
void setup() {
171266
SerialUSB.begin(115200);
172-
173-
#if DEBUG
267+
268+
#if DEBUG
174269
Serial.begin(115200);
175-
#endif
176-
270+
#endif
271+
177272
for (int i = 0; i < 255; i++)
178273
{
179274
executor[i] = &not_implemented;
@@ -183,36 +278,53 @@ void setup() {
183278

184279
/** Commands Callbacks **/
185280
executor[ANALOG_PRECISION_CMD] = &set_analog_precision;
186-
executor[ADD_INPUT_PORT_CMD] = &set_analog_input;
187-
executor[ADD_OUTPUT_PORT_CMD] = &set_analog_output;
281+
executor[ADD_INPUT_PIN_CMD] = &set_analog_input;
282+
executor[ADD_OUTPUT_PIN_CMD] = &set_analog_output;
188283
executor[SET_PIN_MODE_CMD] = &set_pin_mode;
189284
executor[SET_REPORT_MODE_CMD] = &set_report_mode;
190285
executor[ACTUATE_CMD] = &actuate;
286+
executor[RESET_PINS] = &reset;
287+
288+
// executor[SET_PIN_MODE_CMD]("\x04\x02\x3E\x00");
289+
// executor[ANALOG_PRECISION_CMD]("\x01\x01\x0C");
290+
// executor[SET_REPORT_MODE_CMD]("\x05\x03\x00\x09\x00");
291+
// executor[ADD_INPUT_PIN_CMD]("\x02\x01\x3E");
292+
// executor[SET_PIN_MODE_CMD]("\x04\x02\x3E\x00");
293+
// // executor[ADD_INPUT_PIN_CMD]("\x02\x01\x3F");
294+
// // executor[SET_PIN_MODE_CMD]("\x04\x02\x3F\x00");
295+
// executor[ADD_INPUT_PIN_CMD]("\x02\x01\x28");
296+
// executor[SET_PIN_MODE_CMD]("\x04\x02\x28\x00");
297+
// executor[ADD_INPUT_PIN_CMD]("\x02\x01\x29");
298+
// executor[SET_PIN_MODE_CMD]("\x04\x02\x29\x00");
299+
// executor[ADD_INPUT_PIN_CMD]("\x02\x01\x2A");
300+
// executor[SET_PIN_MODE_CMD]("\x04\x02\x2A\x00");
191301

192302
}
193303

194304
void loop() {
195-
//executor[ACTUATE_CMD]("\xF0\x01\x28\x01");
305+
//executor[ACTUATE_CMD]("\xF0\x01\x2B\x01");
196306

197307
if (SerialUSB.available() > 0)
198308
{
199309
LOG("USB serial data available ", SerialUSB.available());
200310
char input[64]; // Esto se reserva en el stack, tal vez hacerlo global consume menos recursos...
201-
311+
202312
byte b_read = 0;
203313
byte b_pos = 0;
204-
314+
205315
while (SerialUSB.available() > 0)
206316
{
207317
b_read += SerialUSB.readBytes(input, SerialUSB.available());
208318
}
209-
319+
210320
// Loop to process all commands received in the buffer
211-
while(b_pos < b_read)
321+
while (b_pos < b_read)
212322
{
213323
LOG("Executing command: ", int(input[b_pos]));
214324
b_pos += executor[input[b_pos]](&input[b_pos]); // Does the callback for the command
215325
LOG("b_pos ", b_pos);
216326
}
217327
}
328+
329+
delay(4000);
218330
}

MLC/arduino/protocol.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"REPORT_MODE" : '\x05\x03%s%s%s',
77
"ACK" : '\xFF\x00',
88
"ACTUATE" : '\xF0',
9+
"RESET" : '\xFE',
910
"ACTUATE_REPORT" : '\xF1' }
1011

1112
class ArduinoInterface:
@@ -19,6 +20,9 @@ def __init__(self, connection, board):
1920
self._anlg_outputs = []
2021
self._digital_outputs = []
2122
self._anlg_precition = 10 #Default Arduino analog precision
23+
self._report_mode = "AVERAGE"
24+
self._read_count = 1 #Default number of inputs read
25+
self._read_delay = 0
2226
self._board = board
2327

2428
def set_precition(self, bits):
@@ -33,9 +37,13 @@ def __set_pin_mode(self, port, mode):
3337

3438
self._connection.send(_PROTOCOL_CMDS["PIN_MODE"] % (chr(port), chr(self.PIN_MOD[mode])))
3539

36-
def set_report_mode(self, mode, read_count=1, read_delay=0):
40+
def set_report_mode(self, mode, read_count=0, read_delay=0):
3741
if mode not in self.REPORT_MOD.keys():
3842
raise Exception("Report mode error. Unknown value: %s" % mode)
43+
44+
self._report_mode = mode
45+
self._read_count = read_count + 1
46+
self._read_delay = read_delay
3947

4048
self._connection.send(_PROTOCOL_CMDS["REPORT_MODE"] % (chr(self.REPORT_MOD[mode]), chr(read_count), chr(read_delay)))
4149

@@ -76,6 +84,9 @@ def __validate_pin(self, pin):
7684
if pin not in self._board["DIGITAL_PINS"] and pin not in self._board["ANALOG_PINS"]:
7785
raise Exception("Invalid pin %s for board %s" % (pin, self._board["NAME"]))
7886
return
87+
88+
def reset(self):
89+
self._connection.send(_PROTOCOL_CMDS["RESET"])
7990

8091
def actuate(self, data):
8192
"""
@@ -120,7 +131,8 @@ def actuate(self, data):
120131
pos = pos + 3
121132
else:
122133
if ord(data[pos]) in self._digital_inputs:
123-
results.append((data[pos], bool(ord(data[pos+1]))))
134+
for i in range(0, self._read_count):
135+
results.append((data[pos], bool(ord(data[pos+1]))))
124136
pos = pos + 2
125137
else:
126138
raise Exception("Unknown port in response. Restart Arduino board, your software and pray")

tests/pocs/test_connection.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,16 @@
88
def actuate(terminal):
99
connection = SerialConnection(port=terminal)
1010
arduinoDue = ArduinoInterface(connection, boards.Due)
11-
11+
12+
arduinoDue.reset()
13+
arduinoDue.set_report_mode("BULK")
1214
arduinoDue.add_output(40)
1315
arduinoDue.add_input(64)
16+
arduinoDue.add_input(30)
1417

1518
output = arduinoDue.actuate([(40,1)])
1619
for i in output:
17-
print "Pin %d output: %s" % (ord(i[0]), i[1])
20+
print "Pin %d input: %s" % (ord(i[0]), i[1])
1821

1922

2023
if __name__ == "__main__":

0 commit comments

Comments
 (0)