RobTillaart / I2CKeyPad

Arduino library for 4x4 (or smaller) keypad connected to an I2C PCF8574.
MIT License
49 stars 9 forks source link

Incorporate the readBytesUntil ( #7

Closed XiaoShiZi closed 2 years ago

XiaoShiZi commented 3 years ago

Dear Rob Tillaart,

I like the lib you made especialy the fact that you just put the keytop into 1 array. Any change you could expand this lib with a function like the Serial.readBytesUntil(character, buffer, length, time) but then for a I2C Keyboard (like the 4x4 matrix)? So that we can easily get our char/String/Array with values till "#" or "*" or "A-D" is pressed, length, buffer size or time.

I2CKeypad::getKeyUntil(char, buffer, length, time)

Kind regards and a lot of appreciation for your work on this library. P.S. If there's another lib capable to give this functionality please be kind and let us know.

XiaoShiZi

Arduino Serial readBytesUntil

RobTillaart commented 2 years ago

@XiaoShiZi Sorry for the late response, somehow I missed this issue. I am busy upgrading the build-CI of all my libraries for a few weeks now. Today this library will be done and after that I will dive into your question.

RobTillaart commented 2 years ago

@XiaoShiZi The keypad library does not know which keys are on the keypad, it just returns 0..15 or 16 =NOKEY (17 = FAIL)

I will try to write an example that uses the I2CKeypad and does also some keymapping. (There will be a new develop branch asap)

RobTillaart commented 2 years ago

@XiaoShiZi

As I have no hardware nearby, can you please

so I can add it as example.

//
//    FILE: I2Ckeypad_readKeyUntil.ino
//  AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// PURPOSE: demo reading until specific keyPress
//     URL: https://github.com/RobTillaart/I2CKeyPad
//

// PCF8574
//    pin p0-p3 rows
//    pin p4-p7 colums
// 4x4 or smaller keypad.

#include "Wire.h"
#include "I2CKeyPad.h"

const uint8_t KEYPAD_ADDRESS = 0x38;

I2CKeyPad keyPad(KEYPAD_ADDRESS);

void setup()
{
  Serial.begin(115200);
  Serial.println(__FILE__);

  Wire.begin();
  Wire.setClock(400000);
  if (keyPad.begin() == false)
  {
    Serial.println("\nERROR: cannot communicate to keypad.\nPlease reboot.\n");
    while (1);
  }
}

void loop()
{
  char buf[20];
  int result = readKeyPad('#', buf, 20, 10000);
  if (result == 0)
  {
    Serial.print("SUCCESS: ");
    Serial.println(buf);
  }
  if (result == -1)
  {
    Serial.print("FAILURE: ");
    Serial.println(buf);
  }
  if (result == -2)
  {
    Serial.print("TIMEOUT: ");
    Serial.println(buf);
  }
}

//
// until  = end character
// buffer = buffer to fill
// length = length of buffer (incl '\0'
// timeout = timeout in milliseconds
// returns false if until character is not read.
//
int readKeyPad(char until, char * buffer, uint8_t length, uint16_t timeout)
{
  char keymap[19] = "123A456B789C*0#DNF";  // ... None  Fail }
  uint8_t bufferIndex = 0;
  uint32_t start = millis();

  // empty buffer
  buffer[bufferIndex] = 0;

  while (true)
  {
    // while no key is pressed wait
    while (keymap[keyPad.getKey()] == 'N')
    {
      yield();
      if (millis() - start > timeout) return -2;
    }

    // get the key pressed
    uint8_t raw = keyPad.getLastKey();

    // process key pressed
    uint8_t key = keymap[raw];

    // handle end conditions
    if ( key == until) return 0;
    if ( key == 'F') return -1;    // failed to read;
    if (bufferIndex == length) return false;

    // add key to buffer
    buffer[bufferIndex++] = key;
    buffer[bufferIndex] = 0;

    // while key is pressed wait
    while (keymap[keyPad.getKey()] == key)
    {
      yield();
      if (millis() - start > timeout) return -2;
    }
  }
}

// -- END OF FILE --
RobTillaart commented 2 years ago

added example to branch - https://github.com/RobTillaart/I2CKeyPad/tree/develop

XiaoShiZi commented 2 years ago

Hi Rob Tillaart, Thanks for the look into this adding functionality. On your request : As I have no hardware nearby, can you please

V verify the following test sketch? +/- confirm this matches the needed functionality? V it compiles so I can add it as example.

Tested your example and indeed it will do the trick ;-) Thank youfor adding this into your library! Kind Regards, XiaoShiZi

XiaoShiZi commented 2 years ago

So you can add it to the list of interface now. Thanks Rob Tillaart!

RobTillaart commented 2 years ago

Thanks for testing. I will merge the example asap.

I am working on another issue in this library to add mapping of the buttons to characters of choice. See #9 After that I will publish a new release.

RobTillaart commented 2 years ago

Example merged into master.

RobTillaart commented 2 years ago

@XiaoShiZi A slightly simpler readUntil() as it is only one loop - please verify. might save a few bytes.

int readKeyPadUntil(char until, char * buffer, uint8_t length, uint16_t timeout)
{
  char keymap[19] = "123A456B789C*0#DNF";     // ... NoKey  Fail }

  uint8_t bufferIndex = 0;
  uint32_t start = millis();
  uint8_t lastKey =  'N';

  // empty the return buffer
  buffer[bufferIndex] = 0;

  while (millis() - start < timeout)
  {
    uint8_t key = keymap[keyPad.getKey()];
    if (key == 'N')         lastKey = 'N';
    else if (key == until)  return 0;
    else if (key == 'F')    return -1;
    else
    {
      if (key != lastKey)
      {
        lastKey = key;
        // add key to buffer
        buffer[bufferIndex++] = key;
        buffer[bufferIndex]   = 0;
        if ( bufferIndex == length - 1 ) return -3;
      }
    }
    yield();
  }
  return -2;    //  timeout
}