diff --git a/lib/CMT2300a/cmt2300a_params_900.h b/lib/CMT2300a/cmt2300a_params_900.h new file mode 100644 index 000000000..70722b246 --- /dev/null +++ b/lib/CMT2300a/cmt2300a_params_900.h @@ -0,0 +1,216 @@ +/* +;--------------------------------------- +; CMT2300A Configuration File +; Generated by CMOSTEK RFPDK 1.46 +; 2023.03.17 23:16 +;--------------------------------------- +; Mode = Advanced +; Part Number = CMT2300A +; Frequency = 900.000 MHz +; Xtal Frequency = 26.0000 MHz +; Demodulation = GFSK +; AGC = On +; Data Rate = 20.0 kbps +; Deviation = 20.0 kHz +; Tx Xtal Tol. = 20 ppm +; Rx Xtal Tol. = 20 ppm +; TRx Matching Network Type = 20 dBm +; Tx Power = +13 dBm +; Gaussian BT = 0.5 +; Bandwidth = Auto-Select kHz +; CDR Type = Counting +; CDR DR Range = NA +; AFC = On +; AFC Method = Auto-Select +; Data Representation = 0:F-low 1:F-high +; Rx Duty-Cycle = Off +; Tx Duty-Cycle = Off +; Sleep Timer = Off +; Sleep Time = NA +; Rx Timer = Off +; Rx Time T1 = NA +; Rx Time T2 = NA +; Rx Exit State = STBY +; Tx Exit State = STBY +; SLP Mode = Disable +; RSSI Valid Source = PJD +; PJD Window = 8 Jumps +; LFOSC Calibration = On +; Xtal Stable Time = 155 us +; RSSI Compare TH = NA +; Data Mode = Packet +; Whitening = Disable +; Whiten Type = NA +; Whiten Seed Type = NA +; Whiten Seed = NA +; Manchester = Disable +; Manchester Type = NA +; FEC = Enable +; FEC Type = x^3+x^2+1 +; Tx Prefix Type = 0 +; Tx Packet Number = 1 +; Tx Packet Gap = 32 +; Packet Type = Variable Length +; Node-Length Position = First Node, then Length +; Payload Bit Order = Start from msb +; Preamble Rx Size = 2 +; Preamble Tx Size = 30 +; Preamble Value = 170 +; Preamble Unit = 8-bit +; Sync Size = 4-byte +; Sync Value = 1296587336 +; Sync Tolerance = None +; Sync Manchester = Disable +; Node ID Size = NA +; Node ID Value = NA +; Node ID Mode = None +; Node ID Err Mask = Disable +; Node ID Free = Disable +; Payload Length = 32 +; CRC Options = IBM-16 +; CRC Seed = 0 crc_seed +; CRC Range = Entire Payload +; CRC Swap = Start from MSB +; CRC Bit Invert = Normal +; CRC Bit Order = Start from bit 15 +; Dout Mute = Off +; Dout Adjust Mode = Disable +; Dout Adjust Percentage = NA +; Collision Detect = Off +; Collision Detect Offset = NA +; RSSI Detect Mode = At PREAM_OK +; RSSI Filter Setting = 32-tap +; RF Performance = High +; LBD Threshold = 2.4 V +; RSSI Offset = 0 +; RSSI Offset Sign = 0 +*/ +#ifndef __CMT2300A_PARAMS_900_H +#define __CMT2300A_PARAMS_900_H + +#include "cmt2300a_defs.h" +#include + +#define CMT_BASE_FREQ_900 900000000 + +/* [CMT Bank] with RSSI offset of +- 0 (and Tx power double bit not set) */ +static uint8_t g_cmt2300aCmtBank_900[CMT2300A_CMT_BANK_SIZE] = { +0x00, +0x66, +0xEC, +0x1C, +0x70, +0x80, +0x14, +0x08, +0x11, +0x02, +0x02, +0x00, +}; + +/* [System Bank] */ +static uint8_t g_cmt2300aSystemBank_900[CMT2300A_SYSTEM_BANK_SIZE] = { +0xAE, +0xE0, +0x35, +0x00, +0x00, +0xF4, +0x10, +0xE2, +0x42, +0x20, +0x0C, +0x81, +}; + +/* [Frequency Bank] 900 MHz */ +static uint8_t g_cmt2300aFrequencyBank_900[CMT2300A_FREQUENCY_BANK_SIZE] = { +0x45, +0x46, +0x0A, +0x84, +0x45, +0x3B, +0xB1, +0x13, +}; + +/* [Data Rate Bank] */ +static uint8_t g_cmt2300aDataRateBank_900[CMT2300A_DATA_RATE_BANK_SIZE] = { +0xA6, +0xC9, +0x20, +0x20, +0xD2, +0x35, +0x0C, +0x0B, +0x9F, +0x4B, +0x29, +0x29, +0xC0, +0x14, +0x05, +0x53, +0x10, +0x00, +0xB4, +0x00, +0x00, +0x01, +0x00, +0x00, +}; + +/* [Baseband Bank] - EU */ +static uint8_t g_cmt2300aBasebandBank_900[CMT2300A_BASEBAND_BANK_SIZE] = { +0x12, +0x1E, +0x00, +0xAA, +0x06, +0x00, +0x00, +0x00, +0x00, +0x48, +0x5A, +0x48, +0x4D, +0x01, +0x1F, +0x00, +0x00, +0x00, +0x00, +0x00, +0xC3, +0x00, +0x00, +0x60, +0xFF, +0x00, +0x00, +0x1F, +0x10, +}; + +/* [Tx Bank] 13 dBm */ +static uint8_t g_cmt2300aTxBank_900[CMT2300A_TX_BANK_SIZE] = { +0x70, +0x4D, +0x06, +0x00, +0x07, +0x50, +0x00, +0x53, +0x09, +0x3F, +0x7F, +}; + +#endif diff --git a/lib/CMT2300a/cmt2300wrapper.cpp b/lib/CMT2300a/cmt2300wrapper.cpp index 5096d0768..cf0b503b3 100644 --- a/lib/CMT2300a/cmt2300wrapper.cpp +++ b/lib/CMT2300a/cmt2300wrapper.cpp @@ -5,6 +5,7 @@ #include "cmt2300wrapper.h" #include "cmt2300a.h" #include "cmt2300a_params_860.h" +#include "cmt2300a_params_900.h" CMT2300A::CMT2300A(uint8_t pin_sdio, uint8_t pin_clk, uint8_t pin_cs, uint8_t pin_fcs, uint32_t spi_speed) { @@ -244,7 +245,25 @@ bool CMT2300A::rxFifoAvailable() uint32_t CMT2300A::getBaseFrequency() { - return CMT_BASE_FREQ_860; // from Frequency Bank in cmt2300a_params.h + switch (_countryMode) { + case CountryFrequency_t::MODE_900: + return CMT_BASE_FREQ_900; + break; + default: + return CMT_BASE_FREQ_860; + break; + } +} + +CountryFrequency_t CMT2300A::getCountryMode() const +{ + return _countryMode; +} + +void CMT2300A::setCountryMode(const CountryFrequency_t mode) +{ + _countryMode = mode; + _init_radio(); } void CMT2300A::flush_rx(void) @@ -266,12 +285,24 @@ bool CMT2300A::_init_radio() } /* config registers */ - CMT2300A_ConfigRegBank(CMT2300A_CMT_BANK_ADDR, g_cmt2300aCmtBank_860, CMT2300A_CMT_BANK_SIZE); - CMT2300A_ConfigRegBank(CMT2300A_SYSTEM_BANK_ADDR, g_cmt2300aSystemBank_860, CMT2300A_SYSTEM_BANK_SIZE); - CMT2300A_ConfigRegBank(CMT2300A_FREQUENCY_BANK_ADDR, g_cmt2300aFrequencyBank_860, CMT2300A_FREQUENCY_BANK_SIZE); - CMT2300A_ConfigRegBank(CMT2300A_DATA_RATE_BANK_ADDR, g_cmt2300aDataRateBank_860, CMT2300A_DATA_RATE_BANK_SIZE); - CMT2300A_ConfigRegBank(CMT2300A_BASEBAND_BANK_ADDR, g_cmt2300aBasebandBank_860, CMT2300A_BASEBAND_BANK_SIZE); - CMT2300A_ConfigRegBank(CMT2300A_TX_BANK_ADDR, g_cmt2300aTxBank_860, CMT2300A_TX_BANK_SIZE); + switch (_countryMode) { + case CountryFrequency_t::MODE_900: + CMT2300A_ConfigRegBank(CMT2300A_CMT_BANK_ADDR, g_cmt2300aCmtBank_900, CMT2300A_CMT_BANK_SIZE); + CMT2300A_ConfigRegBank(CMT2300A_SYSTEM_BANK_ADDR, g_cmt2300aSystemBank_900, CMT2300A_SYSTEM_BANK_SIZE); + CMT2300A_ConfigRegBank(CMT2300A_FREQUENCY_BANK_ADDR, g_cmt2300aFrequencyBank_900, CMT2300A_FREQUENCY_BANK_SIZE); + CMT2300A_ConfigRegBank(CMT2300A_DATA_RATE_BANK_ADDR, g_cmt2300aDataRateBank_900, CMT2300A_DATA_RATE_BANK_SIZE); + CMT2300A_ConfigRegBank(CMT2300A_BASEBAND_BANK_ADDR, g_cmt2300aBasebandBank_900, CMT2300A_BASEBAND_BANK_SIZE); + CMT2300A_ConfigRegBank(CMT2300A_TX_BANK_ADDR, g_cmt2300aTxBank_900, CMT2300A_TX_BANK_SIZE); + break; + default: + CMT2300A_ConfigRegBank(CMT2300A_CMT_BANK_ADDR, g_cmt2300aCmtBank_860, CMT2300A_CMT_BANK_SIZE); + CMT2300A_ConfigRegBank(CMT2300A_SYSTEM_BANK_ADDR, g_cmt2300aSystemBank_860, CMT2300A_SYSTEM_BANK_SIZE); + CMT2300A_ConfigRegBank(CMT2300A_FREQUENCY_BANK_ADDR, g_cmt2300aFrequencyBank_860, CMT2300A_FREQUENCY_BANK_SIZE); + CMT2300A_ConfigRegBank(CMT2300A_DATA_RATE_BANK_ADDR, g_cmt2300aDataRateBank_860, CMT2300A_DATA_RATE_BANK_SIZE); + CMT2300A_ConfigRegBank(CMT2300A_BASEBAND_BANK_ADDR, g_cmt2300aBasebandBank_860, CMT2300A_BASEBAND_BANK_SIZE); + CMT2300A_ConfigRegBank(CMT2300A_TX_BANK_ADDR, g_cmt2300aTxBank_860, CMT2300A_TX_BANK_SIZE); + break; + } // xosc_aac_code[2:0] = 2 uint8_t tmp; diff --git a/lib/CMT2300a/cmt2300wrapper.h b/lib/CMT2300a/cmt2300wrapper.h index 601ebfc28..56f25c35b 100644 --- a/lib/CMT2300a/cmt2300wrapper.h +++ b/lib/CMT2300a/cmt2300wrapper.h @@ -7,6 +7,12 @@ #define FH_OFFSET 100 // value * CMT2300A_ONE_STEP_SIZE = channel frequency offset #define CMT_SPI_SPEED 4000000 // 4 MHz +enum CountryFrequency_t { + MODE_860, + MODE_900, + CountryFrequency_Max, +}; + class CMT2300A { public: CMT2300A(uint8_t pin_sdio, uint8_t pin_clk, uint8_t pin_cs, uint8_t pin_fcs, uint32_t _spi_speed = CMT_SPI_SPEED); @@ -87,6 +93,9 @@ class CMT2300A { uint32_t getBaseFrequency(); + CountryFrequency_t getCountryMode() const; + void setCountryMode(const CountryFrequency_t mode); + /** * Empty the RX (receive) FIFO buffers. */ @@ -110,4 +119,6 @@ class CMT2300A { int8_t _pin_cs; int8_t _pin_fcs; uint32_t _spi_speed; + + CountryFrequency_t _countryMode = CountryFrequency_t::MODE_860; }; diff --git a/lib/Hoymiles/src/HoymilesRadio_CMT.cpp b/lib/Hoymiles/src/HoymilesRadio_CMT.cpp index 6e0211a66..96dd597d5 100644 --- a/lib/Hoymiles/src/HoymilesRadio_CMT.cpp +++ b/lib/Hoymiles/src/HoymilesRadio_CMT.cpp @@ -23,10 +23,14 @@ uint8_t HoymilesRadio_CMT::getChannelFromFrequency(const uint32_t frequency) con frequency / 1000000.0, getMinFrequency() / 1000000.0, getMaxFrequency() / 1000000.0); return 0xFF; // ERROR } - if (frequency < 863000000 || frequency > 870000000) { + if (_radio->getCountryMode() == CountryFrequency_t::MODE_860 && (frequency < 863000000 || frequency > 870000000)) { Hoymiles.getMessageOutput()->printf("!!! caution: %.2f MHz is out of EU legal range! (863 - 870 MHz)\r\n", frequency / 1000000.0); } + if (_radio->getCountryMode() == CountryFrequency_t::MODE_900 && (frequency < 902000000 || frequency > 928000000)) { + Hoymiles.getMessageOutput()->printf("!!! caution: %.2f MHz is out of North America legal range! (902 - 928 MHz)\r\n", + frequency / 1000000.0); + } return (frequency - _radio->getBaseFrequency()) / getChannelWidth(); // frequency to channel } @@ -197,10 +201,28 @@ uint32_t HoymilesRadio_CMT::getChannelWidth() return FH_OFFSET * CMT2300A_ONE_STEP_SIZE; } -uint32_t HoymilesRadio_CMT::getInvBootFrequency() +CountryFrequency_t HoymilesRadio_CMT::getCountryMode() const +{ + return _radio->getCountryMode(); +} + +void HoymilesRadio_CMT::setCountryMode(CountryFrequency_t mode) +{ + _radio->setCountryMode(mode); +} + +uint32_t HoymilesRadio_CMT::getInvBootFrequency() const { // Hoymiles boot/init frequency after power up inverter or connection lost for 15 min - return 868000000; + + switch(_radio->getCountryMode()) { + case CountryFrequency_t::MODE_900: + return 915000000; + break; + default: + return 868000000; + break; + } } void ARDUINO_ISR_ATTR HoymilesRadio_CMT::handleInt1() diff --git a/lib/Hoymiles/src/HoymilesRadio_CMT.h b/lib/Hoymiles/src/HoymilesRadio_CMT.h index 102600409..d8c58b707 100644 --- a/lib/Hoymiles/src/HoymilesRadio_CMT.h +++ b/lib/Hoymiles/src/HoymilesRadio_CMT.h @@ -30,7 +30,10 @@ class HoymilesRadio_CMT : public HoymilesRadio { uint32_t getMaxFrequency() const; static uint32_t getChannelWidth(); - static uint32_t getInvBootFrequency(); + CountryFrequency_t getCountryMode() const; + void setCountryMode(CountryFrequency_t mode); + + uint32_t getInvBootFrequency() const; uint32_t getFrequencyFromChannel(const uint8_t channel) const; uint8_t getChannelFromFrequency(const uint32_t frequency) const; diff --git a/lib/Hoymiles/src/commands/ChannelChangeCommand.cpp b/lib/Hoymiles/src/commands/ChannelChangeCommand.cpp index 1001790d2..3681ca269 100644 --- a/lib/Hoymiles/src/commands/ChannelChangeCommand.cpp +++ b/lib/Hoymiles/src/commands/ChannelChangeCommand.cpp @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (C) 2023 Thomas Basler and others + * Copyright (C) 2023-2024 Thomas Basler and others */ /* @@ -12,7 +12,8 @@ Command structure: 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 ----------------------------------------------------------------------------------------------------------------- -56 71 60 35 46 80 12 23 04 02 15 21 00 14 00 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- +56 71 60 35 46 80 12 23 04 02 15 21 00 14 00 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- (860 MHz band) +56 71 60 35 46 80 12 23 04 03 17 3c 00 14 00 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- (900 MHz band) ^^ ^^^^^^^^^^^ ^^^^^^^^^^^ ^^ ^^ ^^ ^^ ^^ ^^ ID Target Addr Source Addr ? ? ? CH ? CRC8 */ @@ -22,12 +23,10 @@ ChannelChangeCommand::ChannelChangeCommand(const uint64_t target_address, const : CommandAbstract(target_address, router_address) { _payload[0] = 0x56; - _payload[9] = 0x02; - _payload[10] = 0x15; - _payload[11] = 0x21; _payload[13] = 0x14; _payload_size = 14; + setCountryMode(CountryFrequency_t::MODE_860); setChannel(channel); setTimeout(10); } @@ -47,6 +46,22 @@ uint8_t ChannelChangeCommand::getChannel() const return _payload[12]; } +void ChannelChangeCommand::setCountryMode(const CountryFrequency_t mode) +{ + switch (mode) { + case CountryFrequency_t::MODE_900: + _payload[9] = 0x03; + _payload[10] = 0x17; + _payload[11] = 0x3c; + break; + default: + _payload[9] = 0x02; + _payload[10] = 0x15; + _payload[11] = 0x21; + break; + } +} + bool ChannelChangeCommand::handleResponse(InverterAbstract& inverter, const fragment_t fragment[], const uint8_t max_fragment_id) { return true; @@ -56,4 +71,4 @@ uint8_t ChannelChangeCommand::getMaxResendCount() { // This command will never retrieve an answer. Therefor it's not required to repeat it return 0; -} \ No newline at end of file +} diff --git a/lib/Hoymiles/src/commands/ChannelChangeCommand.h b/lib/Hoymiles/src/commands/ChannelChangeCommand.h index a0b38cab1..126215e3f 100644 --- a/lib/Hoymiles/src/commands/ChannelChangeCommand.h +++ b/lib/Hoymiles/src/commands/ChannelChangeCommand.h @@ -2,6 +2,7 @@ #pragma once #include "CommandAbstract.h" +#include class ChannelChangeCommand : public CommandAbstract { public: @@ -12,7 +13,9 @@ class ChannelChangeCommand : public CommandAbstract { void setChannel(const uint8_t channel); uint8_t getChannel() const; + void setCountryMode(const CountryFrequency_t mode); + virtual bool handleResponse(InverterAbstract& inverter, const fragment_t fragment[], const uint8_t max_fragment_id); virtual uint8_t getMaxResendCount(); -}; \ No newline at end of file +}; diff --git a/lib/Hoymiles/src/inverters/HMS_Abstract.cpp b/lib/Hoymiles/src/inverters/HMS_Abstract.cpp index e75f99511..ffa7d7219 100644 --- a/lib/Hoymiles/src/inverters/HMS_Abstract.cpp +++ b/lib/Hoymiles/src/inverters/HMS_Abstract.cpp @@ -19,6 +19,7 @@ bool HMS_Abstract::sendChangeChannelRequest() } auto cmdChannel = _radio->prepareCommand(); + cmdChannel->setCountryMode(Hoymiles.getRadioCmt()->getCountryMode()); cmdChannel->setChannel(Hoymiles.getRadioCmt()->getChannelFromFrequency(Hoymiles.getRadioCmt()->getInverterTargetFrequency())); cmdChannel->setTargetAddress(serial()); _radio->enqueCommand(cmdChannel); diff --git a/lib/Hoymiles/src/inverters/HMT_Abstract.cpp b/lib/Hoymiles/src/inverters/HMT_Abstract.cpp index c4ebcf318..5c232b900 100644 --- a/lib/Hoymiles/src/inverters/HMT_Abstract.cpp +++ b/lib/Hoymiles/src/inverters/HMT_Abstract.cpp @@ -21,6 +21,7 @@ bool HMT_Abstract::sendChangeChannelRequest() } auto cmdChannel = _radio->prepareCommand(); + cmdChannel->setCountryMode(Hoymiles.getRadioCmt()->getCountryMode()); cmdChannel->setChannel(Hoymiles.getRadioCmt()->getChannelFromFrequency(Hoymiles.getRadioCmt()->getInverterTargetFrequency())); cmdChannel->setTargetAddress(serial()); _radio->enqueCommand(cmdChannel);