|
| 1 | + |
| 2 | +#define DEBUG 1 |
| 3 | + |
| 4 | +#ifdef DEBUG |
| 5 | +#define LOG(x,y) Serial.print(x); Serial.println(y); |
| 6 | +#endif |
| 7 | + |
| 8 | +// defines ahorran ROM... aunque nos sobra de eso XD -- Verificar que los const vayan a la rom! |
| 9 | +const uint8_t ANALOG_PRECISION_CMD = 0x01; |
| 10 | +const uint8_t ADD_ANALOG_INPUT_CMD = 0x02; |
| 11 | +const uint8_t ADD_ANALOG_OUTPUT_CMD = 0x03; |
| 12 | +const uint8_t SET_PIN_MODE_CMD = 0x04; |
| 13 | +const uint8_t SET_REPORT_MODE_CMD = 0x05; |
| 14 | +const uint8_t ACTUATE_CMD = 0xF0; |
| 15 | + |
| 16 | +// Commands executor caller -- one vector position == one command |
| 17 | +void (*executor[255])(const char*); |
| 18 | + |
| 19 | +void not_implemented(const char* data) |
| 20 | +{ |
| 21 | + //nothing to do... |
| 22 | + return; |
| 23 | +} |
| 24 | + |
| 25 | +typedef enum ReportModes {average, bulk, rt}; |
| 26 | + |
| 27 | +/** ---------------------------------------------------------- **/ |
| 28 | +/** GLOBAL CONFIG **/ |
| 29 | + |
| 30 | +uint8_t REPORT_READ_COUNT = 0; |
| 31 | +uint8_t REPORT_READ_DELAY = 0; |
| 32 | +ReportModes REPORT_MODE = average; |
| 33 | +uint8_t INPUT_PORTS[129]; // Port count in first position |
| 34 | + |
| 35 | +/** ---------------------------------------------------------- **/ |
| 36 | + |
| 37 | +const char* ACK = "\xFF\x00"; |
| 38 | + |
| 39 | +/** |
| 40 | + ANALOG_PRECISION: 0x01 0x01 [BITS] |
| 41 | +*/ |
| 42 | +void set_analog_precision(const char* data) |
| 43 | +{ |
| 44 | + int i = byte(data[2]); |
| 45 | + // Tal vez conviene separar estas funciones ya que hay boards con resoluciones distintas... |
| 46 | + // Igual, así funciona bien con el due (y con todos, ya que no hay problema en superar el máximo de la resolución) |
| 47 | + analogWriteResolution(i); |
| 48 | + analogReadResolution(i); |
| 49 | + |
| 50 | + LOG("Resolution changed to: ", i); |
| 51 | +} |
| 52 | + |
| 53 | +/** |
| 54 | + PIN_MODE: 0x04 0x02 [PIN] [MODE] |
| 55 | +*/ |
| 56 | +void set_pin_mode(const char* data) |
| 57 | +{ |
| 58 | + pinMode(data[2], data[3]); |
| 59 | + LOG("Changed pin mode on pin ", data[2]); |
| 60 | + LOG("Mode set to ", data[3]); |
| 61 | +} |
| 62 | + |
| 63 | +/** |
| 64 | + REPORT_MODE: 0x05 0x03 [MODE] [READ_COUNT] [READ_DELAY] |
| 65 | +*/ |
| 66 | +void set_report_mode(const char* data) |
| 67 | +{ |
| 68 | + REPORT_MODE = (ReportModes)(data[2]); |
| 69 | + REPORT_READ_COUNT = byte(data[3]); |
| 70 | + REPORT_READ_DELAY = byte(data[4]); |
| 71 | + LOG("Report mode changed on port ", byte(data[3])); |
| 72 | +} |
| 73 | + |
| 74 | +/** |
| 75 | + ANALOG_INPUT: 0x02 0x01 [PORT] |
| 76 | +*/ |
| 77 | +void set_analog_input(const char* data) |
| 78 | +{ |
| 79 | + INPUT_PORTS[0] += 1; |
| 80 | + INPUT_PORTS[INPUT_PORTS[0]] = byte(data[2]); |
| 81 | + LOG("New analog input: ", byte(data[2])); |
| 82 | +} |
| 83 | + |
| 84 | +/** |
| 85 | + * ANALOG_OUTPUT: 0x03 0x01 [PORT] |
| 86 | + */ |
| 87 | +void set_analog_output(const char* data) |
| 88 | +{ |
| 89 | + // No se si vale la pena guardar registro de pines de salida... |
| 90 | +} |
| 91 | + |
| 92 | +/** |
| 93 | + * ACTUATE: 0xF0 [PIN_COUNT] [PIN_A] [VALUE_PIN_A] ... [PIN_N] [VALUE_PIN_N] |
| 94 | + */ |
| 95 | +void actuate(const char* data) |
| 96 | +{ |
| 97 | + int offset = 0; |
| 98 | + int byte_count = byte(data[1]); // Un byte puede llegar a limitar la cantidad de salidas... creo |
| 99 | + |
| 100 | + // ACTUATION ZONE |
| 101 | + while (offset > byte_count) |
| 102 | + { |
| 103 | + //Se aplica la acción a cada puerto indicado |
| 104 | + int port = byte(data[2 + offset]); |
| 105 | + |
| 106 | + //Detects an analog port |
| 107 | + if ( port >= A0 ) |
| 108 | + { |
| 109 | + int value = (data[3 + offset] << 8) + data[4 + offset]; |
| 110 | + analogWrite(port, value); |
| 111 | + offset += 3; |
| 112 | + |
| 113 | + LOG("Analog pin written", port); |
| 114 | + } else |
| 115 | + { |
| 116 | + int value = data[3 + offset] > 0 ? HIGH : LOW; // Creo que da igual si pongo el entero directamente |
| 117 | + digitalWrite(port, value); |
| 118 | + offset += 2; |
| 119 | + |
| 120 | + LOG("Digital pin written ", port); |
| 121 | + } |
| 122 | + } |
| 123 | + |
| 124 | + delayMicroseconds(REPORT_READ_DELAY); // FIXME: Usamos variable de 8 bits cuando la precisión de esta función llega a 16 bits. |
| 125 | + |
| 126 | + char response[130]; |
| 127 | + response[0] = '\xF1'; |
| 128 | + byte len = 1; // Inicia en 1 para evitar pisar el id de comando |
| 129 | + for (int i = 1; i <= byte(INPUT_PORTS[0]); i++) |
| 130 | + { |
| 131 | + if ( INPUT_PORTS[i] >= A0 ) |
| 132 | + { |
| 133 | + int data = analogRead(INPUT_PORTS[i]); |
| 134 | + response[len + 1] = byte((data & 0xFF00) >> 8); // Se guarda el msb en el buffer |
| 135 | + response[len + 2] = byte(data & 0xFF); // Se guarda el lsb en el buffer |
| 136 | + |
| 137 | + len += 2; // Cada lectura de un recurso analógico ocupa dos bytes. FIXME: se puede optimizar con bajas resoluciones |
| 138 | + LOG("Analog pin read: ", INPUT_PORTS[i]); |
| 139 | + } else |
| 140 | + { |
| 141 | + int data = digitalRead(INPUT_PORTS[i]); |
| 142 | + response[len + 1] = byte(data); |
| 143 | + |
| 144 | + len += 1; |
| 145 | + LOG("Digital pin read: ", INPUT_PORTS[i]); |
| 146 | + } |
| 147 | + } |
| 148 | + |
| 149 | + response[1] = len - 1; |
| 150 | + SerialUSB.write(response, len + 2); // 2 bytes extras por el id de comando y la longitud |
| 151 | +} |
| 152 | + |
| 153 | +void setup() { |
| 154 | + SerialUSB.begin(115200); |
| 155 | + |
| 156 | + #ifdef DEBUG |
| 157 | + Serial.begin(57600); |
| 158 | + #endif |
| 159 | + |
| 160 | + for (int i = 0; i < 255; i++) |
| 161 | + { |
| 162 | + executor[i] = ¬_implemented; |
| 163 | + } |
| 164 | + |
| 165 | + INPUT_PORTS[0] = 0; |
| 166 | + |
| 167 | + /** Commands Callbacks **/ |
| 168 | + executor[ANALOG_PRECISION_CMD] = &set_analog_precision; |
| 169 | + executor[ADD_ANALOG_INPUT_CMD] = &set_analog_input; |
| 170 | + executor[ADD_ANALOG_OUTPUT_CMD] = &set_analog_output; |
| 171 | + executor[SET_PIN_MODE_CMD] = &set_pin_mode; |
| 172 | + executor[SET_REPORT_MODE_CMD] = &set_report_mode; |
| 173 | + executor[ACTUATE_CMD] = &actuate; |
| 174 | + |
| 175 | + executor[ANALOG_PRECISION_CMD]("\x01\x01\x12"); |
| 176 | + executor[ADD_ANALOG_INPUT_CMD]("\x02\x01\x37"); // Configura a A1 como lectura |
| 177 | + executor[ADD_ANALOG_INPUT_CMD]("\x02\x01\x38"); // Configura a A2 como lectura |
| 178 | + executor[SET_PIN_MODE_CMD]("\x04\x02\x12\x01"); |
| 179 | + executor[SET_PIN_MODE_CMD]("\x04\x02\x55\x00"); |
| 180 | + |
| 181 | +} |
| 182 | + |
| 183 | +void loop() { |
| 184 | + LOG("Escribiendo...", " "); |
| 185 | + executor[ACTUATE_CMD]("\xF0\x01\x12\x01"); |
| 186 | + |
| 187 | + if (SerialUSB.available() > 0) |
| 188 | + { |
| 189 | + char input[64]; // Esto se reserva en el stack, tal vez hacerlo global consume menos recursos... |
| 190 | + |
| 191 | + while (SerialUSB.available() > 0) |
| 192 | + { |
| 193 | + SerialUSB.readBytes(input, SerialUSB.available()); |
| 194 | + } |
| 195 | + |
| 196 | + executor[input[0]](input); // Does the callback for the command |
| 197 | + } |
| 198 | + |
| 199 | + delay(5000); |
| 200 | +} |
0 commit comments