/* Copyright 2014 Greg Stein * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ // ### docco #include #include #include #define MIDDLEMAN_I2C_ADDR 8 #define MIDDLEMAN_API_PORT 80 #define I2C_RETRIES 3 // how many times we should attempt an I2C operation // Blink the LED while we are active. // ### maybe only during a DEBUG mode? #define LED_PIN 9 // Arduino Ethernet's LED #define BLINK_TIME 700 // flip every 700 ms // Our API endpoint. static EndpointServer *server; static void i2c_handler(const EndpointResponse &response) { if (response.params_len == 0) { // Need at least one byte to specify ADDRESS and READ(1)/WRITE(0). response.respond400(); } else if ((response.params[0] & 1) == 0) { uint8_t retries = I2C_RETRIES; uint8_t result; do { // WRITE to a SLAVE. Wire.beginTransmission(response.params[0] >> 1); Wire.write(&response.params[1], response.params_len - 1); result = Wire.endTransmission(); } while (result != 0 && --retries > 0); // Respond, based on RESULT. if (result) { // Use 504 (Gateway Timeout) ... which makes sense, as we couldn't // reach the device at the requested I2C address. response.errorResponse(504); } else response.respond204(); } else if (response.params_len != 2 || response.params[1] > BUFFER_LENGTH) { // A READ request requires ADDRESS and an expected amount. response.respond400(); } else { uint8_t buf[BUFFER_LENGTH]; uint8_t amt; uint8_t i = 0; // READ from a SLAVE. amt = Wire.requestFrom((uint8_t)(response.params[0] >> 1), response.params[1], (uint8_t)true /* stop */); for (; i < amt; ++i) buf[i] = Wire.read(); response.respondBytes(buf, amt); } } static const EndpointHandler handlers[] = { { 'i', i2c_handler, false }, { 0 } }; // An I2C MASTER will instruct us via a command/WRITE that it wants to read some // data from self/SLAVE. The callback will place the data into READBUF/LEN. #define READBUF_MAX BUFFER_LENGTH // from Wire.h static size_t readbuf_len = 0; static uint8_t readbuf[READBUF_MAX]; // Called when another MASTER writes to us as a SLAVE static void i2c_slave_write(int how_many) { while (Wire.available()) { int v = Wire.read(); // ### do something with V. } } // Called when another MASTER reads from us as a SLAVE. A previous command/WRITE // will have told us what to return on this READ. See READBUF/LEN above. static void i2c_slave_read(void) { Wire.write(readbuf, readbuf_len); } void setup(void) { //Serial.begin(115200); // Register our SLAVE address. We typically operate as MASTER, though. Wire.begin(MIDDLEMAN_I2C_ADDR); Wire.onReceive(i2c_slave_write); Wire.onRequest(i2c_slave_read); static /*const*/ uint8_t mac[] = { 0x90, 0xA2, 0xDA, 0x0D, 0x73, 0x9C }; const IPAddress ip = IPAddress(192, 168, 0, 3); Ethernet.begin(mac, ip); //Serial.println("Starting server..."); server = new EndpointServer(handlers, MIDDLEMAN_API_PORT); // We'll blink the LED while active pinMode(LED_PIN, OUTPUT); } void loop(void) { server->process(); { static unsigned long last_blink = 0; static int led_value = 0; unsigned long now = millis(); signed long duration; // If NOW is less than our last-recorded time, then it has rolled // over, and we need to reinterpet the types/math a bit. if (now < last_blink) duration = (signed long)now - (signed long)last_blink; else duration = now - last_blink; if (duration > BLINK_TIME) { led_value ^= 1; digitalWrite(LED_PIN, led_value); last_blink = now; } } }