bool Adafruit_BluefruitLE_SPI::sendPacket(uint16_t command, const uint8_t* buf, uint8_t count, uint8_t more_data)
{
    // flush old response before sending the new command
    if (more_data == 0) flush();

    sdepMsgCommand_t msgCmd;

    msgCmd.header.msg_type    = SDEP_MSGTYPE_COMMAND;
    msgCmd.header.cmd_id_high = highByte(command);
    msgCmd.header.cmd_id_low  = lowByte(command);
    msgCmd.header.length      = count;
    msgCmd.header.more_data   = (count == SDEP_MAX_PACKETSIZE) ? more_data : 0;

    // Copy payload
    if ( buf != NULL && count > 0) memcpy(msgCmd.payload, buf, count);

    // Starting SPI transaction
    if (m_sck_pin == -1)
        SPI.beginTransaction(bluefruitSPI);

    SPI_CS_ENABLE();

    TimeoutTimer tt(_timeout);

    // Bluefruit may not be ready
    while ( ( spixfer(msgCmd.header.msg_type) == SPI_IGNORED_BYTE ) && !tt.expired() )
    {
        // Disable & Re-enable CS with a bit of delay for Bluefruit to ready itself
        SPI_CS_DISABLE();
        delayMicroseconds(SPI_DEFAULT_DELAY_US);
        SPI_CS_ENABLE();
    }

    bool result = !tt.expired();
    if ( result )
    {
        // transfer the rest of the data
        spixfer((void*) (((uint8_t*)&msgCmd) +1), sizeof(sdepMsgHeader_t)+count-1);
    }

    SPI_CS_DISABLE();
    if (m_sck_pin == -1)
        SPI.endTransaction();

    return result;
}
Adafruit_SharpMem::Adafruit_SharpMem(int8_t ss) :
Adafruit_GFX(SHARPMEM_LCDWIDTH, SHARPMEM_LCDHEIGHT) {
  _ss = ss;
  _mosi = _clk = -1;

  // Set pin state before direction to make sure they start this way (no glitching)
  SPI_CS_DISABLE();
  pinMode(_ss, OUTPUT);
  
  // Set the vcom bit to a defined state
  _sharpmem_vcom = SHARPMEM_BIT_VCOM;
}
void Adafruit_SharpMem::toggleVcom(void)
{
  if (_clk == -1)
  SPI.beginTransaction(sharpmemSPI);

  SPI_CS_ENABLE();
  delayMicroseconds(SPI_DEFAULT_DELAY_US);    
  sendbyte(SHARPMEM_BIT_WRITECMD | _sharpmem_vcom);
  TOGGLE_VCOM;
  sendbyte(SHARPMEM_BIT_DUMMY);
  delayMicroseconds(SPI_DEFAULT_DELAY_US);    
  SPI_CS_DISABLE();

  if (_clk == -1)
  SPI.endTransaction();
}
void Adafruit_SharpMem::refresh(void) 
{
  uint16_t i, totalbytes, currentline, oldline;  
  totalbytes = (SHARPMEM_LCDWIDTH * SHARPMEM_LCDHEIGHT) / 8;

  if (_clk == -1)
    SPI.beginTransaction(sharpmemSPI);

  // Send the write command
  SPI_CS_ENABLE();
  delayMicroseconds(SPI_DEFAULT_DELAY_US);    
  sendbyte(SHARPMEM_BIT_WRITECMD | _sharpmem_vcom);
  TOGGLE_VCOM;

  // Send the address for line 1
  oldline = currentline = 1;
  sendbyte(currentline);

  // Send image buffer
  for (i=0; i<totalbytes; i++)
  {
    sendbyte(sharpmem_buffer[i]);
    currentline = ((i+1)/(SHARPMEM_LCDWIDTH/8)) + 1;
    if(currentline != oldline)
    {
      // Send end of line and address bytes
      sendbyte(SHARPMEM_BIT_DUMMY);
      if (currentline <= SHARPMEM_LCDHEIGHT)
      {
        sendbyte(currentline);
      }
      oldline = currentline;
    }
  }

  // Send another trailing 8 bits for the last line
  sendbyte(SHARPMEM_BIT_DUMMY);
  delayMicroseconds(SPI_DEFAULT_DELAY_US);    
  SPI_CS_DISABLE();

  if (_clk == -1)
    SPI.endTransaction();
}
void Adafruit_SharpMem::clearDisplay(void) 
{
  memset(sharpmem_buffer, 0xff, (SHARPMEM_LCDWIDTH * SHARPMEM_LCDHEIGHT) / 8);

  if (_clk == -1)
    SPI.beginTransaction(sharpmemSPI);

  // Send the clear screen command rather than doing a HW refresh (quicker)
  SPI_CS_ENABLE();
  delayMicroseconds(SPI_DEFAULT_DELAY_US);
  sendbyte(_sharpmem_vcom | SHARPMEM_BIT_CLEAR);
  sendbyte(SHARPMEM_BIT_DUMMY);
  TOGGLE_VCOM;
  delayMicroseconds(SPI_DEFAULT_DELAY_US);
  SPI_CS_DISABLE();

  if (_clk == -1)
    SPI.endTransaction();
}
bool Adafruit_BluefruitLE_SPI::getPacket(sdepMsgResponse_t* p_response)
{
    sdepMsgHeader_t* p_header = &p_response->header;

    if (m_sck_pin == -1)
        SPI.beginTransaction(bluefruitSPI);
    SPI_CS_ENABLE();

    TimeoutTimer tt(_timeout);

    // Bluefruit may not be ready
    while ( ( (p_header->msg_type = spixfer(0xff)) == SPI_IGNORED_BYTE ) && !tt.expired() )
    {
        // Disable & Re-enable CS with a bit of delay for Bluefruit to ready itself
        SPI_CS_DISABLE();
        delayMicroseconds(SPI_DEFAULT_DELAY_US);
        SPI_CS_ENABLE();
    }

    bool result=false;

    // Not a loop, just a way to avoid goto with error handling
    do
    {
        if ( tt.expired() ) break;

        // Look for the header
        while ( p_header->msg_type != SDEP_MSGTYPE_RESPONSE && p_header->msg_type != SDEP_MSGTYPE_ERROR )
        {
            p_header->msg_type = spixfer(0xff);
        }
        memset( (&p_header->msg_type)+1, 0xff, sizeof(sdepMsgHeader_t) - 1);
        spixfer((&p_header->msg_type)+1, sizeof(sdepMsgHeader_t) - 1);

        // Command is 16-bit at odd address, may have alignment issue with 32-bit chip
        uint16_t cmd_id = word(p_header->cmd_id_high, p_header->cmd_id_low);

        // Error Message Response
        if ( p_header->msg_type == SDEP_MSGTYPE_ERROR ) break;

        // Invalid command
        if (!(cmd_id == SDEP_CMDTYPE_AT_WRAPPER ||
                cmd_id == SDEP_CMDTYPE_BLE_UARTTX ||
                cmd_id == SDEP_CMDTYPE_BLE_UARTRX) )
        {
            break;
        }

        // Invalid length
        if(p_header->length > SDEP_MAX_PACKETSIZE) break;

        // read payload
        memset(p_response->payload, 0xff, p_header->length);
        spixfer(p_response->payload, p_header->length);

        result = true;
    } while(0);

    SPI_CS_DISABLE();
    if (m_sck_pin == -1)
        SPI.endTransaction();

    return result;
}
bool Adafruit_BluefruitLE_SPI::getPacket(sdepMsgResponse_t* p_response)
{
  // Wait until IRQ is asserted, double timeout since some commands take long time to start responding
  TimeoutTimer tt(2*_timeout);
  
  while ( !digitalRead(m_irq_pin) ) {
    if (tt.expired()) return false;
  }
  
  sdepMsgHeader_t* p_header = &p_response->header;

  if (m_sck_pin == -1)
    SPI.beginTransaction(bluefruitSPI);
  SPI_CS_ENABLE();

  tt.set(_timeout);

  do {
    if ( tt.expired() ) break;

    p_header->msg_type = spixfer(0xff);

    if (p_header->msg_type == SPI_IGNORED_BYTE)
    {
      // Bluefruit may not be ready
      // Disable & Re-enable CS with a bit of delay for Bluefruit to ready itself
      SPI_CS_DISABLE();
      delayMicroseconds(SPI_DEFAULT_DELAY_US);
      SPI_CS_ENABLE();
    }
    else if (p_header->msg_type == SPI_OVERREAD_BYTE)
    {
      // IRQ may not be pulled down by Bluefruit when returning all data in previous transfer.
      // This could happen when Arduino MCU is running at fast rate comparing to Bluefruit's MCU,
      // causing an SPI_OVERREAD_BYTE to be returned at stage.
      //
      // Walkaround: Disable & Re-enable CS with a bit of delay and keep waiting
      // TODO IRQ is supposed to be OFF then ON, it is better to use GPIO trigger interrupt.

      SPI_CS_DISABLE();
      // wait for the clock to be enabled..
//      while (!digitalRead(m_irq_pin)) {
//        if ( tt.expired() ) break;
//      }
//      if (!digitalRead(m_irq_pin)) break;
      delayMicroseconds(SPI_DEFAULT_DELAY_US);
      SPI_CS_ENABLE();
    }
  }  while (p_header->msg_type == SPI_IGNORED_BYTE || p_header->msg_type == SPI_OVERREAD_BYTE);

  bool result=false;

  // Not a loop, just a way to avoid goto with error handling
  do
  {
    // Look for the header
    // note that we should always get the right header at this point, and not doing so will really mess up things.
    // This whole loop isn't needed with my fix above..
    while ( p_header->msg_type != SDEP_MSGTYPE_RESPONSE && p_header->msg_type != SDEP_MSGTYPE_ERROR && !tt.expired() )
    {
      p_header->msg_type = spixfer(0xff);
    }
    
    if ( tt.expired() ) break;
    
    memset( (&p_header->msg_type)+1, 0xff, sizeof(sdepMsgHeader_t) - 1);
    spixfer((&p_header->msg_type)+1, sizeof(sdepMsgHeader_t) - 1);

    // Command is 16-bit at odd address, may have alignment issue with 32-bit chip
    uint16_t cmd_id = word(p_header->cmd_id_high, p_header->cmd_id_low);

    // Error Message Response
    if ( p_header->msg_type == SDEP_MSGTYPE_ERROR ) break;

    // Invalid command
    if (!(cmd_id == SDEP_CMDTYPE_AT_WRAPPER ||
          cmd_id == SDEP_CMDTYPE_BLE_UARTTX ||
          cmd_id == SDEP_CMDTYPE_BLE_UARTRX) )
    {
      break;
    }

    // Invalid length
    if(p_header->length > SDEP_MAX_PACKETSIZE) break;

    // read payload
    memset(p_response->payload, 0xff, p_header->length);
    spixfer(p_response->payload, p_header->length);

    result = true;
  }while(0);

  SPI_CS_DISABLE();
  if (m_sck_pin == -1)
    SPI.endTransaction();

  return result;
}