import time
from struct import *
import logging
from machine import Pin

# 测试寄存器值对应寄存器
def debug_enum(enum):
  debug = {}
  for k, v in enum.__dict__.items():
    if type(v) is int:
      debug[v] = k
  return debug
#寄存器地址
class Reg:
  MODE              = 0x00
  MODE_CONTROL      = 0x01
  CALIBRATION       = 0x02
  FIFO_1            = 0x03
  ID                = 0x06
  GIO1S             = 0x0b
  CLOCK             = 0x0d
  DATA_RATE         = 0x0e
  PLL_I             = 0x0f
  TX_II             = 0x15
  RX                = 0x18
  RX_GAIN_I         = 0x19
  RX_GAIN_IV        = 0x1C
  CODE_I            = 0x1F
  CODE_II           = 0x20
  IF_CALIBRATION_I  = 0x22
  VCO_CALIBRATION_I = 0x25
  TX_TEST           = 0x28
  RX_DEM_TEST       = 0x29
#测试寄存器
debug_reg = debug_enum(Reg)
#状态寄存器地址
class State:
  SLEEP               = 0x80
  IDLE                = 0x90
  STANDBY             = 0xA0
  PLL                 = 0xB0
  RX                  = 0xC0
  TX                  = 0xD0
  RESET_WRITE_POINTER = 0xE0
  RESET_READ_POINTER  = 0xF0

debug_state = debug_enum(State)

#51个寄存器值
lut_df=[
0x00,0x42,0x00,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x19,0x21,0x05,0x00,0x50,0x9e,0x4b,0x00,0x02,
0x16,0x2b,0x12,0x00,0x62,0x80,0x80,0x00,0x0a,0x32,
0xc3,0x07,0x16,0x00,0x00,0x00,0x00,0x00,0x3b,0x00,
0x17,0x47,0x80,0x03,0x01,0x45,0x18,0x00,0x01,0x0f,
0x00]
#功耗值
class Power:
  _100uW = 0
  _300uW = 1
  _1mW   = 2
  _3mW   = 3
  _10mW  = 4
  _30mW  = 5
  _100mW = 6
  _150mW = 7

debug_power = debug_enum(Power)

# contains PAC and TBG values
power_enums = {}
power_enums[Power._100uW] = ( 0, 0 )
power_enums[Power._300uW] = ( 0, 1 ) # datasheet recommended
power_enums[Power._1mW]   = ( 0, 2 )
power_enums[Power._3mW]   = ( 0, 4 )
power_enums[Power._10mW]  = ( 1, 5 )
power_enums[Power._30mW]  = ( 2, 7 ) # looks like a good value
power_enums[Power._100mW] = ( 3, 7 ) # datasheet recommended
power_enums[Power._150mW] = ( 3, 7 ) # datasheet recommended

#读取
READ_BIT = 0x40 # flag bit specifying register should be read
#允许四线SPI
ENABLE_4WIRE = 0x19
#开始FIFO
FIFO_START = 0x05

def pbyte(byte):
  return pack('B', byte)

def ubyte(bytestring):
  return unpack('B', bytestring)[0]

class FormatPacketLazy:
  def __init__(self, packet):
    self.packet = packet

  def __str__(self):
    return ' '.join('%02x' % ubyte(byte) for byte in self.packet)

def format_packet(packet):
  return FormatPacketLazy(packet)

log = logging.getLogger('a7105')

class A7105:
  def __init__(self, sdi,scl,sdo, cs):
    self.sdi=Pin(sdi,Pin.OUT) #a7105 SDIO ----D7-----GPIO13
    self.scl=Pin(scl,Pin.OUT,value=0) #a7105 SCK----D5---GPIO14
    self.sdo=Pin(sdo,Pin.IN) #a7105 gio1-----D6---GPIO12
    self.cs=Pin(cs,Pin.OUT,value=0)
    
  def spi_write(self,dat):
      read_dat=0
      for i in range(8):
        self.scl(0)
        if (dat&0x80):  
            self.sdi(1)
        else:
            self.sdi(0)
        dat<<=1
        self.scl(1)
        read_dat<<=1
        if self.sdo.value():
            read_dat+=1
        self.scl(0)
      return read_dat

  #初始化
  def init(self): 
    self.reset()
    self.write_reg(Reg.GIO1S, ENABLE_4WIRE)
    self.strobe(State.STANDBY)
    self.set_power(Power._30mW)
    self.strobe(State.STANDBY)
    self.cs(0)
  #配置寄存器值
  def config_chip(self):
      for i in range(1,4):
          self.write_reg(i, lut_df[i])
      for i in range(7,35):
          self.write_reg(i, lut_df[i])
      for i in range(36,50):
          self.write_reg(i, lut_df[i])
  #设置频道
  def set_channel(self, channel):
    self.write_reg(Reg.PLL_I, channel)
  #校验检测
  def calibrate_if(self):
    log.debug('calibrating IF bank')
    self.write_reg(Reg.CALIBRATION, 0x01)
    calib_n = 0
    while True:
      if calib_n == 3:
        raise Exception("IF calibration did not complete.")
      elif self.read_reg(Reg.CALIBRATION) & 0x01 == 0:
        break
      time.sleep(0.001)
      calib_n += 1

    if self.read_reg(Reg.IF_CALIBRATION_I) & 0x01 != 0:
      raise Exception("IF calibration failed.")
    
    self.write_reg(0x24, 0x13)
    self.write_reg(0x25, 0x19)
    print('calibration complete')
    
  #写寄存器
  def write_reg(self, reg, value):
    #log.debug('read_reg(%s, %02x)', debug_reg[reg], value)   
    self.cs(0)
    self.spi_write(reg)
    self.spi_write(value)
    self.cs(1)
    #print(debug_reg[reg],value)
  #读寄存器值
  def read_reg(self, reg):
    self.cs(0)
    self.spi_write(READ_BIT | reg)
    value = self.spi_write(0)
    #print(value)
    self.cs(1)
    #log.debug('read_reg(%s) == %02x', debug_reg[reg], value)
    return value

  #重置
  def reset(self):
    log.debug('reset()')
    self.write_reg(Reg.MODE, 0x00)
    print('reset ok')

  #写通信ID
  def write_id(self, id):
    log.debug('write_id(%s)', format_packet(id))
    self.cs(0)
    self.spi_write(0x06)
    self.spi_write((id >> 24)&0xFF)
    self.spi_write((id >> 16)&0xFF)
    self.spi_write((id >> 8)&0xFF)
    self.spi_write((id >> 0)&0xFF)
    self.cs(1)
  #读取ID
  def read_id(self):
    log.debug('read_id()')
    self.cs(0)
    self.spi_write(0x46)
    result = 0
    for i in range(3):
      result += self.spi_write(0)
      result <<= 8
    result += self.spi_write(0)
    self.cs(1)
    return result
  #设置状态
  def strobe(self, state):
    log.debug('strobe(%s)', debug_state[state])
    self.cs(0)
    self.spi_write(state)
    self.cs(1)
  #设置功耗
  def set_power(self, power):
    log.debug('set_power(%s)', debug_power[power])
    pac, tbg = power_enums[power]
    self.write_reg(Reg.TX_TEST, (pac << 3) | tbg)
  #写数据到FIFO
  def write_data(self, dpbuffer):
    log.debug('write_data(%s)', format_packet(dpbuffer))
    self.cs(0)
    self.spi_write(State.RESET_WRITE_POINTER)
    self.spi_write(0x05)
    for i in range(len(dpbuffer)):
        self.spi_write(dpbuffer[i])
    self.cs(1)
    #print("write ok")
  #从fifo读数据
  def read_data(self, length):
    self.strobe(State.RESET_READ_POINTER)
    dpbuffer=list(range(0,64))
    for i in range(length):
        #print(i)
        dpbuffer[i]=self.read_reg(0x05)
    return dpbuffer