Uasyncio Queue data dirty

The official pyboard running MicroPython.
This is the reference design and main target board for MicroPython.
You can buy one at the store.
Target audience: Users with a pyboard.
Post Reply
skylin008
Posts: 78
Joined: Wed Mar 11, 2015 6:21 am

Uasyncio Queue data dirty

Post by skylin008 » Mon Dec 14, 2020 10:19 am

Hello, shows my code as follow, this code is reading the CAN bus and forwared to UART.Can1Receiver():If the Can data is not Null, and put them to Queue. Uart4Sender(): reading the Queue data, and send to Uart4 port. There are any issue as show:
In uart4Sender function, get the data from q1.get(), the data[0] is Can Id, data[4] is Can bus data. If recieve two Frame, for example :first ID is: 0x18ff0719, the data is: 0x30 ,0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38.The second Id is: 0x18ff0720, the data is: 0x40, 0x41, 0x42, 0x43, 0x44, 0x45,0x46, 0x47. when received first frame, print('uid:', index),is right. print("udata:",da), is 18ff0719's data.But when run to second print, the string content is second fram's data, is: 0x40, 0x41, 0x42, 0x43, 0x44, 0x45,0x46, 0x47, it belongs to second frame data.what happend, how slove this issue.Thanks!

@micropython.native
def encode(self, data):
index = int(data[0])
da = data[4]


if index == 0x18ff0719:
print('uid:',index) #first print
print('udata:',da)


string = str(index) + ',' + str(len(da)) + ','
temp =','.join([str(i) for i in (list(da))])
string = string + temp
string = '<' + string[0: ] + '>' + '\n'
string = 'can' + string


if index == 0x18ff0719:
print(string)
#second print

return string

Code: Select all

import gc                                          # garbage collect

import micropython

import machine

from pyb import Pin, UART, ADC, ADCAll

import utime



from p import queue         # queue  class

from p import switch        # switch class

from p import delay_ms


import uasyncio
from uasyncio import Lock


def timed_function(f, *args, **kwargs):
    myname = str(f).split(' ')[1]
    def new_func(*args, **kwargs):
        t = utime.ticks_us()
        result = f(*args, **kwargs)
        delta = utime.ticks_diff(utime.ticks_us(), t)
        print('Function {} Time = {:6.3f}ms'.format(myname, delta/1000))
        return result
    return new_func


micropython.alloc_emergency_exception_buf(100)

class device:
    """ IO define for PMU """
    def __init__(self,  debug = False, Initvalue = 0):
        self.debug     = debug
        self.pmicenable         = Pin('B1', Pin.OUT_PP)
        self.pmicpoweron        = Pin('C2', Pin.OUT_PP)
        self.externaldevice     = Pin('B0', Pin.OUT_PP)
        self.stby               = Pin('C5', Pin.OUT_PP)
        self.ahdfunction        = Pin('A8', Pin.OUT_PP)
        
        self.pmicenable.value(Initvalue)
        self.pmicpoweron.value(Initvalue)
        self.externaldevice.value(Initvalue)
        self.stby.value(Initvalue)
        self.ahdfunction(Initvalue)

    async def io_on(self, val, timeout):
        self.pmicenable.value(val)                      # PB1 Port
        await uasyncio.sleep_ms(100)
        
        self.externaldevice.value(val)                  # PB0
        await uasyncio.sleep_ms(50)
        
        self.stby.value(val)                            # PC5
        await uasyncio.sleep_ms(timeout)

        """
        self.pmicpoweron.value(val)                     # PC2 Port
        await uasyncio.sleep_ms(timeout)
        """
      
        self.ahdfunction.value(val)                     # PA8
        await uasyncio.sleep_ms(timeout)

        self.debug and print("Io On ok!\r\n")      

    async def io_off(self, val, timeout):
        """ Power Off Sequence """
        self.pmicpoweron.value(val)
        await uasyncio.sleep_ms(timeout)

        self.ahdfunction.value(val)
        await uasyncio.sleep_ms(timeout)

        self.stby.value(val)
        await uasyncio.sleep_ms(timeout)

        self.debug and print("Io Off ok!\r\n")

class adc:
    """
    Read the DC voltage to power on Android.
    when the adc voltage more than 0.87v(DC value is 9v) and
    less than 2.80(DC value is 32v) power up the Android pmu.
    """
    def __init__(self, pin = ADC('C0'), filtercount = 10, debug = False):
        
        self.adcall = ADCAll(12, 0x70000) # 12 bit resolution, internal channel

        self.vref  = self.adcall.read_core_vref( )      # vref voltage

        self.temp  = self.adcall.read_core_temp( )      # core temp

        self.pin   = pin

        self.filtercount = filtercount                        # filter count

        self.debug = debug

        self.value = self.pin.read()

        self.samples = []                                      # store adc value

        self.mean = 0



    async def read(self):
        '''read adc value '''
        self.v = self.value
        samples = []

        for _ in range(self.filtercount):
            samples.append(self.value)
            await uasyncio.sleep_ms(10)
        samples = sorted(samples)
        self.mean = (samples[int(len(samples)/2)]) * 3.24 / 4095.00         # filter median_mean

        self.debug and print("adc value is:%f", self.mean)
            
        return self.mean

class canbus:

    """ can bus driver """

    def __init__(self, id = 0x01, channel = 0x01, bitrate = 250, verbose =False):
        from pyb import CAN
        self.verbose = verbose
        self._channel = channel
        self.fifo = channel - 1
        self.can = CAN(self._channel, extframe=True, mode=CAN.NORMAL, prescaler=(2000 // bitrate), sjw=1, bs1=14, bs2=6)
        self.can.setfilter(0, CAN.MASK16, self.fifo, (0, 0, 0, 0))
        self._evt = uasyncio.Event()
        self.buf = bytearray(8)
        self._null_sink =[0, 0, 0, memoryview(self.buf), self.buf]
        self._rx_buf    =[0, 0, 0, memoryview(self.buf), self.buf]
        self.can.rxcallback(self.fifo, self._rxcallback)  # call back
        
        

    def _rxcallback(self, bus, reason):
        while self.can.any(self.fifo):
            bus.recv(self.fifo, self._rx_buf)            
            self.verbose and print(self._rx_buf)
            self._evt.set()   

    def cb_sched(self):
        self._evt.set()
    
    def flush_fifo(self):
        while self.can.any(self.fifo):
            self.can.recv(self.fifo, list=self._null_sink)
            
    def read(self):              # read can data from buffer        
        if self._evt. is_set():
            self.res = self._rx_buf            
            self._evt.clear()
        else:
            self.res =''
            self._evt.clear()       
        return (self.res)
    
    def write(self, data, index):
        try:
            self.can.send(data, index, timeout=10) 
        except:
            return False
        return True

    def state(self):
        return self.can.state()

    def restart(self):
        self.can.restart()

    @micropython.native
    def encode(self, data):
        index = int(data[0])
        da = data[4]
        
[color=#FF0000]        if index == 0x18ff0719:
            print('uid:',index)
            print('udata:',da)[/color]
        
        string = str(index) + ',' + str(len(da)) + ','
        temp =','.join([str(i) for i in (list(da))])
        string = string + temp
        string = '<' + string[0: ] + '>' + '\n'
        string = 'can' + string
        
 [color=#FF0000]       if index == 0x18ff0719:
            print(string)[/color]
       
        return string



    
        
class App:

    def __init__(self, verbose= False):

        self.verbose = verbose
        self.can1 = canbus(id = 0x01, channel = 0x01, bitrate = 250, verbose = False)
        self.can2 = canbus(id = 0x02, channel = 0x02, bitrate = 250, verbose = False)
        self.d     = device()
        self.v     = adc()
        self.sw   = switch_ext()
        self.q1    = queue.Queue(maxsize = 8192)
        self.q2    = queue.Queue(maxsize = 8192)
        self.q3    = queue.Queue(maxsize = 512)  # forward to uart
        self.q4    = queue.Queue(maxsize = 512)  # forward to uart
        self._rx_buff = None        
        self._ev = uasyncio.Event()
        self.uart4 = UART(4, 1500000)
        self.uart5 = UART(5, 1500000)
        
        self.swriter4 = uasyncio.StreamWriter(self.uart4, {})
        self.sreader4 = uasyncio.StreamReader(self.uart4, {})

        self.swriter5 = uasyncio.StreamWriter(self.uart5, {})
        self.sreader5 = uasyncio.StreamReader(self.uart5, {})
      
        
        
    async def start(self):
        self.verbose and print('App Start!\r\n')
        
        
        uasyncio.create_task(self.can1Receiver())

        uasyncio.create_task(self.can2Receiver())       
        
        uasyncio.create_task(self.uart4Sender())
        
        uasyncio.create_task(self.uart4Receiver())
        uasyncio.create_task(self.can1Sender())

        uasyncio.create_task(self.uart5Receiver())
        uasyncio.create_task(self.can2Sender())
        uasyncio.create_task(self.power())
        
        uasyncio.create_task(self.mem_manage())  
        

        
        while True:
            
            await uasyncio.sleep(0.1)



    async def can1Receiver(self):
        'canbus(1) data receive'        
        while True:            
            data =self.can1.read()
            
            if data is not '':
                await self.q1.put(data)                
            await uasyncio.sleep_ms(100)

    async def can1Sender(self):
        """ Canbus Sender """
        while True:
            if self.can1.state() == 4:
                self.can1.restart()
                await uasyncio.sleep_ms(1)

            msg = ''            
                
            if not self.q4.empty():
                data = await self.q4.get()
                
                id_ = int.from_bytes(data[:4], 'big')
                
                msg = (data[4:13])
                        
                if (len(msg)) == 8:
                    self.can1.write(msg,id_)           
            await uasyncio.sleep_ms(20)

    
    
    async def uart4Receiver(self):
        'Receive data from Android and transfer to Can Bus'
        'protocol1: 0xa5 + 4bytes(address1) + 8bytes(can data) + 1bytes(checksum) + 0x5a + \n'
        
        while True:
            sum =0
            res = await self.sreader4.readline()
            
            if len(res) == 16: # can data forward
                if res[0] == 0xa5 and res[len(res)-2] == 0x5a:
                    for i in range(1,13):
                        sum = (sum + int(res[i]))&0xFF             # checksum one byte
                        #print(sum)
                    if sum == int(res[len(res)- 3]):
                        await self.q4.put(res[1:13])
                        
            await uasyncio.sleep_ms(20)


    async def uart4Sender(self):
        'Forward canbus(1) to UART(4),before the data send,must be encode them '    
        string = ''
        while True:
            while not self.q1.empty():               
                data = await self.q1.get()                
                string = self.can1.encode(data)                                                              
                self.swriter4.write((string))            
                await self.swriter4.drain()               
            await uasyncio.sleep_ms(0)
    

    async def mem_manage(self):                                    # garbage management
        """ garbage collect """
        while True:
            await uasyncio.sleep_ms(1000)                            # delay 1000ms
            gc.collect()
            gc.threshold(gc.mem_free()//4 + gc.mem_alloc())
            #self.verbose and print("mem", gc.mem_free())
            


app = None
async def main():
    print(__version__)
    gc.collect()
    global app
    app = App(verbose = False)
    await app.start()
    

def run():
    try:
        gc.collect()
        uasyncio.run(main())
    except KeyboardInterrupt:
        print('Interrupt')        
    finally:
        uasyncio.new_event_loop()
        print("run again.")

run()

User avatar
pythoncoder
Posts: 4792
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: Uasyncio Queue data dirty

Post by pythoncoder » Mon Dec 14, 2020 5:50 pm

It's a tall order for us to debug this substantial program without access to the hardware. I can't see anything obviously wrong with your code which seems use uasyncio effectively. My approach would be to put plenty of print statements in and try to figure out where it's going wrong.
Peter Hinch

skylin008
Posts: 78
Joined: Wed Mar 11, 2015 6:21 am

Re: Uasyncio Queue data dirty

Post by skylin008 » Tue Dec 15, 2020 11:36 am

@pythoncode ,Thank you very much!

I had add the print function as follow:
@micropython.native
def encode(self, data):
index = int(data[0])
da = data[4]

if index == 0x18eef0f1:
print('uid:',index)
print('udata:',da)
string = str(index) + ',' + str(len(da)) + ','
print('id,length:', string)
temp =','.join([str(i) for i in (list(da))])
print('temp:', temp)
string = string + temp
print('sting1:', string)
string = '<' + string[0: ] + '>' + '\n'
string = 'can' + string
print('string2', string)
return string
else:
return ''

the return is:
uid: 418312433
udata: bytearray(b'\x00\x01\x02\x03\x04\x05\x06\x07')
id,length: 418312433,8,
temp: 255,255,255,255,255,255,0,0
sting1: 418312433,8,255,255,255,255,255,255,0,0
string2 can<418312433,8,255,255,255,255,255,255,0,0>

uid: 418312433
udata: bytearray(b'\x00\x01\x02\x03\x04\x05\x06\x07')
id,length: 418312433,8,
temp: 255,255,255,255,255,255,0,0
sting1: 418312433,8,255,255,255,255,255,255,0,0
string2 can<418312433,8,255,255,255,255,255,255,0,0>

Post Reply