Thread Rating:
  • 1 Vote(s) - 3 Average
  • 1
  • 2
  • 3
  • 4
  • 5
CPU halted
#1
Hi there,

very new to micropython, but enjoying it so far. I am a bit of a novice so this may be where my issue lay Smile

I have a script that produces the error ... 

assertion "ATB_GET_KIND(block) == AT_HEAD" failed: file "/home/LoBo2_Razno/ESP32/MicroPython/MicroPython_ESP32_psRAM_LoBo/MicroPython_BUILD/components/micropython/py/gc.c", line 596, function: gc_free

abort() was called at PC 0x40121da3 on core 1

I have seen this mentioned elsewhere on the forum, wrt ports, but none of these discussions help with my current issue.

before posting here I ran the code through flake8 and pylint (ignoring some capitalization formatting etc), to make sure I was somewhat pythonic and free of some issues.

This is code for a flow meter that squirts it's measurements into influxdb, it has 2 threads that I start, one to manage a queue, and the other to keep an eye on the network.

It is no where near complete, and remember I am a novice ... but happy to take pointers to making it better.

Code:
import itertools
import machine
import utime
import _thread
import network
import uheapq
import urequests
#from machine import Pin
import uos
#import gc

sta_if = network.WLAN(network.STA_IF)

class Globals:
   oldTime = 0.0
   newTime = 0.0
   calibrationFactor = 22
   rtc = machine.RTC()
   rtc.ntp_sync(server="au.pool.ntp.org", tz="AEST-10AEDT,M10.1.0,M4.1.0/3")
   INTERRUPTCOUNTER = 0
   myStatus = 0
   journalfile = '/sd/journal.txt'
   readjournalfile = '/sd/readjournal.txt'
   numFlows = 0
   allTimeLiters = 0
   lperSec = 0
   oldqTime = 0
   upTimeStart = 0.0
   upTimeNow = 0.0

newTime = 0.0
flowRate = 0.0
rtc = machine.RTC()
rtc.ntp_sync(server="au.pool.ntp.org", tz="AEST-10AEDT,M10.1.0,M4.1.0/3")
totalInterruptsCounter = 0
oldPrintTime = 0.0
zeroCount = 0
toteMils = 0.0
theChosenOne = 16
counter = itertools.count()

rtc.synced()
myHeap = []
entry_finder = {}
REMOVED = ''
url_string = 'http://192.168.200.20:8086/write?db=Tankdb&precision=u'
urlPre = 'curl -i -XPOST \''
urlData = '\' --data-binary \''



def add_task(task, priority=0):
   'Add a new task or update the priority of an existing task'
   if task in entry_finder:
       remove_task(task)
   count = next(counter)
   entry = [priority, count, task]
   entry_finder[task] = entry
   uheapq.heappush(myHeap, entry)

def remove_task(task):
   'Mark an existing task as REMOVED.  Raise KeyError if not found.'
   entry = entry_finder.pop(task)
   entry[-1] = REMOVED

def pop_task():
   'Remove and return the lowest priority task. Raise KeyError if empty.'
   while myHeap:
       priority, count, task = uheapq.heappop(myHeap)
       if task is not REMOVED:
           del entry_finder[task]
           return task
   #raise KeyError('pop from an empty priority queue')

def tStamper():
   myNow = utime.time()
   if len(str(myNow).split('.')[1]) == 4:
       myU = str(myNow).split('.')[1] + "00"
   if len(str(myNow).split('.')[1]) == 3:
       myU = str(myNow).split('.')[1] + "000"
   if len(str(myNow).split('.')[1]) == 5:
       myU = str(myNow).split('.')[1] + "0"
   if len(str(myNow).split('.')[1]) == 2:
       myU = str(myNow).split('.')[1] + "0000"
   if len(str(myNow).split('.')[1]) == 1:
       myU = str(myNow).split('.')[1] + "00000"
   myuNow = int(str(myNow).split('.')[0] + myU)
   return myuNow

def easyTime():
   myTime = utime.localtime()
   easyT = (str(myTime[0]) + '-' + str("{:02d}".format(myTime[1])) + '-' + str("{:02d}".format(myTime[2])) + 'T' + str("{:02d}".format(myTime[3])) + ':' + str("{:02d}".format(myTime[4])) +  ':' + str("{:02d}".format(myTime[5])))
   return easyT

def queueThread():
   _thread.allowsuspend(True)
   Globals.oldqTime = utime.time()
   while True:
       utime.sleep(0.1)
       ntf = _thread.getnotification()
       if ntf:
           # some notification received
           if ntf == _thread.EXIT:
               print("queueThread: terminated")
               return

       qTime = utime.time()
       if qTime - Globals.oldqTime >= 60000:
           readjournal()
           Globals.oldqTime = utime.time()
       try:
           popped = pop_task()

           if popped is not None:
               Globals.lperSec = popped.split(" ")[0].strip()
               water_flow = popped.split(" ")[1].strip()
               popEd = popped.split(" ")[2].strip()
               popTime = str(popEd.split('.')[0])
               flowy = 'tank_monitor,host=flow01,location=north_east water_flow=' + str(water_flow) + " " + str(popTime) + '\ntank_monitor,host=flow01,location=north_east lPerSec=' + str(Globals.lperSec) + " " + str(popTime)
               #myTime = utime.localtime()

               if Globals.myStatus == 1:
                   #print(urlPre + url_string + urlData + flowy + '\'')
                   addTime = str(tStamper())
                   writejournal(str(Globals.lperSec) + " " + str(water_flow) + " " + addTime + "\n")
                   urequests.post(url_string, data=flowy)
                   #utime.sleep(2)
                   print(easyTime(), '### Sent to DB ###'+addTime+'\n')
                   deletejournal()
               if Globals.myStatus == 0:
                   try:
                       addTime = str(tStamper())
                       #print(urlPre + url_string + urlData + flowy + '\'')
                       writejournal(str(Globals.lperSec) + " " + str(water_flow) + " " + addTime +"\n")
                       print(easyTime(), '### Sent to JOURNAL ###'+addTime+'\n')
                       deletejournal()
                   except Exception as e:
                       print('Error in threadqueue: {}'.format(e))

           elif popped is None:
               utime.sleep(1) #foo = 1 # need something to silence error about empty heap.

       except Exception as e:
           print('Error: {}'.format(e))

def do_connect():
   if sta_if.isconnected() is True:
       print('Network Connected\n')
   if not sta_if.isconnected():
       while True:
           utime.sleep(0.1)
           print('Not Connected\n')
           print('connecting to network...\n')
           sta_if.active(True)
           sta_if.connect('unifi1-out', 'jedrocks')
           utime.sleep(5)
           print(sta_if.isconnected())
           if sta_if.isconnected() is True:
               return
   print('network config:', sta_if.ifconfig())

def networkThread():
   _thread.allowsuspend(True)

   while True:
       utime.sleep(0.1)
       ntf = _thread.getnotification()
       if ntf:
           if ntf == _thread.EXIT:
               print("networkThread: terminated")
               return
       Globals.myStatus = 1
       if sta_if.isconnected() is False:
           print("Network Not Connected")
           Globals.myStatus = 0
           do_connect()
           utime.sleep(10)
           if sta_if.isconnected() is True:
               Globals.myStatus = 1

def datacb(msg):
   if msg[1] == 'test/message' and msg[2] == 'How Are You':
       print('Health Check')
       client.publish('test/message', 'esp32_flow Says, All the people in my village are happy @ ' + str(easyTime()))
   if msg[1] == 'test/message' and msg[2] == 'How Long Have You Been Awake':
       print('Uptime request')
       Globals.myStatus = utime.time()
       curUp = round(Globals.myStatus - Globals.upTimeStart, 2)
       upUpAndAway = utime.strftime('%H:%M:%S', utime.gmtime(int(str(curUp).split('.')[0])))
       client.publish('test/message', 'esp32_flow has been awake for HH:MM:SS: '+ str(upUpAndAway) + " @: " + str(easyTime()))
   if msg[1] == 'test/message' and msg[2] == 'Whats Been Going On':
       print('How much work have I done')
       Globals.myStatus = utime.time()
       curUp = round(Globals.myStatus - Globals.upTimeStart, 2)
       upUpAndAway = utime.strftime('%H:%M:%S', utime.gmtime(int(str(curUp).split('.')[0])))
       client.publish('test/message', 'esp32_flow has flowed '+ str(Globals.numFlows) + ' Times, in ' + str(upUpAndAway) + ' totalling ' + str(Globals.allTimeLiters) + 'L @: ' + str(easyTime()))
   utime.sleep(0.5)

def callback(pin):
   Globals.INTERRUPTCOUNTER = Globals.INTERRUPTCOUNTER + 1


client = network.mqtt(name="pi", server="192.168.200.135", data_cb=datacb, clientid="flowister")
utime.sleep(1)
client.start()
utime.sleep(1)
status = client.status()[1]
print('MQTT status:', status)
client.subscribe('test/message')



def writejournal(what):
   f = open('/sd/journal.txt', "a")
   f.write(what)
   f.close()

def readjournal():
   try:
       myDir = uos.listdir('/sd/')
       print(myDir)
       for myfiles in myDir:
           if myfiles.startswith('readjournal'):
               uos.remove('/sd/readjournal.txt')
               print('### clean up old readjournals')

           if myfiles.startswith('journal.txt'):
               print(myfiles)
               print('### Reading Journal Entries into Queue ###')
               uos.rename('/sd/journal.txt', '/sd/readjournal.txt')
               with open(Globals.readjournalfile) as f:
                   for line in f:
                       line = line.rstrip()
                       add_task(line)
               uos.remove('/sd/readjournal.txt')
   except Exception as e:
       print(e)
       print('### No Journal left layin\' round ###')

def deletejournal():
   uos.remove(Globals.journalfile)


flowSignal = machine.Pin(theChosenOne, machine.Pin.IN, machine.Pin.PULL_UP)
flowSignal.init(trigger=machine.Pin.IRQ_FALLING, handler=callback)

#_thread.stack_size(4*1024)
networkth = _thread.start_new_thread("netty", networkThread, ())
queueth = _thread.start_new_thread("poppy", queueThread, ())



###########################################################

if __name__ == '__main__':
   client.publish('test/message', 'esp32_flow has just come online @ '+ str(easyTime()))
   Globals.upTimeStart = utime.time()
   try:
       #myDir = uos.listdir('/sd/')
       #print("dir", myDir)
       state = machine.disable_irq()
       machine.enable_irq(state)
       readjournal()

       while True:
           utime.sleep(0.1)
           newTime = utime.ticks_ms()
           printTime = newTime

           if Globals.INTERRUPTCOUNTER > 0:
               totalInterruptsCounter = totalInterruptsCounter + 1
               theDiff = newTime - Globals.oldTime

               if Globals.INTERRUPTCOUNTER <= 5 and zeroCount == 0 and totalInterruptsCounter <= 10:
                   client.publish('test/message', 'esp32_flow Started Spooling to Influxdb at ' + str(easyTime()))
                   utime.sleep(0.5)
                   add_task("0 0 " + str(tStamper()-1))
                   print('###   First ZERO')
                   zeroCount = 1

               if theDiff != 0:
                   flowRate = round(((1000 / theDiff) * Globals.INTERRUPTCOUNTER)/Globals.calibrationFactor, 2)

               if printTime - oldPrintTime >= 2000.0:
                   flowMils = round((flowRate/60), 2)
                   toteMils += flowMils
                   fRate = str(round((flowRate/60)*1000, 2))
                   atTime = tStamper()
                   #print("Amount is: ", toteMils, "L, at:", atTime)
                   #print("Flowrate =", fRate + "ml/sec")
                   Globals.lperSec = flowRate
                   oldPrintTime = printTime

                   try:
                       add_task(str(fRate) + " " + str(toteMils) + " " + str(atTime))
                   except Exception as e:
                       print('Error: {}'.format(e))

               Globals.oldTime = newTime
               Globals.INTERRUPTCOUNTER = 0

           if Globals.INTERRUPTCOUNTER == 0 and newTime - Globals.oldTime >= 10000:
               totalInterruptsCounter = 0
               Globals.oldTime = newTime

           #theCollection = theCollection + 1
           #if  theCollection >= 120:
               #gc.collect()
               #myMem = gc.mem_free()
               #print(myMem)
               #theCollection = 0


           if Globals.INTERRUPTCOUNTER == 0 and newTime - oldPrintTime >= 10000 and zeroCount == 1:
               Globals.allTimeLiters = Globals.allTimeLiters + toteMils
               add_task(str(flowRate) + " " + str(toteMils) + " " + str(tStamper()))
               add_task("0 0 " + str(tStamper() + 1))
               print('Last ZERO   ###')
               toteMils = 0
               zeroCount = 0
               flowRate = 0
               #myDir = uos.listdir('/sd/')
               Globals.numFlows = Globals.numFlows + 1
               client.publish('test/message', 'esp32_flow is Done Spooling to Influxdb at ' + str(easyTime()))
               totalInterruptsCounter = 0

   except KeyboardInterrupt:
       print("CNTRL-C has been invoked")
       threadList = _thread.list(False)

       for i in threadList:
           if "netty" in i[2]:
               toSuspend = i[0]
               _thread.stop(toSuspend)

           if "poppy" in i[2]:
               toSuspend = i[0]
               _thread.stop(toSuspend)
So with the information that upy spits out in the core dump, can I determine which part of the script it gets tripped up on ?
cheers
Brett

EDIT: This is running on an esp32 Cam module, but have tested same code on a esp32 Wroom 32, with same results as described above

EDIT2: Seems I have narrowed it down to urequests(), as soon as it fires in the queueThread, that causes the core dump, after a few seconds/minutes ... if I comment it out, the code will run fine for hours (all I have tested)
Reply
#2
Dear Brett,

just reading your post after coming here from [1], we wanted to humbly point out [2] to you. While we are not sure about that with respect to LoBo MicroPython (we might just get started with it), we definitively saw an opportunity to share this in this context.

With kind regards,
Andreas.

[1] https://community.hiveeyes.org/t/ttgo-t-call/2690/9
[2] https://community.hiveeyes.org/t/random-...-mode/2515
Reply
#3
EDIT3: I changed things around so that none of the threads I start deal with string manipulation, and it all works as it should. Except for mqtt. Once I turn on mqtt it goes back to core dumping ... but at least it's an improvement.

EDIT4: Was a stupid issue where I had invoked gc after mqtt message parsing ... once removed it has become a lot more stable. Seems the only crash I have now is when I write to the SD in short bursts over a long period.... more testing, to see exactly where this is happening, will continue.
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)