0.1.0 M5ROTATE8

This commit is contained in:
Rob Tillaart 2023-08-06 11:40:50 +02:00
parent 32b114e1b6
commit f367ed836c
18 changed files with 878 additions and 0 deletions

View File

@ -0,0 +1,27 @@
platforms:
rpipico:
board: rp2040:rp2040:rpipico
package: rp2040:rp2040
gcc:
features:
defines:
- ARDUINO_ARCH_RP2040
warnings:
flags:
packages:
rp2040:rp2040:
url: https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json
compile:
# Choosing to run compilation tests on 2 different Arduino platforms
platforms:
- uno
# - due
# - zero
# - leonardo
- m4
- esp32
# - esp8266
# - mega2560
- rpipico

View File

@ -0,0 +1,4 @@
# These are supported funding model platforms
github: RobTillaart

View File

@ -0,0 +1,13 @@
name: Arduino-lint
on: [push, pull_request]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: arduino/arduino-lint-action@v1
with:
library-manager: update
compliance: strict

View File

@ -0,0 +1,17 @@
---
name: Arduino CI
on: [push, pull_request]
jobs:
runTest:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: ruby/setup-ruby@v1
with:
ruby-version: 2.6
- run: |
gem install arduino_ci
arduino_ci.rb

View File

@ -0,0 +1,18 @@
name: JSON check
on:
push:
paths:
- '**.json'
pull_request:
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: json-syntax-check
uses: limitusus/json-syntax-check@v1
with:
pattern: "\\.json$"

View File

@ -0,0 +1,10 @@
# Change Log M5ROTATE8
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
## [0.1.0] - 2023-08-03
- initial version

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2023-2023 Rob Tillaart
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.

View File

@ -0,0 +1,114 @@
[![Arduino CI](https://github.com/RobTillaart/M5ROTATE8/workflows/Arduino%20CI/badge.svg)](https://github.com/marketplace/actions/arduino_ci)
[![Arduino-lint](https://github.com/RobTillaart/M5ROTATE8/actions/workflows/arduino-lint.yml/badge.svg)](https://github.com/RobTillaart/M5ROTATE8/actions/workflows/arduino-lint.yml)
[![JSON check](https://github.com/RobTillaart/M5ROTATE8/actions/workflows/jsoncheck.yml/badge.svg)](https://github.com/RobTillaart/M5ROTATE8/actions/workflows/jsoncheck.yml)
[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/RobTillaart/M5ROTATE8/blob/master/LICENSE)
[![GitHub release](https://img.shields.io/github/release/RobTillaart/M5ROTATE8.svg?maxAge=3600)](https://github.com/RobTillaart/M5ROTATE8/releases)
# M5ROTATE8
Arduino library for M5 8ROTATE 8x rotary encoders.
## Description
**Experimental**
M5ROTATE8 is an Arduino class to read the 8 rotary encoders of the
M5 8ENCODER module.
It also provides means to write RGB values to the 8 LED's in the same module.
The rotary encoders can be read as an absolute counter (since start) or as an relative counter (since last time read).
The value can be both positive and negative.
The absolute counter can be given an initial value.
The counters can be reset per channel.
The library can also read the key pressed status of every rotary encoder.
Finally the library can set the RGB value of the 8 LEDS.
No tests with hardware have been done yet, so use with care.
Feedback welcome!
#### I2C
The address range is in theory from 0..127, however the I2C specification
states it should be between 8 and 119 as some addresses are reserved.
The default address is 0x41.
TODO to what clock does it work?
| clock | works |
|:-------:|:-------:|
| 100 KHz | |
| 200 KHz | |
| 400 KHz | |
| 600 KHz | |
| 800 KHz | |
#### Related
- https://github.com/RobTillaart/M5ANGLE8
## Interface
```cpp
#include "m5rotate8.h"
```
- **M5ROTATE8(uint8_t address = M5ROTATE8_DEFAULT_ADDRESS, TwoWire \*wire = &Wire)** constructor.
Default address = 0x41, default Wire.
- **bool begin(int sda, int scl)** ESP32 et al.
- **bool begin()** initialize I2C, check if connected.
- **bool isConnected()** checks if address is on the I2C bus.
- **bool setAddress(uint8_t address = M5ROTATE8_DEFAULT_ADDRESS)** set a new address for the device.
Default address = 0x41.
- **uint8_t getAddress()** convenience function.
- **uint8_t getVersion()** get firmware version from device.
#### IO part
- **int32_t getAbsCounter(uint8_t channel)**
Read a absolute position of the rotary encoder since reset or start.
- **void setAbsCounter(uint8_t channel, int32_t value);
- **int32_t getRelCounter(uint8_t channel)**
Read a relative position of the rotary encoder since reset.
Note: this counter will reset after each read.
- **bool getKeyPressed(uint8_t channel)** get key status of the rotary encoder.
True is pressed.
- **bool resetCounter(uint8_t channel)** reset a rotary encoder.
- **void resetAll()** reset all counters to 0.
- **uint8_t inputSwitch()** read status of the switch.
- **bool writeRGB(uint8_t channel, uint8_t R, uint8_t G, uint8_t B)** Set the RGB value of a LED.
- **bool allOff()** switches all LEDs off.
## Future
#### Must
- improve documentation
- test with hardware
- keep in sync with M5ANGLE8 where possible.
#### Should
- error handling
- optimize low level calls
- merge into two functions => read/write array + length.
- resetAll() could be "one call"
#### Could
- add examples
- add unit tests
- check performance
- **uint32_t readRGB(uint8_t channel)**
- write/readAllRGB() ? less overhead?
#### Wont (unless)

View File

@ -0,0 +1,94 @@
//
// FILE: M5ROTATE8_performance.ino
// AUTHOR: Rob Tillaart
// PURPOSE: meansurement performance
// URL: https://github.com/RobTillaart/M5ROTATE8
#include "m5rotate8.h"
M5ROTATE8 MM;
uint32_t start, stop;
uint16_t x;
void setup()
{
Serial.begin(115200);
Serial.print("M5ROTATE8_LIB_VERSION: ");
Serial.println(M5ROTATE8_LIB_VERSION);
delay(100);
Wire.begin();
MM.begin();
start = micros();
for (int ch = 0; ch < 8; ch++)
{
MM.writeRGB(ch, 128, 128, 128);
}
stop = micros();
Serial.print("writeRGB:\t");
Serial.println((stop - start) / 8.0);
delay(100);
start = micros();
MM.allOff();
stop = micros();
Serial.print("allOff:\t");
Serial.println(stop - start);
delay(100);
start = micros();
x = MM.inputSwitch();
stop = micros();
Serial.print("inputSwitch:\t");
Serial.println(stop - start);
delay(100);
start = micros();
x = MM.getAbsCounter(3);
stop = micros();
Serial.print("getAbsCounter:\t");
Serial.println(stop - start);
delay(100);
start = micros();
x = MM.getRelCounter(5);
stop = micros();
Serial.print("getRelCounter:\t");
Serial.println(stop - start);
delay(100);
start = micros();
x = MM.getKeyPressed(7);
stop = micros();
Serial.print("getKeyPressed:\t");
Serial.println(stop - start);
delay(100);
start = micros();
MM.setAbsCounter(1, 1000);
stop = micros();
Serial.print("setAbsCounter:\t");
Serial.println(stop - start);
delay(100);
start = micros();
x = MM.resetCounter(1);
stop = micros();
Serial.print("resetCounter:\t");
Serial.println(stop - start);
delay(100);
Serial.println("\ndone...");
}
void loop()
{
}
// -- END OF FILE --

View File

@ -0,0 +1,38 @@
//
// FILE: M5ROTATE8_demo_abs_counter.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo
// URL: https://github.com/RobTillaart/M5ROTATE8
#include "m5rotate8.h"
M5ROTATE8 MM;
void setup()
{
Serial.begin(115200);
Serial.print("M5ROTATE8_LIB_VERSION: ");
Serial.println(M5ROTATE8_LIB_VERSION);
delay(100);
Wire.begin();
MM.begin();
}
void loop()
{
for (int ch = 0; ch < 8; ch++)
{
Serial.print(MM.getAbsCounter(ch));
Serial.print("\t");
Serial.print(MM.getKeyPressed(ch));
Serial.print("\n");
delay(125);
}
}
// -- END OF FILE --

View File

@ -0,0 +1,39 @@
//
// FILE: M5ROTATE8_demo_rel_counter.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo
// URL: https://github.com/RobTillaart/M5ROTATE8
#include "m5rotate8.h"
M5ROTATE8 MM;
void setup()
{
Serial.begin(115200);
Serial.print("M5ROTATE8_LIB_VERSION: ");
Serial.println(M5ROTATE8_LIB_VERSION);
delay(100);
Wire.begin();
MM.begin();
}
void loop()
{
for (int ch = 0; ch < 8; ch++)
{
Serial.print(MM.getRelCounter(ch));
Serial.print("\t");
Serial.print(MM.getKeyPressed(ch));
Serial.print("\n");
delay(125);
}
}
// -- END OF FILE --

View File

@ -0,0 +1,38 @@
//
// FILE: M5ROTATE8_led_demo.ino
// AUTHOR: Rob Tillaart
// PURPOSE: demo
// URL: https://github.com/RobTillaart/M5ROTATE8
#include "m5rotate8.h"
M5ROTATE8 MM;
void setup()
{
Serial.begin(115200);
Serial.print("M5ROTATE8_LIB_VERSION: ");
Serial.println(M5ROTATE8_LIB_VERSION);
delay(100);
Wire.begin();
MM.begin();
}
void loop()
{
for (int ch = 0; ch < 8; ch++)
{
Serial.println(ch);
MM.writeRGB(ch, 0, 0, 255);
delay(125);
MM.writeRGB(ch, 0, 0, 0);
delay(125);
}
}
// -- END OF FILE --

View File

@ -0,0 +1,34 @@
# Syntax Colouring Map For M5ROTATE8
# Data types (KEYWORD1)
M5ROTATE8 KEYWORD1
# Methods and Functions (KEYWORD2)
begin KEYWORD2
isConnected KEYWORD2
setAddress KEYWORD2
getAddress KEYWORD2
getVersion KEYWORD2
getAbsCounter KEYWORD2
setAbsCounter KEYWORD2
getRelCounter KEYWORD2
getKeyPressed KEYWORD2
resetCounter KEYWORD2
resetAll KEYWORD2
inputSwitch KEYWORD2
writeRGB KEYWORD2
allOff KEYWORD2
# Constants (LITERAL1)
M5ROTATE8_LIB_VERSION LITERAL1
M5ROTATE8_DEFAULT_ADDRESS LITERAL1
M5ROTATE8_OK LITERAL1
M5ROTATE8_ERR_CHANNEL LITERAL1
M5ROTATE8_ERROR LITERAL1

View File

@ -0,0 +1,23 @@
{
"name": "M5ROTATE8",
"keywords": "M5ROTATE8,rotary,encoder,8encoder",
"description": "Arduino library for M5 8ROTATE 8x rotary encoders.",
"authors":
[
{
"name": "Rob Tillaart",
"email": "Rob.Tillaart@gmail.com",
"maintainer": true
}
],
"repository":
{
"type": "git",
"url": "https://github.com/RobTillaart/M5ROTATE8"
},
"version": "0.1.0",
"license": "MIT",
"frameworks": "*",
"platforms": "*",
"headers": "M5ROTATE8.h"
}

View File

@ -0,0 +1,11 @@
name=M5ROTATE8
version=0.1.0
author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=Arduino library for M5 8ROTATE 8x rotary encoders
paragraph=8EnCoder
category=Signal Input/Output
url=https://github.com/RobTillaart/M5ROTATE8
architectures=*
includes=m5rotate8.h
depends=

View File

@ -0,0 +1,257 @@
//
// FILE: m5rotate8.cpp
// AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// PURPOSE: Arduino library for M5 8ROTATE 8x rotary encoders
// URL: https://github.com/RobTillaart/M5ROTATE8
#include "m5rotate8.h"
#define M5ROTATE8_REG_ADDRESS 0xFF
#define M5ROTATE8_REG_VERSION 0xFE
#define M5ROTATE8_REG_BASE_ABS 0x00
#define M5ROTATE8_REG_BASE_REL 0x20
#define M5ROTATE8_REG_BASE_RESET 0x40
#define M5ROTATE8_REG_BASE_BUTTON 0x50
#define M5ROTATE8_REG_SWITCH 0x60
#define M5ROTATE8_REG_RGB 0x70
M5ROTATE8::M5ROTATE8(uint8_t address, TwoWire *wire)
{
_address = address;
_wire = wire;
}
#if defined (ESP8266) || defined(ESP32)
bool M5ROTATE8::begin(int dataPin, int clockPin)
{
_wire = &Wire;
if ((dataPin < 255) && (clockPin < 255))
{
_wire->begin(dataPin, clockPin);
} else {
_wire->begin();
}
if (! isConnected()) return false;
return true;
}
#endif
bool M5ROTATE8::begin()
{
_wire->begin();
if (! isConnected()) return false;
return true;
}
bool M5ROTATE8::isConnected()
{
_wire->beginTransmission(_address);
return (_wire->endTransmission() == 0);
}
bool M5ROTATE8::setAddress(uint8_t address)
{
_address = address;
write8(M5ROTATE8_REG_ADDRESS, _address);
return isConnected();
}
uint8_t M5ROTATE8::getAddress()
{
return _address;
}
uint8_t M5ROTATE8::getVersion()
{
return read8(M5ROTATE8_REG_VERSION);
}
////////////////////////////////////////////////
//
// INPUT PART
//
int32_t M5ROTATE8::getAbsCounter(uint8_t channel)
{
// if (channel > 7)
// {
// return M5ROTATE8_ERR_CHANNEL;
// }
return read32(M5ROTATE8_REG_BASE_ABS + (channel << 2));
}
bool M5ROTATE8::setAbsCounter(uint8_t channel, int32_t value)
{
// if (channel > 7)
// {
// return M5ROTATE8_ERR_CHANNEL;
// }
return write32(M5ROTATE8_REG_BASE_ABS + (channel << 2), value);
}
int32_t M5ROTATE8::getRelCounter(uint8_t channel)
{
// if (channel > 7)
// {
// return M5ROTATE8_ERR_CHANNEL;
// }
return read32(M5ROTATE8_REG_BASE_REL + (channel << 2));
}
bool M5ROTATE8::getKeyPressed(uint8_t channel)
{
if (channel > 7)
{
return false;
}
return read8(M5ROTATE8_REG_BASE_BUTTON + channel);
}
bool M5ROTATE8::resetCounter(uint8_t channel)
{
if (channel > 7)
{
return false;
}
write8(M5ROTATE8_REG_BASE_RESET + channel, 1);
return true;
}
void M5ROTATE8::resetAll()
{
for (int channel = 0; channel < 8; channel++)
{
write8(M5ROTATE8_REG_BASE_RESET + channel, 1);
}
}
uint8_t M5ROTATE8::inputSwitch()
{
return read8(M5ROTATE8_REG_SWITCH);
}
bool M5ROTATE8::writeRGB(uint8_t channel, uint8_t R, uint8_t G, uint8_t B)
{
if (channel > 7)
{
return false;
}
write24(M5ROTATE8_REG_RGB + (channel * 3), R, G, B);
return true;
}
bool M5ROTATE8::allOff()
{
for (uint8_t ch = 0; ch < 8; ch++)
{
write24(M5ROTATE8_REG_RGB + (ch * 3), 0, 0, 0);
}
return true;
}
////////////////////////////////////////////////
//
// PRIVATE
//
bool M5ROTATE8::write8(uint8_t reg, uint8_t value)
{
_wire->beginTransmission(_address);
_wire->write(reg);
_wire->write(value);
_error = _wire->endTransmission();
return (_error == 0);
}
uint8_t M5ROTATE8::read8(uint8_t reg)
{
_wire->beginTransmission(_address);
_wire->write(reg);
_error = _wire->endTransmission();
if (_error != 0)
{
// error handling
return 0;
}
if (_wire->requestFrom(_address, (uint8_t)1) != 1)
{
// error handling
return 0;
}
return _wire->read();
}
bool M5ROTATE8::write24(uint8_t reg, uint8_t R, uint8_t G, uint8_t B)
{
_wire->beginTransmission(_address);
_wire->write(reg);
_wire->write(R);
_wire->write(G);
_wire->write(B);
_error = _wire->endTransmission();
return (_error == 0);
}
bool M5ROTATE8::write32(uint8_t reg, uint32_t value)
{
_wire->beginTransmission(_address);
_wire->write(reg);
_wire->write(value & 0xFF);
value >>= 8;
_wire->write(value & 0xFF);
value >>= 8;
_wire->write(value & 0xFF);
value >>= 8;
_wire->write(value);
_error = _wire->endTransmission();
return (_error == 0);
}
uint32_t M5ROTATE8::read32(uint8_t reg)
{
_wire->beginTransmission(_address);
_wire->write(reg);
_error = _wire->endTransmission();
if (_error != 0)
{
// error handling
return 0;
}
if (_wire->requestFrom(_address, (uint8_t)1) != 1)
{
// error handling
return 0;
}
uint32_t value = 0;
value += (_wire->read());
value += (((uint32_t)_wire->read()) << 8 );
value += (((uint32_t)_wire->read()) << 16);
value += (((uint32_t)_wire->read()) << 24);
return value;
}
// -- END OF FILE --

View File

@ -0,0 +1,69 @@
#pragma once
//
// FILE: m5rotate8.h
// AUTHOR: Rob Tillaart
// VERSION: 0.1.0
// PURPOSE: Arduino library for M5 8ROTATE 8x rotary encoders
// URL: https://github.com/RobTillaart/M5ROTATE8
#include "Arduino.h"
#include "Wire.h"
#define M5ROTATE8_LIB_VERSION (F("0.1.0"))
#define M5ROTATE8_DEFAULT_ADDRESS 0x41
// prelim error handling
#define M5ROTATE8_OK 0x0000
#define M5ROTATE8_ERR_CHANNEL 0xFF00
#define M5ROTATE8_ERROR 0xFFFF
class M5ROTATE8
{
public:
M5ROTATE8(uint8_t address = M5ROTATE8_DEFAULT_ADDRESS, TwoWire *wire = &Wire);
#if defined (ESP8266) || defined(ESP32)
bool begin(int sda, int scl);
#endif
bool begin();
bool isConnected();
bool setAddress(uint8_t address = M5ROTATE8_DEFAULT_ADDRESS);
uint8_t getAddress();
uint8_t getVersion();
// IO PART
// channel = 0..7
int32_t getAbsCounter(uint8_t channel);
bool setAbsCounter(uint8_t channel, int32_t value);
int32_t getRelCounter(uint8_t channel);
bool getKeyPressed(uint8_t channel);
bool resetCounter(uint8_t channel);
void resetAll();
uint8_t inputSwitch();
// channel = 0..7
// R,G,B = 0..255
bool writeRGB(uint8_t channel, uint8_t R, uint8_t G, uint8_t B);
bool allOff();
private:
uint8_t _address;
int _error;
TwoWire* _wire;
bool write8(uint8_t reg, uint8_t value);
uint8_t read8(uint8_t reg);
bool write24(uint8_t reg, uint8_t R, uint8_t G, uint8_t B);
bool write32(uint8_t reg, uint32_t value);
uint32_t read32(uint8_t reg);
};
// -- END OF FILE --

View File

@ -0,0 +1,51 @@
//
// FILE: unit_test_001.cpp
// AUTHOR: Rob Tillaart
// DATE: 2023-08-03
// PURPOSE: unit tests for the M5ROTATE8 library
// https://github.com/RobTillaart/M5ROTATE8
// https://github.com/Arduino-CI/arduino_ci/blob/master/REFERENCE.md
//
// supported assertions
// ----------------------------
// assertEqual(expected, actual)
// assertNotEqual(expected, actual)
// assertLess(expected, actual)
// assertMore(expected, actual)
// assertLessOrEqual(expected, actual)
// assertMoreOrEqual(expected, actual)
// assertTrue(actual)
// assertFalse(actual)
// assertNull(actual)
#include <ArduinoUnitTests.h>
#include "Arduino.h"
#include "m5rotate8.h"
unittest_setup()
{
fprintf(stderr, "M5ROTATE8_LIB_VERSION: %s\n", (char *) M5ROTATE8_LIB_VERSION);
}
unittest_teardown()
{
}
unittest(test_constructor)
{
M5ROTATE8 MM;
assertEqual(1, 1);
}
unittest_main()
// -- END OF FILE --