ehong-tl/micropySX126X

SOS! something error about that!

Closed this issue · 46 comments

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!

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.

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 ?

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

okey! trying thank you bro!

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?

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.

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.

maybe the 2 libs it's not identical

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.

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.

Paste your modified code here is fine.

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

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

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

`

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

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))

okey,trying...

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

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.

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?

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)

okey, try agin.

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

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)

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]

got it! try again.

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

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]

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

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]

got it! change right now...

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

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

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.

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

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)

yes

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

SX126X_SYNC_WORD_PRIVATE = 0x12

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.

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

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

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

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

Glad to hear that everything's worked out.