From 11a9e9077421244836293fb96b1ee3f8a07c3b66 Mon Sep 17 00:00:00 2001 From: Terry Moore Date: Mon, 29 Nov 2021 22:58:19 +0100 Subject: [PATCH] Issue #323: major refactor of power, peripherals --- library.properties | 4 +- src/Catena.h | 144 ++++++++ src/Catena455x.h | 63 ++++ src/Catena4612.h | 94 ++++-- src/Catena461x.h | 16 +- src/CatenaBase.h | 501 ++++++++++++++++++++++++++++ src/CatenaBase_types.h | 5 + src/Catena_AppObjects.h | 262 +++++++++++++++ src/Catena_Flash.h | 21 +- src/Catena_Flash_at25sf081.h | 19 +- src/Catena_Mx25v8035f.h | 21 +- src/lib/Catena_Flash_at25sf081.cpp | 25 +- src/lib/Catena_setup.cpp | 374 +++++++++++++++++++++ src/lib/stm32/Catena_Mx25v8035f.cpp | 30 +- 14 files changed, 1517 insertions(+), 62 deletions(-) create mode 100644 src/Catena_AppObjects.h create mode 100644 src/lib/Catena_setup.cpp diff --git a/library.properties b/library.properties index 41be3ee..c91c404 100644 --- a/library.properties +++ b/library.properties @@ -1,11 +1,11 @@ name=MCCI Catena Arduino Platform -version=0.21.2 +version=0.23.0-pre1 author=Terry Moore, ChaeHee Won, Sungjoon Park, Dhinesh Kumar Pitchai maintainer=MCCI Corporation sentence=Arduino library for MCCI Catena 44xx, 45xx, 46xx and 48xx systems. paragraph=This library provides platform support for the MCCI Catena family of IoT systems, based on the Adafruit Feather M0 LoRa, or on the Murata LoRaWAN module. FRAM system configuration, generalized polling, and a number of low-level drivers are included for the peripherals that are included with the system. A non-blocking event-driven USB-serial command interface is also provided, along with a generalized command parsing framework. category=Other -architectures=samd,stm32 +architectures=* url=https://github.com/mcci-catena/Catena-Arduino-Platform dot_a_linkage=true includes=Catena.h diff --git a/src/Catena.h b/src/Catena.h index 6ffff97..4c14beb 100644 --- a/src/Catena.h +++ b/src/Catena.h @@ -104,9 +104,153 @@ class Catena : public CATENA_H_SUPER_ Catena(const Catena&&) = delete; Catena& operator=(const Catena&&) = delete; + /// + /// \brief implementation: set up everything on this particular board. + /// + /// \return \c true if setup was successful. + /// + virtual bool setup(void) override; + + virtual uint32_t enable_3v3Boost(bool fRequest) override + { + return this->m_3v3.enable(fRequest); + } + + virtual bool get_3v3BoostRequest() const override + { + return this->m_3v3.getRequest(); + } + + virtual bool has_3v3BoostControl() const override + { + return this->m_3v3.hasControl(); + } + + uint8_t has_screwTerminals() const override + { + return sizeof(this->m_screwTerminal) / sizeof(this->m_screwTerminal[0]); + } + + //virtual const char *get_screwTerminalLabel(uint8_t iTerminal) const override; + //virtual uint8_t get_screwTerminalPin2(uint8_t iTerminal) const override; + //virtual uint8_t get_screwTerminalPin3(uint8_t iTerminal) const override; + + virtual uint32_t enable_screwTerminalVdd(uint8_t iTerminal, bool fState) override + { + if (iTerminal < this->has_screwTerminals()) + return this->m_screwTerminal[iTerminal].enable(fState); + else + return 0; + } + virtual bool get_screwTerminalVddRequest(uint8_t iTerminal) override + { + if (iTerminal < this->has_screwTerminals()) + return this->m_screwTerminal[iTerminal].getRequest(); + else + return false; + } + virtual bool has_screwTerminalVddControl(uint8_t iTerminal) override + { + if (iTerminal < this->has_screwTerminals()) + return this->m_screwTerminal[iTerminal].hasControl(); + else + return false; + } + + virtual uint32_t enable_i2cVdd(bool fState) override + { + return this->m_i2cVdd.enable(fState); + } + virtual bool has_i2cVddControl() const override + { + return this->m_i2cVdd.hasControl(); + } + virtual bool get_i2cVddRequest() const override + { + return this->m_i2cVdd.getRequest(); + } + + virtual bool has_flash() const override; + + virtual cFlash *get_flash() const override; + + virtual SPIClass *get_flashBus() const override; + + virtual uint32_t enable_flashVdd(bool fState) override + { + return this->m_flashVdd.enable(fState); + } + virtual bool has_flashVddControl() const override + { + return this->m_flashVdd.hasControl(); + } + virtual bool get_flashVddRequest() const override + { + return this->m_flashVdd.getRequest(); + } + + /// \brief determine whether flash was successfully probed + bool get_flashFound() const + { + return this->m_flashFound; + } + + /// \brief record whether flash was successfully probed. + void set_flashFound(bool fFound) + { + this->m_flashFound = fFound; + } + + virtual bool has_fram() const override; + + // virtual cFram *getFram(void) override; + virtual uint32_t get_framSize() const override; + virtual ::TwoWire *get_framBus() const override; + + virtual uint32_t enable_framVdd(bool fStatus) override + { + return this->m_framVdd.enable(fStatus); + } + virtual bool has_framVddControl() const override + { + return this->m_framVdd.hasControl(); + } + virtual bool get_framVddRequest() const override + { + return this->m_framVdd.getRequest(); + } + + // virtual bool has_externalI2cBus() const override; + // virtual uint32_t enable_externalI2cBridgeVdd(bool fStatus) override; + // virtual bool get_externalI2cBridgeVddRequest() const override; + // virtual bool has_externalI2cBridgeVddControl() const override; + + // sensors -- these go in the individual files. + + // virtual bool has_BME280() const override; + // virtual bool has_BME680() const override; + // virtual bool has_HS3001() const override; + // virtual bool has_SHT3x() const override; + // virtual uint32_t enable_SHT3x(bool fStatus) override; + // virtual bool get_SHT3xRequest() const override; + // virtual bool has_SHT3xPowerControl() const override; + // virtual bool has_SGPC3() const override; + // virtual uint32_t enable_SGPC3(bool) override; + // virtual bool get_SGPC3Request() const override; + // virtual bool has_SGPC3PowerControl() const override; + // virtual bool has_PMS7003() const override; + // virtual uint32_t enable_PMS7003(bool fStatus) override; + // virtual bool get_PMS7003Request() const override; + // virtual bool has_PMS7003Control() const override; + // virtual bool has_Si1133() const override; + // virtual bool has_BH1750() const override; + // virtual bool get_PMS7003Request() const override; + protected: private: + /// \brief local routine to isolate the flash / download setup. + bool setup_flash(void); }; } // namespace McciCatena diff --git a/src/Catena455x.h b/src/Catena455x.h index c1bb0c2..d14877d 100644 --- a/src/Catena455x.h +++ b/src/Catena455x.h @@ -85,7 +85,70 @@ class Catena455x : public CatenaStm32L0 virtual float ReadVbat(void) const override; virtual float ReadVbus(void) const override; + virtual const char *get_screwTerminalLabel(uint8_t iTerminal) const override + { + static const char jp3[] = "JP3"; + static const char jp4[] = "JP4"; + return iTerminal == 0 ? jp3 : iTerminal == 1 ? jp4 : nullptr; + } + + virtual uint8_t get_screwTerminalPin2(uint8_t iTerminal) const override + { + return iTerminal == 0 ? D5 : iTerminal == 1 ? A1 : 0; + } + virtual uint8_t get_screwTerminalPin3(uint8_t iTerminal) const override + { + return iTerminal == 0 ? D12 : iTerminal == 1 ? A2 : 0; + } + + virtual bool has_BME280() const override + { return true; } + // virtual bool has_BME680() const override; + // virtual bool has_HS3001() const override; + // virtual bool has_SHT3x() const override; + // virtual uint32_t enable_SHT3x(bool fStatus) override; + // virtual bool get_SHT3xRequest() const override; + // virtual bool has_SHT3xPowerControl() const override; + // virtual bool has_SGPC3() const override; + // virtual uint32_t enable_SGPC3(bool) override; + // virtual bool get_SGPC3Request() const override; + // virtual bool has_SGPC3PowerControl() const override; + // virtual bool has_PMS7003() const override; + // virtual uint32_t enable_PMS7003(bool fStatus) override; + // virtual bool get_PMS7003Request() const override; + // virtual bool has_PMS7003Control() const override; + virtual bool has_Si1133() const override + { return true; } + // virtual bool has_BH1750() const override; + // virtual bool get_PMS7003Request() const override; + // virtual uint32_t enable_tcxo(bool fStatus) override; + // virtual bool get_tcxoRequest() const override; + // virtual bool has_txcoControl() const override; + virtual bool has_usbPort() const override + { + return true; + } + virtual bool get_consoleIsUsb() const override + { +#ifdef USBCON + return true; +#else + return false; +#endif + } + virtual bool has_usbVbusMeasurementStandard() const override + { return true; } + virtual uint8_t get_usbVbusMeasurementPin() const override + { return APIN_VBUS_SENSE; } + protected: + cPowerControlDummy m_3v3; + cPowerControlDummy m_flashVdd; + cPowerControlDummy m_screwTerminal[2]; + cPowerControlDummy m_i2cVdd; + cPowerControlDummy m_framVdd; + cPowerControlDummy m_externalI2cBridgeVdd; + cPowerControlDummy m_tcxo; private: }; diff --git a/src/Catena4612.h b/src/Catena4612.h index 0fdbf1b..bbf894b 100644 --- a/src/Catena4612.h +++ b/src/Catena4612.h @@ -1,5 +1,3 @@ -/* Catena4612.h Fri Dec 28 2018 13:58:18 chwon */ - /* Module: Catena4612.h @@ -7,31 +5,12 @@ Module: Catena4612.h Function: class Catena4612: CatenaBase Platform to represent a Catena 4612 -Version: - V0.13.0 Fri Dec 28 2018 13:58:19 chwon Edit level 2 - Copyright notice: - This file copyright (C) 2018 by - - MCCI Corporation - 3520 Krums Corners Road - Ithaca, NY 14850 - - An unpublished work. All rights reserved. - - This file is proprietary information, and may not be disclosed or - copied without the prior permission of MCCI Corporation + See accompanying license file. Author: ChaeHee Won, MCCI Corporation November 2018 -Revision history: - 0.11.0 Thu Nov 15 2018 15:07:23 chwon - Module created. - - 0.13.0 Fri Dec 28 2018 13:58:19 chwon - Add ReadVbat() and ReadVbus() override. - */ #ifndef _Catena4612_H_ /* prevent multiple includes */ @@ -65,6 +44,77 @@ class Catena4612 : public Catena461x virtual float ReadVbat(void) const override; virtual float ReadVbus(void) const override; + virtual const char *get_screwTerminalLabel(uint8_t iTerminal) const override + { + static const char jp4[] = "JP4"; + static const char jp5[] = "JP5"; + return iTerminal == 0 ? jp4 : iTerminal == 1 ? jp5 : nullptr; + } + + virtual uint8_t get_screwTerminalPin2(uint8_t iTerminal) const override + { + return iTerminal == 0 ? D5 : iTerminal == 1 ? A1 : 0; + } + virtual uint8_t get_screwTerminalPin3(uint8_t iTerminal) const override + { + return iTerminal == 0 ? D12 : iTerminal == 1 ? A2 : 0; + } + + virtual bool has_BME280() const override + { return true; } + // virtual bool has_BME680() const override; + // virtual bool has_HS3001() const override; + // virtual bool has_SHT3x() const override; + // virtual uint32_t enable_SHT3x(bool fStatus) override; + // virtual bool get_SHT3xRequest() const override; + // virtual bool has_SHT3xPowerControl() const override; + // virtual bool has_SGPC3() const override; + // virtual uint32_t enable_SGPC3(bool) override; + // virtual bool get_SGPC3Request() const override; + // virtual bool has_SGPC3PowerControl() const override; + // virtual bool has_PMS7003() const override; + // virtual uint32_t enable_PMS7003(bool fStatus) override; + // virtual bool get_PMS7003Request() const override; + // virtual bool has_PMS7003Control() const override; + virtual bool has_Si1133() const override + { return true; } + // virtual bool has_BH1750() const override; + // virtual bool get_PMS7003Request() const override; + virtual uint32_t enable_tcxo(bool fStatus) override + { return this->m_tcxo.enable(fStatus); } + virtual bool get_tcxoRequest() const override + { return this->m_tcxo.getRequest(); } + virtual bool has_tcxoControl() const override + { return this->m_tcxo.hasControl(); } + virtual bool has_usbPort() const override + { + return true; + } + virtual bool get_consoleIsUsb() const override + { +#ifdef USBCON + return true; +#else + return false; +#endif + } + virtual bool has_usbVbusMeasurementStandard() const override + { return true; } + virtual uint8_t get_usbVbusMeasurementPin() const override + { return APIN_VBUS_SENSE; } + +protected: + cPowerControlGPIO m_Vout1 = cPowerControlGPIO{ D10, 10 }; + cPowerControlGPIO m_Vout2 = cPowerControlGPIO{ D11, 10 }; + cPowerControlNested m_screwTerminal[2] = { cPowerControlNested{this->m_Vout1}, cPowerControlNested{this->m_Vout2} }; + cPowerControlGPIO m_PB8 = cPowerControlGPIO{ D33, 10 }; + cPowerControlNested m_3v3 = cPowerControlNested{ this->m_PB8 }; + cPowerControlNested m_tcxo = cPowerControlNested{ this->m_PB8 }; + cPowerControlDummy m_flashVdd; + cPowerControlDummy m_i2cVdd; + cPowerControlDummy m_framVdd; + cPowerControlDummy m_externalI2cBridgeVdd; + protected: // we are required to provide a table of platforms virtual void getPlatformTable( diff --git a/src/Catena461x.h b/src/Catena461x.h index fab9b7e..7f38aea 100644 --- a/src/Catena461x.h +++ b/src/Catena461x.h @@ -1,5 +1,3 @@ -/* Catena461x.h Fri Dec 28 2018 13:54:46 chwon */ - /* Module: Catena461x.h @@ -8,20 +6,8 @@ Module: Catena461x.h class Catena461x: CatenaBase Platform to represent a Catena 461x (4610, 4611, 4612, etc.) -Version: - V0.13.0 Fri Dec 28 2018 13:54:47 chwon Edit level 3 - Copyright notice: - This file copyright (C) 2018 by - - MCCI Corporation - 3520 Krums Corners Road - Ithaca, NY 14850 - - An unpublished work. All rights reserved. - - This file is proprietary information, and may not be disclosed or - copied without the prior permission of MCCI Corporation + See accompanying license file. Author: ChaeHee Won, MCCI Corporation November 2018 diff --git a/src/CatenaBase.h b/src/CatenaBase.h index 7996647..ccfffb2 100644 --- a/src/CatenaBase.h +++ b/src/CatenaBase.h @@ -130,6 +130,8 @@ Copyright notice: #define CATENA_ARDUINO_PLATFORM_VERSION_COMPARE_LE(a, b) \ (CATENA_ARDUINO_PLATFORM_VERSION_TO_INT(a) <= CATENA_ARDUINO_PLATFORM_VERSION_TO_INT(b)) +class TwoWire; // a forward reference. + /// /// \brief The common namespace for this library. /// @@ -229,6 +231,107 @@ constexpr bool operator!=(const Version_t& lhs, const Version_t& rhs){ return !( /* forward reference */ struct CATENA_PLATFORM; +class cPowerControl + { +public: + cPowerControl() {} + virtual uint32_t enable(bool fRequest) = 0; + virtual bool getRequest() const = 0; + virtual bool hasControl() const = 0; + }; + +class cPowerControlDummy : public cPowerControl + { +public: + virtual uint32_t enable(bool fRequest) override + { + if (fRequest) + ++this->m_count; + else + --this->m_count; + return 0; + } + virtual bool getRequest() const override + { + return this->m_count != 0; + } + virtual bool hasControl() const override + { + return false; + } + +private: + uint8_t m_count = 0; + }; + +class cPowerControlGPIO : public cPowerControl + { +public: + cPowerControlGPIO(uint8_t pin, uint16_t delayMs) + : m_delay(delayMs) + , m_pin(pin) + {} + virtual uint32_t enable(bool fRequest) override + { + if (fRequest) + ++this->m_count; + else + --this->m_count; + return 0; + } + virtual bool getRequest() const override + { + return this->m_count != 0; + } + virtual bool hasControl() const override + { + return false; + } + +private: + uint16_t m_delay; + uint8_t m_pin; + uint8_t m_count = 0; + }; + +class cPowerControlNested : public cPowerControl + { +public: + cPowerControlNested(cPowerControl &parent) + : m_parent(parent) + {} + virtual uint32_t enable(bool fRequest) override + { + uint8_t oldCount = this->m_count; + if (fRequest) + { + this->m_count = oldCount + 1; + if (oldCount == 0) + return this->m_parent.enable(true); + } + else + { + if (oldCount > 0) + this->m_count = oldCount - 1; + if (oldCount == 1) + return this->m_parent.enable(false); + } + return 0; + } + virtual bool getRequest() const override + { + return this->m_count != 0; + } + virtual bool hasControl() const override + { + return this->m_parent.hasControl(); + } + +private: + cPowerControl &m_parent; + uint8_t m_count = 0; + }; + /// /// \brief Base class for all Catena objects /// @@ -545,6 +648,391 @@ class CatenaBase /// virtual bool begin(void); + /// \defgroup setup Functions for dealing with Catena configuration variations. + /// \{ + + /// + /// \brief set up everything on this particaular board. + /// + /// \return \c true if setup was successful. + /// + virtual bool setup(void) = 0; + + //******************************************************************** + // + /// \defgroup 3v3boost Some Catenas have an on-board 3.3V boost regulator + // + //******************************************************************** + + /// \{ + + /// + /// \brief enable the on-board 3.3v boost regulator. Ignored if not supported. + /// + /// \param [in] fRequest \c true to request power, \c false to retract a previous + /// request. + /// + /// \return time (from millis()) when power will be ready. + /// + virtual uint32_t enable_3v3Boost(bool fRequest) = 0; + + /// + /// \brief return \c true if the on-board 3.3v boost regulator is enabled + /// + virtual bool get_3v3BoostRequest() const = 0; + + /// + /// \brief return \c true if there's control for an on-board 3.3v boost regulator + /// + virtual bool has_3v3BoostControl() const = 0; + + /// \} + + //******************************************************************** + /// + /// \defgroup screwterminals Most Catenas have one or more 4-pin screw + /// terminals. + /// + //******************************************************************** + + /// \{ + + /// + /// \brief query whether device has screw-terminal capability + /// + /// \return 0 if no screw terminals; otherwise number of 4-pin screw terminals + /// in standard Catena configuration. + /// + virtual uint8_t has_screwTerminals() const = 0; + + /// + /// \brief get label of screw terminal + /// + /// \return nullptr if iTerminal is out of range, otherwise label (like "JP4"). + virtual const char *get_screwTerminalLabel(uint8_t iTerminal) const = 0; + + /// + /// \brief get Arduino pin for screw terminal + /// + virtual uint8_t get_screwTerminalPin2(uint8_t iTerminal) const = 0; + + /// + /// \brief get Arduino pin for screw terminal + /// + virtual uint8_t get_screwTerminalPin3(uint8_t iTerminal) const = 0; + + /// + /// \brief enable power for screw terminal + /// + /// \return delay time in millis() until power will be ready. + /// + virtual uint32_t enable_screwTerminalVdd(uint8_t iTerminal, bool fState) = 0; + + /// + /// \brief query logical power enable for screw terminal + /// + /// \return requested state + /// + virtual bool get_screwTerminalVddRequest(uint8_t iTerminal) = 0; + + /// + /// \brief query whether there's power control for screw terminal. + /// + virtual bool has_screwTerminalVddControl(uint8_t iTerminal) = 0; + + /// \} + + //******************************************************************** + /// + /// \defgroup i2cinternal Most Catenas have an internal I2C bus; + /// these APIs control the power. + /// + //******************************************************************** + + /// \{ + + /// + /// \brief enable/disable power for I2C bus and associated peripherals + /// + /// Since the I2C bus has pullups, the entire bus has to be powered up or + /// down as a unit. If the pullups are not switchable on the target board, + /// the I2C should be brought up and left up during begin(), and this function + /// should be a no-op. + /// + /// The implementation should allow for multiple requests for the same power + /// supply, because typical boards share this supply with the flash chip. + /// + /// \return delay time until power is ready. + /// + virtual uint32_t enable_i2cVdd(bool) = 0; + + /// + /// \brief query whether there's power control for i2c + /// + virtual bool has_i2cVddControl() const = 0; + + /// + /// \brief query whether i2c Vdd is currently requested + /// + virtual bool get_i2cVddRequest() const = 0; + + /// \} + + //******************************************************************** + /// + /// \defgroup flash Many Catenas have an onboard flash. These APIs + /// control the power and abstract access. + /// + //******************************************************************** + + /// \{ + + virtual bool has_flash() const = 0; + + virtual cFlash *get_flash() const = 0; + + virtual SPIClass *get_flashBus() const = 0; + + virtual uint32_t enable_flashVdd(bool) = 0; + virtual bool has_flashVddControl() const = 0; + virtual bool get_flashVddRequest() const = 0; + + /// \brief determine whether flash was successfully probed + bool get_flashFound() const + { + return this->m_flashFound; + } + + /// \brief record whether flash was successfully probed. + void set_flashFound(bool fFound) + { + this->m_flashFound = fFound; + } + + /// \} + + //******************************************************************** + /// + /// \defgroup fram Most Catenas have an onboard FRAM. These APIs + /// control the power and abstract access. + /// + //******************************************************************** + + /// \{ + virtual bool has_fram() const = 0; + virtual uint32_t get_framSize() const = 0; + + virtual ::TwoWire *get_framBus() const = 0; + + virtual uint32_t enable_framVdd(bool) = 0; + virtual bool has_framVddControl() const = 0; + virtual bool get_framVddRequest() const = 0; + + /// \} + + //******************************************************************** + /// + /// \defgroup externali2c Some Catenas separate the external I2C from + /// the internal I2C via a powered mux. These APIs control the + /// external I2C, if it's present. + /// + //******************************************************************** + + /// \{ + + /// \brief query whether there's an external i2c + virtual bool has_externalI2cBus() const + { return false; } + + /// + /// \brief turn on power and access to to the external I2C + /// + /// \return number of millis() to wait for bus to be ready. + /// + virtual uint32_t enable_externalI2cBridgeVdd(bool fStatus) + { return 0; } + + /// + /// \brief query state of request for external I2C bus. + /// + virtual bool get_externalI2cBridgeVddRequest() const + { return false; } + + /// \brief query whether we can control the external I2C bus. + virtual bool has_externalI2cBridgeVddControl() const + { return false; } + + /// \} + + //******************************************************************** + /// + /// \defgroup tcxo Some LPWAN Catenas have a TCXO. These APIs give + /// access. By default, not present and APIs do nothing. + /// + //******************************************************************** + + /// \{ + /// \brief power up the TCXO; return number of milliseconds to delay. + virtual uint32_t enable_tcxo(bool fStatus) + { return 0; } + + /// + /// \brief query TCXO request state + virtual bool get_tcxoRequest() const + { return false; } + + /// \brief query whether TCXO control is part of the design + virtual bool has_tcxoControl() const + { return false; } + + /// \} + + //******************************************************************** + /// + /// \defgroup sensors Catenas have a variety of integrated sensors. + /// These APIs replace the platform flags used in order versions + /// of this library + /// + //******************************************************************** + + /// \{ + + /// \brief query whether there's a BME280 + virtual bool has_BME280() const + { return false; } + + /// \brief query whether there's a BME680 + virtual bool has_BME680() const + { return false; } + + /// \brief query whether there's an HS3001 + virtual bool has_HS3001() const + { return false; } + + /// \defgroup SHT3x These APIs relate to control of the SHT31/SHT35 + /// \{ + + /// \brief query whether there's an SHT31/35 + virtual bool has_SHT3x() const + { return false; } + + /// \brief enable power to the SHT31/35 + virtual uint32_t enable_SHT3x(bool fStatus) + { return 0; } + + /// \brief query whether the SHT31/35 power is requested + virtual bool get_SHT3xRequest() const + { return false; } + + /// \brief query whether the SHT31/35 power can be controlled + virtual bool has_SHT3xPowerControl() const + { return false; } + + /// \} SHT3x + + /// \defgroup SGPC3 These APIs relate to control of the SGPC3 + /// \{ + + /// \brief query whether there's an SGPC3 + virtual bool has_SGPC3() const + { return false; } + + /// \brief enable power to the SHT31/35 + virtual uint32_t enable_SGPC3(bool) + { return 0; } + + /// \brief query whether the SHT31/35 power is requested + virtual bool get_SGPC3Request() const + { return false; } + + /// \brief query whether the SHT31/35 power can be controlled + virtual bool has_SGPC3PowerControl() const + { return false; } + + /// \} SGPC3 + + /// \defgroup PMS7003 These APIs relate to control of the PMS7003 + /// \{ + + /// \brief query whether there's the interface for a PMS7003 + virtual bool has_PMS7003() const + { return false; } + + /// \brief enable power to the PMS7003 + /// + /// \return delay (in milllis) before proceeding. + /// + virtual uint32_t enable_PMS7003(bool) + { return 0; } + + /// \brief query whether the PMS7003 power is requested + virtual bool get_PMS7003Request() const + { return false; } + + virtual bool has_PMS7003Control() const + { return false; } + + /// \} PMS7003 + + /// \defgroup light These APIs relate to light sensors. + /// \{ + /// \brief query whether there's an Si1133 light sensor + virtual bool has_Si1133() const + { return false; } + /// \brief query whether design includes a BH1750 light sensor + virtual bool has_BH1750() const + { return false; } + + /// \} light + /// \} sensors + + //******************************************************************** + /// + /// \defgroup usb Many Catenas can have USB device ports. These APIs + /// query the configuration. + /// + //******************************************************************** + + /// \{ + + /// + /// \brief query whether platform has USB port. Note that USB might + /// not be configured in this build. + /// + virtual bool has_usbPort() const + { return false; } + + /// + /// \brief query configuration to see whether the console is configured + /// to use the USB port + /// + virtual bool get_consoleIsUsb() const + { return false; } + + /// + /// \brief query whether Vbus can be measured. + /// + /// Catenas designed prior to 2018 or so didn't consistently make + /// Vbus measurable. This API returns whether the measurement is a + /// standard feature. + /// + virtual bool has_usbVbusMeasurementStandard() const + { return false; } + + /// + /// \brief query the Vbus measurement pin. + /// + /// Even if Vbus measurement is not standard, Catenas with USB + /// often have pre-assigned pins where Vbus would be measured if + /// the appropriate resistor is stuffed. This API returns that pin, + /// or zero. + /// + virtual uint8_t get_usbVbusMeasurementPin() const + { return 0; } + + /// \} usb + + /// \} setup /// /// \brief return a pointer to string containing the name of this Catena board /// @@ -680,6 +1168,17 @@ class CatenaBase return this->m_appVersion; } + /// + /// \brief delay n millis while polling + /// + void delay(uint32_t nMillis) + { + auto const tStart = millis(); + + while (millis() - tStart < nMillis) + this->poll(); + } + protected: /// \brief set the application version void setAppVersion(Version_t v) @@ -740,6 +1239,8 @@ class CatenaBase /// \brief the command processor McciCatena::cCommandStream m_CommandStream; + bool m_flashFound = false; ///< set true if flash was probed. + private: uint32_t m_OperatingFlags; ///< the operating flags const CATENA_PLATFORM * m_pPlatform; ///< the platform pointer diff --git a/src/CatenaBase_types.h b/src/CatenaBase_types.h index 6df88e9..f155650 100644 --- a/src/CatenaBase_types.h +++ b/src/CatenaBase_types.h @@ -36,11 +36,16 @@ Revision history: #pragma once +class SPIClass; +class TwoWire; + namespace McciCatena { // the forward-reference scalar types from CatenaBase class CatenaBase; +class cFlash; + } /* namespace McciCatena */ /**** end of CatenaBase_types.h ****/ diff --git a/src/Catena_AppObjects.h b/src/Catena_AppObjects.h new file mode 100644 index 0000000..f803dfb --- /dev/null +++ b/src/Catena_AppObjects.h @@ -0,0 +1,262 @@ +/* + +Module: Catena_AppObjects.h + +Function: + Common application objects for use by Catena apps. + +Copyright and License: + This file copyright (C) 2021 by + + MCCI Corporation + 3520 Krums Corners Road + Ithaca, NY 14850 + + See accompanying LICENSE file for copyright and license information. + +Author: + Terry Moore, MCCI Corporation November 2021 + +*/ + +/// \file + +#ifndef _Catena_AppObjects_h_ +#define _Catena_AppObjects_h_ /* prevent multiple includes */ + +#pragma once + +#include +#include + +namespace McciCatena { + + /// + /// \brief the "second" SPI bus. + /// + extern SPIClass gSPI2; + + class cFlash; + class cDownload; + class cBootloaderApi; + class StatusLed; + + /// + /// \brief the primary on-board SPI flash device. + /// + /// \note We use a reference because it's otherwise ugly to refer to a global + /// of abstract type. + /// + extern cFlash &gFlash; + + /// + /// \brief the download object for the command processor. + /// + extern cDownload gDownload; + + /// + /// \brief the abstract wrapper for the main serial port. + /// + extern cSerial gSerial; + + /// + /// \brief the status LED + /// + extern StatusLed gLed; + + /// + /// \brief the bootloader API object + /// + extern cBootloaderApi gBootloaderApi; + +} // end namespace McciCatena + +#define CATENA_PLATFORM_FLASH_TYPE_UNSPECIFIED 0 +#define CATENA_PLATFORM_FLASH_TYPE_AS25SF081 1 +#define CATENA_PLATFORM_FLASH_TYPE_MX25V8035F 2 + + +// compute compile-time variables that are used to control things +// This parallels settings in Catena.h +#if defined(MCCI_CATENA_4450) +# define CATENA_PLATFORM_HAS_BOOTLOADER 0 +# define CATENA_PLATFORM_HAS_FLASH 0 +# define CATENA_PLATFORM_HAS_FRAM 1 +# define CATENA_PLATFORM_FRAM_SIZE 2048 +# define CATENA_PLATFORM_HAS_SPI2_AS_EXTERNAL 0 +# define CATENA_PLATFORM_HAS_DOWNLOAD 0 +#elif defined(MCCI_CATENA_4460) +# define CATENA_PLATFORM_HAS_BOOTLOADER 0 +# define CATENA_PLATFORM_HAS_FLASH 0 +# define CATENA_PLATFORM_HAS_FRAM 1 +# define CATENA_PLATFORM_FRAM_SIZE 2048 +# define CATENA_PLATFORM_HAS_SPI2_AS_EXTERNAL 0 +# define CATENA_PLATFORM_HAS_DOWNLOAD 0 +#elif defined(MCCI_CATENA_4470) +# define CATENA_PLATFORM_HAS_BOOTLOADER 0 +# define CATENA_PLATFORM_HAS_FLASH 1 +# define CATENA_PLATFORM_FLASH_TYPE CATENA_PLATFORM_FLASH_TYPE_AS25SF081 +# define CATENA_PLATFORM_HAS_FRAM 1 +# define CATENA_PLATFORM_FRAM_SIZE 2048 +# define CATENA_PLATFORM_HAS_DOWNLOAD 0 +# define CATENA_PLATFORM_HAS_SPI2_AS_EXTERNAL 0 +#elif defined(MCCI_CATENA_4410) +# define CATENA_PLATFORM_HAS_BOOTLOADER 0 +# define CATENA_PLATFORM_HAS_FLASH 0 +# define CATENA_PLATFORM_HAS_FRAM 0 +# define CATENA_PLATFORM_HAS_SPI2_AS_EXTERNAL 0 +# define CATENA_PLATFORM_HAS_DOWNLOAD 0 +#elif defined(MCCI_CATENA_4420) +# define CATENA_PLATFORM_HAS_BOOTLOADER 0 +# define CATENA_PLATFORM_HAS_FLASH 0 +# define CATENA_PLATFORM_HAS_FRAM 0 +# define CATENA_PLATFORM_HAS_SPI2_AS_EXTERNAL 0 +# define CATENA_PLATFORM_HAS_DOWNLOAD 0 +#elif defined(ARDUINO_MCCI_CATENA_4551) || defined(ARDUINO_CATENA_4551) +# define CATENA_PLATFORM_HAS_BOOTLOADER 0 +# define CATENA_PLATFORM_HAS_FLASH 1 +# define CATENA_PLATFORM_FLASH_TYPE CATENA_PLATFORM_FLASH_TYPE_MX25V8035F +# define CATENA_PLATFORM_HAS_FRAM 1 +# define CATENA_PLATFORM_FRAM_SIZE 8192 +# define CATENA_PLATFORM_HAS_DOWNLOAD 0 +# define CATENA_PLATFORM_HAS_SPI2_AS_EXTERNAL 1 +#elif defined(ARDUINO_MCCI_CATENA_4610) +# define CATENA_PLATFORM_HAS_BOOTLOADER 1 +# define CATENA_PLATFORM_HAS_FLASH 1 +# define CATENA_PLATFORM_FLASH_TYPE CATENA_PLATFORM_FLASH_TYPE_MX25V8035F +# define CATENA_PLATFORM_HAS_FRAM 1 +# define CATENA_PLATFORM_FRAM_SIZE 8192 +# define CATENA_PLATFORM_HAS_SPI2_AS_EXTERNAL 1 +# define CATENA_PLATFORM_HAS_DOWNLOAD 1 +#elif defined(ARDUINO_MCCI_CATENA_4611) +# define CATENA_PLATFORM_HAS_BOOTLOADER 1 +# define CATENA_PLATFORM_HAS_FLASH 1 +# define CATENA_PLATFORM_FLASH_TYPE CATENA_PLATFORM_FLASH_TYPE_MX25V8035F +# define CATENA_PLATFORM_HAS_FRAM 1 +# define CATENA_PLATFORM_FRAM_SIZE 8192 +# define CATENA_PLATFORM_HAS_SPI2_AS_EXTERNAL 1 +# define CATENA_PLATFORM_HAS_DOWNLOAD 1 +#elif defined(ARDUINO_MCCI_CATENA_4612) +# define CATENA_PLATFORM_HAS_BOOTLOADER 1 +# define CATENA_PLATFORM_HAS_FLASH 1 +# define CATENA_PLATFORM_FLASH_TYPE CATENA_PLATFORM_FLASH_TYPE_MX25V8035F +# define CATENA_PLATFORM_HAS_FRAM 1 +# define CATENA_PLATFORM_FRAM_SIZE 8192 +# define CATENA_PLATFORM_HAS_SPI2_AS_EXTERNAL 1 +# define CATENA_PLATFORM_HAS_DOWNLOAD 1 +#elif defined(ARDUINO_MCCI_CATENA_4617) +# define CATENA_PLATFORM_HAS_BOOTLOADER 1 +# define CATENA_PLATFORM_HAS_FLASH 1 +# define CATENA_PLATFORM_FLASH_TYPE CATENA_PLATFORM_FLASH_TYPE_MX25V8035F +# define CATENA_PLATFORM_HAS_FRAM 1 +# define CATENA_PLATFORM_FRAM_SIZE 8192 +# define CATENA_PLATFORM_HAS_SPI2_AS_EXTERNAL 1 +# define CATENA_PLATFORM_HAS_DOWNLOAD 1 +#elif defined(ARDUINO_MCCI_CATENA_4618) +# define CATENA_PLATFORM_HAS_BOOTLOADER 1 +# define CATENA_PLATFORM_HAS_FLASH 1 +# define CATENA_PLATFORM_FLASH_TYPE CATENA_PLATFORM_FLASH_TYPE_MX25V8035F +# define CATENA_PLATFORM_HAS_FRAM 1 +# define CATENA_PLATFORM_FRAM_SIZE 8192 +# define CATENA_PLATFORM_HAS_SPI2_AS_EXTERNAL 1 +# define CATENA_PLATFORM_HAS_DOWNLOAD 1 +#elif defined(ARDUINO_MCCI_CATENA_4630) +# define CATENA_PLATFORM_HAS_BOOTLOADER 1 +# define CATENA_PLATFORM_HAS_FLASH 1 +# define CATENA_PLATFORM_FLASH_TYPE CATENA_PLATFORM_FLASH_TYPE_MX25V8035F +# define CATENA_PLATFORM_HAS_FRAM 1 +# define CATENA_PLATFORM_FRAM_SIZE 8192 +# define CATENA_PLATFORM_HAS_SPI2_AS_EXTERNAL 1 +# define CATENA_PLATFORM_HAS_DOWNLOAD 1 +#elif defined(ARDUINO_MCCI_CATENA_4801) || defined(ARDUINO_CATENA_4801) +# define CATENA_PLATFORM_HAS_BOOTLOADER 1 +# define CATENA_PLATFORM_HAS_FLASH 1 +# define CATENA_PLATFORM_FLASH_TYPE CATENA_PLATFORM_FLASH_TYPE_MX25V8035F +# define CATENA_PLATFORM_HAS_FRAM 1 +# define CATENA_PLATFORM_FRAM_SIZE 2048 +# define CATENA_PLATFORM_HAS_SPI2_AS_EXTERNAL 1 +# define CATENA_PLATFORM_HAS_DOWNLOAD 1 +#elif defined(ARDUINO_MCCI_CATENA_4802) +# define CATENA_PLATFORM_HAS_BOOTLOADER 1 +# define CATENA_PLATFORM_HAS_FLASH 1 +# define CATENA_PLATFORM_FLASH_TYPE CATENA_PLATFORM_FLASH_TYPE_MX25V8035F +# define CATENA_PLATFORM_HAS_FRAM 1 +# define CATENA_PLATFORM_FRAM_SIZE 8192 +# define CATENA_PLATFORM_HAS_SPI2_AS_EXTERNAL 1 +# define CATENA_PLATFORM_HAS_DOWNLOAD 1 +#elif defined(ARDUINO_MCCI_CATENA_5001) +# define CATENA_PLATFORM_HAS_BOOTLOADER 1 +# define CATENA_PLATFORM_HAS_FLASH 1 +# define CATENA_PLATFORM_FLASH_TYPE CATENA_PLATFORM_FLASH_TYPE_MX25V8035F +# define CATENA_PLATFORM_HAS_FRAM 1 +# define CATENA_PLATFORM_FRAM_SIZE 8192 +# define CATENA_PLATFORM_HAS_SPI2_AS_EXTERNAL 1 +# define CATENA_PLATFORM_HAS_DOWNLOAD 1 +#elif defined(ARDUINO_SAMD_FEATHER_M0) +# define CATENA_PLATFORM_HAS_BOOTLOADER 0 +# define CATENA_PLATFORM_HAS_FLASH 0 +# define CATENA_PLATFORM_HAS_FRAM 0 +# define CATENA_PLATFORM_HAS_SPI2_AS_EXTERNAL 0 +# define CATENA_PLATFORM_HAS_DOWNLOAD 0 +#elif defined(ARDUINO_ARCH_SAMD) +# define CATENA_PLATFORM_HAS_BOOTLOADER 0 +# define CATENA_PLATFORM_HAS_FLASH 0 +# define CATENA_PLATFORM_HAS_FRAM 0 +# define CATENA_PLATFORM_HAS_SPI2_AS_EXTERNAL 0 +# define CATENA_PLATFORM_HAS_DOWNLOAD 0 +#elif defined(ARDUINO_ARCH_STM32) +# define CATENA_PLATFORM_HAS_BOOTLOADER 0 +# define CATENA_PLATFORM_HAS_FLASH 0 +# define CATENA_PLATFORM_HAS_FRAM 0 +# define CATENA_PLATFORM_HAS_SPI2_AS_EXTERNAL 0 +# define CATENA_PLATFORM_HAS_DOWNLOAD 0 +#else +# define CATENA_PLATFORM_HAS_BOOTLOADER 0 +# define CATENA_PLATFORM_HAS_FLASH 0 +# define CATENA_PLATFORM_HAS_FRAM 0 +# define CATENA_PLATFORM_HAS_SPI2_AS_EXTERNAL 0 +# define CATENA_PLATFORM_HAS_DOWNLOAD 0 +#endif + +// +// postcondition: CATENA_PLATFORM_HAS_BOOTLOADER, +// CATENA_PLATFORM_HAS_FLASH, CATENA_PLATFORM_FLASH_TYPE +// CATENA_PLATFORM_HAS_SPI2_AS_EXTERNAL, and CATENA_PLATFORM_HAS_DOWNLOAD are defiend +// +#ifndef CATENA_PLATFORM_HAS_BOOTLOADER +# define CATENA_PLATFORM_HAS_BOOTLOADER 0 +#endif + +#ifndef CATENA_PLATFORM_HAS_FLASH +# define CATENA_PLATFORM_HAS_FLASH 0 +#endif + +#ifndef CATENA_PLATFORM_FLASH_TYPE +# define CATENA_PLATFORM_FLASH_TYPE CATENA_PLATFORM_FLASH_TYPE_UNSPECIFIED +#endif + +#ifndef CATENA_PLATFORM_HAS_FRAM +# define CATENA_PLATFORM_HAS_FRAM 0 +#endif + +#ifndef CATENA_PLATFORM_FRAM_SIZE +# define CATENA_PLATFORM_FRAM_SIZE 0 +#endif + +#ifndef CATENA_PLATFORM_HAS_SPI2_AS_EXTERNAL +# define CATENA_PLATFORM_HAS_SPI2_AS_EXTERNAL 0 +#endif + +#ifndef CATENA_PLATFORM_HAS_DOWNLOAD +# define CATENA_PLATFORM_HAS_DOWNLOAD 0 +#endif + +// +// error checking +// +#if CATENA_PLATFORM_HAS_DOWNLOAD && !(CATENA_PLATFORM_HAS_BOOTLOADER && CATENA_PLATFORM_HAS_FLASH) +# error CATENA_PLATFORM_HAS_DOWNLOAD requires CATENA_PLATFORM_HAS_BOOTLOADER and CATENA_PLATFORM_HAS_FLASH +#endif + + +#endif /* _Catena_AppObjects_h_ */ diff --git a/src/Catena_Flash.h b/src/Catena_Flash.h index 9de11f5..5462ec2 100644 --- a/src/Catena_Flash.h +++ b/src/Catena_Flash.h @@ -57,17 +57,28 @@ class cFlash // public methods /// - /// \brief initialize flash driver + /// \brief initialize flash driver with pin. /// /// \param[in] pSpi pointer to SPI bus for this flash device. - /// \param[in] ChipSelectPin pin to be used as chip-select for this flash device. + /// \param[in] ChipSelectPin pin to be used as chip-select for this flash device, or + /// -1 to defer assignment. /// - virtual bool begin(SPIClass *pSpi, uint8_t ChipSelectPin) = 0; + virtual bool begin(SPIClass *pSpi, int16_t ChipSelectPin) = 0; /// - /// \brief get default chip-select pin + /// \brief initialize flash driver using default chip select. /// - virtual uint8_t getDefaultChipSelectPin() const = 0; + /// \param[in] pSpi pointer to SPI bus for this flash device. + /// + /// The default chip select pin from instantiation is used (or the call returns failure if + /// no pin was provided). + /// + virtual bool begin(SPIClass *pSpi) = 0; + + /// + /// \brief get chip-select pin + /// + virtual uint8_t getChipSelectPin() const = 0; /// /// \brief stop the flash driver diff --git a/src/Catena_Flash_at25sf081.h b/src/Catena_Flash_at25sf081.h index b9620f4..989bf29 100644 --- a/src/Catena_Flash_at25sf081.h +++ b/src/Catena_Flash_at25sf081.h @@ -230,6 +230,17 @@ class cFlash_AT25SF081 : public cFlash cFlash_AT25SF081() : m_Initialized(false) , m_registered(false) + , m_csInitialized(false) + {} + + /// + /// \brief the constructor with CS pin provided. + /// + cFlash_AT25SF081(uint8_t ChipSelectPin) + : m_CS(ChipSelectPin) + , m_csInitialized(true) + , m_Initialized(false) + , m_registered(false) {} // uses default destructor @@ -241,12 +252,13 @@ class cFlash_AT25SF081 : public cFlash cFlash_AT25SF081& operator=(const cFlash_AT25SF081&&) = delete; // set up and probe device - virtual bool begin(SPIClass *pSpi, uint8_t ChipSelectPin) override; + virtual bool begin(SPIClass *pSpi) override; + virtual bool begin(SPIClass *pSpi, int16_t ChipSelectPin) override; /// \brief the default chip select pin for this device is D5 - virtual uint8_t getDefaultChipSelectPin() const override + virtual uint8_t getChipSelectPin() const override { - return 5; + return this->m_CS; } // stop using device; use begin() to restart. @@ -414,6 +426,7 @@ class cFlash_AT25SF081 : public cFlash bool m_Initialized; bool m_registered; bool m_PowerDown; + bool m_csInitialized; uint8_t m_CS; SPIClass * m_pSpi; uint32_t m_nesting; diff --git a/src/Catena_Mx25v8035f.h b/src/Catena_Mx25v8035f.h index b6c519e..0d9b448 100644 --- a/src/Catena_Mx25v8035f.h +++ b/src/Catena_Mx25v8035f.h @@ -137,6 +137,13 @@ class Catena_Mx25v8035f : public cFlash , m_registered(false) {} + Catena_Mx25v8035f(uint8_t ChipSelectPin) + : m_CS(ChipSelectPin) + , m_csInitialized(true) + , m_Initialized(false) + , m_registered(false) + {} + // neither copyable nor movable Catena_Mx25v8035f(const Catena_Mx25v8035f&) = delete; Catena_Mx25v8035f& operator=(const Catena_Mx25v8035f&) = delete; @@ -144,13 +151,14 @@ class Catena_Mx25v8035f : public cFlash Catena_Mx25v8035f& operator=(const Catena_Mx25v8035f&&) = delete; // set up and probe device - virtual bool begin(SPIClass *pSpi, uint8_t ChipSelectPin) override; + virtual bool begin(SPIClass *pSpi) override; + virtual bool begin(SPIClass *pSpi, int16_t ChipSelectPin) override; virtual void end(void) override; /// \brief the default chip select pin for this type of flash is D19 - virtual uint8_t getDefaultChipSelectPin() const override + virtual uint8_t getChipSelectPin() const override { - return D19; + return this->m_CS; } // reset chip @@ -189,9 +197,10 @@ class Catena_Mx25v8035f : public cFlash virtual void powerUp(void) override; private: - boolean m_Initialized; - boolean m_PowerDown; - boolean m_registered; + bool m_Initialized; + bool m_PowerDown; + bool m_registered; + bool m_csInitialized; uint8_t m_CS; SPIClass * m_pSpi; diff --git a/src/lib/Catena_Flash_at25sf081.cpp b/src/lib/Catena_Flash_at25sf081.cpp index e983399..1c1e7a3 100644 --- a/src/lib/Catena_Flash_at25sf081.cpp +++ b/src/lib/Catena_Flash_at25sf081.cpp @@ -28,7 +28,7 @@ Name: cFlash_AT25SF081::begin() Definition: bool cFlash_AT25SF081::begin( SPIClass *pSpi, - uint8_t ChipSelectPin + int16_t ChipSelectPin ); Description: @@ -41,7 +41,12 @@ Name: cFlash_AT25SF081::begin() */ -bool cFlash_AT25SF081::begin(SPIClass *pSpi, uint8_t ChipSelectPin) +bool cFlash_AT25SF081::begin(SPIClass *pSpi) + { + return this->begin(pSpi, -1); + } + +bool cFlash_AT25SF081::begin(SPIClass *pSpi, int16_t ChipSelectPin) { uint8_t ManufacturerId; uint16_t DeviceId; @@ -56,8 +61,21 @@ bool cFlash_AT25SF081::begin(SPIClass *pSpi, uint8_t ChipSelectPin) return false; } + if (ChipSelectPin == -1 && this->m_CS == -1) + { + gLog.printf(cLog::kError, "flash pin not set\n"); + return false; + } + else if (! (-1 <= ChipSelectPin && ChipSelectPin <= UINT8_MAX)) + { + gLog.printf(cLog::kError, "flash pin out of range: 0x%x\n", ChipSelectPin); + return false; + } + this->m_pSpi = pSpi; - this->m_CS = ChipSelectPin; + if (ChipSelectPin != -1) + this->m_CS = ChipSelectPin; + digitalWrite(ChipSelectPin, HIGH); pinMode(ChipSelectPin, OUTPUT); @@ -102,7 +120,6 @@ bool cFlash_AT25SF081::begin(SPIClass *pSpi, uint8_t ChipSelectPin) return fResult; } - /* Name: cFlash_AT25SF081::reset diff --git a/src/lib/Catena_setup.cpp b/src/lib/Catena_setup.cpp new file mode 100644 index 0000000..addf6cd --- /dev/null +++ b/src/lib/Catena_setup.cpp @@ -0,0 +1,374 @@ +/* + +Module: Catena_setup.cpp + +Function: + Implmentation of the app framework objects + +Copyright and License: + This file copyright (C) 2021 by + + MCCI Corporation + 3520 Krums Corners Road + Ithaca, NY 14850 + + See accompanying LICENSE file for copyright and license information. + +Author: + Terry Moore, MCCI Corporation November 2021 + +*/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace McciCatena; + +/****************************************************************************\ +| +| Manifest constants & typedefs. +| +\****************************************************************************/ + +#if CATENA_PLATFORM_HAS_FLASH && CATENA_PLATFORM_HAS_BOOTLOADER + + // forward reference to the command function + static cCommandStream::CommandFn cmdUpdate; + +#endif + + +/****************************************************************************\ +| +| Read-only data. +| +\****************************************************************************/ + + + +/****************************************************************************\ +| +| Variables. +| +\****************************************************************************/ + +#if CATENA_PLATFORM_HAS_FLASH +# if CATENA_PLATFORM_FLASH_TYPE == CATENA_PLATFORM_FLASH_TYPE_AS25SF081 + +# include + static cFlash_AT25SF081 sFlash_AT25SF081(D5); + cFlash &McciCatena::gFlash = sFlash_AT25SF081; + +# elif CATENA_PLATFORM_FLASH_TYPE == CATENA_PLATFORM_FLASH_TYPE_MX25V8035F + +# include + static Catena_Mx25v8035f sFlash_Mx25v8035f(D19); + cFlash &McciCatena::gFlash = sFlash_Mx25v8035f; + +# endif +#endif + +#if CATENA_PLATFORM_HAS_BOOTLOADER +cBootloaderApi McciCatena::gBootloaderApi; +#endif + +#if CATENA_PLATFORM_HAS_FLASH && CATENA_PLATFORM_HAS_BOOTLOADER +cDownload McciCatena::gDownload; + +// the individual commmands are put in this table +static const cCommandStream::cEntry sDownloadCommmands[] = + { + { "fallback", cmdUpdate }, + { "update", cmdUpdate }, + // other commands go here.... + }; + +/* a top-level structure wraps the above and connects to the system table */ +/* it optionally includes a "first word" so you can for sure avoid name clashes */ +static cCommandStream::cDispatch +sDownloadCommands_top( + sDownloadCommmands, /* this is the pointer to the table */ + sizeof(sDownloadCommmands), /* this is the size of the table */ + "system" /* this is the "first word" for all the commands in this table */ + ); +#endif + +/* instantiate the standard status light */ +StatusLed McciCatena::gLed (LED_BUILTIN); + +#if CATENA_PLATFORM_HAS_SPI2_AS_EXTERNAL + +/* instantiate SPI */ +SPIClass McciCatena::gSPI2( + Catena::PIN_SPI2_MOSI, + Catena::PIN_SPI2_MISO, + Catena::PIN_SPI2_SCK + ); + +#endif + +/* instantiate a serial object */ +cSerial McciCatena::gSerial(Serial); + +/****************************************************************************\ +| +| Code. +| +\****************************************************************************/ + + +/* + +Name: Catena::setup() + +Function: + Set up a Catena. + +Definition: + bool Catena::setup( + void + ); + +Description: + This function does the platform-specific work for all the canonical Catena + peripherals for a given platform. + +Returns: + true for success. + +Notes: + + +*/ + +#define FUNCTION "Catena::setup" + +bool +Catena::setup( + void + ) + { + /// TODO(tmm@mcci.com) this should really be in begin(). + delay(this->enable_3v3Boost(true)); + delay(this->enable_i2cVdd(true)); + + this->begin(); + + /* register the LED */ + gLed.begin(); + this->registerObject(&gLed); + + auto const OperatingFlags = this->GetOperatingFlags(); + + /* do the serial port raindance */ + if (! (OperatingFlags & static_cast(Catena::OPERATING_FLAGS::fUnattended))) + { + if (this->get_consoleIsUsb()) + { + while (! Serial.dtr()) + yield(); + } + } + + Serial.begin(115200); + +#if CATENA_PLATFORM_HAS_DOWNLOAD + /* add our application-specific commands */ + this->addCommands( + /* name of app dispatch table, passed by reference */ + sDownloadCommands_top, + /* + || optionally a context pointer using static_cast(). + || normally only libraries (needing to be reentrant) need + || to use the context pointer. + */ + nullptr + ); +#endif + + this->setup_flash(); + + if (this->get_flashFound()) + { +#if CATENA_PLATFORM_HAS_DOWNLOAD + gDownload.begin(gFlash, gBootloaderApi); +#endif + } + + // always successful + return true; + } + +#undef FUNCTION + +bool Catena::setup_flash(void) + { + this->set_flashFound(false); + +#if CATENA_PLATFORM_HAS_FLASH + auto const pFlashSpi = this->get_flashBus(); + if (pFlashSpi == nullptr) + return false; + + auto &flashSpi = *pFlashSpi; + + gLog.printf(cLog::kInfo, "Init Flash\n"); + flashSpi.begin(); + + if (gFlash.begin(&flashSpi)) + { + uint8_t ManufacturerId; + uint16_t DeviceId; + + gFlash.readId(&ManufacturerId, &DeviceId); + gLog.printf( + cLog::kInfo, + "FLASH found, ManufacturerId=%02x, DeviceId=%04x\n", + ManufacturerId, DeviceId + ); + + this->set_flashFound(true); + } + else + { + gFlash.end(); + flashSpi.end(); + gLog.printf( + cLog::kError, + "No Flash chip found, wiring problem?\n" + ); + } +#endif + + return this->get_flashFound(); + } + +bool Catena::has_flash() const + { + return CATENA_PLATFORM_HAS_FLASH; + } + +cFlash *Catena::get_flash() const + { + #if ! CATENA_PLATFORM_HAS_FLASH + return nullptr; + #else + return &gFlash; + #endif + } + +SPIClass *Catena::get_flashBus() const + { + #if ! CATENA_PLATFORM_HAS_FLASH + return nullptr; + #elif CATENA_PLATFORM_HAS_SPI2_AS_EXTERNAL + return &gSPI2; + #else + return SPI; + #endif + } + +bool Catena::has_fram() const + { + return CATENA_PLATFORM_HAS_FRAM; + } + +uint32_t Catena::get_framSize() const + { + return CATENA_PLATFORM_FRAM_SIZE; + } + +::TwoWire *Catena::get_framBus() const + { + #if ! CATENA_PLATFORM_HAS_FRAM + return nullptr; + #else + return &Wire; + #endif + } + +#if CATENA_PLATFORM_HAS_FLASH && CATENA_PLATFORM_HAS_BOOTLOADER + +/* process "update" / "fallback" -- args are ignored */ +// argv[0] is "update"/"fallbck" +// argv[1..argc-1] are the (ignored) arguments +static cCommandStream::CommandStatus cmdUpdate( + cCommandStream *pThis, + void *pContext, + int argc, + char **argv + ) + { + pThis->printf( + "Update firmware: echo off, timeout %d seconds\n", + (cDownload::kTransferTimeoutMs + 500) / 1000 + ); + + struct context_t + { + cCommandStream *pThis; + bool fWorking; + cDownload::Status_t status; + cCommandStream::CommandStatus cmdStatus; + cDownload::Request_t request; + }; + + context_t context { pThis, true }; + + auto doneFn = + [](void *pUserData, cDownload::Status_t status) -> void + { + context_t * const pCtx = (context_t *)pUserData; + + cCommandStream * const pThis = pCtx->pThis; + cCommandStream::CommandStatus cmdStatus; + + cmdStatus = cCommandStream::CommandStatus::kSuccess; + + if (status != cDownload::Status_t::kSuccessful) + { + pThis->printf( + "download error, status %u\n", + unsigned(status) + ); + cmdStatus = cCommandStream::CommandStatus::kIoError; + } + + pCtx->cmdStatus = cmdStatus; + pCtx->fWorking = false; + }; + + if (gDownload.evStartSerialDownload( + argv[0][0] == 'u' ? cDownload::DownloadRq_t::GetUpdate + : cDownload::DownloadRq_t::GetFallback, + gSerial, + context.request, + doneFn, + (void *) &context) + ) + { + while (context.fWorking) + Catena::pCatenaBase->poll(); + + return context.cmdStatus; + } + + pThis->printf( + "download launch failure\n" + ); + + return cCommandStream::CommandStatus::kInternalError; + } + +#endif /* CATENA_PLATFORM_HAS_FLASH && CATENA_PLATFORM_HAS_BOOTLOADER */ + +/**** end of Catena_setup.cpp ****/ diff --git a/src/lib/stm32/Catena_Mx25v8035f.cpp b/src/lib/stm32/Catena_Mx25v8035f.cpp index 3e81e51..9b4f90b 100644 --- a/src/lib/stm32/Catena_Mx25v8035f.cpp +++ b/src/lib/stm32/Catena_Mx25v8035f.cpp @@ -45,8 +45,9 @@ Revision history: #include #include - +#include #include "CatenaBase.h" + using namespace McciCatena; /****************************************************************************\ @@ -81,7 +82,7 @@ Name: Catena_Mx25v8035f::begin Definition: boolean Catena_Mx25v8035f::begin( SPIClass *pSpi, - uint8_t ChipSelectPin + int16_t ChipSelectPin ); Description: @@ -92,9 +93,16 @@ Name: Catena_Mx25v8035f::begin */ +bool Catena_Mx25v8035f::begin( + SPIClass *pSpi + ) + { + return this->begin(pSpi, -1); + } + bool Catena_Mx25v8035f::begin( SPIClass *pSpi, - uint8_t ChipSelectPin + int16_t ChipSelectPin ) { uint8_t ManufacturerId; @@ -104,12 +112,24 @@ bool Catena_Mx25v8035f::begin( if (pSpi == NULL) { // invalid parameter - Serial.println("pSpi is NULL"); + gLog.printf(cLog::kError, "pSpi is NULL\n"); + return false; + } + + if (ChipSelectPin == -1 && this->m_CS == -1) + { + gLog.printf(cLog::kError, "flash pin not set\n"); + return false; + } + else if (! (-1 <= ChipSelectPin && ChipSelectPin <= UINT8_MAX)) + { + gLog.printf(cLog::kError, "flash pin out of range: 0x%x\n", ChipSelectPin); return false; } this->m_pSpi = pSpi; - this->m_CS = ChipSelectPin; + if (ChipSelectPin != -1) + this->m_CS = ChipSelectPin; pSpi->beginTransaction(this->m_CS, SpiSettings);