Grove 6-position DIP problem

I have a Grove 6-position DIP switch. It uses I2C to read the switch. I want to use it on a MKR NB 1500. I installed the library according to the instructions here: Grove - 6-Position DIP Switch | Seeed Studio Wiki
I get compile errors where it can't find twoWire or something similar. I am not home right now so I don't know the exact error. There is an include for Wire.h, but I could not find that library in the Library manager so that may be a problem.

I have the Grove LCD 16x2 display which also uses I2C and that works OK, so I know I2C works with the MKR NB 1500.

The example program comes with the library, and it has events for when the switches are moved which is more than I need. All I want to do is read the value of the DIP switch, so if you have any ideas about that please let me know.

Has anyone successfully compiled and used the example program?

Post the example sketch here, using code tags when you do

Which you have not supplied us :woozy_face:

It comes with the library and can be seen at the link above. I can copy it from there if you wish and post it.

Yes.

#include "Grove_Multi_Switch.h"

GroveMultiSwitch mswitch[1];
const char* grove_5way_tactile_keys[] = {
 "KEY A",
 "KEY B",
 "KEY C",
 "KEY D",
 "KEY E",
};
const char* grove_6pos_dip_switch_keys[] = {
 "POS 1",
 "POS 2",
 "POS 3",
 "POS 4",
 "POS 5",
 "POS 6",
};

const char** key_names;

int deviceDetect(void) {
 if (!mswitch->begin()) {
  Serial.println("***** Device probe failed *****");
  return -1;
 }

 Serial.println("***** Device probe OK *****");
 if (PID_VAL(mswitch->getDevID()) == PID_5_WAY_TACTILE_SWITCH) {
  Serial.println("Grove 5-Way Tactile Switch Inserted!");
  key_names = grove_5way_tactile_keys;
 } else if (PID_VAL(mswitch->getDevID()) == PID_6_POS_DIP_SWITCH) {
  Serial.println("Grove 6-Position DIP Switch Inserted!");
  key_names = grove_6pos_dip_switch_keys;
 }

 // enable event detection
 mswitch->setEventMode(true);

 // report device model
 Serial.print("A ");
 Serial.print(mswitch->getSwitchCount());
 Serial.print(" Button/Switch Device ");
 Serial.println(mswitch->getDevVer());
 return 0;
}

void setup()
{
 Serial.begin(115200);
 Serial.println("Grove Multi Switch");

 // Initial device probe
 if (deviceDetect() < 0) {
  Serial.println("Insert Grove 5-Way Tactile");
  Serial.println("or Grove 6-Position DIP Switch");
  for (;;);
 }

 return;
}

void loop()
{
 GroveMultiSwitch::ButtonEvent_t* evt;

 delay(1);

 evt = mswitch->getEvent();
 if (!evt) {
  // dynamic device probe
  deviceDetect();
  delay(1000);
  return;
 }

 if (!(evt->event & GroveMultiSwitch::BTN_EV_HAS_EVENT)) {
  #if 0
  Serial.print("No event, errno = ");
  Serial.println(mswitch->errno);
  #endif
  return;
 }

 for (int i = 0; i < mswitch->getSwitchCount(); i++) {
  Serial.print(key_names[i]);
  Serial.print(": RAW - ");
  Serial.print((evt->button[i] & GroveMultiSwitch::BTN_EV_RAW_STATUS)?
               "HIGH ": "LOW ");
  if (PID_VAL(mswitch->getDevID()) == PID_5_WAY_TACTILE_SWITCH) {
   Serial.print((evt->button[i] & GroveMultiSwitch::BTN_EV_RAW_STATUS)?
                "RELEASED ": "PRESSED ");
  } else if (PID_VAL(mswitch->getDevID()) == PID_6_POS_DIP_SWITCH) {
   Serial.print((evt->button[i] & GroveMultiSwitch::BTN_EV_RAW_STATUS)?
                "OFF ": "ON ");
  }
  Serial.println("");
 }

 for (int i = 0; i < mswitch->getSwitchCount(); i++) {
  if (evt->button[i] & ~GroveMultiSwitch::BTN_EV_RAW_STATUS) {
   Serial.println("");
   Serial.print(key_names[i]);
   Serial.print(": EVENT - ");
  }
  if (evt->button[i] & GroveMultiSwitch::BTN_EV_SINGLE_CLICK) {
   Serial.print("SINGLE-CLICK ");
  }
  if (evt->button[i] & GroveMultiSwitch::BTN_EV_DOUBLE_CLICK) {
   Serial.print("DOUBLE-CLICK ");
  }
  if (evt->button[i] & GroveMultiSwitch::BTN_EV_LONG_PRESS) {
   Serial.print("LONG-PRESS ");
  }
  if (evt->button[i] & GroveMultiSwitch::BTN_EV_LEVEL_CHANGED) {
   Serial.print("LEVEL-CHANGED ");
  }
 }
 Serial.println("");
}

And what is the error message?

Here is the .h file for it:

/*
    Name: Grove_Multi_Switch.h
 	Grove 5-Way Tactile & Grove 6-Position DIP Switch library.


    Author: turmary <turmary@126.com>
    Copyright (c) 2018 Seeed Corporation.

    The MIT License (MIT)

    Permission is hereby granted, free of charge, to any person obtaining
    a copy of this software and associated documentation files (the
    "Software"), to deal in the Software without restriction, including
    without limitation the rights to use, copy, modify, merge, publish,
    distribute, sublicense, and/or sell copies of the Software, and to
    permit persons to whom the Software is furnished to do so, subject to
    the following conditions:

    The above copyright notice and this permission notice shall be
    included in all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
    LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
    WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef __GROVE_MULTI_SWITCH__
#define __GROVE_MULTI_SWITCH__

#include <stdint.h>
#include <Wire.h>

class GroveMultiSwitch {
  public:
    enum button_event_t {
        BTN_EV_NO_EVENT     = 0,
        BTN_EV_HAS_EVENT    = 0x80000000UL,

#define RAW_DIGITAL_BTN_PRESSED		0
#define RAW_DIP_SWITCH_ON		0
        BTN_EV_RAW_STATUS   = 1UL << 0,
        BTN_EV_SINGLE_CLICK = 1UL << 1,
        BTN_EV_DOUBLE_CLICK = 1UL << 2,
        BTN_EV_LONG_PRESS   = 1UL << 3,
        BTN_EV_LEVEL_CHANGED = 1UL << 4,
    };

    struct ButtonEvent_t {
        uint32_t event;			// BTN_EV_NO_EVENT/BTN_EV_HAS_EVENT
#define BUTTON_MAX		6
        uint8_t button[BUTTON_MAX];	// one button each element
    };

    /**
        Create GroveMultiSwitch object.

        @param addr - The i2c address of device.
        @return - none
    */
#define _MULTI_SWITCH_DEF_I2C_ADDR	0x03	// The device i2c address in default
    GroveMultiSwitch(uint8_t addr = _MULTI_SWITCH_DEF_I2C_ADDR) {
        m_devAddr = addr;
        m_i2c = &Wire;
        version = 0;
    }

    /**
        Initialize the switch interface

        @return  bool - true for success or false for fail
    */
    bool begin(void) {
        m_i2c->begin();
        probeDevID();
        // versions needed
        getDevVer();
        m_btnCnt = getSwitchCount();
        return (m_btnCnt > 0);
    }

    /**
        @param none
        @return - Vendor ID(high 16 bits) & Product ID(low 16 bits)
                 0 if device unexist.
    */
    uint32_t getDevID(void) {
        return m_devID;
    }
#define VID_VAL(x)			((x) >> 16)
#define PID_VAL(x)			((x) & 0xFFFFUL)
#define VID_MULTI_SWITCH 		0x2886	// Vender ID of the device
#define PID_5_WAY_TACTILE_SWITCH	0x0002	// Grove 5-Way Tactile
#define PID_6_POS_DIP_SWITCH		0x0003	// Grove 6-Position DIP Switch

    /**
        Get device model and version
        @return - NULL if device unexist.
    */
    const char* getDevVer(void);

    /**
        Change i2c address of device.

        @param addr - The new i2c address of device.
        @return - none
    */
    void setDevAddr(uint8_t addr);

    /**
        Get button/Switch count
    */
    int getSwitchCount(void);

    /**
         Disable or enable event detecting mode.
        Tactile switch events: single/double click, long press
        DIP switch events    : level changed

         Raw switch status could be checked by getEvent()
        no matter what mode has been setup.
        Tactile switch status: press/non-press
        DIP switch status    : switch on/off

        @param enable - true for enable, else for disable.
        @return  bool - true for success or false for fail
    */
    bool setEventMode(bool enable);

    /**
        Get button/switch event,
        refer to setEventMode() to get all available events.

        @return ButtonEvent_t* -
               NULL if error, such as device unexist.
               .event = BTN_EV_NO_EVENT if no event
               .event = BTN_EV_HAS_EVENT if event occured,
                        and .button to check event of each button/switch.
    */
    ButtonEvent_t* getEvent(void);

  private:
    int readDev(uint8_t* data, int len);
    int writeDev(const uint8_t* data, int len);
    int readReg(uint8_t reg, uint8_t* data, int len);

    /**
        probe device & it's VID & PID

    */
    uint32_t probeDevID(void);

#define _MULTI_SWITCH_VERSIONS_SZ			10
    char versions[_MULTI_SWITCH_VERSIONS_SZ];
    int version;

    TwoWire* m_i2c;
    uint8_t m_devAddr;
    uint32_t m_btnCnt;
    uint32_t m_devID;
  public:
    // debug purpose
    int errno;
};

#endif //__GROVE_MULTI_SWITCH__
Here are the errors:
<code>
In file included from C:\Users\Tom\Documents\Arduino\libraries\Grove_Multiple_Switch_library\src\Grove_Multi_Switch.cpp:30:0:
C:\Users\Tom\Documents\Arduino\libraries\Grove_Multiple_Switch_library\src\Grove_Multi_Switch.h:159:5: error: 'TwoWire' does not name a type; did you mean 'TwoWire_h'?
     TwoWire* m_i2c;
     ^~~~~~~
     TwoWire_h
C:\Users\Tom\Documents\Arduino\libraries\Grove_Multiple_Switch_library\src\Grove_Multi_Switch.h: In constructor 'GroveMultiSwitch::GroveMultiSwitch(uint8_t)':
C:\Users\Tom\Documents\Arduino\libraries\Grove_Multiple_Switch_library\src\Grove_Multi_Switch.h:66:9: error: 'm_i2c' was not declared in this scope
         m_i2c = &Wire;
         ^~~~~
C:\Users\Tom\Documents\Arduino\libraries\Grove_Multiple_Switch_library\src\Grove_Multi_Switch.h: In member function 'bool GroveMultiSwitch::begin()':
C:\Users\Tom\Documents\Arduino\libraries\Grove_Multiple_Switch_library\src\Grove_Multi_Switch.h:76:9: error: 'm_i2c' was not declared in this scope
         m_i2c->begin();
         ^~~~~
C:\Users\Tom\Documents\Arduino\libraries\Grove_Multiple_Switch_library\src\Grove_Multi_Switch.cpp: In member function 'int GroveMultiSwitch::readDev(uint8_t*, int)':
C:\Users\Tom\Documents\Arduino\libraries\Grove_Multiple_Switch_library\src\Grove_Multi_Switch.cpp:50:5: error: 'm_i2c' was not declared in this scope
     m_i2c->requestFrom((int)m_devAddr, len);
     ^~~~~
C:\Users\Tom\Documents\Arduino\libraries\Grove_Multiple_Switch_library\src\Grove_Multi_Switch.cpp: In member function 'int GroveMultiSwitch::writeDev(const uint8_t*, int)':
C:\Users\Tom\Documents\Arduino\libraries\Grove_Multiple_Switch_library\src\Grove_Multi_Switch.cpp:68:5: error: 'm_i2c' was not declared in this scope
     m_i2c->beginTransmission(m_devAddr);
     ^~~~~

exit status 1

Compilation error: exit status 1
</code>

Check your version of Wire.h, that it declares a class TwoWire.
On my system this file resides in
F:\Arduino\hardware\arduino\avr\libraries\Wire\src
maybe different for your system.

Later on you may have trouble with the I2C address 3. Valid I2C addresses reside above 8.

It was a brand new install of the IDE last week so I expect I have the latest versions. I could not find Wire.h using the library manager. Since I am using a SamD board, maybe it didn't think Wire.h should be loaded? My Grove 16x2 LCD uses I2C and it works fine.

I'll look for the Wire.h file. Doesn't the compiler give an error if one of the include files is missing? I got no error like that.

The Wire library is part of the standard Arduino board package and will not appear in Library Manager.

Most probably the standard file Wire.h is not missing on your system, but it misses the expected TwoWire class declaration. Find out how that class is named on your installation.

Have you tried the Seeed forum and/or support?

Yes, two days ago. No response yet.

Let me be more clear. I sent an email to their tech support two days ago and searched the forum and found one topic where someone had the same issue 4 months ago.

I just now sent tech support another email and replied to the topic that I was having the same problem. I never would have thought reading a DIP switch would be so difficult. This is the only I2C dip switch I could find to buy. The I2C fits my project well as I have few pins left and don't want to dedicate them to a dip switch.

I haven't found the Wire.h file yet either. I was hoping that someone would download the library and try to compile the example to verify the error. You don't need the switch to get the error, just hit the check mark.

On my portable IDE v1.18.19 installation, the wire library is here:
D:\arduino-1.8.19\portable\packages\arduino\hardware\samd\1.8.13\libraries\Wire

I believe your problem is that the definition of all the Arduino core classes for this board are encapsulated in a namespace called "arduino". For example, in wire.h:

namespace arduino {

class TwoWire : public HardwareI2C
{
  public:

The declaration of the Wire object occurs outside of this namespace (wire.h):

  extern arduino::TwoWire Wire;

That would be fine, but your Grove library tries to use a pointer to an object of the TwoWire class. Try modifying Grove_Multi_Switch.h:

 arduino::TwoWire* m_i2c;

@twesthoff is using an MKR NB 1500

Does that board have a different version of the Wire library than the AVR boards ?

1 Like

There was one occurrence of TwoWire* in the .h file.
I changed it to arduino::TwoWire* m_i2c;
Now I get these errors: 'TwoWire' does not name a type; did you mean 'TwoWire_h'? and 'm_i2c' was not declared in this scope.

I used the Windows file explorer to search for Wire.h and it didn't find any file of that name.

I don't know what to tell you. With this change to Grove_Multi_Switch.h, the example compiles for me.

    arduino::TwoWire *m_i2c;