mirror of
https://github.com/eried/portapack-mayhem.git
synced 2024-12-24 23:09:26 -05:00
5020e5bd28
I2C shell implementation.
108 lines
5.2 KiB
C++
108 lines
5.2 KiB
C++
/*
|
|
* Copyright (C) 2024 HTotoo.
|
|
*
|
|
* This file is part of PortaPack.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; see the file COPYING. If not, write to
|
|
* the Free Software Foundation, Inc., 51 Franklin Street,
|
|
* Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#ifndef __I2CDEVMANAGER_H__
|
|
#define __I2CDEVMANAGER_H__
|
|
|
|
#include <cstdint>
|
|
#include <vector>
|
|
#include <memory>
|
|
#include "ch.h"
|
|
#include "portapack.hpp"
|
|
#include "i2c_pp.hpp"
|
|
#include "i2cdevlist.hpp"
|
|
#include "event_m0.hpp"
|
|
|
|
#define i2cbus portapack::i2c0
|
|
|
|
extern I2C portapack::i2c0;
|
|
|
|
namespace i2cdev {
|
|
|
|
// The device class. You'll derive your from this. Override init() and update();
|
|
class I2cDev {
|
|
public:
|
|
virtual ~I2cDev(){};
|
|
virtual bool init(uint8_t addr); // returns true if it is that that device we are looking for.
|
|
virtual void update() = 0; // override this, and you'll be able to query your device and broadcast the result to the system
|
|
|
|
void set_update_interval(uint8_t interval); // sets the device's update interval in sec. if you change it, don't forget to change back to it's original value after you finished!
|
|
uint8_t get_update_interval(); // gets the device's update interval in sec
|
|
|
|
bool i2c_read(uint8_t* reg, uint8_t reg_size, uint8_t* data, uint8_t bytes); // if want to read without register addr, just set reg_size to 0. this way can read 8, or 16 or 32 bit registers too. reg_size in bytes! returns true on succes. handles the errcnt automatically!
|
|
bool i2c_write(uint8_t* reg, uint8_t reg_size, uint8_t* data, uint8_t bytes); // if want to write without register addr, just set reg_size to 0. this way can read 8, or 16 or 32 bit registers too. reg_size in bytes! returns true on succes. handles the errcnt automatically!
|
|
|
|
// helpers for easier i2c communication
|
|
uint8_t read8_1(uint8_t reg);
|
|
bool write8_1(uint8_t reg, uint8_t data);
|
|
uint16_t read16_1(uint8_t reg);
|
|
int16_t readS16_1(uint8_t reg);
|
|
uint16_t read16_LE_1(uint8_t reg);
|
|
int16_t readS16_LE_1(uint8_t reg);
|
|
uint32_t read24_1(uint8_t reg);
|
|
|
|
bool need_del = false; // device can self destruct, and re-init when new scan discovers it
|
|
I2C_DEVMDL model = I2CDEVMDL_NOTSET; // overwrite it in the init()!!!
|
|
uint8_t query_interval = 5; // in seconds. can be overriden in init() if necessary
|
|
protected:
|
|
void got_error(); // i2c communication will call this when communication was not ok. you can call it from any part of your code too.
|
|
void got_success(); // i2c communication will call this when the communication was ok. you can call it from any part of your code too.
|
|
|
|
uint8_t addr = 0; // some devices can have different addresses, so we store what was it wound with
|
|
uint8_t errcnt = 0; // error count during communication. if it reaches a threshold set need_del to remove itself from the device list
|
|
};
|
|
|
|
// store for the devices. may not have a driver if not supported
|
|
class I2DevListElement {
|
|
public:
|
|
uint8_t addr = 0; // i2c addr of the device
|
|
std::unique_ptr<I2cDev> dev = nullptr; // device driver if any
|
|
};
|
|
|
|
class I2CDevManager {
|
|
public:
|
|
static void init(); // creates the thread, and sets an one time full scan
|
|
static void manual_scan(); // it'll init a forced device scan in the thread's next cycle. (1sec max)
|
|
static void set_autoscan_interval(uint16_t interval); // 0 no auto scan, other values: seconds
|
|
static uint16_t get_autoscan_interval();
|
|
static I2cDev* get_dev_by_addr(uint8_t addr); // caller function needs to cast to the specific device!
|
|
static I2cDev* get_dev_by_model(I2C_DEVMDL model); // caller function needs to cast to the specific device!
|
|
static std::vector<I2C_DEVMDL> get_dev_list_by_model(); // returns the currently discovered
|
|
static std::vector<uint8_t> get_gev_list_by_addr(); // returns the currently discovered
|
|
static void setEventDispatcher(EventDispatcher* ed) { _eventDispatcher = ed; }
|
|
static EventDispatcher* get_event_dispatcher() { return _eventDispatcher; }
|
|
|
|
private:
|
|
static uint16_t scan_interval;
|
|
static bool force_scan; // if set to true, on hte next run it'll do an i2c scan, ONCE
|
|
static std::vector<I2DevListElement> devlist;
|
|
|
|
static bool found(uint8_t addr); // returns true on any new device. also initializes the driver if there is a suitable one
|
|
static bool scan(); // return true on any change (delete or found new)
|
|
static void create_thread();
|
|
static msg_t timer_fn(void* arg);
|
|
static Thread* thread;
|
|
static Mutex mutex_list;
|
|
static EventDispatcher* _eventDispatcher;
|
|
};
|
|
}; // namespace i2cdev
|
|
|
|
#endif |