mpython.py源码

mpython.py源码下载

   1# --- autodoc 兼容(同步脚本注入):CPython 下补齐 MicroPython 专有 API ---
   2import time as _time_mod
   3for _n in ('sleep_ms', 'sleep_us'):
   4    if not hasattr(_time_mod, _n):
   5        setattr(_time_mod, _n, lambda *a, **k: None)
   6
   7# labplus mPython library
   8# MIT license; Copyright (c) 2018 labplus
   9# V1.0 Zhang KaiHua(apple_eat@126.com)
  10
  11# mpython buildin periphers drivers
  12
  13# history:
  14# V1.1 add oled draw function,add buzz.freq().  by tangliufeng
  15# V1.2 add servo/ui class,by tangliufeng
  16
  17from machine import I2C, PWM, Pin, ADC, TouchPad
  18from ssd1106 import SSD1106_I2C
  19import esp, math, time, network
  20import ustruct, array
  21from neopixel import NeoPixel
  22# from esp import dht_readinto
  23from time import sleep_ms, sleep_us, sleep
  24import framebuf 
  25import calibrate_img
  26from micropython import schedule,const
  27import NVS
  28import ubinascii
  29import machine
  30
  31try:
  32    i2c = I2C(0, scl=Pin(Pin.P19), sda=Pin(Pin.P20), freq=400000)
  33except Exception:  # autodoc 兼容:无硬件环境降级为 None
  34    i2c = None
  35
  36if '_print' not in dir(): _print = print
  37
  38def print(_t, *args, sep=' ', end='\n'):
  39    _s = str(_t)[0:1]
  40    if u'\u4e00' <= _s <= u'\u9fff':
  41        _print(' ' + str(_t), *args, sep=sep, end=end)
  42    else:
  43        _print(_t, *args, sep=sep, end=end)
  44
  45# my_wifi = wifi()
  46#多次尝试连接wifi
  47def try_connect_wifi(_wifi, _ssid, _pass, _times):
  48    if _times < 1: return False
  49    try:
  50        print("Try Connect WiFi ... {} Times".format(_times) )
  51        _wifi.connectWiFi(_ssid, _pass)
  52        if _wifi.sta.isconnected(): return True
  53        else:
  54            time.sleep(5)
  55            return try_connect_wifi(_wifi, _ssid, _pass, _times-1)
  56    except:
  57        time.sleep(5)
  58        return try_connect_wifi(_wifi, _ssid, _pass, _times-1)
  59
  60class Font(object):
  61    def __init__(self, font_address=0x400000):
  62        self.font_address = font_address
  63        buffer = bytearray(18)
  64        esp.flash_read(self.font_address, buffer)
  65        self.header, \
  66            self.height, \
  67            self.width, \
  68            self.baseline, \
  69            self.x_height, \
  70            self.Y_height, \
  71            self.first_char,\
  72            self.last_char = ustruct.unpack('4sHHHHHHH', buffer)
  73        self.first_char_info_address = self.font_address + 18
  74
  75    def GetCharacterData(self, c):
  76        uni = ord(c)
  77        # if uni not in range(self.first_char, self.last_char):
  78        #     return None
  79        if (uni < self.first_char or uni > self.last_char):
  80            return None
  81        char_info_address = self.first_char_info_address + \
  82            (uni - self.first_char) * 6
  83        buffer = bytearray(6)
  84        esp.flash_read(char_info_address, buffer)
  85        ptr_char_data, len = ustruct.unpack('IH', buffer)
  86        if (ptr_char_data) == 0 or (len == 0):
  87            return None
  88        buffer = bytearray(len)
  89        esp.flash_read(ptr_char_data + self.font_address, buffer)
  90        return buffer
  91
  92
  93class TextMode():
  94    normal = 1
  95    rev = 2
  96    trans = 3
  97    xor = 4
  98
  99
 100class OLED(SSD1106_I2C):
 101    """ 128x64 oled display """
 102
 103    def __init__(self):
 104        super().__init__(128, 64, i2c)
 105        self.f = Font()
 106        if self.f is None:
 107            raise Exception('font load failed')
 108
 109    def DispChar(self, s, x, y, mode=TextMode.normal, auto_return=False):
 110            row = 0
 111            str_width = 0
 112            if self.f is None:
 113                return
 114            for c in s:
 115                data = self.f.GetCharacterData(c)
 116                if data is None:
 117                    if auto_return is True:
 118                        x = x + self.f.width
 119                    else:
 120                        x = x + self.width
 121                    continue
 122                width, bytes_per_line = ustruct.unpack('HH', data[:4])
 123                # print('character [%d]: width = %d, bytes_per_line = %d' % (ord(c)
 124                # , width, bytes_per_line))
 125                if auto_return is True:
 126                    if x > self.width - width:
 127                        str_width += self.width - x
 128                        x = 0
 129                        row += 1
 130                        y += self.f.height
 131                        if y > (self.height - self.f.height)+0:
 132                            y, row = 0, 0
 133                for h in range(0, self.f.height):
 134                    w = 0
 135                    i = 0
 136                    while w < width:
 137                        mask = data[4 + h * bytes_per_line + i]
 138                        if (width - w) >= 8:
 139                            n = 8
 140                        else:
 141                            n = width - w
 142                        py = y + h
 143                        page = py >> 3
 144                        bit = 0x80 >> (py % 8)
 145                        for p in range(0, n):
 146                            px = x + w + p
 147                            c = 0
 148                            if (mask & 0x80) != 0:
 149                                if mode == TextMode.normal or \
 150                                        mode == TextMode.trans:
 151                                    c = 1
 152                                if mode == TextMode.rev:
 153                                    c = 0
 154                                if mode == TextMode.xor:
 155                                    c = self.buffer[page * (self.width if auto_return is True else 128) + px] & bit
 156                                    if c != 0:
 157                                        c = 0
 158                                    else:
 159                                        c = 1
 160                                super().pixel(px, py, c)
 161                            else:
 162                                if mode == TextMode.normal:
 163                                    c = 0
 164                                    super().pixel(px, py, c)
 165                                if mode == TextMode.rev:
 166                                    c = 1
 167                                    super().pixel(px, py, c)
 168                            mask = mask << 1
 169                        w = w + 8
 170                        i = i + 1
 171                x = x + width + 1
 172                str_width += width + 1
 173            return (str_width-1,(x-1, y))
 174
 175    def DispChar_font(self, font, s, x, y, invert=False):
 176        """
 177        custom font display.Ref by , https://github.com/peterhinch/micropython-font-to-py
 178        :param font:  use font_to_py.py script convert to `py` from `ttf` or `otf`.
 179        """
 180        screen_width = self.width
 181        screen_height = self.height
 182        text_row = x
 183        text_col = y
 184        text_length = 0
 185        if font.hmap():
 186            font_map = framebuf.MONO_HMSB if font.reverse() else framebuf.MONO_HLSB
 187        else:
 188            raise ValueError('Font must be horizontally mapped.')
 189        for c in s:
 190            glyph, char_height, char_width = font.get_ch(c)
 191            buf = bytearray(glyph)
 192            if invert:
 193                for i, v in enumerate(buf):
 194                    buf[i] = 0xFF & ~ v
 195            fbc = framebuf.FrameBuffer(buf, char_width, char_height, font_map)
 196            if text_row + char_width > screen_width - 1:
 197                text_length += screen_width-text_row
 198                text_row = 0
 199                text_col += char_height
 200            if text_col + char_height > screen_height + 2:
 201                text_col = 0
 202
 203            super().blit(fbc, text_row, text_col)
 204            text_row = text_row + char_width+1
 205            text_length += char_width+1
 206        return (text_length-1, (text_row-1, text_col))
 207
 208# display
 209if 60 in i2c.scan():
 210    oled = OLED()
 211    display = oled
 212else:
 213    print("oled init error!")
 214
 215class MOTION(object):
 216    def __init__(self):
 217        self.i2c = i2c
 218        addr = self.i2c.scan()
 219        if 38 in addr:
 220            MOTION.chip = 1  # MSA300
 221            MOTION.IIC_ADDR = 38
 222        elif 107 in addr:
 223            MOTION.chip = 2  # QMI8658
 224            MOTION.IIC_ADDR = 107
 225        else:
 226            raise OSError("MOTION init error")
 227        if(MOTION.chip == 1):
 228            pass
 229        elif(MOTION.chip == 2):
 230            MOTION._writeReg(0x60, 0x01) # soft reset regist value.
 231            time.sleep_ms(20)
 232            MOTION._writeReg(0x02, 0x60) # Enabe reg address auto increment auto
 233            MOTION._writeReg(0x08, 0x03) # Enable accel and gyro
 234            MOTION._writeReg(0x03, 0x1c) # accel range:4g ODR 128HZ
 235            MOTION._writeReg(0x04, 0x40) # gyro ODR 8000HZ, FS 256dps
 236            MOTION._writeReg(0x06, 0x55) # Enable accel and gyro Low-Pass Filter
 237        # print('Motion init finished!')
 238
 239    # @staticmethod
 240    def _readReg(reg, nbytes=1):
 241        return i2c.readfrom_mem(MOTION.IIC_ADDR, reg, nbytes)
 242
 243    # @staticmethod
 244    def _writeReg(reg, value):
 245        i2c.writeto_mem(MOTION.IIC_ADDR, reg, value.to_bytes(1, 'little'))
 246
 247    def get_fw_version(self):
 248        if(self.chip==1):
 249            pass
 250        elif(self.chip==2):
 251            MOTION._writeReg(0x0a, 0x10) # send ctrl9R read FW cmd
 252            while True:
 253                if (MOTION._readReg(0x2F, 1)[0] & 0X01) == 0X01:
 254                    break
 255            buf = MOTION._readReg(0X49, 3)
 256            # print(buf[0])
 257            # print(buf[1])
 258            # print(buf[2])
 259        
 260    class Accelerometer():
 261        """MSA300"""
 262        # Range and resolustion
 263        RANGE_2G = const(0)
 264        RANGE_4G = const(1)
 265        RANGE_8G = const(2)
 266        RANGE_16G = const(3)
 267        RES_14_BIT = const(0) 
 268        RES_12_BIT = const(1)
 269        RES_10_BIT = const(2)
 270        # Event
 271        TILT_LEFT = const(0)
 272        TILT_RIGHT = const(1)
 273        TILT_UP = const(2)
 274        TILT_DOWN = const(3)
 275        FACE_UP = const(4)
 276        FACE_DOWN = const(5)
 277        SINGLE_CLICK = const(6)
 278        DOUBLE_CLICK = const(7)
 279        FREEFALL = const(8)
 280
 281        """QMI8658C"""
 282        # Range and resolustion
 283        # QMI8658C_RANGE_2G = const(0x00)
 284        # QMI8658C_RANGE_4G = const(0x10)
 285        # QMI8658C_RANGE_8G = const(0x20)
 286        # QMI8658C_RANGE_16G = const(0x40)
 287
 288        def __init__(self):
 289            if(MOTION.chip==1):
 290                self.set_resolution(MOTION.Accelerometer.RES_10_BIT)
 291                self.set_range(MOTION.Accelerometer.RANGE_2G)
 292                MOTION._writeReg(0x12, 0x03)               # polarity of y,z axis,
 293                MOTION._writeReg(0x11, 0)                  # set power mode = normal
 294                # interrupt
 295                MOTION._writeReg(0x16, 0x70)      # int enabled: Orient | S_TAP | D_TAP 
 296                MOTION._writeReg(0x17, 0x08)      # int enabled: Freefall
 297                MOTION._writeReg(0x19, 0x71)      # int1 map to: Orient, S_TAP, D_TAP, Freefall
 298                MOTION._writeReg(0x20, 0x02)      # int1 active level = 0, output = OD
 299                MOTION._writeReg(0x21, 0x0C)      # int tempoary latched 25ms
 300                # freefall:
 301                #   single mode: |acc_x| < Threshold && |acc_y| < Threshold && |acc_z| < Threshold, at least time > Duration
 302                #   sum mode: |acc_x| + |acc_y| + |acc_z| < Threshold, at least time > Duration
 303                MOTION._writeReg(0x22, 20)    # Freefall Duration:(n+1)*2ms, range from 2ms to 512ms
 304                MOTION._writeReg(0x23, 48)    # Freefall Threshold: n*7.81mg
 305                MOTION._writeReg(0x24, 0x01)  # Freefall mode = 0-singlemode;hysteresis = n*125mg
 306                # tap:
 307                MOTION._writeReg(0x2A, 0x06)  # Tap duration:quit = 30ms, shock=50ms, time window for secent shock=500ms
 308                MOTION._writeReg(0x2B, 0x0A)  # Tap threshold = 10*[62.5mg@2G | 125mg@4G | 250mg@8G | 500mg@16g]
 309                # Orient
 310                MOTION._writeReg(0x2C, 0x18)  # Orient hysteresis= 1*62.5mg; 
 311                                            #        block mode = 10 z_axis blocking or slope in any axis > 0.2g;
 312                                            #        orient mode = 00-symetrical
 313                MOTION._writeReg(0x2D, 8)     # Z-axis block
 314                # int pin irq register
 315                self.int = Pin(37, Pin.IN)
 316                self.int.irq(trigger=Pin.IRQ_FALLING, handler=self.irq)
 317                # event handler 
 318                self.event_tilt_up = None
 319                self.event_tilt_down = None
 320                self.event_tilt_left = None
 321                self.event_tilt_right = None
 322                self.event_face_up = None
 323                self.event_face_down = None
 324                self.event_single_click = None
 325                self.event_double_click = None
 326                self.event_freefall = None
 327            elif(MOTION.chip==2):
 328                # 设置偏移值
 329                self.x_offset = 0
 330                self.y_offset = 0
 331                self.z_offset = 0
 332                self.get_nvs_offset()
 333                try:
 334                    id =  MOTION._readReg(0x0, 2)
 335                except:
 336                    pass
 337                self.set_range(MOTION.Accelerometer.RANGE_2G) #设置默认分辨率+-2g
 338                self.int = Pin(37, Pin.IN)
 339                self.int.irq(trigger=Pin.IRQ_FALLING, handler=self.irq)
 340                # event handler 
 341                self.wom = None
 342            
 343
 344        def irq(self, arg):
 345            if(MOTION.chip==1):
 346                reg_int = MOTION._readReg(0x09)[0]
 347                reg_orent = MOTION._readReg(0x0C)[0]
 348                # orient_int
 349                if (reg_int & 0x40):
 350                    if ((reg_orent & 0x30) == 0x00 and self.event_tilt_left is not None):
 351                        schedule(self.event_tilt_left, self.TILT_LEFT)
 352                    if ((reg_orent & 0x30) == 0x10 and self.event_tilt_right is not None):
 353                        schedule(self.event_tilt_right, self.TILT_RIGHT)
 354                    if ((reg_orent & 0x30) == 0x20 and self.event_tilt_up is not None):
 355                        schedule(self.event_tilt_up, self.TILT_UP)
 356                    if ((reg_orent & 0x30) == 0x30 and self.event_tilt_down is not None):
 357                        schedule(self.event_tilt_down, self.TILT_DOWN)
 358                    if ((reg_orent & 0x40) == 0x00 and self.event_face_up):
 359                        schedule(self.event_face_up, self.FACE_UP)
 360                    if ((reg_orent & 0x40) == 0x40 and self.event_face_down):
 361                        schedule(self.event_face_down, self.FACE_DOWN)
 362                # single tap
 363                if (reg_int & 0x20):
 364                    if (self.event_single_click is not None):
 365                        schedule(self.event_single_click, self.SINGLE_CLICK)
 366                # double tap
 367                if (reg_int & 0x10):
 368                    if (self.event_double_click is not None):
 369                        schedule(self.event_double_click, self.DOUBLE_CLICK)
 370                # freefall
 371                if (reg_int & 0x01):
 372                    if (self.event_freefall is not None):
 373                        schedule(self.event_freefall, self.FREEFALL)
 374                # print("acc sensor interrupt, because 0x%2x, orient = 0x%2x" % (reg_int, reg_orent))
 375            elif(MOTION.chip==2):  
 376                flag = MOTION._readReg(0x2F, 1)[0]
 377                if (flag & 0x04) == 0x04:
 378                    print('wom int trigged.')
 379
 380        def wom_config(self):
 381            if(MOTION.chip==1):
 382                pass
 383            elif(MOTION.chip==2):
 384                MOTION._writeReg(0x60, 0x01) # soft reset regist value.
 385                time.sleep_ms(20)
 386                MOTION._writeReg(0x08, 0x0) # disable all sensor
 387                MOTION._writeReg(0x03, 0x1c) # accel range:4g ODR 128HZ
 388                MOTION._writeReg(0x0B, 0xfF) # CAL_L WoM Threshold(1mg/LSB resolution)
 389                MOTION._writeReg(0x0C, 0x8F) # CAL_H WoM (INT1 blank time 0x1f)
 390                MOTION._writeReg(0x0A, 0x08)
 391                while True:
 392                    if (MOTION._readReg(0x2F, 1)[0] & 0X01) == 0X01:
 393                        break
 394                MOTION._writeReg(0x08, 0x01) # enable accel
 395
 396        def set_resolution(self, resolution):# set data output rate
 397            if(MOTION.chip==1):
 398                format = MOTION._readReg(0x0f, 1)
 399                format = format[0] & ~0xC
 400                format |= (resolution << 2)
 401                MOTION._writeReg(0x0f, format)
 402            elif(MOTION.chip==2):
 403                self.odr = resolution
 404                format = MOTION._readReg(0x03, 1)
 405                format = format[0] & 0xf0
 406                format |= (resolution & 0x0f)
 407                MOTION._writeReg(0x03, format)
 408                
 409        def set_range(self, range):
 410            if(MOTION.chip==1):
 411                self.range = range
 412                format = MOTION._readReg(0x0f, 1)
 413                format = format[0] & ~0x3
 414                format |= range
 415                MOTION._writeReg(0x0f, format)
 416            elif(MOTION.chip==2):
 417                if(range==3):
 418                    range = 64 #0x40
 419                else:
 420                    range = range << 4
 421                self.FS = 2*(2**(range >> 4))
 422                format = MOTION._readReg(0x03, 1)
 423                format = format[0] & 0x8F
 424                format |= range
 425                MOTION._writeReg(0x03, format)
 426
 427        def set_offset(self, x=None, y=None, z=None):
 428            if(MOTION.chip==1):
 429                for i in (x, y, z):
 430                    if i is not None:
 431                        if i < -1 or i > 1:
 432                            raise ValueError("out of range,only offset 1 gravity")
 433                if x is not None:
 434                    MOTION._writeReg(0x39, int(round(x/0.0039)))
 435                elif y is not None:
 436                    MOTION._writeReg(0x38, int(round(y/0.0039)))
 437                elif z is not None:
 438                    MOTION._writeReg(0x3A, int(round(z/0.0039)))
 439            elif(MOTION.chip==2):
 440                for i in (x, y, z):
 441                    if i is not None:
 442                        if i < -16 or i > 16:
 443                            raise ValueError("超出调整范围!!!")
 444                if x is not None:
 445                    self.x_offset = x
 446                    self.set_nvs_offset("x", x)
 447                if y is not None:
 448                    self.y_offset = y
 449                    self.set_nvs_offset("y", y)
 450                if z is not None:
 451                    self.z_offset = z
 452                    self.set_nvs_offset("z", z)
 453                
 454        def get_x(self):
 455            if(MOTION.chip==1):
 456                retry = 0
 457                if (retry < 5):
 458                    try:
 459                        buf = MOTION._readReg(0x02, 2)
 460                        x = ustruct.unpack('h', buf)[0]
 461                        return x / 4 / 4096 * 2**self.range
 462                    except:
 463                        retry = retry + 1
 464                else:
 465                    raise Exception("i2c read/write error!")
 466            elif(MOTION.chip==2):
 467                buf = MOTION._readReg(0x35, 2)
 468                x = ustruct.unpack('<h', buf)[0]
 469                return (x * self.FS) / 32768 + self.x_offset
 470
 471        def get_y(self):
 472            if(MOTION.chip==1):
 473                retry = 0
 474                if (retry < 5):
 475                    try:
 476                        buf = MOTION._readReg(0x04, 2)
 477                        y = ustruct.unpack('h', buf)[0]
 478                        return y / 4 / 4096 * 2**self.range
 479                    except:
 480                        retry = retry + 1
 481                else:
 482                    raise Exception("i2c read/write error!")
 483            elif(MOTION.chip==2):
 484                buf = MOTION._readReg(0x37, 2)
 485                y = ustruct.unpack('<h', buf)[0]
 486                return (y * self.FS) / 32768  + self.y_offset
 487
 488        def get_z(self):
 489            if(MOTION.chip==1):
 490                retry = 0
 491                if (retry < 5):
 492                    try:
 493                        buf = MOTION._readReg(0x06, 2)
 494                        z = ustruct.unpack('h', buf)[0]
 495                        return z / 4 / 4096 * 2**self.range
 496                    except:
 497                        retry = retry + 1
 498                else:
 499                    raise Exception("i2c read/write error!")
 500            elif(MOTION.chip==2):
 501                buf = MOTION._readReg(0x39, 2)
 502                z = ustruct.unpack('<h', buf)[0]
 503                return (z * self.FS) / 32768 + self.z_offset
 504                # return -(z * self.FS) / 32768
 505     
 506        def roll_pitch_angle(self):
 507            x, y, z = self.get_x(), self.get_y(), -self.get_z()
 508            # vector normalize
 509            mag = math.sqrt(x ** 2 + y ** 2+z ** 2)
 510            x /= mag
 511            y /= mag
 512            z /= mag
 513            roll = math.degrees(-math.asin(y))
 514            pitch = math.degrees(math.atan2(x, z))
 515
 516            return roll, pitch
 517        
 518        def get_nvs_offset(self):
 519            try:
 520                tmp = NVS("offset_a")
 521                self.x_offset = round(tmp.get_i32("x")/1e5, 5)
 522                self.y_offset = round(tmp.get_i32("y")/1e5, 5)
 523                self.z_offset = round(tmp.get_i32("z")/1e5, 5)
 524            except OSError as e:
 525                # print('Accelerometer get_nvs_offset:',e)
 526                # self.x_offset = 0
 527                # self.y_offset = 0
 528                # self.z_offset = 0
 529                self.set_offset(0,0,0)
 530        
 531        def set_nvs_offset(self, key, value):
 532            try:
 533                nvs = NVS("offset_a")
 534                nvs.set_i32(key, int(value*1e5))
 535                nvs.commit()
 536            except OSError as e:
 537                print('Gyroscope set_nvs_offset error:',e)
 538
 539    class Gyroscope():
 540        # gyro full scale
 541        RANGE_16_DPS =  const(0x00)
 542        RANGE_32_DPS =  const(0x10)
 543        RANGE_64_DPS =  const(0x20)
 544        RANGE_128_DPS =  const(0x30)
 545        RANGE_256_DPS =  const(0x40)
 546        RANGE_512_DPS =  const(0x50)
 547        RANGE_1024_DPS = const(0x60)
 548        RANGE_2048_DPS = const(0x70)
 549
 550        def __init__(self):
 551            if(MOTION.chip==1):
 552                pass
 553            elif(MOTION.chip==2):
 554                # 设置偏移值
 555                self.x_offset = 0
 556                self.y_offset = 0
 557                self.z_offset = 0
 558                self.get_nvs_offset()
 559                self.set_range(MOTION.Gyroscope.RANGE_256_DPS)
 560
 561        def set_range(self, range):
 562            if(MOTION.chip==1):
 563                pass
 564            elif(MOTION.chip==2):
 565                self.FS = 16*(2**(range >> 4))        
 566                format = MOTION._readReg(0x04, 1)
 567                format = format[0] & 0x8F
 568                format |= range
 569                MOTION._writeReg(0x04, format)
 570
 571        def set_ODR(self, odr):  # set data output rate
 572            if(MOTION.chip==1):
 573                pass
 574            elif(MOTION.chip==2):
 575                self.odr = odr
 576                format = MOTION._readReg(0x04, 1)
 577                format = format[0] & 0xF0
 578                format |= odr
 579                MOTION._writeReg(0x04, format)
 580
 581        def get_x(self):
 582            if(MOTION.chip==1):
 583                pass
 584            elif(MOTION.chip==2):
 585                buf = MOTION._readReg(0x3b, 2)
 586                x = ustruct.unpack('<h', buf)[0]
 587                return (x * self.FS) / 32768 + self.x_offset
 588
 589        def get_y(self):
 590            if(MOTION.chip==1):
 591                pass
 592            elif(MOTION.chip==2):
 593                buf = MOTION._readReg(0x3d, 2)
 594                y = ustruct.unpack('<h', buf)[0]
 595                return (y * self.FS) / 32768 + self.y_offset
 596
 597        def get_z(self):
 598            if(MOTION.chip==1):
 599                pass
 600            elif(MOTION.chip==2):
 601                buf = MOTION._readReg(0x3f, 2)
 602                z = ustruct.unpack('<h', buf)[0]
 603                return (z * self.FS) / 32768 + self.z_offset
 604        
 605        def set_offset(self, x=None, y=None, z=None):
 606            if(MOTION.chip==1):
 607                pass
 608            elif(MOTION.chip==2):
 609                for i in (x, y, z):
 610                    if i is not None:
 611                        if i < -4096 or i > 4096:
 612                            raise ValueError("超出调整范围!!!")
 613                if x is not None:
 614                    self.x_offset = x
 615                    self.set_nvs_offset("x", x)
 616                if y is not None:
 617                    self.y_offset = y
 618                    self.set_nvs_offset("y", y)
 619                if z is not None:
 620                    self.z_offset = z
 621                    self.set_nvs_offset("z", z)
 622
 623        def get_nvs_offset(self):
 624            if(MOTION.chip==1):
 625                pass
 626            elif(MOTION.chip==2):
 627                try:
 628                    tmp = NVS("offset_g")
 629                    self.x_offset = round(tmp.get_i32("x")/1e5, 5)
 630                    self.y_offset = round(tmp.get_i32("y")/1e5, 5)
 631                    self.z_offset = round(tmp.get_i32("z")/1e5, 5)
 632                except OSError as e:
 633                    # print('Gyroscope get_nvs_offset:',e)
 634                    self.set_offset(0,0,0)
 635                    # self.x_offset = 0
 636                    # self.y_offset = 0
 637                    # self.z_offset = 0
 638
 639        def set_nvs_offset(self, key, value):
 640            try:
 641                nvs = NVS("offset_g")
 642                nvs.set_i32(key, int(value*1e5))
 643                nvs.commit()
 644            except OSError as e:
 645                print('Gyroscope set_nvs_offset error:',e)
 646
 647    
 648try:
 649    motion = MOTION()
 650except Exception:  # autodoc 兼容:无硬件环境降级为 None
 651    motion = None
 652try:
 653    accelerometer = motion.Accelerometer()
 654except Exception:  # autodoc 兼容:无硬件环境降级为 None
 655    accelerometer = None
 656try:
 657    gyroscope = motion.Gyroscope()
 658except Exception:  # autodoc 兼容:无硬件环境降级为 None
 659    gyroscope = None
 660
 661class Magnetic(object):
 662    """ MMC5983MA driver """
 663    """ MMC5603NJ driver 20211028替换"""
 664    def __init__(self):
 665        self.addr = 48
 666        self.i2c = i2c
 667        self._judge_id()
 668        time.sleep_ms(5)
 669        if (self.product_ID==48):
 670            pass  # MMC5983MA
 671        elif (self.product_ID==16):
 672            pass  # MMC5603NJ
 673        else:
 674            raise OSError("Magnetic init error")
 675        """ MMC5983MA driver """
 676        # 传量器裸数据,乘0.25后转化为mGS
 677        self.raw_x = 0.0
 678        self.raw_y = 0.0
 679        self.raw_z = 0.0
 680        # 校准后的偏移量, 基于裸数据
 681        self.cali_offset_x = 0.0 
 682        self.cali_offset_y = 0.0
 683        self.cali_offset_z = 0.0
 684        # 去皮偏移量,类似电子秤去皮功能,基于裸数据。
 685        self.peeling_x = 0.0
 686        self.peeling_y = 0.0
 687        self.peeling_z = 0.0
 688        self.is_peeling = 0
 689        if (self.chip==1):
 690            self.i2c.writeto(self.addr, b'\x09\x20\xbd\x00', True)
 691        """ MMC5603NJ driver """
 692        if (self.chip==2):
 693            self._writeReg(0x1C, 0x80)#软件复位
 694            time.sleep_ms(100)
 695            self._writeReg(0x1A, 255)
 696            self._writeReg(0x1B, 0b10100001)
 697            # self._writeReg(0x1C, 0b00000011)
 698            self._writeReg(0x1C, 0b00000000)
 699            self._writeReg(0x1D, 0b10010000)
 700            time.sleep_ms(100)
 701
 702    def _readReg(self, reg, nbytes=1):
 703        return i2c.readfrom_mem(self.addr, reg, nbytes)
 704
 705    def _writeReg(self, reg, value):
 706        i2c.writeto_mem(self.addr, reg, value.to_bytes(1, 'little')) 
 707
 708    def _set_offset(self):
 709        if(self.chip == 1):
 710            self.i2c.writeto(self.addr, b'\x09\x08', True)  #set
 711            self.i2c.writeto(self.addr, b'\x09\x01', True)
 712            while True:
 713                self.i2c.writeto(self.addr, b'\x08', False)
 714                buf = self.i2c.readfrom(self.addr, 1)
 715                status = ustruct.unpack('B', buf)[0]
 716                if(status & 0x01):
 717                    break
 718            self.i2c.writeto(self.addr, b'\x00', False)
 719            buf = self.i2c.readfrom(self.addr, 6)
 720            data = ustruct.unpack('>3H', buf)
 721
 722            self.i2c.writeto(self.addr, b'\x09\x10', True)  #reset
 723
 724            self.i2c.writeto(self.addr, b'\x09\x01', True)
 725            while True:
 726                self.i2c.writeto(self.addr, b'\x08', False)
 727                buf = self.i2c.readfrom(self.addr, 1)
 728                status = ustruct.unpack('B', buf)[0]
 729                if(status & 0x01):
 730                    break
 731            self.i2c.writeto(self.addr, b'\x00', False)
 732            buf = self.i2c.readfrom(self.addr, 6)
 733            data1 = ustruct.unpack('>3H', buf)
 734
 735            self.x_offset = (data[0] + data1[0])/2
 736            self.y_offset = (data[1] + data1[1])/2
 737            self.z_offset = (data[2] + data1[2])/2
 738        elif(self.chip == 2):
 739            pass
 740    
 741    def _get_raw(self):
 742        if (self.chip == 1):
 743            retry = 0
 744            if (retry < 5):
 745                try:
 746                    self.i2c.writeto(self.addr, b'\x09\x08', True)  #set
 747
 748                    self.i2c.writeto(self.addr, b'\x09\x01', True)
 749                    while True:
 750                        self.i2c.writeto(self.addr, b'\x08', False)
 751                        buf = self.i2c.readfrom(self.addr, 1)
 752                        status = ustruct.unpack('B', buf)[0]
 753                        if(status & 0x01):
 754                            break
 755                    self.i2c.writeto(self.addr, b'\x00', False)
 756                    buf = self.i2c.readfrom(self.addr, 6)
 757                    data = ustruct.unpack('>3H', buf)
 758
 759                    self.i2c.writeto(self.addr, b'\x09\x10', True)  #reset
 760
 761                    self.i2c.writeto(self.addr, b'\x09\x01', True)
 762                    while True:
 763                        self.i2c.writeto(self.addr, b'\x08', False)
 764                        buf = self.i2c.readfrom(self.addr, 1)
 765                        status = ustruct.unpack('B', buf)[0]
 766                        if(status & 0x01):
 767                            break
 768                    self.i2c.writeto(self.addr, b'\x00', False)
 769                    buf = self.i2c.readfrom(self.addr, 6)
 770                    data1 = ustruct.unpack('>3H', buf)
 771
 772                    self.raw_x = -((data[0] - data1[0])/2)
 773                    self.raw_y = -((data[1] - data1[1])/2)
 774                    self.raw_z = -((data[2] - data1[2])/2)
 775                    # print(str(self.raw_x) + "   " + str(self.raw_y) + "  " + str(self.raw_z))
 776                except:
 777                    retry = retry + 1
 778            else:
 779                raise Exception("i2c read/write error!")     
 780        elif(self.chip == 2):
 781            retry = 0
 782            if (retry < 5):
 783                try:
 784                    _raw_x = 0.0
 785                    _raw_y = 0.0
 786                    _raw_z = 0.0
 787
 788                    # self.i2c.writeto(self.addr, b'\x1B\x08', True)  #set
 789                    # self.i2c.writeto(self.addr, b'\x1B\x01', True)
 790                    
 791                    # while True:
 792                    #     buf = self._readReg(0x18, 1)
 793                    #     status = buf[0]
 794                    #     if(status & 0x40):
 795                    #         break
 796
 797                    # _buf = self._readReg(0x00, 9)
 798
 799                    self.i2c.writeto(self.addr, b'\x1B\x08', True)  #set
 800                    # self.i2c.writeto(self.addr, b'\x1B\x80', True)
 801                    self.i2c.writeto(self.addr, b'\x1B\x01', True)
 802                    
 803                    while True:
 804                        sleep_ms(25)
 805                        buf = self._readReg(0x18, 1)
 806                        status = buf[0]
 807                        if(status & 0x40):
 808                            break
 809
 810                    buf = self._readReg(0x00, 9)
 811
 812                    _raw_x = (buf[0] << 12) | (buf[1] << 4) | (buf[6] >> 4)
 813                    _raw_y = (buf[2] << 12) | (buf[3] << 4) | (buf[7] >> 4)
 814                    _raw_z = (buf[4] << 12) | (buf[5] << 4) | (buf[8] >> 4)
 815
 816                    self.raw_x = _raw_x
 817                    self.raw_y = _raw_y
 818                    self.raw_z = _raw_z
 819                except:
 820                    retry = retry + 1
 821            else:
 822                raise Exception("i2c read/write error!")
 823
 824    def peeling(self):
 825        '''
 826        去除磁场环境
 827        '''
 828        self._get_raw()
 829        self.peeling_x = self.raw_x
 830        self.peeling_y = self.raw_y
 831        self.peeling_z = self.raw_z
 832        self.is_peeling = 1
 833
 834    def clear_peeling(self):
 835        self.peeling_x = 0.0
 836        self.peeling_y = 0.0
 837        self.peeling_z = 0.0
 838        self.is_peeling = 0
 839
 840    def get_x(self):
 841        if (self.chip == 1):
 842            self._get_raw()
 843            return self.raw_x * 0.25
 844        if (self.chip == 2):
 845            self._get_raw()
 846            if(self.cali_offset_x):
 847                return -0.0625 * (self.raw_x - self.cali_offset_x)
 848            else:
 849                return -0.0625 * (self.raw_x - 524288)
 850            # return -(self.raw_x - 524288)/16384
 851
 852    def get_y(self):
 853        if (self.chip == 1):
 854            self._get_raw()
 855            return self.raw_y * 0.25
 856        if (self.chip == 2):
 857            self._get_raw()
 858            if(self.cali_offset_y):
 859                return -0.0625 * (self.raw_y - self.cali_offset_y)
 860            else:
 861                return -0.0625 * (self.raw_y - 524288)
 862            # return -(self.raw_y - 524288)/16384
 863
 864    def get_z(self):
 865        if (self.chip == 1):
 866            self._get_raw()
 867            return self.raw_z * 0.25 
 868        if (self.chip == 2):
 869            self._get_raw()
 870            if(self.cali_offset_z):
 871                return 0.0625 * (self.raw_z - self.cali_offset_z)
 872            else:
 873                return 0.0625 * (self.raw_z - 524288)
 874            # return (self.raw_z - 524288)/16384
 875
 876    def get_field_strength(self):
 877        if(self.chip==1):
 878            self._get_raw()
 879            if self.is_peeling == 1:
 880                return (math.sqrt((self.raw_x - self.peeling_x)*(self.raw_x - self.peeling_x) + (self.raw_y - self.peeling_y)*(self.raw_y - self.peeling_y) + (self.raw_z - self.peeling_z)*(self.raw_z - self.peeling_z)))*0.25
 881            return (math.sqrt(self.raw_x * self.raw_x + self.raw_y * self.raw_y + self.raw_z * self.raw_z))*0.25
 882        elif(self.chip==2):
 883            self._get_raw()
 884            if self.is_peeling == 1:
 885                return (math.sqrt(math.pow(self.raw_x - self.peeling_x, 2) + pow(self.raw_y - self.peeling_y, 2) + pow(self.raw_z - self.peeling_z , 2)))*0.0625
 886            return (math.sqrt(math.pow(self.get_x(), 2) + pow(self.get_y(), 2) + pow(self.get_z(), 2)))
 887
 888    def calibrate(self):
 889        oled.fill(0)
 890        oled.DispChar("步骤1:", 0,0,1)
 891        oled.DispChar("如图",0,26,1)
 892        oled.DispChar("转几周",0,43,1)
 893        oled.bitmap(64,0,calibrate_img.rotate,64,64,1)
 894        oled.show()
 895        self._get_raw()
 896        min_x = max_x = self.raw_x
 897        min_y = max_y = self.raw_y
 898        min_z = max_z = self.raw_z
 899        ticks_start = time.ticks_ms()
 900        while (time.ticks_diff(time.ticks_ms(), ticks_start) < 15000) :
 901            self._get_raw()
 902            min_x = min(self.raw_x, min_x)
 903            min_y = min(self.raw_y, min_y)
 904            max_x = max(self.raw_x, max_x)
 905            max_y = max(self.raw_y, max_y)
 906            time.sleep_ms(100)
 907        self.cali_offset_x = (max_x + min_x) / 2
 908        self.cali_offset_y = (max_y + min_y) / 2
 909        print('cali_offset_x: ' + str(self.cali_offset_x) + '  cali_offset_y: ' + str(self.cali_offset_y))
 910        oled.fill(0)
 911        oled.DispChar("步骤2:", 85,0,1)
 912        oled.DispChar("如图",85,26,1)
 913        oled.DispChar("转几周",85,43,1)
 914        oled.bitmap(0,0,calibrate_img.rotate1,64,64,1)
 915        oled.show()
 916        ticks_start = time.ticks_ms()
 917        while (time.ticks_diff(time.ticks_ms(), ticks_start) < 15000) :
 918            self._get_raw()
 919            min_z = min(self.raw_z, min_z)
 920            max_z = max(self.raw_z, max_z)
 921            time.sleep_ms(100)
 922        self.cali_offset_z = (max_z + min_z) / 2
 923  
 924        print('cali_offset_z: ' + str(self.cali_offset_z))
 925
 926        oled.fill(0)
 927        oled.DispChar("校准完成", 40,24,1)
 928        oled.show()
 929        oled.fill(0)
 930
 931    def get_heading(self):
 932        if(self.chip==1):
 933            self._get_raw()
 934            temp_x = self.raw_x - self.cali_offset_x
 935            temp_y = self.raw_y - self.cali_offset_y
 936            # temp_z = self.raw_z - self.cali_offset_z
 937            heading = math.atan2(temp_y, -temp_x) * (180 / 3.14159265) + 180 + 3
 938            return heading
 939        else:
 940            if(self.cali_offset_x):
 941                self._get_raw()
 942                temp_x = -(self.raw_x - self.cali_offset_x)
 943                temp_y = -(self.raw_y - self.cali_offset_y)
 944                heading = math.atan2(temp_y, -temp_x) * (180 / 3.14159265) + 180 + 3
 945            else:
 946                heading = math.atan2(self.get_y(), -self.get_x()) * (180 / 3.14159265) + 180 + 3
 947            return heading
 948        
 949    def _get_temperature(self):
 950        if(self.chip==1):
 951            retry = 0
 952            if (retry < 5):
 953                try:
 954                    self.i2c.writeto(self.addr, b'\x09\x02', True)
 955                    while True:
 956                        self.i2c.writeto(self.addr, b'\x08', False)
 957                        buf = self.i2c.readfrom(self.addr, 1)
 958                        status = ustruct.unpack('B', buf)[0]
 959                        if(status & 0x02):
 960                            break
 961                    self.i2c.writeto(self.addr, b'\x07', False)
 962                    buf = self.i2c.readfrom(self.addr, 1)
 963                    temp = (ustruct.unpack('B', buf)[0])*0.8 -75
 964                    # print(data)
 965                    return temp
 966                except:
 967                    retry = retry + 1
 968            else:
 969                raise Exception("i2c read/write error!")   
 970        elif(self.chip == 2):
 971            pass
 972
 973    def _get_id(self):
 974        if (self.chip==1):
 975            retry = 0
 976            if (retry < 5):
 977                try:
 978                    self.i2c.writeto(self.addr, bytearray([0x2f]), False)
 979                    buf = self.i2c.readfrom(self.addr, 1, True)
 980                    print(buf)
 981                    id = ustruct.unpack('B', buf)[0]
 982                    return id
 983                except:
 984                    retry = retry + 1
 985            else:
 986                raise Exception("i2c read/write error!")
 987        elif (self.chip==2):
 988            retry = 0
 989            if (retry < 5):
 990                try:
 991                    self.i2c.writeto(self.addr, bytearray([0x39]), False)
 992                    buf = self.i2c.readfrom(self.addr, 1, True)
 993                    id = ustruct.unpack('B', buf)[0]
 994                    return id
 995                except:
 996                    retry = retry + 1
 997            else:
 998                raise Exception("i2c read/write error!")
 999
1000    def _judge_id(self):
1001        """
1002        判断product_ID
1003        """
1004        retry = 0
1005        if (retry < 5):
1006            try:
1007                self.i2c.writeto(self.addr, bytearray([0x39]), False)
1008                buf = self.i2c.readfrom(self.addr, 1, True)
1009                id = ustruct.unpack('B', buf)[0]
1010                if(id == 16):
1011                    self.chip = 2
1012                    self.product_ID = 16
1013                else:
1014                    self.chip = 1
1015                    self.product_ID = 48
1016            except:
1017                retry = retry + 1
1018        else:
1019            raise Exception("i2c read/write error!") 
1020
1021# Magnetic
1022if 48 in i2c.scan():
1023    magnetic = Magnetic()
1024else:
1025    print("magnetic init error!")
1026
1027class BME280(object):
1028    def __init__(self):
1029        self.addr = 119
1030        # The “ctrl_hum” register sets the humidity data acquisition options of the device
1031        # 0x01 = [2:0]oversampling ×1
1032        i2c.writeto(self.addr, b'\xF2\x01')
1033        # The “ctrl_meas” register sets the pressure and temperature data acquisition options of the device.
1034        # The register needs to be written after changing “ctrl_hum” for the changes to become effective.
1035        # 0x27 = [7:5]Pressure oversampling ×1 | [4:2]Temperature oversampling ×4 | [1:0]Normal mode
1036        i2c.writeto(self.addr, b'\xF4\x27')
1037        # The “config” register sets the rate, filter and interface options of the device. Writes to the “config”
1038        # register in normal mode may be ignored. In sleep mode writes are not ignored.
1039        i2c.writeto(self.addr, b'\xF5\x00')
1040
1041        i2c.writeto(self.addr, b'\x88', False)
1042        bytes = i2c.readfrom(self.addr, 6)
1043        self.dig_T = ustruct.unpack('Hhh', bytes)
1044
1045        i2c.writeto(self.addr, b'\x8E', False)
1046        bytes = i2c.readfrom(self.addr, 18)
1047        self.dig_P = ustruct.unpack('Hhhhhhhhh', bytes)
1048
1049        i2c.writeto(self.addr, b'\xA1', False)
1050        self.dig_H = array.array('h', [0, 0, 0, 0, 0, 0])
1051        self.dig_H[0] = i2c.readfrom(self.addr, 1)[0]
1052        i2c.writeto(self.addr, b'\xE1', False)
1053        buff = i2c.readfrom(self.addr, 7)
1054        self.dig_H[1] = ustruct.unpack('h', buff[0:2])[0]
1055        self.dig_H[2] = buff[2]
1056        self.dig_H[3] = (buff[3] << 4) | (buff[4] & 0x0F)
1057        self.dig_H[4] = (buff[5] << 4) | (buff[4] >> 4 & 0x0F)
1058        self.dig_H[5] = buff[6]
1059
1060    def temperature(self):
1061        retry = 0
1062        if (retry < 5):
1063            try:
1064                i2c.writeto(self.addr, b'\xFA', False)
1065                buff = i2c.readfrom(self.addr, 3)
1066                T = (((buff[0] << 8) | buff[1]) << 4) | (buff[2] >> 4 & 0x0F)
1067                c1 = (T / 16384.0 - self.dig_T[0] / 1024.0) * self.dig_T[1]
1068                c2 = ((T / 131072.0 - self.dig_T[0] / 8192.0) * (T / 131072.0 - self.dig_T[0] / 8192.0)) * self.dig_T[2]
1069                self.tFine = c1 + c2
1070                return self.tFine / 5120.0
1071            except:
1072                retry = retry + 1
1073        else:
1074            raise Exception("i2c read/write error!")
1075
1076    def pressure(self):
1077        retry = 0
1078        if (retry < 5):
1079            try:
1080                self.temperature()
1081                i2c.writeto(self.addr, b'\xF7', False)
1082                buff = i2c.readfrom(self.addr, 3)
1083                P = (((buff[0] << 8) | buff[1]) << 4) | (buff[2] >> 4 & 0x0F)
1084                c1 = self.tFine / 2.0 - 64000.0
1085                c2 = c1 * c1 * self.dig_P[5] / 32768.0
1086                c2 = c2 + c1 * self.dig_P[4] * 2.0
1087                c2 = c2 / 4.0 + self.dig_P[3] * 65536.0
1088                c1 = (self.dig_P[2] * c1 * c1 / 524288.0 + self.dig_P[1] * c1) / 524288.0
1089                c1 = (1.0 + c1 / 32768.0) * self.dig_P[0]
1090                if c1 == 0.0:
1091                    return 0
1092                p = 1048576.0 - P
1093                p = (p - c2 / 4096.0) * 6250.0 / c1
1094                c1 = self.dig_P[8] * p * p / 2147483648.0
1095                c2 = p * self.dig_P[7] / 32768.0
1096                p = p + (c1 + c2 + self.dig_P[6]) / 16.0
1097                return p
1098            except:
1099                retry = retry + 1
1100        else:
1101            raise Exception("i2c read/write error!")
1102
1103    def humidity(self):
1104        retry = 0
1105        if (retry < 5):
1106            try:
1107                self.temperature()
1108                i2c.writeto(self.addr, b'\xFD', False)
1109                buff = i2c.readfrom(self.addr, 2)
1110                H = buff[0] << 8 | buff[1]
1111                h = self.tFine - 76800.0
1112                h = (H - (self.dig_H[3] * 64.0 + self.dig_H[4] / 16384.0 * h)) * \
1113                    (self.dig_H[1] / 65536.0 * (1.0 + self.dig_H[5] / 67108864.0 * h * \
1114                    (1.0 + self.dig_H[2] / 67108864.0 * h)))
1115                h = h * (1.0 - self.dig_H[0] * h / 524288.0)
1116                if h > 100.0:
1117                    return 100.0
1118                elif h < 0.0:
1119                    return 0.0
1120                else:
1121                    return h
1122            except:
1123                retry = retry + 1
1124        else:
1125            raise Exception("i2c read/write error!")
1126
1127# bm280
1128# if 119 in i2c.scan():
1129#     bme280 = BME280()
1130
1131class PinMode(object):
1132    IN = 1
1133    OUT = 2
1134    PWM = 3
1135    ANALOG = 4
1136    OUT_DRAIN = 5
1137
1138
1139pins_remap_esp32 = (33, 32, 35, 34, 39, 0, 16, 17, 26, 25, 36, 2, -1, 18, 19, 21, 5, -1, -1, 22, 23, -1, -1, 27, 14, 12,
1140                    13, 15, 4)
1141
1142
1143class MPythonPin():
1144    def __init__(self, pin, mode=PinMode.IN, pull=None):
1145        if mode not in [PinMode.IN, PinMode.OUT, PinMode.PWM, PinMode.ANALOG, PinMode.OUT_DRAIN]:
1146            raise TypeError("mode must be 'IN, OUT, PWM, ANALOG,OUT_DRAIN'")
1147        if pin == 4:
1148            raise TypeError("P4 is used for light sensor")
1149        if pin == 10:
1150            raise TypeError("P10 is used for sound sensor")
1151        try:
1152            self.id = pins_remap_esp32[pin]
1153        except IndexError:
1154            raise IndexError("Out of Pin range")
1155        if mode == PinMode.IN:
1156            # if pin in [3]:
1157            #     raise TypeError('IN not supported on P%d' % pin)
1158            self.Pin = Pin(self.id, Pin.IN, pull)
1159        if mode == PinMode.OUT:
1160            if pin in [2, 3]:
1161                raise TypeError('OUT not supported on P%d' % pin)
1162            self.Pin = Pin(self.id, Pin.OUT, pull)
1163        if mode == PinMode.OUT_DRAIN:
1164            if pin in [2, 3]:
1165                raise TypeError('OUT_DRAIN not supported on P%d' % pin)
1166            self.Pin = Pin(self.id, Pin.OPEN_DRAIN, pull)
1167        if mode == PinMode.PWM:
1168            if pin not in [0, 1, 5, 6, 7, 8, 9, 11, 13, 14, 15, 16, 19, 20, 23, 24, 25, 26, 27, 28]:
1169                raise TypeError('PWM not supported on P%d' % pin)
1170            self.pwm = PWM(Pin(self.id), duty=0)
1171        if mode == PinMode.ANALOG:
1172            if pin not in [0, 1, 2, 3, 4, 10]:
1173                raise TypeError('ANALOG not supported on P%d' % pin)
1174            self.adc = ADC(Pin(self.id))
1175            self.adc.atten(ADC.ATTN_11DB)
1176        self.mode = mode
1177
1178    def irq(self, handler=None, trigger=Pin.IRQ_RISING):
1179        if not self.mode == PinMode.IN:
1180            raise TypeError('the pin is not in IN mode')
1181        return self.Pin.irq(handler, trigger)
1182
1183    def read_digital(self):
1184        if not self.mode == PinMode.IN:
1185            raise TypeError('the pin is not in IN mode')
1186        return self.Pin.value()
1187
1188    def write_digital(self, value):
1189        if self.mode not in [PinMode.OUT, PinMode.OUT_DRAIN]:
1190            raise TypeError('the pin is not in OUT or OUT_DRAIN mode')
1191        self.Pin.value(value)
1192
1193    def read_analog(self):
1194        if not self.mode == PinMode.ANALOG:
1195            raise TypeError('the pin is not in ANALOG mode')
1196        return self.adc.read()
1197        
1198
1199    def write_analog(self, duty, freq=1000):
1200        if not self.mode == PinMode.PWM:
1201            raise TypeError('the pin is not in PWM mode')
1202        self.pwm.freq(freq)
1203        self.pwm.duty(duty)
1204
1205
1206'''
1207# to be test
1208class LightSensor(ADC):
1209    
1210    def __init__(self):
1211        super().__init__(Pin(pins_remap_esp32[4]))
1212        # super().atten(ADC.ATTN_11DB)
1213    
1214    def value(self):
1215        # lux * k * Rc = N * 3.9/ 4096
1216        # k = 0.0011mA/Lux
1217        # lux = N * 3.9/ 4096 / Rc / k
1218        return super().read() * 1.1 / 4095 / 6.81 / 0.011
1219    
1220'''
1221
1222
1223class wifi:
1224    def __init__(self):
1225        self.sta = network.WLAN(network.STA_IF)
1226        self.ap = network.WLAN(network.AP_IF)
1227
1228    def connectWiFi(self, ssid, passwd, timeout=10):
1229        if self.sta.isconnected():
1230            self.sta.disconnect()
1231        self.sta.active(True)
1232        list = self.sta.scan()
1233        for i, wifi_info in enumerate(list):
1234            try:
1235                if wifi_info[0].decode() == ssid:
1236                    self.sta.connect(ssid, passwd)
1237                    wifi_dbm = wifi_info[3]
1238                    break
1239            except UnicodeError:
1240                self.sta.connect(ssid, passwd)
1241                wifi_dbm = '?'
1242                break
1243            if i == len(list) - 1:
1244                raise OSError("SSID invalid / failed to scan this wifi")
1245        start = time.time()
1246        print("Connection WiFi", end="")
1247        while (self.sta.ifconfig()[0] == '0.0.0.0'):
1248            if time.ticks_diff(time.time(), start) > timeout:
1249                print("")
1250                raise OSError("Timeout!,check your wifi password and keep your network unblocked")
1251            print(".", end="")
1252            time.sleep_ms(500)
1253        print("")
1254        print('WiFi(%s,%sdBm) Connection Successful, Config:%s' % (ssid, str(wifi_dbm), str(self.sta.ifconfig())))
1255
1256    def disconnectWiFi(self):
1257        if self.sta.isconnected():
1258            self.sta.disconnect()
1259        self.sta.active(False)
1260        print('disconnect WiFi...')
1261
1262    def enable_APWiFi(self, essid, password=b'',channel=10):
1263        self.ap.active(True)
1264        if password:
1265            authmode=4
1266        else:
1267            authmode=0
1268        self.ap.config(essid=essid,password=password,authmode=authmode, channel=channel)
1269
1270    def disable_APWiFi(self):
1271        self.ap.active(False)
1272        print('disable AP WiFi...')
1273
1274
1275# 3 rgb leds
1276try:
1277    rgb = NeoPixel(Pin(17, Pin.OUT), 3, 3, 1, brightness=0.3)
1278except Exception:  # autodoc 兼容:无硬件环境降级为 None
1279    rgb = None
1280rgb.write()
1281
1282# light sensor
1283try:
1284    light = ADC(Pin(39))
1285except Exception:  # autodoc 兼容:无硬件环境降级为 None
1286    light = None
1287light.atten(light.ATTN_11DB)
1288
1289# sound sensor
1290try:
1291    sound = ADC(Pin(36))
1292except Exception:  # autodoc 兼容:无硬件环境降级为 None
1293    sound = None
1294sound.atten(sound.ATTN_11DB)
1295
1296# buttons
1297class Button:
1298    def __init__(self, pin_num, reverse=False):
1299        self.__reverse = reverse
1300        (self.__press_level, self.__release_level) = (0, 1) if not self.__reverse else (1, 0)
1301        self.__pin = Pin(pin_num, Pin.IN, pull=Pin.PULL_UP)
1302        self.__pin.irq(trigger=Pin.IRQ_FALLING | Pin.IRQ_RISING, handler=self.__irq_handler)
1303        # self.__user_irq = None
1304        self.event_pressed = None
1305        self.event_released = None
1306        self.__pressed_count = 0
1307        self.__was_pressed = False
1308        # print("level: pressed is {}, released is {}." .format(self.__press_level, self.__release_level))
1309    
1310
1311    def __irq_handler(self, pin):
1312        irq_falling = True if pin.value() == self.__press_level else False
1313        # debounce
1314        time.sleep_ms(10)
1315        if self.__pin.value() == (self.__press_level if irq_falling else self.__release_level):
1316            # new event handler
1317            # pressed event
1318            if irq_falling:
1319                if self.event_pressed is not None:
1320                    schedule(self.event_pressed, self.__pin)
1321                # key status
1322                self.__was_pressed = True
1323                if (self.__pressed_count < 100):
1324                    self.__pressed_count = self.__pressed_count + 1
1325            # release event
1326            else:
1327                if self.event_released is not None:
1328                    schedule(self.event_released, self.__pin)
1329
1330                
1331    def is_pressed(self):
1332        if self.__pin.value() == self.__press_level:
1333            return True
1334        else:
1335            return False
1336
1337    def was_pressed(self):
1338        r = self.__was_pressed
1339        self.__was_pressed = False
1340        return r
1341
1342    def get_presses(self):
1343        r = self.__pressed_count
1344        self.__pressed_count = 0
1345        return r
1346
1347    def value(self):
1348        return self.__pin.value()
1349    
1350    def status(self):
1351        val = self.__pin.value()
1352        if(val==0):
1353            return 1
1354        elif(val==1):
1355            return 0
1356
1357    def irq(self, *args, **kws):
1358        self.__pin.irq(*args, **kws)
1359
1360
1361
1362class Touch:
1363
1364    def __init__(self, pin):
1365        self.__touch_pad = TouchPad(pin)
1366        self.__touch_pad.irq(self.__irq_handler)
1367        self.event_pressed = None
1368        self.event_released = None
1369        self.__pressed_count = 0
1370        self.__was_pressed = False
1371        self.__value = 0
1372
1373    def __irq_handler(self, value):
1374        # when pressed
1375        if value == 1:
1376            if self.event_pressed is not None:
1377                self.event_pressed(value)
1378            self.__was_pressed = True
1379            self.__value = 1
1380            if (self.__pressed_count < 100):
1381                self.__pressed_count = self.__pressed_count + 1
1382        # when released
1383        else:
1384            self.__value = 0
1385            if self.event_released is not None:
1386                self.event_released(value)
1387            
1388    def config(self, threshold):
1389        self.__touch_pad.config(threshold)
1390
1391    def is_pressed(self):
1392        if self.__value:
1393            return True
1394        else:
1395            return False
1396
1397    def was_pressed(self):
1398        r = self.__was_pressed
1399        self.__was_pressed = False
1400        return r
1401
1402    def get_presses(self):
1403        r = self.__pressed_count
1404        self.__pressed_count = 0
1405        return r
1406
1407    def read(self):
1408        return self.__touch_pad.read()
1409
1410
1411# button_a = Pin(0, Pin.IN, Pin.PULL_UP)
1412# button_b = Pin(2, Pin.IN, Pin.PULL_UP)
1413try:
1414    button_a = Button(0)
1415except Exception:  # autodoc 兼容:无硬件环境降级为 None
1416    button_a = None
1417try:
1418    button_b = Button(2)
1419except Exception:  # autodoc 兼容:无硬件环境降级为 None
1420    button_b = None
1421
1422
1423# touchpad
1424touchpad_p = touchPad_P = Touch(Pin(27))
1425touchpad_y = touchPad_Y = Touch(Pin(14))
1426touchpad_t = touchPad_T = Touch(Pin(12))
1427touchpad_h = touchPad_H = Touch(Pin(13))
1428touchpad_o = touchPad_O = Touch(Pin(15))
1429touchpad_n = touchPad_N = Touch(Pin(4))
1430
1431from gui import *
1432
1433
1434def numberMap(inputNum, bMin, bMax, cMin, cMax):
1435    outputNum = 0
1436    outputNum = ((cMax - cMin) / (bMax - bMin)) * (inputNum - bMin) + cMin
1437    return outputNum
1438
1439
1440"""
1441uuid
1442"""
1443def uuid():
1444    uuid = ''
1445    try:
1446        uuid = ubinascii.hexlify(machine.unique_id_custom()).decode().upper()
1447    except Exception as e:
1448        uuid = ubinascii.hexlify(machine.unique_id()).decode().upper()
1449    
1450    if(uuid=='ffffffffffff'.upper()):
1451        uuid = ubinascii.hexlify(machine.unique_id()).decode().upper()
1452
1453    return uuid