Code made on V1.18 not working on V.1.20



  • Hi All,

    I wrote this code over a year or so ago and don't remember too much about it...

    Now the devices have been updated/new ones purchased and they are failing on the latest build which I'm a bit confused about. I've tried exploring the documentation but it seems Pycom has had an overhaul of it's documentation and I'm struggling to find what I need so I've come here.

    Here is my code:

    from LIS2HH12 import LIS2HH12
    from pytrack import Pytrack
    from network import WLAN
    import machine
    from machine import Pin
    from machine import I2C
    from machine import Timer
    import socket
    import binascii
    import struct
    import time
    import array
    wlan = WLAN(mode=WLAN.STA)
    nets = wlan.scan()
    for net in nets:
        if net.ssid == 'XXX-Pi':
            print('Network found!')
            wlan.connect(net.ssid, auth=(net.sec, 'raspberry'), timeout=30)
            wlan.ifconfig(config=('192.168.1.20', '255.255.255.0', '192.168.1.40', '8.8.8.8'))
            print(wlan.isconnected())
            while not wlan.isconnected():
                machine.idle() # save power while waiting
            print('WLAN connection succeeded!')
    chrono = Timer.Chrono()
    chrono.start()
    HOST = '192.168.1.1'
    PORT = 10000
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_TCP)
    print("line 31")
    print(wlan.isconnected())
    sockett = False
    while sockett == False:
        try:
            print('Connection...')
            s.connect((HOST, PORT))
        except OSError:
            print('xception...')
            # //machine.reset()
        else:
            sockett = True
    print("line 33")
    
    while wlan.isconnected():
        lap = chrono.read()
        py = Pytrack()
        battery = py.read_battery_voltage()
        acc = LIS2HH12()
        xyz = acc.acceleration()
        x = xyz[0]
        y = xyz[1]
        z = xyz[2]
        b = (x**2 + y**2 + z**2) **(0.5)
        a = "\n"
        data = (str(lap) + "," + str(b) + "," + str(battery) + "\n")
        print(data)
        s.send(data)
        print("sent")
        time.sleep(0.1)
    
    if not wlan.isconnected():
        machine.reset()
    
    

    I know it's not perfect but it worked (at the time).

    The output is an OSError during line 35: s.connect((HOST, PORT))

    Anyone have any ideas what could be going wrong here?

    I updated back to V1.18. and it still no longer works...



  • @Dylan as @Gijs wrote, it’s obvious from the output that the module didn’t connect to the WLAN.

    What is weird is that even when it works you don’t have the Network found! output. Are you running the same code on both?

    If the first log comes from a device actually running the code you gave, it means it didn’t find the network. Try logging all networks found to check for a typo of some sort, or loop around scan (with a small sleep) until you find it.


  • Global Moderator

    It seems the issue with your 'bricked' device is that it is not actually connected to WiFi (note how it says line 31 False. This will cause the socket to throw the exception, as there is no working network adapter available.

    Your updated device never seems to run through this part:

    for net in nets:
        if net.ssid == 'XXX-Pi':
            print('Network found!')
            wlan.connect(net.ssid, auth=(net.sec, 'raspberry'), timeout=30)
            wlan.ifconfig(config=('192.168.1.20', '255.255.255.0', '192.168.1.40', '8.8.8.8'))
            print(wlan.isconnected())
            while not wlan.isconnected():
                machine.idle() # save power while waiting
            print('WLAN connection succeeded!')
    

    That is supposed to create the connection.
    On second thought, perhaps the timeout is too short at 30 ms?



  • Hi, thank you for your reply.

    Here are the outputs:

    rst:0x7 (TG0WDT_SYS_RESET),boot:0x17 (SPI_FAST_FLASH_BOOT)
    configsip: 0, SPIWP:0xee
    clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
    mode:DIO, clock div:1
    load:0x3fff8020,len:8
    load:0x3fff8028,len:2128
    load:0x4009fa00,len:19760
    entry 0x400a05bc
    line 31
    False
    Connection...
    xception...
    Connection...
    xception...
    Connection...
    xception...
    

    This is the output from a board that hasn't been updated or touched since I first wrote the code:

    Connecting to COM7...
    WLAN connection succeeded!
    line 31
    True
    Connection...
    line 33
    0.01096298,0.0,4.696739
    
    sent
    0.1555956,1.022109,4.701756
    
    sent
    0.2996252,1.023995,4.706775
    
    sent
    0.4436324,1.028087,4.701756
    
    sent
    0.5876054,1.028255,4.711792
    
    sent
    0.7316323,1.027779,4.706775
    
    sent
    0.8755957,1.022246,4.696739
    
    sent
    1.019628,1.025475,4.701756
    
    sent
    1.163599,1.022926,4.701756
    
    sent
    1.307628,1.029247,4.706775
    
    sent
    1.451632,1.029623,4.696739
    

    When I try to download the code from the older units I only get the main.py file for some reason, I have all the code I wrote though so have been able to re-upload. They are:

    LIS2HH12.py:

    import math
    import time
    import struct
    from machine import Pin
    
    
    FULL_SCALE_2G = const(0)
    FULL_SCALE_4G = const(2)
    FULL_SCALE_8G = const(3)
    
    ODR_POWER_DOWN = const(0)
    ODR_10_HZ = const(1)
    ODR_50_HZ = const(2)
    ODR_100_HZ = const(3)
    ODR_200_HZ = const(4)
    ODR_400_HZ = const(5)
    ODR_800_HZ = const(6)
    
    ACC_G_DIV = 1000 * 65536
    
    class LIS2HH12:
    
        ACC_I2CADDR = const(30)
    
        PRODUCTID_REG = const(0x0F)
        CTRL1_REG = const(0x20)
        CTRL2_REG = const(0x21)
        CTRL3_REG = const(0x22)
        CTRL4_REG = const(0x23)
        CTRL5_REG = const(0x24)
        ACC_X_L_REG = const(0x28)
        ACC_X_H_REG = const(0x29)
        ACC_Y_L_REG = const(0x2A)
        ACC_Y_H_REG = const(0x2B)
        ACC_Z_L_REG = const(0x2C)
        ACC_Z_H_REG = const(0x2D)
        ACT_THS = const(0x1E)
        ACT_DUR = const(0x1F)
    
        def __init__(self, pysense = None, sda = 'P22', scl = 'P21'):
            if pysense is not None:
                self.i2c = pysense.i2c
            else:
                from machine import I2C
                self.i2c = I2C(0, mode=I2C.MASTER, pins=(sda, scl))
    
            self.reg = bytearray(1)
            self.odr = 0
            self.full_scale = 0
            self.x = 0
            self.y = 0
            self.z = 0
            self.int_pin = None
            self.act_dur = 0
            self.debounced = False
    
            self.scales = {FULL_SCALE_2G: 4000, FULL_SCALE_4G: 8000, FULL_SCALE_8G: 16000}
            self.odrs = [0, 10, 50, 100, 200, 400, 800]
    
            whoami = self.i2c.readfrom_mem(ACC_I2CADDR , PRODUCTID_REG, 1)
            if (whoami[0] != 0x41):
                raise ValueError("LIS2HH12 not found")
    
            # enable acceleration readings at 50Hz
            self.set_odr(ODR_50_HZ)
    
            # change the full-scale to 4g
            self.set_full_scale(FULL_SCALE_4G)
    
            # set the interrupt pin as active low and open drain
            self.i2c.readfrom_mem_into(ACC_I2CADDR , CTRL5_REG, self.reg)
            self.reg[0] |= 0b00000011
            self.i2c.writeto_mem(ACC_I2CADDR , CTRL5_REG, self.reg)
    
            # make a first read
            self.acceleration()
    
        def acceleration(self):
            x = self.i2c.readfrom_mem(ACC_I2CADDR , ACC_X_L_REG, 2)
            self.x = struct.unpack('<h', x)
            y = self.i2c.readfrom_mem(ACC_I2CADDR , ACC_Y_L_REG, 2)
            self.y = struct.unpack('<h', y)
            z = self.i2c.readfrom_mem(ACC_I2CADDR , ACC_Z_L_REG, 2)
            self.z = struct.unpack('<h', z)
            _mult = self.scales[self.full_scale] / ACC_G_DIV
            return (self.x[0] * _mult, self.y[0] * _mult, self.z[0] * _mult)
    
        def roll(self):
            x,y,z = self.acceleration()
            rad = math.atan2(-x, z)
            return (180 / math.pi) * rad
    
        def pitch(self):
            x,y,z = self.acceleration()
            rad = -math.atan2(y, (math.sqrt(x*x + z*z)))
            return (180 / math.pi) * rad
    
        def set_full_scale(self, scale):
            self.i2c.readfrom_mem_into(ACC_I2CADDR , CTRL4_REG, self.reg)
            self.reg[0] &= ~0b00110000
            self.reg[0] |= (scale & 3) << 4
            self.i2c.writeto_mem(ACC_I2CADDR , CTRL4_REG, self.reg)
            self.full_scale = scale
    
        def set_odr(self, odr):
            self.i2c.readfrom_mem_into(ACC_I2CADDR , CTRL1_REG, self.reg)
            self.reg[0] &= ~0b01110000
            self.reg[0] |= (odr & 7) << 4
            self.i2c.writeto_mem(ACC_I2CADDR , CTRL1_REG, self.reg)
            self.odr = odr
    
        def enable_activity_interrupt(self, threshold, duration, handler=None):
            # Threshold is in mg, duration is ms
            self.act_dur = duration
    
            _ths = int((threshold * self.scales[self.full_scale]) / 2000 / 128) & 0x7F
            _dur = int((duration * self.odrs[self.odr]) / 1000 / 8)
    
            self.i2c.writeto_mem(ACC_I2CADDR , ACT_THS, _ths)
            self.i2c.writeto_mem(ACC_I2CADDR , ACT_DUR, _dur)
    
            # enable the activity/inactivity interrupt
            self.i2c.readfrom_mem_into(ACC_I2CADDR , CTRL3_REG, self.reg)
            self.reg[0] |= 0b00100000
            self.i2c.writeto_mem(ACC_I2CADDR , CTRL3_REG, self.reg)
    
            self._user_handler = handler
            self.int_pin = Pin('P13', mode=Pin.IN)
            self.int_pin.callback(trigger=Pin.IRQ_FALLING | Pin.IRQ_RISING, handler=self._int_handler)
    
        def activity(self):
            if not self.debounced:
                time.sleep_ms(self.act_dur)
                self.debounced = True
            if self.int_pin():
                return True
            return False
    
        def _int_handler(self, pin_o):
            if self._user_handler is not None:
                self._user_handler(pin_o)
            else:
                if pin_o():
                    print('Activity interrupt')
                else:
                    print('Inactivity interrupt')
    
    

    pyocoproc.py:

    import machine
    from machine import Pin
    from machine import I2C
    import time
    import pycom
    
    __version__ = '0.0.1'
    
    """ PIC MCU wakeup reason types """
    WAKE_REASON_ACCELEROMETER = 1
    WAKE_REASON_PUSH_BUTTON = 2
    WAKE_REASON_TIMER = 4
    WAKE_REASON_INT_PIN = 8
    
    class Pycoproc:
        """ class for handling interraction with PIC MCU """
    
        I2C_SLAVE_ADDR = const(8)
    
        CMD_PEEK = const(0x0)
        CMD_POKE = const(0x01)
        CMD_MAGIC = const(0x02)
        CMD_HW_VER = const(0x10)
        CMD_FW_VER = const(0x11)
        CMD_PROD_ID = const(0x12)
        CMD_SETUP_SLEEP = const(0x20)
        CMD_GO_SLEEP = const(0x21)
        CMD_CALIBRATE = const(0x22)
        CMD_BAUD_CHANGE = const(0x30)
        CMD_DFU = const(0x31)
    
        REG_CMD = const(0)
        REG_ADDRL = const(1)
        REG_ADDRH = const(2)
        REG_AND = const(3)
        REG_OR = const(4)
        REG_XOR = const(5)
    
        ANSELA_ADDR = const(0x18C)
        ANSELB_ADDR = const(0x18D)
        ANSELC_ADDR = const(0x18E)
    
        ADCON0_ADDR = const(0x9D)
        ADCON1_ADDR = const(0x9E)
    
        IOCAP_ADDR = const(0x391)
        IOCAN_ADDR = const(0x392)
    
        INTCON_ADDR = const(0x0B)
        OPTION_REG_ADDR = const(0x95)
    
        _ADCON0_CHS_POSN = const(0x02)
        _ADCON0_ADON_MASK = const(0x01)
        _ADCON1_ADCS_POSN = const(0x04)
        _ADCON0_GO_nDONE_MASK = const(0x02)
    
        ADRESL_ADDR = const(0x09B)
        ADRESH_ADDR = const(0x09C)
    
        TRISC_ADDR = const(0x08E)
    
        PORTA_ADDR = const(0x00C)
        PORTC_ADDR = const(0x00E)
    
        WPUA_ADDR = const(0x20C)
    
        WAKE_REASON_ADDR = const(0x064C)
        MEMORY_BANK_ADDR = const(0x0620)
    
        PCON_ADDR = const(0x096)
        STATUS_ADDR = const(0x083)
    
        EXP_RTC_PERIOD = const(7000)
    
        def __init__(self, i2c=None, sda='P22', scl='P21'):
            if i2c is not None:
                self.i2c = i2c
            else:
                self.i2c = I2C(0, mode=I2C.MASTER, pins=(sda, scl))
    
            self.sda = sda
            self.scl = scl
            self.clk_cal_factor = 1
            self.reg = bytearray(6)
            self.wake_int = False
            self.wake_int_pin = False
            self.wake_int_pin_rising_edge = True
    
            try:
                self.read_fw_version()
            except Exception:
                time.sleep_ms(2)
            try:
                # init the ADC for the battery measurements
                self.poke_memory(ANSELC_ADDR, 1 << 2)
                self.poke_memory(ADCON0_ADDR, (0x06 << _ADCON0_CHS_POSN) | _ADCON0_ADON_MASK)
                self.poke_memory(ADCON1_ADDR, (0x06 << _ADCON1_ADCS_POSN))
                # enable the pull-up on RA3
                self.poke_memory(WPUA_ADDR, (1 << 3))
                # make RC5 an input
                self.set_bits_in_memory(TRISC_ADDR, 1 << 5)
                # set RC6 and RC7 as outputs and enable power to the sensors and the GPS
                self.mask_bits_in_memory(TRISC_ADDR, ~(1 << 6))
                self.mask_bits_in_memory(TRISC_ADDR, ~(1 << 7))
    
                if self.read_fw_version() < 6:
                    raise ValueError('Firmware out of date')
    
            except Exception:
                print(i2c)
                machine.reset()
                raise Exception('Board not detected')
    
    
        def _write(self, data, wait=True):
            self.i2c.writeto(I2C_SLAVE_ADDR, data)
            if wait:
                self._wait()
    
        def _read(self, size):
            return self.i2c.readfrom(I2C_SLAVE_ADDR, size + 1)[1:(size + 1)]
    
        def _wait(self):
            count = 0
            time.sleep_us(10)
            while self.i2c.readfrom(I2C_SLAVE_ADDR, 1)[0] != 0xFF:
                time.sleep_us(100)
                count += 1
                if (count > 500):  # timeout after 50ms
                    raise Exception('Board timeout')
    
        def _send_cmd(self, cmd):
            self._write(bytes([cmd]))
    
        def read_hw_version(self):
            self._send_cmd(CMD_HW_VER)
            d = self._read(2)
            return (d[1] << 8) + d[0]
    
        def read_fw_version(self):
            self._send_cmd(CMD_FW_VER)
            d = self._read(2)
            return (d[1] << 8) + d[0]
    
        def read_product_id(self):
            self._send_cmd(CMD_PROD_ID)
            d = self._read(2)
            return (d[1] << 8) + d[0]
    
        def peek_memory(self, addr):
            self._write(bytes([CMD_PEEK, addr & 0xFF, (addr >> 8) & 0xFF]))
            return self._read(1)[0]
    
        def poke_memory(self, addr, value):
            self._write(bytes([CMD_POKE, addr & 0xFF, (addr >> 8) & 0xFF, value & 0xFF]))
    
        def magic_write_read(self, addr, _and=0xFF, _or=0, _xor=0):
            self._write(bytes([CMD_MAGIC, addr & 0xFF, (addr >> 8) & 0xFF, _and & 0xFF, _or & 0xFF, _xor & 0xFF]))
            return self._read(1)[0]
    
        def toggle_bits_in_memory(self, addr, bits):
            self.magic_write_read(addr, _xor=bits)
    
        def mask_bits_in_memory(self, addr, mask):
            self.magic_write_read(addr, _and=mask)
    
        def set_bits_in_memory(self, addr, bits):
            self.magic_write_read(addr, _or=bits)
    
        def get_wake_reason(self):
            """ returns the wakeup reason, a value out of constants WAKE_REASON_* """
            return self.peek_memory(WAKE_REASON_ADDR)
    
        def get_sleep_remaining(self):
            """ returns the remaining time from sleep, as an interrupt (wakeup source) might have triggered """
            c3 = self.peek_memory(WAKE_REASON_ADDR + 3)
            c2 = self.peek_memory(WAKE_REASON_ADDR + 2)
            c1 = self.peek_memory(WAKE_REASON_ADDR + 1)
            time_device_s = (c3 << 16) + (c2 << 8) + c1
            # this time is from PIC internal oscilator, so it needs to be adjusted with the calibration value
            try:
                self.calibrate_rtc()
            except Exception:
                pass
            time_s = int((time_device_s / self.clk_cal_factor) + 0.5) # 0.5 used for round
            return time_s
    
        def setup_sleep(self, time_s):
            try:
                self.calibrate_rtc()
            except Exception:
                pass
            time_s = int((time_s * self.clk_cal_factor) + 0.5)  # round to the nearest integer
            self._write(bytes([CMD_SETUP_SLEEP, time_s & 0xFF, (time_s >> 8) & 0xFF, (time_s >> 16) & 0xFF]))
    
        def go_to_sleep(self, gps=True):
            # enable or disable back-up power to the GPS receiver
            if gps:
                self.set_bits_in_memory(PORTC_ADDR, 1 << 7)
            else:
                self.mask_bits_in_memory(PORTC_ADDR, ~(1 << 7))
            # disable the ADC
            self.poke_memory(ADCON0_ADDR, 0)
    
            if self.wake_int:
                # Don't touch RA3, RA5 or RC1 so that interrupt wake-up works
                self.poke_memory(ANSELA_ADDR, ~((1 << 3) | (1 << 5)))
                self.poke_memory(ANSELC_ADDR, ~((1 << 6) | (1 << 7) | (1 << 1)))
            else:
                # disable power to the accelerometer, and don't touch RA3 so that button wake-up works
                self.poke_memory(ANSELA_ADDR, ~(1 << 3))
                self.poke_memory(ANSELC_ADDR, ~(1 << 7))
    
            self.poke_memory(ANSELB_ADDR, 0xFF)
    
            # check if INT pin (PIC RC1), should be used for wakeup
            if self.wake_int_pin:
                if self.wake_int_pin_rising_edge:
                    self.set_bits_in_memory(OPTION_REG_ADDR, 1 << 6) # rising edge of INT pin
                else:
                    self.mask_bits_in_memory(OPTION_REG_ADDR, ~(1 << 6)) # falling edge of INT pin
                self.mask_bits_in_memory(ANSELC_ADDR, ~(1 << 1)) # disable analog function for RC1 pin
                self.set_bits_in_memory(TRISC_ADDR, 1 << 1) # make RC1 input pin
                self.mask_bits_in_memory(INTCON_ADDR, ~(1 << 1)) # clear INTF
                self.set_bits_in_memory(INTCON_ADDR, 1 << 4) # enable interrupt; set INTE)
    
            self._write(bytes([CMD_GO_SLEEP]), wait=False)
            # kill the run pin
            Pin('P3', mode=Pin.OUT, value=0)
    
        def calibrate_rtc(self):
            # the 1.024 factor is because the PIC LF operates at 31 KHz
            # WDT has a frequency divider to generate 1 ms
            # and then there is a binary prescaler, e.g., 1, 2, 4 ... 512, 1024 ms
            # hence the need for the constant
            self._write(bytes([CMD_CALIBRATE]), wait=False)
            self.i2c.deinit()
            Pin('P21', mode=Pin.IN)
            pulses = pycom.pulses_get('P21', 50)
            self.i2c.init(mode=I2C.MASTER, pins=(self.sda, self.scl))
            try:
                period = pulses[2][1] - pulses[0][1]
            except:
                pass
            if period > 0:
                self.clk_cal_factor = (EXP_RTC_PERIOD / period) * (1000 / 1024)
    
        def button_pressed(self):
            button = self.peek_memory(PORTA_ADDR) & (1 << 3)
            return not button
    
        def read_battery_voltage(self):
            self.set_bits_in_memory(ADCON0_ADDR, _ADCON0_GO_nDONE_MASK)
            time.sleep_us(50)
            while self.peek_memory(ADCON0_ADDR) & _ADCON0_GO_nDONE_MASK:
                time.sleep_us(100)
            adc_val = (self.peek_memory(ADRESH_ADDR) << 2) + (self.peek_memory(ADRESL_ADDR) >> 6)
            return (((adc_val * 3.3 * 280) / 1023) / 180) + 0.01    # add 10mV to compensate for the drop in the FET
    
        def setup_int_wake_up(self, rising, falling):
            """ rising is for activity detection, falling for inactivity """
            wake_int = False
            if rising:
                self.set_bits_in_memory(IOCAP_ADDR, 1 << 5)
                wake_int = True
            else:
                self.mask_bits_in_memory(IOCAP_ADDR, ~(1 << 5))
    
            if falling:
                self.set_bits_in_memory(IOCAN_ADDR, 1 << 5)
                wake_int = True
            else:
                self.mask_bits_in_memory(IOCAN_ADDR, ~(1 << 5))
            self.wake_int = wake_int
    
        def setup_int_pin_wake_up(self, rising_edge = True):
            """ allows wakeup to be made by the INT pin (PIC -RC1) """
            self.wake_int_pin = True
            self.wake_int_pin_rising_edge = rising_edge
    
    

    Pytrack.py:

    from pycoproc import Pycoproc
    
    __version__ = '1.4.0'
    
    class Pytrack(Pycoproc):
    
        def __init__(self, i2c=None, sda='P22', scl='P21'):
            Pycoproc.__init__(self, i2c, sda, scl)
    
    

    Wifi network is definitely available, the output of the working device double checks that. The config=('192.168.1.20', get changed per device so that it's not two devices on the same IP, eg 192.168.1.21/22/23.
    There is another few sets of these devices out in the field working perfectly, but I fear once/if they are updated they'll all be "bricked" as they have no technical staff.



  • @Dylan can you provide the full output? Is the WiFi network still available, with the same IPs? Is there indeed no other device on the network with that IP? Does the module actually connect to it? Can you ping the module from another device?


Log in to reply
 

Pycom on Twitter