// Similar to the command function, let's do a set parameter genrealization.
BLEMate2::opResult BLEMate2::stdSetParam(String command, String param)
{
  String buffer;
  String EOL = String("\n\r");
  
  knownStart();  // Clear Arduino and module serial buffers.
  
  _serialPort->print("SET ");
  _serialPort->print(command);
  _serialPort->print("=");
  _serialPort->print(param);
  _serialPort->print("\r");
  _serialPort->flush();
  
  // We're going to use the internal timer to track the elapsed time since we
  //  issued the reset. Bog-standard Arduino stuff.
  unsigned long startTime = millis();
  
  // This is our timeout loop. We'll give the module 2 seconds to reset.
  while ((startTime + 2000) > millis())
  {
    // Grow the current buffered data, until we receive the EOL string.    
    if (_serialPort->available() >0) buffer.concat(char(_serialPort->read()));

    if (buffer.endsWith(EOL))
    {
      if (buffer.startsWith("ER")) return MODULE_ERROR;
      else if (buffer.startsWith("OK")) return SUCCESS;
      buffer = "";
    }    
  }
  return TIMEOUT_ERROR;
}
BLEMate2::opResult BLEMate2::disconnect()
{
  String buffer;
  String EOL = String("\n\r"); // This is just handy.
  
  knownStart();
  _serialPort->print("DCN\r"); 
  _serialPort->flush();
  
  // We're going to use the internal timer to track the elapsed time since we
  //  issued the connect command. Bog-standard Arduino stuff.
  unsigned long disconnectStart = millis();
  
  buffer = "";

  // The timeout on this is 5 seconds; that may be a bit long.
  while (disconnectStart + 5000 > millis())
  {
    // Grow the current buffered data, until we receive the EOL string.    
    if (_serialPort->available() >0) buffer.concat(char(_serialPort->read()));
    
    if (buffer.endsWith(EOL))
    {
      if (buffer.startsWith("ERR")) return MODULE_ERROR;
      if (buffer.startsWith("DCN")) 
      {
        stdCmd("SCN OFF"); 
        return SUCCESS;
      }
      buffer = "";    
    }
  }
  return TIMEOUT_ERROR;
}
// connect by address
//  Attempts to connect to one of the Bluetooth devices which has an address
//  stored in the _addresses array.
BLEMate2::opResult BLEMate2::connect(String address)
{
  // Before we go any further, we'll do a simple error check on the incoming
  //  address. We know that it should be 12 hex digits, all uppercase; to
  //  minimize execution time and code size, we'll only check that it's 12
  //  characters in length.
  if (address.length() != 12) return INVALID_PARAM;

  // We need a buffer to store incoming data.
  String buffer;
  String EOL = String("\n\r"); // This is just handy.
  
  
  knownStart(); // Purge serial buffers on both the module and the Arduino.
  
  // The module has to be in SCAN mode for the CON command to work.
  //  We can't use BLEScan() b/c it's a blocking function.
  _serialPort->print("SCN ON\r");
  
  // Now issue the inquiry command.
  _serialPort->print("CON "); 
  _serialPort->print(address);
  _serialPort->print(" 0\r");
  // We need to wait until the command finishes before we start looking for a
  //  response; that's what flush() does.
  _serialPort->flush();
  
  // We're going to use the internal timer to track the elapsed time since we
  //  issued the connect command. Bog-standard Arduino stuff.
  unsigned long connectStart = millis();
  
  buffer = "";

  // The timeout on this is 5 seconds; that may be a bit long.
  while (connectStart + 5000 > millis())
  {
    // Grow the current buffered data, until we receive the EOL string.    
    if (_serialPort->available() >0) buffer.concat(char(_serialPort->read()));
    
    if (buffer.endsWith(EOL))
    {
      if (buffer.startsWith("ERR")) return MODULE_ERROR;
      if (buffer.startsWith("RPD")) return SUCCESS;
      buffer = "";    
    }
  }
  return TIMEOUT_ERROR;
}
// We may at some point not know whether we're a central or peripheral
//  device; that's important information, so we should be able to query
//  the module regarding that. We're not going to store that info, however, 
//  since the whole point is to get it "from the horse's mouth" rather than
//  trusting that our software is in sync with the state of the module.
BLEMate2::opResult BLEMate2::amCentral(boolean &inCentralMode)
{
  String buffer;
  String EOL = String("\n\r");
  
  knownStart(); // Clear the serial buffer in the module and the Arduino.
  
  _serialPort->print("STS\r");
  _serialPort->flush();
  
  // We're going to use the internal timer to track the elapsed time since we
  //  issued the command. Bog-standard Arduino stuff.
  unsigned long startTime = millis();
    
  // This is our timeout loop. We'll give the module 3 seconds.
  while ((startTime + 3000) > millis())
  {
    // Grow the current buffered data, until we receive the EOL string.    
    if (_serialPort->available() > 0) 
    {
      buffer.concat(char(_serialPort->read()));
    }
    if (buffer.endsWith(EOL))
    {
      if (buffer.startsWith("ER")) 
      {
        return MODULE_ERROR;
      }
      else if (buffer.startsWith("OK")) 
      {
        return SUCCESS;
      }
      else if (buffer.startsWith("STS")) 
      {
        if (buffer.charAt(4) == 'C')
        {
          inCentralMode = true;
        }
        else
        {
          inCentralMode = false;
        }
      } 
      buffer = "";
    }    
  }
  return TIMEOUT_ERROR;
}
// Issue the "RESET" command over the serial port to the BC118. If it works, 
//  we expect to see a string that looks something like this:
//    Melody Smart v2.6.0
//    BlueCreation Copyright 2012 - 2014
//    www.bluecreation.com
//    READY
// If there is some sort of error, the module will respond with
//    ERR
// We'll buffer characters until we see an EOL (\n\r), then check the string.
BLEMate2::opResult BLEMate2::reset()
{
  String buffer;
  String EOL = String("\n\r");
  
  knownStart();
  
  // Now issue the reset command.
  _serialPort->print("RST");
  _serialPort->print("\r");
  _serialPort->flush();
  
  // We're going to use the internal timer to track the elapsed time since we
  //  issued the reset. Bog-standard Arduino stuff.
  unsigned long resetStart = millis();
  
  // This is our timeout loop. We'll give the module 6 seconds to reset.
  while ((resetStart + 6000) > millis())
  {
    // Grow the current buffered data, until we receive the EOL string.    
    if (_serialPort->available() > 0) 
    {
      char temp = _serialPort->read();
      buffer.concat(temp);
    }
    
    if (buffer.endsWith(EOL))
    {
      // If ERR or READY, we've finished the reset. Otherwise, just discard
      //  the data and wait for the next EOL.
      if (buffer.startsWith("ER")) return MODULE_ERROR;
      if (buffer.startsWith("RE")) 
      {
        stdCmd("SCN OFF"); // When we come out of reset, we *could* be
                           //  in scan mode. We don't want that; it's too
                           //  random and noisy.
        delay(500);        // Let the scanning noise complete.
        while(_serialPort->available())
        {
          _serialPort->read();
        } 
        return SUCCESS;
      }
      buffer = "";
    }    
  }
  return TIMEOUT_ERROR;
}
// Also, do a get paramater generalization. This is, of course, a bit more
//  difficult; we need to return both the result (SUCCESS/ERROR) and the
//  string returned.
BLEMate2::opResult BLEMate2::stdGetParam(String command, String &param)
{
  String buffer;
  String EOL = String("\n\r");
  
  knownStart();  // Clear the serial buffers.
  
  _serialPort->print("GET ");
  _serialPort->print(command);
  _serialPort->print("\r");
  _serialPort->flush();
  
  // We're going to use the internal timer to track the elapsed time since we
  //  issued the get command. Bog-standard Arduino stuff.
  unsigned long loopStart = millis();
  
  // This is our timeout loop. We'll give the module 2 seconds to get the value.
  while (loopStart + 2000 > millis())
  {
    // Grow the current buffered data, until we receive the EOL string.    
    if (_serialPort->available() >0) buffer.concat(char(_serialPort->read()));

    // Each time we encounter an EOL, we'll parse the current buffer.
    if (buffer.endsWith(EOL))
    {
      // ER and OK are simple enough- success or failure.
      if (buffer.startsWith("ER")) return MODULE_ERROR;
      if (buffer.startsWith("OK")) return SUCCESS;
      // BUT if the buffer starts with the command value, we'll want to extract
      //  the value returned by the module. As an example, "get ADDR" will 
      //  cause the module to return with "ADDR=value\n\rOK\n\r"
      if (buffer.startsWith(command))
      {
        // First, get the portion of the string beginning after the command
        //  string + 1 (to account for that equals sign).
        param = buffer.substring(command.length()+1);
        // Then, trim the whitespace (/n/r) off the buffer.
        param.trim();
      }
      buffer = "";
    }    
  }
  // We don't expect this operation to take too long, so we can return a
  //  timeout if we get here.
  return TIMEOUT_ERROR;
}
// With the BC118, *scan* is a much more important thing that with the BC127.
//  It's a "state", and in order to initiate a connection as a central device,
//  the BC118 *must* be in scan state.
// Timeout is not inherent to the scan command, either; that's a separate 
//  parameter that needs to be set.
BLEMate2::opResult BLEMate2::BLEScan(unsigned int timeout)
{

  // Let's assume that we find nothing; we'll call that a REMOTE_ERROR and
  //  report that to the user. Should we find something, we'll report success.
  opResult result = REMOTE_ERROR;
  String buffer = "";
  String addressTemp;
  String EOL = String("\n\r");
  
  String timeoutString = String(timeout, DEC);
  stdSetParam("SCNT", timeoutString);
  for (byte i = 0; i <5; i++) _addresses[i] = "";
  _numAddresses = 0;
    
  knownStart();
  
  // Now issue the scan command. 
  _serialPort->print("SCN ON\r");
  _serialPort->flush();
  
  // We're going to use the internal timer to track the elapsed time since we
  //  issued the command. Bog-standard Arduino stuff.
  unsigned long loopStart = millis();
  
  // Calculate a timeout value that's a tish longer than the module will
  //  use. This is our catch-all, so we don't sit in this loop forever waiting
  //  for input that will never come from the module.
  unsigned long loopTimeout = timeout*1300;
  
  // Oooookaaaayyy...now the fun part. A state machine that parses the input
  //  from the Bluetooth module!
  while (loopStart + loopTimeout > millis())
  {
    // Grow the current buffered data, until we receive the EOL string.    
    if (_serialPort->available() >0)
    {
      buffer.concat(char(_serialPort->read()));
    }
    if (buffer.endsWith(EOL))
    {
      // There are two possibilities for return values:
      //  1. ERR - indicates a problem with the module. Either we're in the
      //           wrong state to be trying to do this (we're not central,
      //           not idle, or both) or there's a syntax error.
      //  2. SCN=X 12charaddrxx xxxxxxxxxxxxxxx\n\r
      //           In this case, all we care about is the content from char
      //           6 to 18.
      // Note the lack of any kind of completion string! The module just stops
      //  reporting when done, and we'll never know if it doesn't find anything
      //  to report.
      if (buffer.startsWith("ER")) 
      {
        return MODULE_ERROR;
      }
      else if (buffer.startsWith("SC")) // An address has been found!
      {
        // The returned device string looks like this:
        //  scn=? 12charaddrxx bunch of other stuff\n\r
        // We can ignore the other stuff, and the first stuff, and just
        //  report the address. 
        addressTemp = buffer.substring(6,18);
        buffer = "";
        if (_numAddresses == 0) 
        {
          _addresses[0] = addressTemp;
          _numAddresses++;
          result = SUCCESS;
        }
        else // search the list for this address, and append if it's not in
             //  the list and the list isn't too long.
        {
          for (byte i = 0; i < _numAddresses; i++)
          {
            if (addressTemp == _addresses[i])
            {
              addressTemp = "x";
              break;
            }
          }
          if (addressTemp != "x")
          {
            _addresses[_numAddresses++] = addressTemp;
          }
          if (_numAddresses == 5) return SUCCESS;
        }
      }
      else // buffer is not a valid value
      {
        buffer = "";
      }
    }
  }
  // result will either have been unchanged (we didn't see anything) and
  //  be REMOTE_ERROR or will have been changed to SUCCESS when we saw our
  //  first address.
  return result;
}
// Scan is very similar to inquiry, but for BLE devices rather than for classic.
//  Result format is slightly different, however- different enough to warrant
//  another whole function, IMO.
BC127::opResult BC127::BLEScan(int timeout)
{
  // We're going to assume that what's going to happen is a timeout with no
  //  valid input from the module.
  int result = 0;
  String buffer = "";
  String addressTemp;
  String EOL = String("\n\r");
  
  for (byte i = 0; i <5; i++) _addresses[i] = "";
  _numAddresses = 0;
    
  knownStart();
  
  // Now issue the inquiry command.
  _serialPort->print("SCAN "); _serialPort->print(timeout); _serialPort->print("\r");
  _serialPort->flush();
  
  // We're going to use the internal timer to track the elapsed time since we
  //  issued the command. Bog-standard Arduino stuff.
  unsigned long loopStart = millis();
  
  // Calculate a timeout value that's a tish longer than the module will
  //  use. This is our catch-all, so we don't sit in this loop forever waiting
  //  for input that will never come from the module.
  unsigned long loopTimeout = timeout*1300;
  
  // Oooookaaaayyy...now the fun part. A state machine that parses the input
  //  from the Bluetooth module!
  while (loopStart + loopTimeout > millis())
  {
    // Grow the current buffered data, until we receive the EOL string.    
    if (_serialPort->available() >0) buffer.concat(char(_serialPort->read()));
    
    // If we've received the EOL string, we should parse the current buffer
    //  contents. There are three potential results to expect, here:
    // "OK" - The module has finished scanning (timed out) and the results we
    //   have are the only ones we'll ever get.
    // "ERROR" - Something went wrong and we're not scanning.
    //  SCAN <addr> <short_name> <role> <RSS>
    //  <addr> is a 12-digit hex value
    //  <short_name> is a string, surrounded by carets ( <like this> )
    //  <role> is advertising flags. BC127 devices will show up as 0A; single mode
    //    devices as 02.
    //  <RSS> is the signal strength. Anything better than -70dBm is likely to be
    //    quite okay for connecting.
    if (buffer.endsWith(EOL))
    {
      if (buffer.startsWith("OK")) return (opResult)result;
      if (buffer.startsWith("ER")) return MODULE_ERROR;
      if (buffer.startsWith("SC")) // An address has been found!
      {
        addressTemp = buffer.substring(5,17);
        buffer = "";
        if (_numAddresses == 0) 
        {
          _addresses[0] = addressTemp;
          _numAddresses++;
          result = (opResult)1;
        }
        else // search the list for this address, and append if it's not in
             //  the list and the list isn't too long.
        {
          for (char i = 0; i < _numAddresses; i++)
          {
            if (addressTemp == _addresses[i])
            {
              addressTemp = "x";
              break;
            }
          }
          if (addressTemp != "x")
          {
            _addresses[_numAddresses++] = addressTemp;
            result++;
          }
          if (_numAddresses == 5) return (opResult)result;
        }
      }
    }
  }
  return TIMEOUT_ERROR;
}
// There are times when it is useful to be able to know whether or not the
//  module is connected; this function will tell you whether or not the module
//  is connected with a certain protocol, or if it is connected at all. This is
//  particularly challenging; the strings coming from the module are so fast,
//  even at 9600 baud, that you don't really have time to parse them. The only
//  solution I've been able to come up with is to just let the buffer overflow
//  and give up on identifying connections by type.
BC127::opResult BC127::connectionState()
{
  String buffer;
  String EOL = String("\n\r");
  
  opResult retVal = TIMEOUT_ERROR;
  
  knownStart();
  
  _serialPort->print("STATUS");
  _serialPort->print("\r");
  _serialPort->flush();
  
  // We're going to use the internal timer to track the elapsed time since we
  //  issued the command. Bog-standard Arduino stuff.
  unsigned long startTime = millis();
  
  // This is our timeout loop. We'll give the module 500 milliseconds.
  //  Note: if you have more than one active connection this WILL overflow a
  //  software serial buffer. Working under this assumption, we're going to
  //  try and deal with both the overflow and no overflow case gracefully. I'm
  //  also removing the ability to check on a specific connection type, since
  //  that's what causes the overflow.
  while ((startTime + 500) > millis())
  {  
    // Grow the current buffered data, until we receive the EOL string.  
    while (_serialPort->available() > 0) 
    {
      char temp = _serialPort->read();
      buffer.concat(temp);
      if (temp = '\r') break;
    }  

    // Parse the current line of text from the module and see what we find out.
    if (buffer.endsWith(EOL))
    {
      // If the current line starts with "STATE", we need more parsing. This is
      //  also the only guaranteed result.
      if (buffer.startsWith("ST"))
      {
        // If "CONNECTED" is in the received string, we know we're connected,
        //  but not if we're connected with the particular profile we're
        //  interested in. So, we need to consider a bit further.
        if (buffer.substring(13, 15) == "ED") retVal = SUCCESS;
        // If "CONNECTED" *isn't* there, we want to return an appropriate error.
        else retVal = CONNECT_ERROR;
      }
      // If we ARE connected, we'll get a list of different link types. We'll
      //  want to parse over those and see if the profile we want is in it. If
      //  it is, we can call it a success; if not, do nothing.
      
      // NB This is commented out, because we'll always overflow the soft serial
      //  buffer if we have more than one type of connection open. I'm leaving
      //  it in just in case somebody wants to use it in a "hardware-only" mode.
      /*
      if (buffer.startsWith("LI"))
      {
        switch(connection)
        {
          case SPP:
            if (buffer.substring(17,19) == "SP") retVal = SUCCESS;
            break;
          case BLE:
            if (buffer.substring(17,19) == "BL") retVal = SUCCESS;
            break;
          case A2DP:
            if (buffer.substring(17,19) == "A2") retVal = SUCCESS;
            break;
          case HFP:
            if (buffer.substring(17,19) == "HF") retVal = SUCCESS;
            break;
          case AVRCP:
            if (buffer.substring(17,19) == "AV") retVal = SUCCESS;
            break;
          case PBAP:
            if (buffer.substring(17,19) == "PB") retVal = SUCCESS;
            break;
          case ANY:
          default:
            break;
        }
      }
      */
      // If by some miracle we *do* get to this point without a buffer overflow,
      //  we're safe to return without a buffer purge.
      if (buffer.startsWith("OK")) return retVal;
      buffer = "";
    }
  }
  // Okay, now we need to clean up our input buffer on the serial port. After
  //  all, we can be pretty sure that an overflow happened, and there's crap in
  //  the buffer.
  while (_serialPort->available() > 0) _serialPort->read();
  return retVal;
}
// Runs the "INQUIRY" command, with user defined timeout. Returns the number of
//  devices found, up to 5. The response expected looks like this:
//    INQUIRY 20FABB010272 240404 -37db
//    INQUIRY A4D1D203A4F4 6A041C -91db
//    OK
// "ERROR" is, as always, a possible result. What we want to do is extract that
//  12-digit hex value and save it. We may get duplicates; we only want to keep
//  new addresses. The parameter "timeout" is not in seconds; it can be between
//  1 and 48 inclusive, and the timeout period will be 1.28*timeout. We'll set
//  an internal timeout period that is slightly longer than that, for safety.
BC127::opResult BC127::inquiry(int timeout)
{

  int result = 0;
  String buffer = "";
  String addressTemp;
  String EOL = String("\n\r");
  
  for (byte i = 0; i <5; i++) _addresses[i] = "";
  _numAddresses = -1;
    
  knownStart(); // Purge serial buffers on Arduino and module.
  
  // Now issue the inquiry command.
  _serialPort->print("INQUIRY "); 
  _serialPort->print(timeout);
  _serialPort->print("\r");
  _serialPort->flush();
  
  // We're going to use the internal timer to track the elapsed time since we
  //  issued the inquiry. Bog-standard Arduino stuff.
  unsigned long loopStart = millis();
  
  // Calculate a reset timeout value that's a tish longer than the module will
  //  use. This is our catch-all, so we don't sit in this loop forever waiting
  //  for input that will never come from the module.
  unsigned long loopTimeout = timeout*1300;
  
  // Oooookaaaayyy...now the fun part. A state machine that parses the input
  //  from the Bluetooth module!
  while (loopStart + loopTimeout > millis())
  {
    // Grow the current buffered data, until we receive the EOL string.    
    if (_serialPort->available() >0) buffer.concat(char(_serialPort->read()));
    
    // If we've received the EOL string, we should parse the current buffer
    //  contents. There are three potential results to expect, here:
    // "OK" - The module has finished scanning (timed out) and the results we
    //   have are the only ones we'll ever get.
    // "ERROR" - Something went wrong and we're not scanning.
    // "INQUIRY <addr> <class> <rss>" - A remote device has responded. <addr>
    //   will be 12 upper case hex digits, and is the remote device's address,
    //   to be used to refer to that device later on. <class> is the remote
    //   device class; for example, by default, the BC127 will return 240404,
    //   which corresponds to a Bluetooth headset. <rss> is the received signal
    //   strength; generally, -70dBm is a good link strength.
    if (buffer.endsWith(EOL))
    {
      if (buffer.startsWith("OK")) return (opResult)result;
      if (buffer.startsWith("ER")) return MODULE_ERROR;
      if (buffer.startsWith("IN")) // An address has been found!
      {
        // Nab the address from the received string and store it in addressTemp.
        addressTemp = buffer.substring(8,20);
        buffer = "";   // Clear the buffer for next round of data collection.
        // If this is the first address, we need to do some things to ensure
        //  that we get the right result value. If it's not first...
        if (_numAddresses == -1) 
        {
          _addresses[0] = addressTemp;
          _numAddresses = 1;
          result = 1;
        }
        else // ...search the list for this address, and append if it's not in
             //  the list and the list isn't too long.
        {
          // If we find it, change the addressTemp value to 'x'.
          for (char i = 0; i <= _numAddresses; i++)
          {
            if (addressTemp == _addresses[i])
            {
              addressTemp = "x";
              break;
            }
          }
          // If we get here and the value isn't x, it was a new value, and can
          //  be stored.
          if (addressTemp != "x")
          {
            _addresses[_numAddresses++] = addressTemp;
            result++;
          }
          // If we get HERE, our address list is full and we should return.
          if (_numAddresses == 5) return (opResult)result;
        }
      }
    }
  }
  return TIMEOUT_ERROR;
}
// connect by address
//  Attempts to connect to one of the Bluetooth devices which has an address
//  stored in the _addresses array.
BC127::opResult BC127::connect(String address, connType connection)
{
  // Before we go any further, we'll do a simple error check on the incoming
  //  address. We know that it should be 12 hex digits, all uppercase; to
  //  minimize execution time and code size, we'll only check that it's 12
  //  characters in length.
  if (address.length() != 12) return INVALID_PARAM;

  // We need a buffer to store incoming data.
  String buffer;
  String EOL = String("\n\r"); // This is just handy.
  
  // Convert our connType enum into the actual string we need to send to the
  //  BC127 module.
  switch(connection)
  {
    case SPP:
      buffer = " SPP";
      break;
    case BLE:
      buffer = " BLE";
      break;
    case A2DP:
      buffer = " A2DP";
      break;
    case AVRCP:
      buffer = " AVRCP";
      break;
    case HFP:
      buffer = " HFP";
      break;
    case PBAP:
      buffer = " PBAP";
      break;
    default:
      buffer = " SPP";
      break;
  }
  
  knownStart(); // Purge serial buffers on both the module and the Arduino.
  
  // Now issue the inquiry command.
  _serialPort->print("OPEN "); 
  _serialPort->print(address);
  _serialPort->print(buffer);
  _serialPort->print("\r");
  // We need to wait until the command finishes before we start looking for a
  //  response; that's what flush() does.
  _serialPort->flush();
  
  // We're going to use the internal timer to track the elapsed time since we
  //  issued the connect command. Bog-standard Arduino stuff.
  unsigned long connectStart = millis();
  
  buffer = "";

  // The timeout on this is 5 seconds; that may be a bit long.
  while (connectStart + 5000 > millis())
  {
    // Grow the current buffered data, until we receive the EOL string.    
    if (_serialPort->available() >0) buffer.concat(char(_serialPort->read()));
    
    // At some point, the BC127 response string will contain the EOL string.
    //  Once that happens, we can figure out what the response looks like:
    //  "ERROR" - there's a syntax error in your message to the module; this is
    //    kind of unlikely, although it could happen if you call this function
    //    with an invalid address (something not entirely uppercase hex digits)
    //  "OPEN_ERROR" - most likely, the module can't find any devices with that
    //    address.
    //  "PAIR_ERROR" - the connection was refused by the remote module.
    //  "PAIR_OK" - the connection has been made, but the SPP channel is not
    //    yet open. We should probably just ignore this.
    //  "OPEN_OK" - ready to rock! This is when we should return success.
    if (buffer.endsWith(EOL))
    {
      if (buffer.startsWith("ERROR")) return MODULE_ERROR;
      if (buffer.startsWith("OPEN_ERROR")) return CONNECT_ERROR;
      if (buffer.startsWith("PAIR_ERROR")) return REMOTE_ERROR;
      if (buffer.startsWith("OPEN_OK")) return SUCCESS;
      buffer = "";    
    }
  }
  return TIMEOUT_ERROR;
}
// The only way to get the true full address of the module is to check the
//  module's firmware version with the "VER" command. The stdCmd() function
//  isn't really useful here; we'll take our cue from the BLEScan() function.
BLEMate2::opResult BLEMate2::addressQuery(String &address)
{
  // We're going to assume a failure to find the appropriate string, but a
  //  response of some kind. We'll call that a MODULE_ERROR.
  opResult result  = MODULE_ERROR;
  String buffer = "";
  String EOL = String("\n\r");
  
  knownStart();
  
  // Send the command and wait for it to complete.
  _serialPort->print("VER\r");
  _serialPort->flush();
  
  // We're going to use the internal timer to track the elapsed time since we
  //  issued the command. Bog-standard Arduino stuff.
  unsigned long loopStart = millis();
  unsigned long loopTimeout = 2000;
  
  // Oooookaaaayyy...now the fun part. A state machine that parses the input
  //  from the Bluetooth module!
  while (loopStart + loopTimeout > millis())
  {
    // Grow the current buffered data, until we receive the EOL string.    
    if (_serialPort->available() >0)
    {
      buffer.concat(char(_serialPort->read()));
    }
    if (buffer.endsWith(EOL))
    {
      // There are several possibilities for return values:
      //  1. ERR - indicates a problem with the module. Either we're in the
      //           wrong state to be trying to do this (we're not central,
      //           not idle, or both) or there's a syntax error.
      //  2. Bluetooth Address xxxxxxxxxxxx - this is the one we want to
      //           match. HOWEVER, there are *other* input strings after
      //           issuing the VER command.
      //  3. BlueCreation Copyright 2012-2014
      //  4. www.bluecreation.com
      //  5. Melody Smart vxxxxxxx
      //  6. Build: xxxxxxxxx
      //  7. OK
      // The important string is number 2, and of course it comes last.
      //  Thus, we want to discard any string that doesn't start with "Bluet".
      //  We also need to return upon "OK".
      if (buffer.startsWith("ER")) 
      {
        return MODULE_ERROR;
      }
      if (buffer.startsWith("Bluet")) // The address has been found!
      {
        // The returned device string looks like this:
        //  Bluetooth Address xxxxxxxxxxxx         
        // We can ignore the other stuff, and the first stuff, and just
        //  report the address. 
        address = buffer.substring(18,30);
        buffer = "";
        result = SUCCESS;
      }
      else if (buffer.startsWith("OK"))
      {
        return result;
      }
      else // buffer is not a valid value
      {
        buffer = "";
      }
    }
  }
  // This command is always going to return TIMEOUT; the BC118 doesn't report
  //  anything when it stops sending out data. It just...stops.
  return TIMEOUT_ERROR;
}