ehong-tl / micropySX126X

Semtech SX126X LoRa driver for Micropython and CircuitPython.
MIT License
102 stars 22 forks source link

SOS! something error about that! #6

Closed QiaoTuCodes closed 2 years ago

QiaoTuCodes commented 2 years ago

hey! i look at your micropySX126X drivers in 2days ago . but i want know how to working that ? if all files push down to mpy-boards . like pyboard_v1.1 . it's not working! return msg say : no memory .... so um ~~ how can i cut driver to mini ver? come on suggest something for me. thanks so much!

ehong-tl commented 2 years ago

Hi, instead of just copy all the python files into your pyboard, you can try to compile the python files into the firmware then flash it to your pyboard.

QiaoTuCodes commented 2 years ago

oh! so i just copy the lib all files to micropython firmware freezing folder and compile bin files . flash it to pyboard may can used right ?

ehong-tl commented 2 years ago

Yes, hopefully this will resolve the memory problem, otherwise have to use board that has more memory, i.e. ESP32 based board, etc.

QiaoTuCodes commented 2 years ago

okey! trying thank you bro!

QiaoTuCodes commented 2 years ago

hello bro. a new problem say:

Traceback (most recent call last): File "main.py", line 4, in File "sx1262.py", line 20, in init File "sx126x.py", line 46, in init TypeError: extra keyword arguments given MicroPython v1.15 on 2021-11-10: pyBoard Plus with STM32F407VGT6

i checked the 3 files error line codes but nothing. just full copy from your sample. so what happend? how can i do that?

ehong-tl commented 2 years ago

I think may be in the file sx126x.py, line 46 self.spi = SPI(0, baudrate=2000000, pins=(clk, mosi, miso)) pins keyword argument might not be compatible with pyboard's micropython. May be you can try modify the SPI object calling code here and try again.

QiaoTuCodes commented 2 years ago

oh yeah! great! i'll also think may default useing from machine import SPI , Pin maybe change 'from pyb import SPI , Pin' will be fix the compatible. i'll trying... thank you.

QiaoTuCodes commented 2 years ago

maybe the 2 libs it's not identical

QiaoTuCodes commented 2 years ago

help sir. a new problem again:

Traceback (most recent call last): File "main.py", line 4, in <module> File "sx1268.py", line 20, in __init__ File "sx126x.py", line 46, in __init__ TypeError: extra keyword arguments given MicroPython v1.15 on 2021-11-13; PYBv1.1_CN with STM32F405RG Type "help()" for more information. i don't know why? check all codes not change that.
i just change my Pin ports.

ehong-tl commented 2 years ago

It is back to the same problem you encountered initially. I think it's best if you can send me your modified code, let me have a look.

ehong-tl commented 2 years ago

Paste your modified code here is fine.

QiaoTuCodes commented 2 years ago

okey zip pack for U. so thank you very much!

QiaoTuCodes commented 2 years ago

http://47.106.223.45/modules.zip

ehong-tl commented 2 years ago

Can you paste your modified sx126x.py code to the comment instead?

QiaoTuCodes commented 2 years ago

okey!

`from _sx126x import *

from sys import implementation

if implementation.name == 'micropython': from machine import SPI, Pin from utime import sleep_ms, sleep_us, ticks_ms, ticks_us, ticks_diff

if implementation.name == 'circuitpython': import digitalio import busio from time import sleep, monotonic_ns

_MS_PER_NS = const(1000000)
_US_PER_NS = const(1000)
_MS_PER_S = const(1000)
_TICKS_MAX = const(536870911)
_TICKS_PERIOD = const(536870912)
_TICKS_HALFPERIOD = const(268435456)

def sleep_ms(ms):
    sleep(ms/1000)

def sleep_us(us):
    sleep(us/1000000)

def ticks_ms():
    return (monotonic_ns() // _MS_PER_NS) & _TICKS_MAX

def ticks_us():
   return (monotonic_ns() // _US_PER_NS) & _TICKS_MAX

def ticks_diff(end, start):
    diff = (end - start) & _TICKS_MAX
    diff = ((diff + _TICKS_HALFPERIOD) & _TICKS_MAX) - _TICKS_HALFPERIOD
    return diff

class SX126X:

def __init__(self, cs, irq, rst, gpio, clk='Y6', mosi='Y8', miso='Y7'):
    self._irq = irq
    if implementation.name == 'micropython':
      try:
          self.spi = SPI(2, mode=SPI.MASTER, baudrate=2000000, pins=(clk, mosi, miso))  # Pycom variant uPy
      except:
          self.spi = SPI(2, baudrate=2000000, pins=(clk, mosi, miso))                   # Generic variant uPy
      self.cs = Pin(cs, mode=Pin.OUT)
      self.cs = Pin(cs, mode=Pin.OUT)
      self.irq = Pin(irq, mode=Pin.IN)
      self.rst = Pin(rst, mode=Pin.OUT)
      self.gpio = Pin(gpio, mode=Pin.IN)

    if implementation.name == 'circuitpython':
      self.spi = busio.SPI(clk, MOSI=mosi, MISO=miso)
      while not self.spi.try_lock():
          pass
      self.spi.configure(baudrate=2000000, phase=0, polarity=0, bits=8)
      self.spi.unlock()
      self.cs = digitalio.DigitalInOut(cs)
      self.cs.switch_to_output(value=True)
      self.irq = digitalio.DigitalInOut(irq)
      self.irq.switch_to_input()
      self.rst = digitalio.DigitalInOut(rst)
      self.rst.switch_to_output(value=True)
      self.gpio = digitalio.DigitalInOut(gpio)
      self.gpio.switch_to_input()

    self._bwKhz = 0
    self._sf = 0
    self._bw = 0
    self._cr = 0
    self._ldro = 0
    self._crcType = 0
    self._preambleLength = 0
    self._tcxoDelay = 0
    self._headerType = 0
    self._implicitLen = 0
    self._txIq = 0
    self._rxIq = 0
    self._invertIQ = 0
    self._ldroAuto = True

    self._br = 0
    self._freqDev = 0
    self._rxBw = 0
    self._rxBwKhz = 0
    self._pulseShape = 0
    self._crcTypeFSK = 0
    self._preambleLengthFSK = 0
    self._addrComp = 0
    self._syncWordLength = 0
    self._whitening = 0
    self._packetType = 0
    self._dataRate = 0
    self._packetLength = 0
    self._preambleDetectorLength = 0

def begin(self, bw, sf, cr, syncWord, currentLimit, preambleLength, tcxoVoltage, useRegulatorLDO=False, txIq=False, rxIq=False):
    self._bwKhz = bw
    self._sf = sf

    self._bw = SX126X_LORA_BW_125_0
    self._cr = SX126X_LORA_CR_4_7
    self._ldro = 0x00
    self._crcType = SX126X_LORA_CRC_ON
    self._preambleLength = preambleLength
    self._tcxoDelay = 0
    self._headerType = SX126X_LORA_HEADER_EXPLICIT
    self._implicitLen = 0xFF

    self._txIq = txIq
    self._rxIq = rxIq
    self._invertIQ = SX126X_LORA_IQ_STANDARD

    state = self.reset()
    ASSERT(state)

    state = self.standby()
    ASSERT(state)

    state = self.config(SX126X_PACKET_TYPE_LORA)
    ASSERT(state)

    if tcxoVoltage > 0.0:
        state = self.setTCXO(tcxoVoltage)
        ASSERT(state)

    state = self.setSpreadingFactor(sf)
    ASSERT(state)

    state = self.setBandwidth(bw)
    ASSERT(state)

    state = self.setCodingRate(cr)
    ASSERT(state)

    state = self.setSyncWord(syncWord)
    ASSERT(state)

    state = self.setCurrentLimit(currentLimit)
    ASSERT(state)

    state = self.setPreambleLength(preambleLength)
    ASSERT(state)

    state = self.setDio2AsRfSwitch(True)
    ASSERT(state)

    if useRegulatorLDO:
        state = self.setRegulatorLDO()
    else:
        state = self.setRegulatorDCDC()

    return state

def beginFSK(self, br, freqDev, rxBw, currentLimit, preambleLength, dataShaping, preambleDetectorLength, tcxoVoltage, useRegulatorLDO=False):
    self._br = 21333
    self._freqDev = 52428
    self._rxBw = SX126X_GFSK_RX_BW_156_2
    self._rxBwKhz = 156.2
    self._pulseShape = SX126X_GFSK_FILTER_GAUSS_0_5
    self._crcTypeFSK = SX126X_GFSK_CRC_2_BYTE_INV
    self._preambleLengthFSK = preambleLength
    self._addrComp = SX126X_GFSK_ADDRESS_FILT_OFF
    self._preambleDetectorLength = preambleDetectorLength

    state = self.reset()
    ASSERT(state)

    state = self.standby()
    ASSERT(state)

    state = self.config(SX126X_PACKET_TYPE_GFSK)
    ASSERT(state)

    if tcxoVoltage > 0.0:
        state = self.setTCXO(tcxoVoltage)
        ASSERT(state)

    state = self.setBitRate(br)
    ASSERT(state)

    state = self.setFrequencyDeviation(freqDev)
    ASSERT(state)

    state = self.setRxBandwidth(rxBw)
    ASSERT(state)

    state = self.setCurrentLimit(currentLimit)
    ASSERT(state)

    state = self.setDataShaping(dataShaping)
    ASSERT(state)

    state = self.setPreambleLength(preambleLength)
    ASSERT(state)

    sync = [0x2D, 0x01]
    state = self.setSyncWord(sync, 2)
    ASSERT(state)

    state = self.setWhitening(True, 0x0100)
    ASSERT(state)

    state = self.variablePacketLengthMode(SX126X_MAX_PACKET_LENGTH)
    ASSERT(state)

    state = self.setDio2AsRfSwitch(True)
    ASSERT(state)

    if useRegulatorLDO:
        state = self.setRegulatorLDO()
    else:
        state = self.setRegulatorDCDC()

    return state

def reset(self, verify=True):
    if implementation.name == 'micropython':
      self.rst.value(1)
      sleep_us(150)
      self.rst.value(0)
      sleep_us(150)
      self.rst.value(1)
      sleep_us(150)

    if implementation.name == 'circuitpython':
      self.rst.value = True
      sleep_us(150)
      self.rst.value = False
      sleep_us(150)
      self.rst.value = True
      sleep_us(150)

    if not verify:
        return ERR_NONE

    start = ticks_ms()
    while True:
        state = self.standby()
        if state == ERR_NONE:
            return ERR_NONE
        if abs(ticks_diff(start, ticks_ms())) >= 3000:
            return state
        sleep_ms(10)

def transmit(self, data, len_, addr=0):
    state = self.standby()
    ASSERT(state)

    if len_ > SX126X_MAX_PACKET_LENGTH:
        return ERR_PACKET_TOO_LONG

    timeout = 0

    modem = self.getPacketType()
    if modem == SX126X_PACKET_TYPE_LORA:
        timeout = int((self.getTimeOnAir(len_) * 3) / 2)

    elif modem == SX126X_PACKET_TYPE_GFSK:
        timeout = int(self.getTimeOnAir(len_) * 5)

    else:
        return ERR_UNKNOWN

    state = self.startTransmit(data, len_, addr)
    ASSERT(state)

    start = ticks_us()
    while not self.irq.value():
        yield_()
        if abs(ticks_diff(start, ticks_us())) > timeout:
            self.clearIrqStatus()
            self.standby()
            return ERR_TX_TIMEOUT

    elapsed = abs(ticks_diff(start, ticks_us()))

    self._dataRate = (len_*8.0)/(float(elapsed)/1000000.0)

    state = self.clearIrqStatus()
    ASSERT(state)

    state = self.standby()

    return state

def receive(self, data, len_, timeout_en, timeout_ms):
    state = self.standby()
    ASSERT(state)

    timeout = 0

    modem = self.getPacketType()
    if modem == SX126X_PACKET_TYPE_LORA:
        symbolLength = float(1 << self._sf) / float(self._bwKhz)
        timeout = int(symbolLength * 100.0 * 1000.0)
    elif modem == SX126X_PACKET_TYPE_GFSK:
        maxLen = len_
        if len_ == 0:
            maxLen = 0xFF
        brBps = (float(SX126X_CRYSTAL_FREQ) * 1000000.0 * 32.0) / float(self._br)
        timeout = int(((maxLen * 8.0) / brBps) * 1000000.0 * 5.0)
    else:
        return ERR_UNKNOWN

    if timeout_ms == 0:
        pass
    else:
        timeout = timeout_ms * 1000

    if timeout_en:
        timeoutValue = int(float(timeout) / 15.625)
    else:
        timeoutValue = SX126X_RX_TIMEOUT_NONE

    state = self.startReceive(timeoutValue)
    ASSERT(state)

    start = ticks_us()
    while not self.irq.value():
        yield_()
        if timeout_en:
            if abs(ticks_diff(start, ticks_us())) > timeout:
                self.fixImplicitTimeout()
                self.clearIrqStatus()
                self.standby()
                return ERR_RX_TIMEOUT

    if self._headerType == SX126X_LORA_HEADER_IMPLICIT and self.getPacketType() == SX126X_PACKET_TYPE_LORA:
        state = self.fixImplicitTimeout()
        ASSERT(state)

    return self.readData(data, len_)

def transmitDirect(self, frf=0):
    state = ERR_NONE
    if frf != 0:
        state = self.setRfFrequency(frf)
    ASSERT(state)

    data = [SX126X_CMD_NOP]
    return self.SPIwriteCommand([SX126X_CMD_SET_TX_CONTINUOUS_WAVE], 1, data, 1)

def receiveDirect(self):
    return ERR_UNKNOWN

def scanChannel(self):
    if self.getPacketType() != SX126X_PACKET_TYPE_LORA:
        return ERR_WRONG_MODEM

    state = self.standby()
    ASSERT(state)

    state = self.setDioIrqParams(SX126X_IRQ_CAD_DETECTED | SX126X_IRQ_CAD_DONE, SX126X_IRQ_CAD_DETECTED | SX126X_IRQ_CAD_DONE)
    ASSERT(state)

    state = self.clearIrqStatus()
    ASSERT(state)

    state = self.setCad()
    ASSERT(state)

    while not self.irq.value():
        yield_()

    cadResult = self.getIrqStatus()
    if cadResult & SX126X_IRQ_CAD_DETECTED:
        self.clearIrqStatus()
        return LORA_DETECTED
    elif cadResult & SX126X_IRQ_CAD_DONE:
        self.clearIrqStatus()
        return CHANNEL_FREE

    return ERR_UNKNOWN

def sleep(self, retainConfig=True):
    sleepMode = [SX126X_SLEEP_START_WARM | SX126X_SLEEP_RTC_OFF]
    if not retainConfig:
        sleepMode = [SX126X_SLEEP_START_COLD | SX126X_SLEEP_RTC_OFF]
    state = self.SPIwriteCommand([SX126X_CMD_SET_SLEEP], 1, sleepMode, 1, False)

    sleep_us(500)

    return state

def standby(self, mode=SX126X_STANDBY_RC):
    data = [mode]
    return self.SPIwriteCommand([SX126X_CMD_SET_STANDBY], 1, data, 1)

def setDio1Action(self, func):
    try:
        self.irq.callback(trigger=Pin.IRQ_RISING, handler=func)     # Pycom variant uPy
    except:
        self.irq.irq(trigger=Pin.IRQ_RISING, handler=func)          # Generic variant uPy

def clearDio1Action(self):
    if implementation.name == 'micropython':
      self.irq = Pin(self._irq, mode=Pin.IN)

    if implementation.name == 'circuitpython':
      self.irq = digitalio.DigitalInOut(self._irq)
      self.irq.switch_to_input()

def startTransmit(self, data, len_, addr=0):
    if len_ > SX126X_MAX_PACKET_LENGTH:
        return ERR_PACKET_TOO_LONG

    if self._addrComp != SX126X_GFSK_ADDRESS_FILT_OFF and len_ > (SX126X_MAX_PACKET_LENGTH - 1):
        return ERR_PACKET_TOO_LONG

    state = ERR_NONE
    modem = self.getPacketType()
    if modem == SX126X_PACKET_TYPE_LORA:
        if self._txIq:
            self._invertIQ = SX126X_LORA_IQ_INVERTED
        else:
            self._invertIQ = SX126X_LORA_IQ_STANDARD

        if self._headerType == SX126X_LORA_HEADER_IMPLICIT:
            if len_ != self._implicitLen:
                return ERR_INVALID_PACKET_LENGTH

        state = self.setPacketParams(self._preambleLength, self._crcType, len_, self._headerType, self._invertIQ)
    elif modem == SX126X_PACKET_TYPE_GFSK:
        if self._packetType == SX126X_GFSK_PACKET_FIXED:
            if len_ != self._packetLength:
                return ERR_INVALID_PACKET_LENGTH

        state = self.setPacketParamsFSK(self._preambleLengthFSK, self._crcTypeFSK, self._syncWordLength, self._addrComp, self._whitening, self._packetType, len_, self._preambleDetectorLength)
    else:
        return ERR_UNKNOWN
    ASSERT(state)

    state = self.setDioIrqParams(SX126X_IRQ_TX_DONE | SX126X_IRQ_TIMEOUT, SX126X_IRQ_TX_DONE)
    ASSERT(state)

    state = self.setBufferBaseAddress()
    ASSERT(state)

    state = self.writeBuffer(data, len_)
    ASSERT(state)

    state = self.clearIrqStatus()
    ASSERT(state)

    state = self.fixSensitivity()
    ASSERT(state)

    state = self.setTx(SX126X_TX_TIMEOUT_NONE)
    ASSERT(state)

    if implementation.name == 'micropython':
      while self.gpio.value():
          yield_()

    if implementation.name == 'circuitpython':
      while self.gpio.value:
          yield_()

    return state

def startReceive(self, timeout=SX126X_RX_TIMEOUT_INF):
    state = ERR_NONE
    modem = self.getPacketType()
    if modem == SX126X_PACKET_TYPE_LORA:
        if self._rxIq:
            self._invertIQ = SX126X_LORA_IQ_INVERTED
        else:
            self._invertIQ = SX126X_LORA_IQ_STANDARD

        state = self.setPacketParams(self._preambleLength, self._crcType, self._implicitLen, self._headerType, self._invertIQ)
    elif modem == SX126X_PACKET_TYPE_GFSK:
        state = self.setPacketParamsFSK(self._preambleLengthFSK, self._crcTypeFSK, self._syncWordLength, self._addrComp, self._whitening, self._packetType, self._packetLength, self._preambleDetectorLength)
    else:
        return ERR_UNKNOWN
    ASSERT(state)

    state = self.startReceiveCommon()
    ASSERT(state)

    state = self.setRx(timeout)

    return state

def startReceiveDutyCycle(self, rxPeriod, sleepPeriod):
    transitionTime = int(self._tcxoDelay + 1000)
    sleepPeriod -= transitionTime

    rxPeriodRaw = int((rxPeriod * 8) / 125)
    sleepPeriodRaw = int((sleepPeriod * 8) / 125)

    if rxPeriodRaw & 0xFF000000 or rxPeriodRaw == 0:
        return ERR_INVALID_RX_PERIOD

    if sleepPeriodRaw & 0xFF000000 or sleepPeriodRaw == 0:
        return ERR_INVALID_SLEEP_PERIOD

    state = self.startReceiveCommon()
    ASSERT(state)

    data = [int((rxPeriodRaw >> 16) & 0xFF), int((rxPeriodRaw >> 8) & 0xFF), int(rxPeriodRaw & 0xFF),
            int((sleepPeriodRaw >> 16) & 0xFF),int((sleepPeriodRaw >> 8) & 0xFF),int(sleepPeriodRaw & 0xFF)]
    return self.SPIwriteCommand([SX126X_CMD_SET_RX_DUTY_CYCLE], 1, data, 6)

def startReceiveDutyCycleAuto(self, senderPreambleLength=0, minSymbols=8):
    if senderPreambleLength == 0:
        senderPreambleLength = self._preambleLength

    sleepSymbols = int(senderPreambleLength - 2 * minSymbols)

    if (2 * minSymbols) > senderPreambleLength:
        return self.startReceive()

    symbolLength = int(((10*1000) << self._sf) / (10 * self._bwKhz))
    sleepPeriod = symbolLength * sleepSymbols

    wakePeriod = int(max((symbolLength * (senderPreambleLength + 1) - (sleepPeriod - 1000)) / 2, symbolLength * (minSymbols + 1)))

    if sleepPeriod < (self._tcxoDelay + 1016):
        return self.startReceive()

    return self.startReceiveDutyCycle(wakePeriod, sleepPeriod)

def startReceiveCommon(self):
    state = self.setDioIrqParams(SX126X_IRQ_RX_DONE | SX126X_IRQ_TIMEOUT | SX126X_IRQ_CRC_ERR | SX126X_IRQ_HEADER_ERR, SX126X_IRQ_RX_DONE)
    ASSERT(state)

    state = self.setBufferBaseAddress()
    ASSERT(state)

    state = self.clearIrqStatus()

    modem = self.getPacketType()
    if modem == SX126X_PACKET_TYPE_LORA:
        state = self.setPacketParams(self._preambleLength, self._crcType, self._implicitLen, self._headerType, self._invertIQ)
    elif modem == SX126X_PACKET_TYPE_GFSK:
        state = self.setPacketParamsFSK(self._preambleLengthFSK, self._crcTypeFSK, self._syncWordLength, self._addrComp, self._whitening, self._packetType)
    else:
        return ERR_UNKNOWN

    return state

def readData(self, data, len_):
    state = self.standby()
    ASSERT(state)

    irq = self.getIrqStatus()
    crcState = ERR_NONE
    if irq & SX126X_IRQ_CRC_ERR or irq & SX126X_IRQ_HEADER_ERR:
        crcState = ERR_CRC_MISMATCH

    length = len_
    if len_ == SX126X_MAX_PACKET_LENGTH:
        length = self.getPacketLength()

    state = self.readBuffer(data, length)
    ASSERT(state)

    state = self.clearIrqStatus()

    ASSERT(crcState)

    return state

def setBandwidth(self, bw):
    if self.getPacketType() != SX126X_PACKET_TYPE_LORA:
        return ERR_WRONG_MODEM

    if not ((bw > 0) and (bw < 510)):
        return ERR_INVALID_BANDWIDTH

    bw_div2 = int(bw / 2 + 0.01)
    switch = {3: SX126X_LORA_BW_7_8,
              5: SX126X_LORA_BW_10_4,
              7: SX126X_LORA_BW_15_6,
              10: SX126X_LORA_BW_20_8,
              15: SX126X_LORA_BW_31_25,
              20: SX126X_LORA_BW_41_7,
              31: SX126X_LORA_BW_62_5,
              62: SX126X_LORA_BW_125_0,
              125: SX126X_LORA_BW_250_0,
              250: SX126X_LORA_BW_500_0}
    try:
        self._bw = switch[bw_div2]
    except:
        return ERR_INVALID_BANDWIDTH

    self._bwKhz = bw
    return self.setModulationParams(self._sf, self._bw, self._cr, self._ldro)

def setSpreadingFactor(self, sf):
    if self.getPacketType() != SX126X_PACKET_TYPE_LORA:
        return ERR_WRONG_MODEM

    if not ((sf >= 5) and (sf <= 12)):
        return ERR_INVALID_SPREADING_FACTOR

    self._sf = sf
    return self.setModulationParams(self._sf, self._bw, self._cr, self._ldro)

def setCodingRate(self, cr):
    if self.getPacketType() != SX126X_PACKET_TYPE_LORA:
        return ERR_WRONG_MODEM

    if not ((cr >= 5) and (cr <= 8)):
        return ERR_INVALID_CODING_RATE

    self._cr = cr - 4
    return self.setModulationParams(self._sf, self._bw, self._cr, self._ldro)

def setSyncWord(self, syncWord, *args):
    if self.getPacketType() == SX126X_PACKET_TYPE_LORA:
        if len(args) > 0:
            controlBits = args[0]
        else:
            controlBits = 0x44
        data = [int((syncWord & 0xF0) | ((controlBits & 0xF0) >> 4)), int(((syncWord & 0x0F) << 4) | (controlBits & 0x0F))]
        return self.writeRegister(SX126X_REG_LORA_SYNC_WORD_MSB, data, 2)

    elif self.getPacketType() == SX126X_PACKET_TYPE_GFSK:
        len_ = args[0]
        if len_ > 8:
            return ERR_INVALID_SYNC_WORD

        state = self.writeRegister(SX126X_REG_SYNC_WORD_0, syncWord, len_)
        ASSERT(state)

        self._syncWordLength = len_ * 8
        state = self.setPacketParamsFSK(self._preambleLengthFSK, self._crcTypeFSK, self._syncWordLength, self._addrComp, self._whitening, self._packetType, self._packetLength, self._preambleDetectorLength)

        return state

    else:
        return ERR_WRONG_MODEM

def setCurrentLimit(self, currentLimit):
    if not ((currentLimit >= 0) and (currentLimit <= 140)):
        return ERR_INVALID_CURRENT_LIMIT

    rawLimit = [int(currentLimit / 2.5)]

    return self.writeRegister(SX126X_REG_OCP_CONFIGURATION, rawLimit, 1)

def getCurrentLimit(self):
    ocp = bytearray(1)
    ocp_mv = memoryview(ocp)
    self.readRegister(SX126X_REG_OCP_CONFIGURATION, ocp_mv, 1)

    return float(ocp[0]) * 2.5

def setPreambleLength(self, preambleLength):
    modem = self.getPacketType()
    if modem == SX126X_PACKET_TYPE_LORA:
        self._preambleLength = preambleLength
        return self.setPacketParams(self._preambleLength, self._crcType, self._implicitLen, self._headerType, self._invertIQ)
    elif modem == SX126X_PACKET_TYPE_GFSK:
        self._preambleLengthFSK = preambleLength
        return self.setPacketParamsFSK(self._preambleLengthFSK, self._crcTypeFSK, self._syncWordLength, self._addrComp, self._whitening, self._packetType, self._packetLength, self._preambleDetectorLength)

    return ERR_UNKNOWN

def setFrequencyDeviation(self, freqDev):
    if self.getPacketType() != SX126X_PACKET_TYPE_GFSK:
        return ERR_WRONG_MODEM

    if not (freqDev <= 200.0):
        return ERR_INVALID_FREQUENCY_DEVIATION

    freqDevRaw = int(((freqDev * 1000.0) * float(1 << 25)) / (SX126X_CRYSTAL_FREQ * 1000000.0))

    self._freqDev = freqDevRaw
    return self.setModulationParamsFSK(self._br, self._pulseShape, self._rxBw, self._freqDev)

def setBitRate(self, br):
    if self.getPacketType() != SX126X_PACKET_TYPE_GFSK:
        return ERR_WRONG_MODEM

    if not ((br >= 0.6) and (br <= 300.0)):
        return ERR_INVALID_BIT_RATE

    brRaw = int((SX126X_CRYSTAL_FREQ * 1000000.0 * 32.0) / (br * 1000.0))

    self._br = brRaw

    return self.setModulationParamsFSK(self._br, self._pulseShape, self._rxBw, self._freqDev)

def setRxBandwidth(self, rxBw):
    if self.getPacketType() != SX126X_PACKET_TYPE_GFSK:
        return ERR_WRONG_MODEM

    self._rxBwKhz = rxBw

    if abs(rxBw - 4.8) <= 0.001:
        self._rxBw = SX126X_GFSK_RX_BW_4_8
    elif abs(rxBw - 5.8) <= 0.001:
        self._rxBw = SX126X_GFSK_RX_BW_5_8
    elif abs(rxBw - 7.3) <= 0.001:
        self._rxBw = SX126X_GFSK_RX_BW_7_3
    elif abs(rxBw - 9.7) <= 0.001:
        self._rxBw = SX126X_GFSK_RX_BW_9_7
    elif abs(rxBw - 11.7) <= 0.001:
        self._rxBw = SX126X_GFSK_RX_BW_11_7
    elif abs(rxBw - 14.6) <= 0.001:
        self._rxBw = SX126X_GFSK_RX_BW_14_6
    elif abs(rxBw - 19.5) <= 0.001:
        self._rxBw = SX126X_GFSK_RX_BW_19_5
    elif abs(rxBw - 23.4) <= 0.001:
        self._rxBw = SX126X_GFSK_RX_BW_23_4
    elif abs(rxBw - 29.3) <= 0.001:
        self._rxBw = SX126X_GFSK_RX_BW_29_3
    elif abs(rxBw - 39.0) <= 0.001:
        self._rxBw = SX126X_GFSK_RX_BW_39_0
    elif abs(rxBw - 46.9) <= 0.001:
        self._rxBw = SX126X_GFSK_RX_BW_46_9
    elif abs(rxBw - 58.6) <= 0.001:
        self._rxBw = SX126X_GFSK_RX_BW_58_6
    elif abs(rxBw - 78.2) <= 0.001:
        self._rxBw = SX126X_GFSK_RX_BW_78_2
    elif abs(rxBw - 93.8) <= 0.001:
        self._rxBw = SX126X_GFSK_RX_BW_93_8
    elif abs(rxBw - 117.3) <= 0.001:
        self._rxBw = SX126X_GFSK_RX_BW_117_3
    elif abs(rxBw - 156.2) <= 0.001:
        self._rxBw = SX126X_GFSK_RX_BW_156_2
    elif abs(rxBw - 187.2) <= 0.001:
        self._rxBw = SX126X_GFSK_RX_BW_187_2
    elif abs(rxBw - 234.3) <= 0.001:
        self._rxBw = SX126X_GFSK_RX_BW_234_3
    elif abs(rxBw - 312.0) <= 0.001:
        self._rxBw = SX126X_GFSK_RX_BW_312_0
    elif abs(rxBw - 373.6) <= 0.001:
        self._rxBw = SX126X_GFSK_RX_BW_373_6
    elif abs(rxBw - 467.0) <= 0.001:
        self._rxBw = SX126X_GFSK_RX_BW_467_0
    else:
        return ERR_INVALID_RX_BANDWIDTH

    return self.setModulationParamsFSK(self._br, self._pulseShape, self._rxBw, self._freqDev)

def setDataShaping(self, sh):
    if self.getPacketType() != SX126X_PACKET_TYPE_GFSK:
        return ERR_WRONG_MODEM

    sh *= 10.0
    if abs(sh - 0.0) <= 0.001:
        self._pulseShape = SX126X_GFSK_FILTER_NONE
    elif abs(sh - 3.0) <= 0.001:
        self._pulseShape = SX126X_GFSK_FILTER_GAUSS_0_3
    elif abs(sh - 5.0) <= 0.001:
        self._pulseShape = SX126X_GFSK_FILTER_GAUSS_0_5
    elif abs(sh - 7.0) <= 0.001:
        self._pulseShape = SX126X_GFSK_FILTER_GAUSS_0_7
    elif abs(sh - 10.0) <= 0.001:
        self._pulseShape = SX126X_GFSK_FILTER_GAUSS_1
    else:
        return ERR_INVALID_DATA_SHAPING

    return self.setModulationParamsFSK(self._br, self._pulseShape, self._rxBw, self._freqDev)

def setSyncBits(self, syncWord, bitsLen):
    if self.getPacketType() != SX126X_PACKET_TYPE_GFSK:
        return ERR_WRONG_MODEM

    if bitsLen > 0x40:
        return ERR_INVALID_SYNC_WORD

    bytesLen = int(bitsLen / 8)
    if (bitsLen % 8) != 0:
        bytesLen += 1

    state = self.writeRegister(SX126X_REG_SYNC_WORD_0, syncWord, bytesLen)
    ASSERT(state)

    self._syncWordLength = bitsLen
    state = self.setPacketParamsFSK(self._preambleLengthFSK, self._crcTypeFSK, self._syncWordLength, self._addrComp, self._whitening, self._packetType, self._packetLength, self._preambleDetectorLength)

    return state

def setNodeAddress(self, nodeAddr):
    if self.getPacketType() != SX126X_PACKET_TYPE_GFSK:
        return ERR_WRONG_MODEM

    self._addrComp = SX126X_GFSK_ADDRESS_FILT_NODE

    state = self.setPacketParamsFSK(self._preambleLengthFSK, self._crcTypeFSK, self._syncWordLength, self._addrComp, self._whitening, self._packetType, self._packetLength, self._preambleDetectorLength)
    ASSERT(state)

    state = self.writeRegister(SX126X_REG_NODE_ADDRESS, [nodeAddr], 1)

    return state

def setBroadcastAddress(self, broadAddr):
    if self.getPacketType() != SX126X_PACKET_TYPE_GFSK:
        return ERR_WRONG_MODEM

    self._addrComp = SX126X_GFSK_ADDRESS_FILT_NODE_BROADCAST
    state = self.setPacketParamsFSK(self._preambleLengthFSK, self._crcTypeFSK, self._syncWordLength, self._addrComp, self._whitening, self._packetType, self._packetLength, self._preambleDetectorLength)
    ASSERT(state)

    state = self.writeRegister(SX126X_REG_BROADCAST_ADDRESS, [broadAddr], 1)

    return state

def disableAddressFiltering(self):
    if self.getPacketType() != SX126X_PACKET_TYPE_GFSK:
        return ERR_WRONG_MODEM

    self._addrComp = SX126X_GFSK_ADDRESS_FILT_OFF
    return self.setPacketParamsFSK(self._preambleLengthFSK, self._crcTypeFSK, self._syncWordLength, self._addrComp, self._whitening, self._packetType, self._packetLength, self._preambleDetectorLength)

def setCRC(self, len_, initial=0x1D0F, polynomial=0x1021, inverted=True):
    modem = self.getPacketType()

    if modem == SX126X_PACKET_TYPE_GFSK:
        if len_ == 0:
            self._crcTypeFSK = SX126X_GFSK_CRC_OFF
        elif len_ == 1:
            if inverted:
                self._crcTypeFSK = SX126X_GFSK_CRC_1_BYTE_INV
            else:
                self._crcTypeFSK = SX126X_GFSK_CRC_1_BYTE
        elif len_ == 2:
            if inverted:
                self._crcTypeFSK = SX126X_GFSK_CRC_2_BYTE_INV
            else:
                self._crcTypeFSK = SX126X_GFSK_CRC_2_BYTE
        else:
            return ERR_INVALID_CRC_CONFIGURATION

        state = self.setPacketParamsFSK(self._preambleLengthFSK, self._crcTypeFSK, self._syncWordLength, self._addrComp, self._whitening, self._packetType, self._packetLength, self._preambleDetectorLength)
        ASSERT(state)

        data = [int((initial >> 8) & 0xFF), int(initial & 0xFF)]
        state = self.writeRegister(SX126X_REG_CRC_INITIAL_MSB, data, 2)
        ASSERT(state)

        data[0] = int((polynomial >> 8) & 0xFF)
        data[1] = int(polynomial & 0xFF)
        state = self.writeRegister(SX126X_REG_CRC_POLYNOMIAL_MSB, data, 2)

        return state

    elif modem == SX126X_PACKET_TYPE_LORA:

        if len_:
            self._crcType = SX126X_LORA_CRC_ON
        else:
            self._crcType = SX126X_LORA_CRC_OFF

        return self.setPacketParams(self._preambleLength, self._crcType, self._implicitLen, self._headerType, self._invertIQ)

    return ERR_UNKNOWN

def setWhitening(self, enabled, initial=0x0100):
    if self.getPacketType() != SX126X_PACKET_TYPE_GFSK:
        return ERR_WRONG_MODEM

    state = ERR_NONE
    if enabled != True:
        self._whitening = SX126X_GFSK_WHITENING_OFF

        state = self.setPacketParamsFSK(self._preambleLengthFSK, self._crcTypeFSK, self._syncWordLength, self._addrComp, self._whitening, self._packetType, self._packetLength, self._preambleDetectorLength)
        ASSERT(state)
    else:
        self._whitening = SX126X_GFSK_WHITENING_ON

        data = bytearray(1)
        data_mv = memoryview(data)
        state = self.readRegister(SX126X_REG_WHITENING_INITIAL_MSB, data_mv, 1)
        ASSERT(state)
        data2 = [(data[0] & 0xFE) | int((initial >> 8) & 0x01), int(initial & 0xFF)]
        state = self.writeRegister(SX126X_REG_WHITENING_INITIAL_MSB, data2, 2)
        ASSERT(state)

        state = self.setPacketParamsFSK(self._preambleLengthFSK, self._crcTypeFSK, self._syncWordLength, self._addrComp, self._whitening, self._packetType, self._packetLength, self._preambleDetectorLength)
        ASSERT(state)
    return state

def getDataRate(self):
    return self._dataRate

def getRSSI(self):
    packetStatus = self.getPacketStatus()
    rssiPkt = int(packetStatus & 0xFF)
    return -1.0 * rssiPkt/2.0

def getSNR(self):
    if self.getPacketType() != SX126X_PACKET_TYPE_LORA:
        return ERR_WRONG_MODEM

    packetStatus = self.getPacketStatus()
    snrPkt = int((packetStatus >> 8) & 0xFF)
    if snrPkt < 128:
        return snrPkt/4.0
    else:
        return (snrPkt - 256)/4.0

def getPacketLength(self, update=True):
    rxBufStatus = bytearray(2)
    rxBufStatus_mv = memoryview(rxBufStatus)
    self.SPIreadCommand([SX126X_CMD_GET_RX_BUFFER_STATUS], 1, rxBufStatus_mv, 2)
    return rxBufStatus[0]

def fixedPacketLengthMode(self, len_=SX126X_MAX_PACKET_LENGTH):
    return self.setPacketMode(SX126X_GFSK_PACKET_FIXED, len_)

def variablePacketLengthMode(self, maxLen=SX126X_MAX_PACKET_LENGTH):
    return self.setPacketMode(SX126X_GFSK_PACKET_VARIABLE, maxLen)

def getTimeOnAir(self, len_):
    if self.getPacketType() == SX126X_PACKET_TYPE_LORA:
        symbolLength_us = int(((1000 * 10) << self._sf) / (self._bwKhz * 10))
        sfCoeff1_x4 = 17
        sfCoeff2 = 8
        if self._sf == 5 or self._sf == 6:
            sfCoeff1_x4 = 25
            sfCoeff2 = 0
        sfDivisor = 4*self._sf
        if symbolLength_us >= 16000:
            sfDivisor = 4*(self._sf - 2)
        bitsPerCrc = 16
        N_symbol_header = 20 if self._headerType == SX126X_LORA_HEADER_EXPLICIT else 0

        bitCount = int(8 * len_ + self._crcType * bitsPerCrc - 4 * self._sf  + sfCoeff2 + N_symbol_header)
        if bitCount < 0:
            bitCount = 0

        nPreCodedSymbols = int((bitCount + (sfDivisor - 1)) / sfDivisor)

        nSymbol_x4 = int((self._preambleLength + 8) * 4 + sfCoeff1_x4 + nPreCodedSymbols * (self._cr + 4) * 4)

        return int((symbolLength_us * nSymbol_x4) / 4)
    else:
        return int((len_ * 8 * self._br) / (SX126X_CRYSTAL_FREQ * 32))

def implicitHeader(self, len_):
    return self.setHeaderType(SX126X_LORA_HEADER_IMPLICIT, len_)

def explicitHeader(self):
    return self.setHeaderType(SX126X_LORA_HEADER_EXPLICIT)

def setRegulatorLDO(self):
    return self.setRegulatorMode(SX126X_REGULATOR_LDO)

def setRegulatorDCDC(self):
    return self.setRegulatorMode(SX126X_REGULATOR_DC_DC)

def setEncoding(self, encoding):
    return self.setWhitening(encoding)

def forceLDRO(self, enable):
    if self.getPacketType() != SX126X_PACKET_TYPE_LORA:
        return ERR_WRONG_MODEM

    self._ldroAuto = False
    self._ldro = enable
    return self.setModulationParams(self._sf, self._bw, self._cr, self._ldro)

def autoLDRO(self):
    if self.getPacketType() != SX126X_PACKET_TYPE_LORA:
        return ERR_WRONG_MODEM

    self._ldroAuto = True
    return self.setModulationParams(self._sf, self._bw, self._cr, self._ldro)

def setTCXO(self, voltage, delay=5000):
    self.standby()

    if self.getDeviceErrors() & SX126X_XOSC_START_ERR:
        self.clearDeviceErrors()

    if abs(voltage - 0.0) <= 0.001:
        return self.reset()

    data = [0,0,0,0]
    if abs(voltage - 1.6) <= 0.001:
        data[0] = SX126X_DIO3_OUTPUT_1_6
    elif abs(voltage - 1.7) <= 0.001:
        data[0] = SX126X_DIO3_OUTPUT_1_7
    elif abs(voltage - 1.8) <= 0.001:
        data[0] = SX126X_DIO3_OUTPUT_1_8
    elif abs(voltage - 2.2) <= 0.001:
        data[0] = SX126X_DIO3_OUTPUT_2_2
    elif abs(voltage - 2.4) <= 0.001:
        data[0] = SX126X_DIO3_OUTPUT_2_4
    elif abs(voltage - 2.7) <= 0.001:
        data[0] = SX126X_DIO3_OUTPUT_2_7
    elif abs(voltage - 3.0) <= 0.001:
        data[0] = SX126X_DIO3_OUTPUT_3_0
    elif abs(voltage - 3.3) <= 0.001:
        data[0] = SX126X_DIO3_OUTPUT_3_3
    else:
        return ERR_INVALID_TCXO_VOLTAGE

    delayValue = int(float(delay) / 15.625)
    data[1] = int((delayValue >> 16) & 0xFF)
    data[2] = int((delayValue >> 8) & 0xFF)
    data[3] = int(delayValue & 0xFF)

    self._tcxoDelay = delay

    return self.SPIwriteCommand([SX126X_CMD_SET_DIO3_AS_TCXO_CTRL], 1, data, 4)

def setDio2AsRfSwitch(self, enable=True):
    data = [0]
    if enable:
        data = [SX126X_DIO2_AS_RF_SWITCH]
    else:
        data = [SX126X_DIO2_AS_IRQ]
    return self.SPIwriteCommand([SX126X_CMD_SET_DIO2_AS_RF_SWITCH_CTRL], 1, data, 1)

def setTx(self, timeout=0):
    data = [int((timeout >> 16) & 0xFF), int((timeout >> 8) & 0xFF), int(timeout & 0xFF)]
    return self.SPIwriteCommand([SX126X_CMD_SET_TX], 1, data, 3)

def setRx(self, timeout):
    data = [int((timeout >> 16) & 0xFF), int((timeout >> 8) & 0xFF), int(timeout & 0xFF)]
    return self.SPIwriteCommand([SX126X_CMD_SET_RX], 1, data, 3)

def setCad(self):
    return self.SPIwriteCommand([SX126X_CMD_SET_CAD], 1, [], 0)

def setPaConfig(self, paDutyCycle, deviceSel, hpMax=SX126X_PA_CONFIG_HP_MAX, paLut=SX126X_PA_CONFIG_PA_LUT):
    data = [paDutyCycle, hpMax, deviceSel, paLut]
    return self.SPIwriteCommand([SX126X_CMD_SET_PA_CONFIG], 1, data, 4)

def writeRegister(self, addr, data, numBytes):
    cmd = [SX126X_CMD_WRITE_REGISTER, int((addr >> 8) & 0xFF), int(addr & 0xFF)]
    state = self.SPIwriteCommand(cmd, 3, data, numBytes)
    return state

def readRegister(self, addr, data, numBytes):
    cmd = [SX126X_CMD_READ_REGISTER, int((addr >> 8) & 0xFF), int(addr & 0xFF)]
    return self.SPItransfer(cmd, 3, False, [], data, numBytes, True)

def writeBuffer(self, data, numBytes, offset=0x00):
    cmd = [SX126X_CMD_WRITE_BUFFER, offset]
    state = self.SPIwriteCommand(cmd, 2, data, numBytes)

    return state

def readBuffer(self, data, numBytes):
    cmd = [SX126X_CMD_READ_BUFFER, SX126X_CMD_NOP]
    state = self.SPIreadCommand(cmd, 2, data, numBytes)

    return state

def setDioIrqParams(self, irqMask, dio1Mask, dio2Mask=SX126X_IRQ_NONE, dio3Mask=SX126X_IRQ_NONE):
    data = [int((irqMask >> 8) & 0xFF), int(irqMask & 0xFF),
            int((dio1Mask >> 8) & 0xFF), int(dio1Mask & 0xFF),
            int((dio2Mask >> 8) & 0xFF), int(dio2Mask & 0xFF),
            int((dio3Mask >> 8) & 0xFF), int(dio3Mask & 0xFF)]
    return self.SPIwriteCommand([SX126X_CMD_SET_DIO_IRQ_PARAMS], 1, data, 8)

def getIrqStatus(self):
    data = bytearray(2)
    data_mv = memoryview(data)
    self.SPIreadCommand([SX126X_CMD_GET_IRQ_STATUS], 1, data_mv, 2)
    return int((data[0] << 8) | data[1])

def clearIrqStatus(self, clearIrqParams=SX126X_IRQ_ALL):
    data = [int((clearIrqParams >> 8) & 0xFF), int(clearIrqParams & 0xFF)]
    return self.SPIwriteCommand([SX126X_CMD_CLEAR_IRQ_STATUS], 1, data, 2)

def setRfFrequency(self, frf):
    data = [int((frf >> 24) & 0xFF),
            int((frf >> 16) & 0xFF),
            int((frf >> 8) & 0xFF),
            int(frf & 0xFF)]
    return self.SPIwriteCommand([SX126X_CMD_SET_RF_FREQUENCY], 1, data, 4)

def calibrateImage(self, data):
    return self.SPIwriteCommand([SX126X_CMD_CALIBRATE_IMAGE], 1, data, 2)

def getPacketType(self):
    data = bytearray([0xFF])
    data_mv = memoryview(data)
    self.SPIreadCommand([SX126X_CMD_GET_PACKET_TYPE], 1, data_mv, 1)
    return data[0]

def setTxParams(self, power, rampTime=SX126X_PA_RAMP_200U):
    data = [power, rampTime]
    return self.SPIwriteCommand([SX126X_CMD_SET_TX_PARAMS], 1, data, 2)

def setPacketMode(self, mode, len_):
    if self.getPacketType() != SX126X_PACKET_TYPE_GFSK:
        return ERR_WRONG_MODEM

    state = self.setPacketParamsFSK(self._preambleLengthFSK, self._crcTypeFSK, self._syncWordLength, self._addrComp, self._whitening, mode, len_, self._preambleDetectorLength)
    ASSERT(state)

    self._packetType = mode
    self._packetLength = len_
    return state

def setHeaderType(self, headerType, len_=0xFF):
    if self.getPacketType() != SX126X_PACKET_TYPE_LORA:
        return ERR_WRONG_MODEM

    state = self.setPacketParams(self._preambleLength, self._crcType, len_, headerType, self._invertIQ)
    ASSERT(state)

    self._headerType = headerType
    self._implicitLen = len_

    return state

def setModulationParams(self, sf, bw, cr, ldro):
    if self._ldroAuto:
        symbolLength = float((1 << self._sf)) / float(self._bwKhz)
        if symbolLength >= 16.0:
            self._ldro = SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_ON
        else:
            self._ldro = SX126X_LORA_LOW_DATA_RATE_OPTIMIZE_OFF
    else:
        self._ldro = ldro

    data = [sf, bw, cr, self._ldro]
    return self.SPIwriteCommand([SX126X_CMD_SET_MODULATION_PARAMS], 1, data, 4)

def setModulationParamsFSK(self, br, pulseShape, rxBw, freqDev):
    data = [int((br >> 16) & 0xFF), int((br >> 8) & 0xFF), int(br & 0xFF),
            pulseShape, rxBw,
            int((freqDev >> 16) & 0xFF), int((freqDev >> 8) & 0xFF), int(freqDev & 0xFF)]
    return self.SPIwriteCommand([SX126X_CMD_SET_MODULATION_PARAMS], 1, data, 8)

def setPacketParams(self, preambleLength, crcType, payloadLength, headerType, invertIQ=SX126X_LORA_IQ_STANDARD):
    state = self.fixInvertedIQ(invertIQ)
    ASSERT(state)
    data = [int((preambleLength >> 8) & 0xFF), int(preambleLength & 0xFF),
            headerType, payloadLength, crcType, invertIQ]
    return self.SPIwriteCommand([SX126X_CMD_SET_PACKET_PARAMS], 1, data, 6)

def setPacketParamsFSK(self, preambleLength, crcType, syncWordLength, addrComp, whitening, packetType=SX126X_GFSK_PACKET_VARIABLE, payloadLength=0xFF, preambleDetectorLength=SX126X_GFSK_PREAMBLE_DETECT_16):
    data = [int((preambleLength >> 8) & 0xFF), int(preambleLength & 0xFF),
            preambleDetectorLength, syncWordLength, addrComp,
            packetType, payloadLength, crcType, whitening]
    return self.SPIwriteCommand([SX126X_CMD_SET_PACKET_PARAMS], 1, data, 9)

def setBufferBaseAddress(self, txBaseAddress=0x00, rxBaseAddress=0x00):
    data = [txBaseAddress, rxBaseAddress]
    return self.SPIwriteCommand([SX126X_CMD_SET_BUFFER_BASE_ADDRESS], 1, data, 2)

def setRegulatorMode(self, mode):
    data = [mode]
    return self.SPIwriteCommand([SX126X_CMD_SET_REGULATOR_MODE], 1, data, 1)

def getStatus(self):
    data = bytearray(1)
    data_mv = memoryview(data)
    self.SPIreadCommand([SX126X_CMD_GET_STATUS], 1, data_mv, 1)
    return data[0]

def getPacketStatus(self):
    data = bytearray(3)
    data_mv = memoryview(data)
    self.SPIreadCommand([SX126X_CMD_GET_PACKET_STATUS], 1, data_mv, 3)
    return (data[0] << 16) | (data[1] << 8) | data[2]

def getDeviceErrors(self):
    data = bytearray(2)
    data_mv = memoryview(data)
    self.SPIreadCommand([SX126X_CMD_GET_DEVICE_ERRORS], 1, data_mv, 2)
    opError = ((data[0] & 0xFF) << 8) & data[1]
    return opError

def clearDeviceErrors(self):
    data = [SX126X_CMD_NOP, SX126X_CMD_NOP]
    return self.SPIwriteCommand([SX126X_CMD_CLEAR_DEVICE_ERRORS], 1, data, 2)

def setFrequencyRaw(self, freq):
    frf = int((freq * (1 << SX126X_DIV_EXPONENT)) / SX126X_CRYSTAL_FREQ)
    return self.setRfFrequency(frf)

def fixSensitivity(self):
    sensitivityConfig = bytearray(1)
    sensitivityConfig_mv = memoryview(sensitivityConfig)
    state = self.readRegister(SX126X_REG_SENSITIVITY_CONFIG, sensitivityConfig_mv, 1)
    ASSERT(state)

    if self.getPacketType() == SX126X_PACKET_TYPE_LORA and abs(self._bwKhz - 500.0) <= 0.001:
        sensitivityConfig_mv[0] &= 0xFB
    else:
        sensitivityConfig_mv[0] |= 0x04
    return self.writeRegister(SX126X_REG_SENSITIVITY_CONFIG, sensitivityConfig, 1)

def fixPaClamping(self):
    clampConfig = bytearray(1)
    clampConfig_mv = memoryview(clampConfig)
    state = self.readRegister(SX126X_REG_TX_CLAMP_CONFIG, clampConfig_mv, 1)
    ASSERT(state)

    clampConfig_mv[0] |= 0x1E
    return self.writeRegister(SX126X_REG_TX_CLAMP_CONFIG, clampConfig, 1)

def fixImplicitTimeout(self):
    if not (self._headerType == SX126X_LORA_HEADER_IMPLICIT and self.getPacketType() == SX126X_PACKET_TYPE_LORA):
        return ERR_WRONG_MODEM

    rtcStop = [0x00]
    state = self.writeRegister(SX126X_REG_RTC_STOP, rtcStop, 1)
    ASSERT(state)

    rtcEvent = bytearray(1)
    rtcEvent_mv = memoryview(rtcEvent)
    state = self.readRegister(SX126X_REG_RTC_EVENT, rtcEvent_mv, 1)
    ASSERT(state)

    rtcEvent_mv[0] |= 0x02
    return self.writeRegister(SX126X_REG_RTC_EVENT, rtcEvent, 1)

def fixInvertedIQ(self, iqConfig):
    iqConfigCurrent = bytearray(1)
    iqConfigCurrent_mv = memoryview(iqConfigCurrent)
    state = self.readRegister(SX126X_REG_IQ_CONFIG, iqConfigCurrent_mv, 1)
    ASSERT(state)

    if iqConfig == SX126X_LORA_IQ_STANDARD:
        iqConfigCurrent_mv[0] &= 0xFB
    else:
        iqConfigCurrent_mv[0] |= 0x04

    return self.writeRegister(SX126X_REG_IQ_CONFIG, iqConfigCurrent, 1)

def config(self, modem):
    state = self.setBufferBaseAddress()
    ASSERT(state)

    data = [0,0,0,0,0,0,0]
    data[0] = modem
    state = self.SPIwriteCommand([SX126X_CMD_SET_PACKET_TYPE], 1, data, 1)
    ASSERT(state)

    data[0] = SX126X_RX_TX_FALLBACK_MODE_STDBY_RC
    state = self.SPIwriteCommand([SX126X_CMD_SET_RX_TX_FALLBACK_MODE], 1, data, 1)
    ASSERT(state)

    data[0] = SX126X_CAD_ON_8_SYMB
    data[1] = self._sf + 13
    data[2] = 10
    data[3] = SX126X_CAD_GOTO_STDBY
    data[4] = 0x00
    data[5] = 0x00
    data[6] = 0x00
    state = self.SPIwriteCommand([SX126X_CMD_SET_CAD_PARAMS], 1, data, 7)
    ASSERT(state)

    state = self.clearIrqStatus()
    state |= self.setDioIrqParams(SX126X_IRQ_NONE, SX126X_IRQ_NONE)
    ASSERT(state)

    data[0] = SX126X_CALIBRATE_ALL
    state = self.SPIwriteCommand([SX126X_CMD_CALIBRATE], 1, data, 1)
    ASSERT(state)

    sleep_ms(5)

    if implementation.name == 'micropython':
      while self.gpio.value():
          yield_()

    if implementation.name == 'circuitpython':
      while self.gpio.value:
          yield_()

    return ERR_NONE

def SPIwriteCommand(self, cmd, cmdLen, data, numBytes, waitForBusy=True):
    return self.SPItransfer(cmd, cmdLen, True, data, [], numBytes, waitForBusy)

def SPIreadCommand(self, cmd, cmdLen, data, numBytes, waitForBusy=True):
    return self.SPItransfer(cmd, cmdLen, False, [], data, numBytes, waitForBusy)

def SPItransfer(self, cmd, cmdLen, write, dataOut, dataIn, numBytes, waitForBusy, timeout=5000):
    if implementation.name == 'micropython':
      self.cs.value(0)

      start = ticks_ms()
      while self.gpio.value():
          yield_()
          if abs(ticks_diff(start, ticks_ms())) >= timeout:
              self.cs.value(1)
              return ERR_SPI_CMD_TIMEOUT

      for i in range(cmdLen):
          self.spi.write(cmd[i])

    if implementation.name == 'circuitpython':
      while not self.spi.try_lock():
          pass
      self.cs.value = False

      start = ticks_ms()
      while self.gpio.value:
          yield_()
          if abs(ticks_diff(start, ticks_ms())) >= timeout:
              self.cs.value = True
              self.spi.unlock()
              return ERR_SPI_CMD_TIMEOUT

      for i in range(cmdLen):
          self.spi.write(bytes([cmd[i]]))

      in_ = bytearray(1)

    status = 0

    if write:
        for i in range(numBytes):
            if implementation.name == 'micropython':
              in_ = self.spi.read(1, write=dataOut[i])

            if implementation.name == 'circuitpython':
              self.spi.write_readinto(bytes([dataOut[i]]), in_)

            if (in_[0] & 0b00001110) == SX126X_STATUS_CMD_TIMEOUT or\
               (in_[0] & 0b00001110) == SX126X_STATUS_CMD_INVALID or\
               (in_[0] & 0b00001110) == SX126X_STATUS_CMD_FAILED:
                status = in_[0] & 0b00001110
                break
            elif (in_[0] == 0x00) or (in_[0] == 0xFF):
                status = SX126X_STATUS_SPI_FAILED
                break
    else:
        if implementation.name == 'micropython':
          in_ = self.spi.read(1, write=SX126X_CMD_NOP)

        if implementation.name == 'circuitpython':
          self.spi.readinto(in_)

        if (in_[0] & 0b00001110) == SX126X_STATUS_CMD_TIMEOUT or\
           (in_[0] & 0b00001110) == SX126X_STATUS_CMD_INVALID or\
           (in_[0] & 0b00001110) == SX126X_STATUS_CMD_FAILED:
            status = in_[0] & 0b00001110
        elif (in_[0] == 0x00) or (in_[0] == 0xFF):
            status = SX126X_STATUS_SPI_FAILED
        else:
            if implementation.name == 'micropython':
              for i in range(numBytes):
                  dataIn[i] = self.spi.read(1, write=SX126X_CMD_NOP)[0]

            if implementation.name == 'circuitpython':
              for i in range(numBytes):
                  self.spi.readinto(in_)
                  dataIn[i] = in_[0]

    if implementation.name == 'micropython':
      self.cs.value(1)

    if implementation.name == 'circuitpython':
      self.cs.value = True
      self.spi.unlock()

    if waitForBusy:
        sleep_us(1)
        start = ticks_ms()
        if implementation.name == 'micropython':
          while self.gpio.value():
              yield_()
              if abs(ticks_diff(start, ticks_ms())) >= timeout:
                  status =  SX126X_STATUS_CMD_TIMEOUT
                  break

        if implementation.name == 'circuitpython':
          while self.gpio.value:
              yield_()
              if abs(ticks_diff(start, ticks_ms())) >= timeout:
                  status =  SX126X_STATUS_CMD_TIMEOUT
                  break

    switch = {SX126X_STATUS_CMD_TIMEOUT: ERR_SPI_CMD_TIMEOUT,
              SX126X_STATUS_CMD_INVALID: ERR_SPI_CMD_INVALID,
              SX126X_STATUS_CMD_FAILED: ERR_SPI_CMD_FAILED,
              SX126X_STATUS_SPI_FAILED: ERR_CHIP_NOT_FOUND}
    try:
        return switch[status]
    except:
        return ERR_NONE

`

QiaoTuCodes commented 2 years ago

i'll not change anything. just change my Pin ports to appay pyboard_v1.1_cn boards.

ehong-tl commented 2 years ago

Can try to change line 46 to the following code, self.spi = SPI(2, baudrate=2000000, sck=Pin(clk), mosi=Pin(mosi), miso=Pin(miso))

QiaoTuCodes commented 2 years ago

okey,trying...

QiaoTuCodes commented 2 years ago

now new problem say: ValueError: explicit choice of sck/mosi/miso is not implemented

ehong-tl commented 2 years ago

how about this? self.spi = SPI(2, baudrate=2000000)

The pin of your SPI connection should be based on id as stated here.

In your case id=2 should be, (NSS, SCK, MISO, MOSI) = (Y5, Y6, Y7, Y8) = (PB12, PB13, PB14, PB15)

Sorry, I don't have pyboard in hand, its difficult for me to debug.

QiaoTuCodes commented 2 years ago

yes , it's 'B12=Y5=NSS \ B13=Y6=SCK \ B14=Y7=MISO \ B15=Y8=MOSI' , so i think self.spi = SPI(2, baudrate=2000000, sck=Pin(clk), mosi=Pin(mosi), miso=Pin(miso)) match that : Y6=SCK \ Y8=MOSI \ Y7=MISO . it's no problem right?

ehong-tl commented 2 years ago

sck, mosi and miso arguments are not implemented on micropython port for pyboard, should remove that from SPI object.

Just use self.spi = SPI(2, baudrate=2000000)

QiaoTuCodes commented 2 years ago

okey, try agin.

QiaoTuCodes commented 2 years ago

guy. new problem here:

Traceback (most recent call last): File "main.py", line 11, in <module> File "sx1268.py", line 27, in begin File "sx126x.py", line 116, in begin File "sx126x.py", line 241, in reset File "sx126x.py", line 390, in standby File "sx126x.py", line 1271, in SPIwriteCommand File "sx126x.py", line 1288, in SPItransfer TypeError: object with buffer protocol required

QiaoTuCodes commented 2 years ago

i'll changed :

with sx126x.py code:

line 40 def __init__(self, cs, irq, rst, gpio): line 46 self.spi = SPI(2, baudrate=2000000) line 44 self.spi = SPI(2, mode=SPI.MASTER, baudrate=2000000)

with sx1268.py code:

line 19 def __init__(self, cs, irq, rst, gpio): line 20 super().__init__(cs, irq, rst, gpio)

ehong-tl commented 2 years ago

try change the followings,

  1. line 1286 to self.spi.write(bytes([cmd[i]]))
  2. line 1311 to in_ = self.spi.read(1, write=bytes([dataOut[i]]))
  3. line 1326 to in_ = self.spi.read(1, write=bytes([SX126X_CMD_NOP]))
  4. line 1340 to dataIn[i] = self.spi.read(1, write=bytes([SX126X_CMD_NOP]))[0]
QiaoTuCodes commented 2 years ago

got it! try again.

QiaoTuCodes commented 2 years ago

changed say:

Traceback (most recent call last): File "main.py", line 11, in File "sx1268.py", line 27, in begin File "sx126x.py", line 116, in begin File "sx126x.py", line 241, in reset File "sx126x.py", line 390, in standby File "sx126x.py", line 1271, in SPIwriteCommand File "sx126x.py", line 1315, in SPItransfer TypeError: function doesn't take keyword arguments

ehong-tl commented 2 years ago

try change the following lines,

line 1311 to in_ = self.spi.read(1, bytes([dataOut[i]])) line 1326 to in_ = self.spi.read(1, bytes([SX126X_CMD_NOP])) line 1340 to dataIn[i] = self.spi.read(1, bytes([SX126X_CMD_NOP]))[0]

QiaoTuCodes commented 2 years ago

changed say:

Traceback (most recent call last): File "main.py", line 11, in File "sx1268.py", line 27, in begin File "sx126x.py", line 116, in begin File "sx126x.py", line 241, in reset File "sx126x.py", line 390, in standby File "sx126x.py", line 1271, in SPIwriteCommand File "sx126x.py", line 1316, in SPItransfer TypeError: can't convert bytes to int

ehong-tl commented 2 years ago

try change the following lines,

line 1311 to in = self.spi.read(1, dataOut[i]) line 1326 to in = self.spi.read(1, SX126X_CMD_NOP) line 1340 to dataIn[i] = self.spi.read(1, SX126X_CMD_NOP)[0]

QiaoTuCodes commented 2 years ago

got it! change right now...

QiaoTuCodes commented 2 years ago

resay:

Traceback (most recent call last): File "main.py", line 11, in File "sx1268.py", line 40, in begin File "_sx126x.py", line 12, in ASSERT AssertionError: ERR_INVALID_FREQUENCY

ehong-tl commented 2 years ago

May I know what frequency you are using? SX1268 is meant for 410MHz to 810 MHz

QiaoTuCodes commented 2 years ago

just default frequency . because i want to conn 2 sx1268 modules. just useing RX and TX somthing text will be okey. so i have 2 sx1268 modules here.

ehong-tl commented 2 years ago

the default example is using sx1262, try to change that and your frequency.

QiaoTuCodes commented 2 years ago

so like edit right:

sx.begin(freq=433, bw=500.0, sf=12, cr=8, syncWord=0x12, power=-5, currentLimit=60.0, preambleLength=8, implicit=False, implicitLen=0xFF, crcOn=True, txIq=False, rxIq=False, tcxoVoltage=1.7, useRegulatorLDO=False, blocking=True)

ehong-tl commented 2 years ago

yes

QiaoTuCodes commented 2 years ago

i'll changed that:

freq=434.0, bw=125.0, sf=9, cr=7, syncWord=SX126X_SYNC_WORD_PRIVATE, power=14, currentLimit=60.0, preambleLength=8, implicit=False, implicitLen=0xFF, crcOn=True, txIq=False, rxIq=False, tcxoVoltage=1.6, useRegulatorLDO=False, blocking=True

copy from sx1268.py code line 23

but got a new problem say:

Traceback (most recent call last): File "main.py", line 11, in File "sx1268.py", line 40, in begin File "_sx126x.py", line 12, in ASSERT AssertionError: ERR_SPI_CMD_FAILED

QiaoTuCodes commented 2 years ago

SX126X_SYNC_WORD_PRIVATE = 0x12

ehong-tl commented 2 years ago

Can you check your sx1268, does it comes with TCXO? If it does, try to set the correct voltage with tcxoVoltage, or disable it by setting to 0 if it is not present.

QiaoTuCodes commented 2 years ago

oh !!!!! guy! did it! it's work!!! so! cool!

QiaoTuCodes commented 2 years ago

ERR_NONE b'Hello World!' ERR_NONE b'Hello World!' ERR_NONE b'Hello World!' ERR_NONE b'Hello World!' ERR_NONE b'Hello World!' ERR_NONE b'Hello World!' ERR_NONE b'Hello World!' ERR_NONE b'Hello World!' ERR_NONE b'Hello World!' ERR_NONE b'Hello World!' ERR_NONE b'Hello World!' ERR_NONE

QiaoTuCodes commented 2 years ago

i'll useing pyboard_v1.1_cn and pyboard_plus to driver here!

QiaoTuCodes commented 2 years ago

thank you guy ! you're so nice to me.! did you have chat tools number ? join you friend and show you somthing...:)

ehong-tl commented 2 years ago

Glad to hear that everything's worked out.