const char* WiFlyDevice::ip() { /* The return value is intended to be dropped directly into calls to 'print' or 'println' style methods. */ static char ip[IP_ADDRESS_BUFFER_SIZE] = ""; // TODO: Ensure we're not in a connection? _enter_command_mode(); // Version 2.19 of the WiFly firmware has a "get ip a" command but // we can't use it because we want to work with 2.18 too. _send_command( F( "get ip" ), false, "IP=" ); char newChar; byte offset = 0; // Copy the IP address from the response into our buffer while( offset < IP_ADDRESS_BUFFER_SIZE ) { newChar = _uart->read(); if( newChar == ':' ) { ip[offset] = '\x00'; break; } else if( newChar != -1 ) { ip[offset] = newChar; offset++; } } // This handles the case when we reach the end of the buffer // in the loop. (Which should never happen anyway.) // And hopefully this prevents us from failing completely if // there's a mistake above. ip[IP_ADDRESS_BUFFER_SIZE-1] = '\x00'; // This should skip the remainder of the output. // TODO: Handle this better? _wait_for_response( "<" ); while (_uart->read() != ' '); // Skip the prompt. // For some reason the "sendCommand" approach leaves the system // in a state where it misses the first/next connection so for // now we don't check the response. // TODO: Fix this _uart->println( "exit" ); //_send_command("exit", false, "EXIT"); return ip; }
static int _start(SercomI2cm *dev, uint16_t addr) { /* Wait for hardware module to sync */ DEBUG("Wait for device to be ready\n"); while (dev->SYNCBUSY.reg & SERCOM_I2CM_SYNCBUSY_MASK) {} /* Set action to ACK. */ dev->CTRLB.reg &= ~SERCOM_I2CM_CTRLB_ACKACT; /* Send Start | Address | Write/Read */ DEBUG("Generate start condition by sending address\n"); dev->ADDR.reg = (addr) | (0 << SERCOM_I2CM_ADDR_HS_Pos); /* Wait for response on bus. */ if (addr & I2C_READ) { /* Some devices (e.g. SHT2x) can hold the bus while preparing the reply */ if (_wait_for_response(dev, 100 * SAMD21_I2C_TIMEOUT) < 0) return -ETIMEDOUT; } else { if (_wait_for_response(dev, SAMD21_I2C_TIMEOUT) < 0) return -ETIMEDOUT; } /* Check for address response error unless previous error is detected. */ /* Check for error and ignore bus-error; workaround for BUSSTATE * stuck in BUSY */ if (dev->INTFLAG.reg & SERCOM_I2CM_INTFLAG_SB) { /* Clear write interrupt flag */ dev->INTFLAG.reg = SERCOM_I2CM_INTFLAG_SB; /* Check arbitration. */ if (dev->STATUS.reg & SERCOM_I2CM_STATUS_ARBLOST) { DEBUG("STATUS_ERR_PACKET_COLLISION\n"); return -EAGAIN; } } /* Check that slave responded with ack. */ else if (dev->STATUS.reg & SERCOM_I2CM_STATUS_RXNACK) { /* Slave busy. Issue ack and stop command. */ dev->CTRLB.reg |= SERCOM_I2CM_CTRLB_CMD(3); DEBUG("STATUS_ERR_BAD_ADDRESS\n"); return -ENXIO; } return 0; }
static inline int _read(SercomI2cm *dev, uint8_t *data, int length, uint8_t stop) { uint8_t count = 0; /* Set action to ack. */ dev->CTRLB.reg &= ~SERCOM_I2CM_CTRLB_ACKACT; /* Read data buffer. */ while (length--) { /* Check that bus ownership is not lost. */ if ((dev->STATUS.reg & SERCOM_I2CM_STATUS_BUSSTATE_Msk) != BUSSTATE_OWNER) { DEBUG("STATUS_ERR_PACKET_COLLISION\n"); return -EAGAIN; } /* Wait for hardware module to sync */ while (dev->SYNCBUSY.reg & SERCOM_I2CM_SYNCBUSY_MASK) {} /* Check if this is the last byte to read */ if (length == 0 && stop) { /* Send NACK before STOP */ dev->CTRLB.reg |= SERCOM_I2CM_CTRLB_ACKACT; /* Prepare stop command before read last byte otherwise hardware will request an extra byte to read */ _stop(dev); } /* Save data to buffer. */ data[count] = dev->DATA.reg; /* Wait for response on bus. */ if (length > 0) { if (_wait_for_response(dev, SAMD21_I2C_TIMEOUT) < 0) return -ETIMEDOUT; } count++; } return 0; }
static inline int _write(SercomI2cm *dev, const uint8_t *data, int length, uint8_t stop) { uint8_t count = 0; /* Write data buffer until the end. */ DEBUG("Looping through bytes\n"); while (length--) { /* Check that bus ownership is not lost. */ if ((dev->STATUS.reg & SERCOM_I2CM_STATUS_BUSSTATE_Msk) != BUSSTATE_OWNER) { DEBUG("STATUS_ERR_PACKET_COLLISION\n"); return -EAGAIN; } /* Wait for hardware module to sync */ while (dev->SYNCBUSY.reg & SERCOM_I2CM_SYNCBUSY_MASK) {} DEBUG("Written byte #%i to data reg, now waiting for DR" " to be empty again\n", count); dev->DATA.reg = data[count++]; /* Wait for response on bus. */ if (_wait_for_response(dev, SAMD21_I2C_TIMEOUT) < 0) { return -ETIMEDOUT; } /* Check for NACK from slave. */ if (dev->STATUS.reg & SERCOM_I2CM_STATUS_RXNACK) { DEBUG("STATUS_ERR_OVERFLOW\n"); return -EIO; } } if (stop) { /* Issue stop command */ _stop(dev); } return 0; }