::::::::::textpak=>_Desc_adcRead_pkg.py.txt
***********************************
adcRead_pkg.py Description (simple)
***********************************
adcRead_pkg.py
# function Package adcRead_pkg.py
# contains
#   various functions needed by adcRead()
#   adcRead() itself
#   adcReadInit() which must be run before adcRead
#   see test_adcRead.py for main program setup

import cmd, time, logging, smbus, RPi.GPIO as GPIO
for Rpi 5B will need RPi5GPIO to use gpiozero
************************************************************************************
FROM
smartyPies.com
welcome projects misc imprint - legal - GDPR
ADS1115Runner.py
Mark&copy&paste the code into a file named "ADS1115Runner.py".
Thanks to the guys from GeSHi and Curt, who made me revise the code.

Created with GeSHi http://qbnz.com/highlighter/
************************************************************************************
/_Desc_adcRead_pkg.py.txt
::::::::::textpak=>_Desc_ambRead_pkg.py.txt
***********************************
ambRead_pkg.py Description (Simple)
***********************************
This package contains functions that measure ambient parameters.
/_Desc_ambRead_pkg.py.txt
::::::::::textpak=>_Desc_functionList_pkg.py.txt
***********************************************************************
functionList_pkg.py  Description (simple)
***********************************************************************
This package is used by n_v04.py
***********************************************************************
retrieved from Seagate 3T2021
BUs_ByH/2022/2022HAug23/_Fla58D064G/
    BUs_byHand/2022DApr02Fla53S032G/functionList_pkg.py
     dated 4/2/2022 38 KB
***********************************************************************
/_Desc_functionList_pkg.py.txt
::::::::::textpak=>_Desc_ix~ix_pkg.py.txt
ix/ix_pkg.py.txt
by D@CC on 2024BFeb09

This is the main pkg of general-purpose IX
Python functions.  It contains the most-used
functions in the IX software library such as:
	f3()
	inputWTO()
	show()
It is stored in Desktop/IX_assets/

/_Desc_ix~ix_pkg.py.txt
::::::::::textpak=>_Desc_textpack_pkg.py.txt
************************************
textpack_pkg.py Description (simple)
************************************
this package is quite stable
it allows pack and unpack
of code into a package

It works with n.py
   textpack.py
   textunpack.py
   etc    
The latest version v04 of n.py
display  much info about the files 
in a package.
***********************************
/_Desc_textpack_pkg.py.txt
::::::::::textpak=>_mod8.py.txt
# store this in Desktop/mod6 as _mod8.py
# point Files to /home/pi/Desktop
# then run this with
# >>>import mod6
# >>>mod8.hello()
# This worked on 2021EMay28 by D@CC using Python3
# and with MicroPython in a package folder w/o __init__.py
# Source: https://wiki.micropython.org/Importing-Modules
def hello():
    print('hello from mod8')
hello()
#/mod8.py

::::::::::textpak=>1Char_py.py.txt
def bChar(strB):
    #  given a string like b'z' this returns the "z"
    # tested by D@CC on 2021FJun15
    
    #strB=input("eg b'h' :")
    b=strB[2:]
    print("b:"+b)
    c=b[0]
    #c="zz"
    print("bChar("+'"'+strB+ '"):'+c)
    return c
#end def

while True:
    print(bChar(input("eg b'h' :")))
#end while
::::::::::textpak=>adcRead_pkg.py.txt
#::::::::::textpak=>adcRead_pkg.py
# function Package adcRead_pkg.py
# contains
#   various functions needed by adcRead()
#   adcRead() itself
#   adcReadInit() which must be run before adcRead
#   see test_adcRead.py for main program setup

import cmd, time, logging, smbus, RPi.GPIO as GPIO

#Source: https://smartypies.com/projects/ads1115-with-raspberrypi-and-python/ads1115runner/  #DC
#ADS1115 Datasheet: https://www.ti.com/lit/ds/symlink/ads1115.pdf?ts=1647366695082&ref_url=https%253A%252F%252Fwww.digchip.com%252F

#   Usage once:
#   define adcRead constants               # see the main program test_adcRead.py
#   BUS = adcReadInit(I2C_BUS,icNumber)    # create BUS class object
#   BUS.open(I2C_BUS)
#   . . . then repeatedly
#   value = adcRead(nChannel)              # read nChannel of the ADS1115 once
#   # no other functions need to be called
#   # the only externally callable functions are 
#         adcReadInit() 
#         adcRead()
#   # stop this program using ctrl+c       # how to stop the test    

def MUX(n):
    if n==0: m="00"
    if n==1: m="01"
    if n==2: m="10"
    if n==3: m="11"
    return m
#def end

def swap2Bytes(c):
    '''Revert Byte order for Words (2 Bytes, 16 Bit).'''
    return (c>>8 |c<<8)&0xFFFF
#def end
 
def prepareLEconf(BEconf):
    '''Prepare LittleEndian Byte pattern from BigEndian configuration string, with separators.'''
    c = int(BEconf.replace('-',''), base=2)
    return swap2Bytes(c)
#def end
 
def LEtoBE(c):
    '''Little Endian to BigEndian conversion for signed 2Byte integers (2 complement).'''
    c = swap2Bytes(c)
    if(c >= 2**15):
        c= c-2**16
    return c
#def end
 
def BEtoLE(c):
    '''BigEndian to LittleEndian conversion for signed 2 Byte integers (2 complement).'''
    if(c < 0):
        c= 2**16 + c
    return swap2Bytes(c)
#def end
 
def resetChip(RESET_ADDRESS, RESET_COMMAND):
    #BUS.write_byte(RESET_ADDRESS, RESET_COMMAND)
    return
#def end

class ADS1115Runner(cmd.Cmd):
    # this is the entry-point for  Runner.cmdloop() 
    # NB cmd.Cmd has been deprecated
    # cmd.Cmd will cause the self.cmdLoop() to return to the object's main method.
    # the ''' permits the definition of a string variable containing LFs
    #intro = '''usage: type following commands
    #     1    - one-shot measurement mode, timed
    #     2    - one-shot measurement mode, alerted through GPIO
    #     3    - continuous measurment mode, alerted through GPIO
    #     4  low high  - continuous mode, alerted when value out of range [low, high]
    #     q (quit)
    #     just hitting enter quits any mode 1-4. Enter 'y' to continue in modes 1 and 2.'''
    #prompt = 'Enter 1,2,3,4 or q >>'
    # if you enter 1 it will run do_1(), 2 . . . do_2() etc
    file = None
 
    __logfile = None
 
    def alerted(self, arg):  
        # deprecated      
        data_raw =  BUS.read_word_data(DEVICE_ADDRESS, POINTER_CONVERSION)
        print('alerted:' + str(LEtoBE(data_raw)))
        return
    #def end  alerted()
   
    def do_q(self, arg):
        exit
    #def end do_q()

    def mydo_1(self,BUS,AINn):
        RESET_ADDRESS = 0b0000000
        RESET_COMMAND = 0b00000110
        POINTER_CONVERSION = 0x0
        POINTER_CONFIGURATION  = 0x1
        POINTER_LOW_THRESHOLD  = 0x2
        POINTER_HIGH_THRESHOLD = 0x3
        DEVICE_ADDRESS = 0x48        # device address selected on the IC chip
        # replaces do_1 routine
        #print("into do_1 arg:",arg)
        #print("into do_1")
        '''One-shot, Read value from channel AINn with wait time'''
        #resetChip(RESET_ADDRESS, RESET_COMMAND)      #deprecated
        BUS.write_byte(RESET_ADDRESS, RESET_COMMAND)  #replace
       
        # compare with configuration settings from ADS1115 datasheet           #DC
        # start single conversion - AIN2/GND - 4.096V - single shot - 8SPS - X
        # - X - X - disable comparator
        # conf = prepareLEconf('1-110-001-1-000-0-0-0-11')                     #DC
        # AINn = 2 arg1 is AINn the nChannel to read
        ADSn = MUX(AINn)         #e.g. AINn=2 read AIN2  ( AIN2 to GND*)       #DC
        conf = prepareLEconf('1-1'+ADSn+'-001-1-000-0-0-0-11')                 #DC
        go = 'y'
        #while True and go in ['y','Y']:
        if True :           #only do this once
            BUS.write_word_data(DEVICE_ADDRESS, POINTER_CONFIGURATION, conf)
            # long enough to be safe that data acquisition (conversion) has completed
            # may be calculated from data rate + some extra time for safety.
            # check accuracy in any case.
            time.sleep(0.2)
            value_raw = BUS.read_word_data(DEVICE_ADDRESS, POINTER_CONVERSION)
            value = LEtoBE(value_raw)

            #print("mid do_1")

            global g_adcValue
            g_adcValue = value        # so adcRead() can see it

            #print(value)          # test_adcRead() will print it
            #enter to break, repeat with 'y'
            if False :             # deprecated
                go= input('continue: n/y')
                if (len(go)==0):
                    go='n'
            #time.sleep(sleepTime)
        #if end
        return value
    #def end mydo_1()

    def shutdown(self):
        #GPIO.cleanup()
        #BUS.close()
        pass 
    #def end shutdown()

#class end ADS1115Runner()

def adcRead(BUS,nChannel=0) :
    # nChannel is the number of the analog input to read i.e. 0 = AIN0

    # adcRead returns value 0 to ~11000 as the actual reading

    #by D@CC on 202CMar16 DC

    #must be preceded by 
    #    BUS.adcReadInit(I2C_BUS,icNumber)
    #    BUS.open(I2C_BUS)

    #Source: https://smartypies.com/projects/ads1115-with-raspberrypi-and-python/ads1115runner/  #DC
    #ADS1115 Datasheet: https://www.ti.com/lit/ds/symlink/ads1115.pdf?ts=1647366695082&ref_url=https%253A%252F%252Fwww.digchip.com%252F

    #Jumper S of KY-18 photo-cell to AIN2
    # invert the KY-18 3v3 and GND to measure the opposite [ light (not dark) ]
    # terminal strip is L-R  on the ADS1115 for RPi from SeeedStudios
    #  3V3,AIN3,AIN2,AIN1,AIN0,GND
    # Uses 3 objects:BUS.write_byte(RESET_ADDRESS, RESET_COMMAND)  #replace
    #   Runner.      for ADS1115 ADC
    #   BUS.         for ADS11#Jumper S of KY-18 photo-cell to AIN2  #DC

    #   GPIO.        for ALERTPIN  class is not used  #DC

    try:
        # I (D@CC) do not know anything about the logging
        logging.basicConfig(
            level=logging.DEBUG,
            #format='%(name)-12s: %(levelname)-8s %(message)s')
            format='%(message)s')
        logger = logging.getLogger('ADS1115Runner')
        #print("logger:",logger)
        #AINn=2                          # AINn=2 to read AIN2
        Runner = ADS1115Runner()    # create object Runner
        #print("before .cmdloop")
        Runner.mydo_1(BUS,nChannel)     # nChannel is 2 to read AIN2
        #Runner.cmdloop()            # will run the main Runner.method (cmd.Cmd)
                                    # which prompts for a response & invokes do_r(arg)
                                    # for a response of "r arg"
        #print("after .cmdloop")
  
        global g_adcValue
        returnValue = g_adcValue     # from mydo_1
        return returnValue  
    finally:
        Runner.shutdown()               #release this object
        #BUS.close()                     #release this object
#if end adcRead()

def adcReadInit(I2C_BUS=1,icNumber="ADS1115") :
    # arg1 is the BUS number used by the IC chip
    # arg2 is the number of the IC chip used on the Seeed ADS1115 4 channel RPi board
    # usage of global variables
    # global g_adcValue

    if icNumber=="ADS1115" :
        BUS=smbus.SMBus(I2C_BUS)
        #returns the BUS object , (usually BUS=smbus.SMBus(I2C_BUS) )
        # Open I2C device
        # I2C_BUS = 1
        # DEVICE_ADDRESS = 0x48

        return BUS
    else:
        print('ERROR025: ic supported is "ADS1115"')
        exit
#def end adcReadInit()

#   9 constants included in adcRead_Pkg.py
    RESET_ADDRESS = 0b0000000
    RESET_COMMAND = 0b00000110
    POINTER_CONVERSION = 0x0
    POINTER_CONFIGURATION  = 0x1
    POINTER_LOW_THRESHOLD  = 0x2
    POINTER_HIGH_THRESHOLD = 0x3
    DEVICE_ADDRESS = 0x48        # device address selected on the IC chip
    icNumber = "ADS1115"         # IC chip used
    I2C_BUS = 1                  # BUS number used by the IC chip

# end of adcRead_pkg.py

::::::::::textpak=>adcRead_pkg_bu.py.txt
#::::::::::textpak=>adcRead_pkg.py
# function Package adcRead_pkg.py
# contains
#   various functions needed by adcRead()
#   adcRead() itself
#   adcReadInit() which must be run before adcRead
#   see test_adcRead.py for main program setup

import cmd, time, logging, smbus, RPi.GPIO as GPIO

#Source: https://smartypies.com/projects/ads1115-with-raspberrypi-and-python/ads1115runner/  #DC
#ADS1115 Datasheet: https://www.ti.com/lit/ds/symlink/ads1115.pdf?ts=1647366695082&ref_url=https%253A%252F%252Fwww.digchip.com%252F

#   Usage once:
#   define adcRead constants               # see the main program test_adcRead.py
#   BUS = adcReadInit(I2C_BUS,icNumber)    # create BUS class object
#   BUS.open(I2C_BUS)
#   . . . then repeatedly
#   value = adcRead(nChannel)              # read nChannel of the ADS1115 once
#   # no other functions need to be called
#   # the only externally callable functions are 
#         adcReadInit() 
#         adcRead()
#   # stop this program using ctrl+c       # how to stop the test    

def MUX(n):
    if n==0: m="00"
    if n==1: m="01"
    if n==2: m="10"
    if n==3: m="11"
    return m
#def end

def swap2Bytes(c):
    '''Revert Byte order for Words (2 Bytes, 16 Bit).'''
    return (c>>8 |c<<8)&0xFFFF
#def end
 
def prepareLEconf(BEconf):
    '''Prepare LittleEndian Byte pattern from BigEndian configuration string, with separators.'''
    c = int(BEconf.replace('-',''), base=2)
    return swap2Bytes(c)
#def end
 
def LEtoBE(c):
    '''Little Endian to BigEndian conversion for signed 2Byte integers (2 complement).'''
    c = swap2Bytes(c)
    if(c >= 2**15):
        c= c-2**16
    return c
#def end
 
def BEtoLE(c):
    '''BigEndian to LittleEndian conversion for signed 2 Byte integers (2 complement).'''
    if(c < 0):
        c= 2**16 + c
    return swap2Bytes(c)
#def end
 
def resetChip(RESET_ADDRESS, RESET_COMMAND):
    #BUS.write_byte(RESET_ADDRESS, RESET_COMMAND)
    return
#def end

class ADS1115Runner(cmd.Cmd):
    # this is the entry-point for  Runner.cmdloop() 
    # NB cmd.Cmd has been deprecated
    # cmd.Cmd will cause the self.cmdLoop() to return to the object's main method.
    # the ''' permits the definition of a string variable containing LFs
    #intro = '''usage: type following commands
    #     1    - one-shot measurement mode, timed
    #     2    - one-shot measurement mode, alerted through GPIO
    #     3    - continuous measurment mode, alerted through GPIO
    #     4  low high  - continuous mode, alerted when value out of range [low, high]
    #     q (quit)
    #     just hitting enter quits any mode 1-4. Enter 'y' to continue in modes 1 and 2.'''
    #prompt = 'Enter 1,2,3,4 or q >>'
    # if you enter 1 it will run do_1(), 2 . . . do_2() etc
    file = None
 
    __logfile = None
 
    def alerted(self, arg):  
        # deprecated      
        data_raw =  BUS.read_word_data(DEVICE_ADDRESS, POINTER_CONVERSION)
        print('alerted:' + str(LEtoBE(data_raw)))
        return
    #def end  alerted()
   
    def do_q(self, arg):
        exit
    #def end do_q()

    def mydo_1(self,BUS,AINn):
        RESET_ADDRESS = 0b0000000
        RESET_COMMAND = 0b00000110
        POINTER_CONVERSION = 0x0
        POINTER_CONFIGURATION  = 0x1
        POINTER_LOW_THRESHOLD  = 0x2
        POINTER_HIGH_THRESHOLD = 0x3
        DEVICE_ADDRESS = 0x48        # device address selected on the IC chip
        # replaces do_1 routine
        #print("into do_1 arg:",arg)
        #print("into do_1")
        '''One-shot, Read value from channel AINn with wait time'''
        #resetChip(RESET_ADDRESS, RESET_COMMAND)      #deprecated
        BUS.write_byte(RESET_ADDRESS, RESET_COMMAND)  #replace
       
        # compare with configuration settings from ADS1115 datasheet           #DC
        # start single conversion - AIN2/GND - 4.096V - single shot - 8SPS - X
        # - X - X - disable comparator
        # conf = prepareLEconf('1-110-001-1-000-0-0-0-11')                     #DC
        # AINn = 2 arg1 is AINn the nChannel to read
        ADSn = MUX(AINn)         #e.g. AINn=2 read AIN2  ( AIN2 to GND*)       #DC
        conf = prepareLEconf('1-1'+ADSn+'-001-1-000-0-0-0-11')                 #DC
        go = 'y'
        #while True and go in ['y','Y']:
        if True :           #only do this once
            BUS.write_word_data(DEVICE_ADDRESS, POINTER_CONFIGURATION, conf)
            # long enough to be safe that data acquisition (conversion) has completed
            # may be calculated from data rate + some extra time for safety.
            # check accuracy in any case.
            time.sleep(0.2)
            value_raw = BUS.read_word_data(DEVICE_ADDRESS, POINTER_CONVERSION)
            value = LEtoBE(value_raw)

            #print("mid do_1")

            global g_adcValue
            g_adcValue = value        # so adcRead() can see it

            #print(value)          # test_adcRead() will print it
            #enter to break, repeat with 'y'
            if False :             # deprecated
                go= input('continue: n/y')
                if (len(go)==0):
                    go='n'
            #time.sleep(sleepTime)
        #if end
        return value
    #def end mydo_1()

    def shutdown(self):
        #GPIO.cleanup()
        #BUS.close()
        pass 
    #def end shutdown()

#class end ADS1115Runner()

def adcRead(BUS,nChannel=0) :
    # nChannel is the number of the analog input to read i.e. 0 = AIN0

    # adcRead returns value 0 to ~11000 as the actual reading

    #by D@CC on 202CMar16 DC

    #must be preceded by 
    #    BUS.adcReadInit(I2C_BUS,icNumber)
    #    BUS.open(I2C_BUS)

    #Source: https://smartypies.com/projects/ads1115-with-raspberrypi-and-python/ads1115runner/  #DC
    #ADS1115 Datasheet: https://www.ti.com/lit/ds/symlink/ads1115.pdf?ts=1647366695082&ref_url=https%253A%252F%252Fwww.digchip.com%252F

    #Jumper S of KY-18 photo-cell to AIN2
    # invert the KY-18 3v3 and GND to measure the opposite [ light (not dark) ]
    # terminal strip is L-R  on the ADS1115 for RPi from SeeedStudios
    #  3V3,AIN3,AIN2,AIN1,AIN0,GND
    # Uses 3 objects:BUS.write_byte(RESET_ADDRESS, RESET_COMMAND)  #replace
    #   Runner.      for ADS1115 ADC
    #   BUS.         for ADS11#Jumper S of KY-18 photo-cell to AIN2  #DC

    #   GPIO.        for ALERTPIN  class is not used  #DC

    try:
        # I (D@CC) do not know anything about the logging
        logging.basicConfig(
            level=logging.DEBUG,
            #format='%(name)-12s: %(levelname)-8s %(message)s')
            format='%(message)s')
        logger = logging.getLogger('ADS1115Runner')
        #print("logger:",logger)
        #AINn=2                          # AINn=2 to read AIN2
        Runner = ADS1115Runner()    # create object Runner
        #print("before .cmdloop")
        Runner.mydo_1(BUS,nChannel)     # nChannel is 2 to read AIN2
        #Runner.cmdloop()            # will run the main Runner.method (cmd.Cmd)
                                    # which prompts for a response & invokes do_r(arg)
                                    # for a response of "r arg"
        #print("after .cmdloop")
  
        global g_adcValue
        returnValue = g_adcValue     # from mydo_1
        return returnValue  
    finally:
        Runner.shutdown()               #release this object
        #BUS.close()                     #release this object
#if end adcRead()

def adcReadInit(I2C_BUS=1,icNumber="ADS1115") :
    # arg1 is the BUS number used by the IC chip
    # arg2 is the number of the IC chip used on the Seeed ADS1115 4 channel RPi board
    # usage of global variables
    # global g_adcValue

    if icNumber=="ADS1115" :
        BUS=smbus.SMBus(I2C_BUS)
        #returns the BUS object , (usually BUS=smbus.SMBus(I2C_BUS) )
        # Open I2C device
        # I2C_BUS = 1
        # DEVICE_ADDRESS = 0x48

        return BUS
    else:
        print('ERROR025: ic supported is "ADS1115"')
        exit
#def end adcReadInit()

#   9 constants included in adcRead_Pkg.py
    RESET_ADDRESS = 0b0000000
    RESET_COMMAND = 0b00000110
    POINTER_CONVERSION = 0x0
    POINTER_CONFIGURATION  = 0x1
    POINTER_LOW_THRESHOLD  = 0x2
    POINTER_HIGH_THRESHOLD = 0x3
    DEVICE_ADDRESS = 0x48        # device address selected on the IC chip
    icNumber = "ADS1115"         # IC chip used
    I2C_BUS = 1                  # BUS number used by the IC chip

# end of adcRead_pkg_bu.py

::::::::::textpak=>adcRead_pkg_v01.py.txt
#::::::::::textpak=>ADS1115Runner_wComments.txt
smartyPies.com
welcome projects misc imprint - legal - GDPR
ADS1115Runner.py
Mark&copy&paste the code into a file named "ADS1115Runner.py".
Thanks to the guys from GeSHi and Curt, who made me revise the code.

Created with GeSHi http://qbnz.com/highlighter/
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
'''
@author: guido lutterbach
@contact: guido@smartypies.com
@version: 1.1
@licence: Public Domain
 
This program implements 4 cases for ADS1115 on raspberry pi with default libraries.
1) single-shot - open drain - timed
2) single-shot - open drain - GPIO alert
3) continuous mode - differential - GPIO alert
4) continuous mode - differential - GPIO alert when value leaves high/low threshold range
Please check the electric circuit that goes with it at www.smartypies.com (ADS1115 project)
For testing 1) + 2) use potentiometer 1
For testing 3) + 4) use potentiometer 2
Enjoy!
'''
 
import cmd, time, logging, smbus, RPi.GPIO as GPIO
 
# ADS1115 + hardware constants
I2C_BUS = 1
DEVICE_ADDRESS = 0x4B
POINTER_CONVERSION = 0x0
POINTER_CONFIGURATION = 0x1
POINTER_LOW_THRESHOLD = 0x2
POINTER_HIGH_THRESHOLD = 0x3
 
RESET_ADDRESS = 0b0000000
RESET_COMMAND = 0b00000110
 
# Open I2C device
BUS = smbus.SMBus(I2C_BUS)
BUS.open(I2C_BUS)
 
ALERTPIN =  27
       
def swap2Bytes(c):
    '''Revert Byte order for Words (2 Bytes, 16 Bit).'''
    return (c>>8 |c<<8)&0xFFFF
 
def prepareLEconf(BEconf):
    '''Prepare LittleEndian Byte pattern from BigEndian configuration string, with separators.'''
    c = int(BEconf.replace('-',''), base=2)
    return swap2Bytes(c)
 
def LEtoBE(c):
    '''Little Endian to BigEndian conversion for signed 2Byte integers (2 complement).'''
    c = swap2Bytes(c)
    if(c >= 2**15):
        c= c-2**16
    return c
 
def BEtoLE(c):
    '''BigEndian to LittleEndian conversion for signed 2 Byte integers (2 complement).'''
    if(c < 0):
        c= 2**16 + c
    return swap2Bytes(c)
 
def resetChip():
    BUS.write_byte(RESET_ADDRESS, RESET_COMMAND)
    return
# Use BCM GPIO references
GPIO.setmode(GPIO.BCM)
GPIO.setup(ALERTPIN, GPIO.IN, pull_up_down=GPIO.PUD_UP) ## read mode, pull up resistor
 
 
class ADS1115Runner(cmd.Cmd):
    intro = '''usage: type following commands
          1    - one-shot measurement mode, timed
          2    - one-shot measurement mode, alerted through GPIO
          3    - continuous measurment mode, alerted through GPIO
          4  low high  - continuous mode, alerted when value out of range [low, high]
          q (quit)
          just hitting enter quits any mode 1-4. Enter 'y' to continue in modes 1 and 2.'''
    prompt = 'Enter 1,2,3,4 or q >>'
    file = None
 
#    __logfile = None
 
    def alerted(self, arg):        
        data_raw =  BUS.read_word_data(DEVICE_ADDRESS, POINTER_CONVERSION)
        print('alerted:' + str(LEtoBE(data_raw)))
        return
   
    def do_1(self, arg):
        '''One-shot, Read value from channel 0 with wait time'''
        resetChip()
       
        # compare with configuration settings from ADS115 datasheet
        # start single conversion - AIN2/GND - 4.096V - single shot - 8SPS - X
        # - X - X - disable comparator
        conf = prepareLEconf('1-110-001-1-000-0-0-0-11')
 
        go = 'y'
        while True and go in ['y','Y']:
            BUS.write_word_data(DEVICE_ADDRESS, POINTER_CONFIGURATION, conf)
            # long enough to be safe that data acquisition (conversion) has completed
            # may be calculated from data rate + some extra time for safety.
            # check accuracy in any case.
            time.sleep(0.2)
            value_raw = BUS.read_word_data(DEVICE_ADDRESS, POINTER_CONVERSION)
            value = LEtoBE(value_raw)
            print(value)
            #enter to break, repeat with 'y'
            go= input('continue: n/y')
            if (len(go)==0):
                go='n'
        return
   
    def do_2(self, arg):
        '''One-shot with GPIO alert'''
        # register callback for alerts
        GPIO.add_event_detect(ALERTPIN, GPIO.RISING, callback=self.alerted)
        # reset call
        resetChip()
        # compare with configuration settings from ADS115 datasheet:
        # start single conversion - AIN2/GND - 4.096V - single shot - 8SPS -
        # trad. comparator - active high - latching - assert after one conversion
        conf = prepareLEconf('1-110-001-1-000-0-1-1-00')
        BUS.write_byte(0b0000000,0b00000110) # reset call
        # set High and Low threshold for ALERT pin mode
        BUS.write_word_data(DEVICE_ADDRESS, POINTER_LOW_THRESHOLD, 0xFF7F) # 0x7FFF in BigEndian
        BUS.write_word_data(DEVICE_ADDRESS, POINTER_HIGH_THRESHOLD, 0x0080) # 0x8000 in BigEndian  
        go = 'y'
        while True and go in ['y','Y']:
            BUS.write_word_data(DEVICE_ADDRESS, POINTER_CONFIGURATION, conf)
            #enter to break, repeat with 'y'
            go= input('continue: n/y\n')
 
        # remove event listener
        GPIO.remove_event_detect(ALERTPIN)
        return
   
    def do_3(self, arg):
        '''Continuous mode with GPIO alert'''
        # register callback for alerts
        GPIO.add_event_detect(ALERTPIN, GPIO.RISING, callback=self.alerted)
        # reset call
        resetChip()
        # compare with configuration settings from ADS115 datasheet
        # X - AIN0/AIN1 - 2.048V - continuous mode - 64SPS -
        # window comparator - active high - nonlatching - assert after one conversion      
        conf = prepareLEconf('0-000-010-0-011-1-1-0-00')
        # set High and Low threshold for ALERT pin mode
        BUS.write_word_data(DEVICE_ADDRESS, POINTER_LOW_THRESHOLD, 0xFF7F) # 0x7FFF in BigEndian
        BUS.write_word_data(DEVICE_ADDRESS, POINTER_HIGH_THRESHOLD, 0x0080) # 0x8000 in BigEndian
        # write configuration ONCE
        BUS.write_word_data(DEVICE_ADDRESS, POINTER_CONFIGURATION, conf)
       
        # wait for input(), enter to break
        input('enter to stop\n' )
        # remove event listener to stop execution
        GPIO.remove_event_detect(ALERTPIN)
        return
   
    def do_4(self, arg):
        ''' Continuous measurements with latch and allowable data range'''
        largs = tuple(map(int, arg.split()))
        if len(largs) != 2:
            print('please call with exactly 2 integer arguments')
            return
        # reset call
        resetChip()
        # compare with configuration settings from ADS115 datasheet
        # X - AIN0/AIN1 - 2.048V - continuous mode - 8SPS -
        # window comparator - active high - latching - assert after one conversion      
        conf = prepareLEconf('0-000-010-0-000-1-1-1-00')
        # register callback for alerts
        GPIO.add_event_detect(ALERTPIN, GPIO.RISING, callback=self.alerted)
        # prepare for ALERT pin mode - define window
 
        low = min(largs) # Python BigEndian - RaspberryPi LittleEndian
        high = max(largs)
        low_val = BEtoLE(low)
        high_val = BEtoLE(high)
        logger.debug( "{:04X} {:04x} {:04x} {:04x} ".format(low, low_val, high, high_val))
        BUS.write_word_data(DEVICE_ADDRESS, POINTER_LOW_THRESHOLD, low_val)
        BUS.write_word_data(DEVICE_ADDRESS, POINTER_HIGH_THRESHOLD, high_val)
       
        # write configuration ONCE
        BUS.write_word_data(DEVICE_ADDRESS, POINTER_CONFIGURATION, conf)
       
        # wait for input(), enter to break
        input('enter to stop\n' )
        # remove event listener to stop execution
        GPIO.remove_event_detect(ALERTPIN)
        return
   
    def do_q(self, arg):
        '''Quit.'''
        return True
   
    def default(self, line):
        print('undefined key')
   
    def shutdown(self):
        GPIO.cleanup()
        BUS.close()
        pass    
 
if __name__ == "__main__":
    try:
        logging.basicConfig(
            level=logging.DEBUG,
            #format='%(name)-12s: %(levelname)-8s %(message)s')
            format='%(message)s')
        logger = logging.getLogger('ADS1115Runner')
        Runner = ADS1115Runner()
        Runner.cmdloop()
    finally:
        Runner.shutdown()
# © Copyright 2017-20 by Guido Lutterbach
# guido@smartypies.com
# / ADS1115Runner.p
#::::::::::textpak=>ADS1115Runner_pgmOnly.py
import cmd, time, logging, smbus, RPi.GPIO as GPIO
 
# ADS1115 + hardware constants
I2C_BUS = 1
#DEVICE_ADDRESS = 0x4B                      #DC
DEVICE_ADDRESS = 0x48                       #DC
POINTER_CONVERSION = 0x0
POINTER_CONFIGURATION = 0x1
POINTER_LOW_THRESHOLD = 0x2
POINTER_HIGH_THRESHOLD = 0x3
 
RESET_ADDRESS = 0b0000000
RESET_COMMAND = 0b00000110
 
# Open I2C device
BUS = smbus.SMBus(I2C_BUS)
BUS.open(I2C_BUS)
 
ALERTPIN =  27                #GPIO27       #DC
       
def swap2Bytes(c):
    '''Revert Byte order for Words (2 Bytes, 16 Bit).'''
    return (c>>8 |c<<8)&0xFFFF
 
def prepareLEconf(BEconf):
    '''Prepare LittleEndian Byte pattern from BigEndian configuration string, with separators.'''
    c = int(BEconf.replace('-',''), base=2)
    return swap2Bytes(c)
 
def LEtoBE(c):
    '''Little Endian to BigEndian conversion for signed 2Byte integers (2 complement).'''
    c = swap2Bytes(c)
    if(c >= 2**15):
        c= c-2**16
    return c
 
def BEtoLE(c):
    '''BigEndian to LittleEndian conversion for signed 2 Byte integers (2 complement).'''
    if(c < 0):
        c= 2**16 + c
    return swap2Bytes(c)
 
def resetChip():
    BUS.write_byte(RESET_ADDRESS, RESET_COMMAND)
    return
# Use BCM GPIO references
GPIO.setmode(GPIO.BCM)
GPIO.setup(ALERTPIN, GPIO.IN, pull_up_down=GPIO.PUD_UP) ## read mode, pull up resistor
 
 
class ADS1115Runner(cmd.Cmd):
    intro = '''usage: type following commands
          1    - one-shot measurement mode, timed
          2    - one-shot measurement mode, alerted through GPIO
          3    - continuous measurment mode, alerted through GPIO
          4  low high  - continuous mode, alerted when value out of range [low, high]
          q (quit)
          just hitting enter quits any mode 1-4. Enter 'y' to continue in modes 1 and 2.'''
    prompt = 'Enter 1,2,3,4 or q >>'
    file = None
 
#    __logfile = None
 
    def alerted(self, arg):        
        data_raw =  BUS.read_word_data(DEVICE_ADDRESS, POINTER_CONVERSION)
        print('alerted:' + str(LEtoBE(data_raw)))
        return
   
    def do_1(self, arg):
        '''One-shot, Read value from channel 0 with wait time'''
        resetChip()
       
        # compare with configuration settings from ADS115 datasheet
        # start single conversion - AIN2/GND - 4.096V - single shot - 8SPS - X
        # - X - X - disable comparator
        conf = prepareLEconf('1-110-001-1-000-0-0-0-11')
 
        go = 'y'
        while True and go in ['y','Y']:
            BUS.write_word_data(DEVICE_ADDRESS, POINTER_CONFIGURATION, conf)
            # long enough to be safe that data acquisition (conversion) has completed
            # may be calculated from data rate + some extra time for safety.
            # check accuracy in any case.
            time.sleep(0.2)
            value_raw = BUS.read_word_data(DEVICE_ADDRESS, POINTER_CONVERSION)
            value = LEtoBE(value_raw)
            print(value)
            #enter to break, repeat with 'y'
            go= input('continue: n/y')
            if (len(go)==0):
                go='n'
        return
   
    def do_2(self, arg):
        '''One-shot with GPIO alert'''
        # register callback for alerts
        GPIO.add_event_detect(ALERTPIN, GPIO.RISING, callback=self.alerted)
        # reset call
        resetChip()
        # compare with configuration settings from ADS115 datasheet:
        # start single conversion - AIN2/GND - 4.096V - single shot - 8SPS -
        # trad. comparator - active high - latching - assert after one conversion
        conf = prepareLEconf('1-110-001-1-000-0-1-1-00')
        BUS.write_byte(0b0000000,0b00000110) # reset call
        # set High and Low threshold for ALERT pin mode
        BUS.write_word_data(DEVICE_ADDRESS, POINTER_LOW_THRESHOLD, 0xFF7F) # 0x7FFF in BigEndian
        BUS.write_word_data(DEVICE_ADDRESS, POINTER_HIGH_THRESHOLD, 0x0080) # 0x8000 in BigEndian  
        go = 'y'
        while True and go in ['y','Y']:
            BUS.write_word_data(DEVICE_ADDRESS, POINTER_CONFIGURATION, conf)
            #enter to break, repeat with 'y'
            go= input('continue: n/y\n')
 
        # remove event listener
        GPIO.remove_event_detect(ALERTPIN)
        return
   
    def do_3(self, arg):
        '''Continuous mode with GPIO alert'''
        # register callback for alerts
        GPIO.add_event_detect(ALERTPIN, GPIO.RISING, callback=self.alerted)
        # reset call
        resetChip()
        # compare with configuration settings from ADS115 datasheet
        # X - AIN0/AIN1 - 2.048V - continuous mode - 64SPS -
        # window comparator - active high - nonlatching - assert after one conversion      
        conf = prepareLEconf('0-000-010-0-011-1-1-0-00')
        # set High and Low threshold for ALERT pin mode
        BUS.write_word_data(DEVICE_ADDRESS, POINTER_LOW_THRESHOLD, 0xFF7F) # 0x7FFF in BigEndian
        BUS.write_word_data(DEVICE_ADDRESS, POINTER_HIGH_THRESHOLD, 0x0080) # 0x8000 in BigEndian
        # write configuration ONCE
        BUS.write_word_data(DEVICE_ADDRESS, POINTER_CONFIGURATION, conf)
       
        # wait for input(), enter to break
        input('enter to stop\n' )
        # remove event listener to stop execution
        GPIO.remove_event_detect(ALERTPIN)
        return
   
    def do_4(self, arg):
        ''' Continuous measurements with latch and allowable data range'''
        largs = tuple(map(int, arg.split()))
        if len(largs) != 2:
            print('please call with exactly 2 integer arguments')
            return
        # reset call
        resetChip()
        # compare with configuration settings from ADS115 datasheet
        # X - AIN0/AIN1 - 2.048V - continuous mode - 8SPS -
        # window comparator - active high - latching - assert after one conversion      
        conf = prepareLEconf('0-000-010-0-000-1-1-1-00')
        # register callback for alerts
        GPIO.add_event_detect(ALERTPIN, GPIO.RISING, callback=self.alerted)
        # prepare for ALERT pin mode - define window
 
        low = min(largs) # Python BigEndian - RaspberryPi LittleEndian
        high = max(largs)
        low_val = BEtoLE(low)
        high_val = BEtoLE(high)
        logger.debug( "{:04X} {:04x} {:04x} {:04x} ".format(low, low_val, high, high_val))
        BUS.write_word_data(DEVICE_ADDRESS, POINTER_LOW_THRESHOLD, low_val)
        BUS.write_word_data(DEVICE_ADDRESS, POINTER_HIGH_THRESHOLD, high_val)
       
        # write configuration ONCE
        BUS.write_word_data(DEVICE_ADDRESS, POINTER_CONFIGURATION, conf)
       
        # wait for input(), enter to break
        input('enter to stop\n' )
        # remove event listener to stop execution
        GPIO.remove_event_detect(ALERTPIN)
        return
   
    def do_q(self, arg):
        '''Quit.'''
        return True
   
    def default(self, line):
        print('undefined key')
   
    def shutdown(self):
        GPIO.cleanup()
        BUS.close()
        pass    
 
if __name__ == "__main__":
    try:
        logging.basicConfig(
            level=logging.DEBUG,
            #format='%(name)-12s: %(levelname)-8s %(message)s')
            format='%(message)s')
        logger = logging.getLogger('ADS1115Runner')
        Runner = ADS1115Runner()
        Runner.cmdloop()
    finally:
        Runner.shutdown()
# © Copyright 2017-20 by Guido Lutterbach
# guido@smartypies.com
# / ADS1115Runner_pgmOnly.p
#::::::::::textpak=>adcRead_Pkg.py
# function Package adcRead_Pkg.py
import cmd, time, logging, smbus, RPi.GPIO as GPIO

#Source: https://smartypies.com/projects/ads1115-with-raspberrypi-and-python/ads1115runner/  #DC
#ADS1115 Datasheet: https://www.ti.com/lit/ds/symlink/ads1115.pdf?ts=1647366695082&ref_url=https%253A%252F%252Fwww.digchip.com%252F

#   Usage once:
#   define adcRead constants               # see the main program test_adcRead.py
#   BUS = adcReadInit(I2C_BUS,icNumber)    # create BUS class object
#   BUS.open(I2C_BUS)
#   . . . then repeatedly
#   value = adcRead(nChannel)              # read nChannel of the ADS1115 once
#   # no other functions need to be called
#   # the only externally callable functions are 
#         adcReadInit() 
#         adcRead()
#   # stop this program using ctrl+c       # how to stop the test    

def MUX(n):
    if n==0: m="00"
    if n==1: m="01"
    if n==2: m="10"
    if n==3: m="11"
    return m
#def end

def swap2Bytes(c):
    '''Revert Byte order for Words (2 Bytes, 16 Bit).'''
    return (c>>8 |c<<8)&0xFFFF
#def end
 
def prepareLEconf(BEconf):
    '''Prepare LittleEndian Byte pattern from BigEndian configuration string, with separators.'''
    c = int(BEconf.replace('-',''), base=2)
    return swap2Bytes(c)
#def end
 
def LEtoBE(c):
    '''Little Endian to BigEndian conversion for signed 2Byte integers (2 complement).'''
    c = swap2Bytes(c)
    if(c >= 2**15):
        c= c-2**16
    return c
#def end
 
def BEtoLE(c):
    '''BigEndian to LittleEndian conversion for signed 2 Byte integers (2 complement).'''
    if(c < 0):
        c= 2**16 + c
    return swap2Bytes(c)
#def end
 
def resetChip(RESET_ADDRESS, RESET_COMMAND):
    #BUS.write_byte(RESET_ADDRESS, RESET_COMMAND)
    return
#def end

class ADS1115Runner(cmd.Cmd):
    # this is the entry-point for  Runner.cmdloop() 
    # NB cmd.Cmd has been deprecated
    # cmd.Cmd will cause the self.cmdLoop() to return to the object's main method.
    # the ''' permits the definition of a string variable containing LFs
    #intro = '''usage: type following commands
    #     1    - one-shot measurement mode, timed
    #     2    - one-shot measurement mode, alerted through GPIO
    #     3    - continuous measurment mode, alerted through GPIO
    #     4  low high  - continuous mode, alerted when value out of range [low, high]
    #     q (quit)
    #     just hitting enter quits any mode 1-4. Enter 'y' to continue in modes 1 and 2.'''
    #prompt = 'Enter 1,2,3,4 or q >>'
    # if you enter 1 it will run do_1(), 2 . . . do_2() etc
    file = None
 
    __logfile = None
 
    def alerted(self, arg):  
        # deprecated      
        data_raw =  BUS.read_word_data(DEVICE_ADDRESS, POINTER_CONVERSION)
        print('alerted:' + str(LEtoBE(data_raw)))
        return
    #def end  alerted()
   
    def do_q(self, arg):
        exit
    #def end do_q()

    def mydo_1(self,BUS,AINn):
        RESET_ADDRESS = 0b0000000
        RESET_COMMAND = 0b00000110
        POINTER_CONVERSION = 0x0
        POINTER_CONFIGURATION  = 0x1
        POINTER_LOW_THRESHOLD  = 0x2
        POINTER_HIGH_THRESHOLD = 0x3
        DEVICE_ADDRESS = 0x48        # device address selected on the IC chip
        # replaces do_1 routine
        #print("into do_1 arg:",arg)
        #print("into do_1")
        '''One-shot, Read value from channel AINn with wait time'''
        #resetChip(RESET_ADDRESS, RESET_COMMAND)      #deprecated
        BUS.write_byte(RESET_ADDRESS, RESET_COMMAND)  #replace
       
        # compare with configuration settings from ADS1115 datasheet           #DC
        # start single conversion - AIN2/GND - 4.096V - single shot - 8SPS - X
        # - X - X - disable comparator
        # conf = prepareLEconf('1-110-001-1-000-0-0-0-11')                     #DC
        # AINn = 2 arg1 is AINn the nChannel to read
        ADSn = MUX(AINn)         #e.g. AINn=2 read AIN2  ( AIN2 to GND*)       #DC
        conf = prepareLEconf('1-1'+ADSn+'-001-1-000-0-0-0-11')                 #DC
        go = 'y'
        #while True and go in ['y','Y']:
        if True :           #only do this once
            BUS.write_word_data(DEVICE_ADDRESS, POINTER_CONFIGURATION, conf)
            # long enough to be safe that data acquisition (conversion) has completed
            # may be calculated from data rate + some extra time for safety.
            # check accuracy in any case.
            time.sleep(0.2)
            value_raw = BUS.read_word_data(DEVICE_ADDRESS, POINTER_CONVERSION)
            value = LEtoBE(value_raw)

            #print("mid do_1")

            global g_adcValue
            g_adcValue = value        # so adcRead() can see it

            #print(value)          # test_adcRead() will print it
            #enter to break, repeat with 'y'
            if False :             # deprecated
                go= input('continue: n/y')
                if (len(go)==0):
                    go='n'
            #time.sleep(sleepTime)
        #if end
        return value
    #def end mydo_1()

    def shutdown(self):
        #GPIO.cleanup()
        #BUS.close()
        pass 
    #def end shutdown()

#class end ADS1115Runner()

def adcRead(BUS,nChannel=0) :
    # nChannel is the number of the analog input to read i.e. 0 = AIN0

    # adcRead returns value 0 to ~11000 as the actual reading

    #by D@CC on 202CMar16 DC

    #must be preceded by 
    #    BUS.adcReadInit(I2C_BUS,icNumber)
    #    BUS.open(I2C_BUS)

    #Source: https://smartypies.com/projects/ads1115-with-raspberrypi-and-python/ads1115runner/  #DC
    #ADS1115 Datasheet: https://www.ti.com/lit/ds/symlink/ads1115.pdf?ts=1647366695082&ref_url=https%253A%252F%252Fwww.digchip.com%252F

    #Jumper S of KY-18 photo-cell to AIN2
    # invert the KY-18 3v3 and GND to measure the opposite [ light (not dark) ]
    # terminal strip is L-R  on the ADS1115 for RPi from SeeedStudios
    #  3V3,AIN3,AIN2,AIN1,AIN0,GND
    # Uses 3 objects:BUS.write_byte(RESET_ADDRESS, RESET_COMMAND)  #replace
    #   Runner.      for ADS1115 ADC
    #   BUS.         for ADS11#Jumper S of KY-18 photo-cell to AIN2  #DC

    #   GPIO.        for ALERTPIN  class is not used  #DC

    try:
        # I (D@CC) do not know anything about the logging
        logging.basicConfig(
            level=logging.DEBUG,
            #format='%(name)-12s: %(levelname)-8s %(message)s')
            format='%(message)s')
        logger = logging.getLogger('ADS1115Runner')
        #print("logger:",logger)
        #AINn=2                          # AINn=2 to read AIN2
        Runner = ADS1115Runner()    # create object Runner
        #print("before .cmdloop")
        Runner.mydo_1(BUS,nChannel)     # nChannel is 2 to read AIN2
        #Runner.cmdloop()            # will run the main Runner.method (cmd.Cmd)
                                    # which prompts for a response & invokes do_r(arg)
                                    # for a response of "r arg"
        #print("after .cmdloop")
  
        global g_adcValue
        returnValue = g_adcValue     # from mydo_1
        return returnValue  
    finally:
        Runner.shutdown()               #release this object
        #BUS.close()                     #release this object
#if end adcRead()

def adcReadInit(I2C_BUS=1,icNumber="ADS1115") :
    # arg1 is the BUS number used by the IC chip
    # arg2 is the number of the IC chip used on the Seeed ADS1115 4 channel RPi board
    # usage of global variables
    # global g_adcValue

    if icNumber=="ADS1115" :
        BUS=smbus.SMBus(I2C_BUS)
        #returns the BUS object , (usually BUS=smbus.SMBus(I2C_BUS) )
        # Open I2C device
        # I2C_BUS = 1
        # DEVICE_ADDRESS = 0x48

        return BUS
    else:
        print('ERROR025: ic supported is "ADS1115"')
        exit
#def end adcReadInit()

#   9 constants included in adcRead_Pkg.py
    RESET_ADDRESS = 0b0000000
    RESET_COMMAND = 0b00000110
    POINTER_CONVERSION = 0x0
    POINTER_CONFIGURATION  = 0x1
    POINTER_LOW_THRESHOLD  = 0x2
    POINTER_HIGH_THRESHOLD = 0x3
    DEVICE_ADDRESS = 0x48        # device address selected on the IC chip
    icNumber = "ADS1115"         # IC chip used
    I2C_BUS = 1                  # BUS number used by the IC chip

# end of adcRead_pkg.p
#::::::::::textpak=>test_adcRead.py
# test_adcRead.py   
# program to test adcRead() to read nChannel on the ADS1115 ADC RPi module from SeeedStuios
# by D@CC on 2022CMar16

# needs to have adcRead_Pkg.py in the same folder as test_adcRead.py
# needs import time
import time
# needs from adcRead_Pkg import adcRead,adcReadInit
from adcRead_Pkg import adcRead,adcReadInit

#needs to be run as >$ python3 test_adcRead.py


if __name__ == "__main__":
    # import adcRead_pkg.py      # is needed

    progName="test_adcRead.py"     #this is the main program to test adcRead()
    print("starting:"+progName)

    # These 9 parameters are also defined in 
    #    adcRead_pkg.py:
    #    mydo_1()
    RESET_ADDRESS = 0b0000000
    RESET_COMMAND = 0b00000110
    POINTER_CONVERSION = 0x0
    POINTER_CONFIGURATION  = 0x1
    POINTER_LOW_THRESHOLD  = 0x2
    POINTER_HIGH_THRESHOLD = 0x3
    DEVICE_ADDRESS = 0x48        # device address selected on the IC chip
    icNumber = "ADS1115"         # IC chip used
    I2C_BUS = 1                  # BUS number used by the IC chip
    # above constants are used with the ADS1115 IC chip:
    # [they could be defined as global variables in adcRead_init() instead]

    # These 2 constants must be defined in the test_adcRead.py program
    dT = 1                # sleep time between readings (set by the user of this program)
    nChannel = 2          # AINn is the analog pin # to read on the ADS1115 IC chip

    #                     # more than 1 channel can be read by the program 
    #                     # simply use adcRead(nChannel) where nChannel is the channel to read

    # usage of global variables
    # global g_adcValue

    # this variable can be referenced (seen) by any program using adcRead()
    # it always contains the most-recent-value read by adcRead()

    #create the BUS object

    BUS = adcReadInit(I2C_BUS,icNumber)
    BUS.open(I2C_BUS)

    while True :                            # loop
        value = adcRead(BUS,nChannel)           # reading nChannel of the ADS1115 once
        AINn="AIN"+str(nChannel)
        AINn=AINn.strip(" ")
        print ("value of "+AINn+" reading:", value)
        if dT==0 :
            break        #out of while loop # dT=0 will only read it once
        else:
            time.sleep(dT)                  # dT>0 will read it continuously
        #if end
    #while end
#end test_adcRead.py
/adcRead_pkg_v01.py

::::::::::textpak=>adcRead_pkg_v02.py.txt
#::::::::::textpak=>ADS1115Runner_wComments.txt
smartyPies.com
welcome projects misc imprint - legal - GDPR
ADS1115Runner.py
Mark&copy&paste the code into a file named "ADS1115Runner.py".
Thanks to the guys from GeSHi and Curt, who made me revise the code.

Created with GeSHi http://qbnz.com/highlighter/
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
'''
@author: guido lutterbach
@contact: guido@smartypies.com
@version: 1.1
@licence: Public Domain
 
This program implements 4 cases for ADS1115 on raspberry pi with default libraries.
1) single-shot - open drain - timed
2) single-shot - open drain - GPIO alert
3) continuous mode - differential - GPIO alert
4) continuous mode - differential - GPIO alert when value leaves high/low threshold range
Please check the electric circuit that goes with it at www.smartypies.com (ADS1115 project)
For testing 1) + 2) use potentiometer 1
For testing 3) + 4) use potentiometer 2
Enjoy!
'''
 
import cmd, time, logging, smbus, RPi.GPIO as GPIO
 
# ADS1115 + hardware constants
I2C_BUS = 1
DEVICE_ADDRESS = 0x4B
POINTER_CONVERSION = 0x0
POINTER_CONFIGURATION = 0x1
POINTER_LOW_THRESHOLD = 0x2
POINTER_HIGH_THRESHOLD = 0x3
 
RESET_ADDRESS = 0b0000000
RESET_COMMAND = 0b00000110
 
# Open I2C device
BUS = smbus.SMBus(I2C_BUS)
BUS.open(I2C_BUS)
 
ALERTPIN =  27
       
def swap2Bytes(c):
    '''Revert Byte order for Words (2 Bytes, 16 Bit).'''
    return (c>>8 |c<<8)&0xFFFF
 
def prepareLEconf(BEconf):
    '''Prepare LittleEndian Byte pattern from BigEndian configuration string, with separators.'''
    c = int(BEconf.replace('-',''), base=2)
    return swap2Bytes(c)
 
def LEtoBE(c):
    '''Little Endian to BigEndian conversion for signed 2Byte integers (2 complement).'''
    c = swap2Bytes(c)
    if(c >= 2**15):
        c= c-2**16
    return c
 
def BEtoLE(c):
    '''BigEndian to LittleEndian conversion for signed 2 Byte integers (2 complement).'''
    if(c < 0):
        c= 2**16 + c
    return swap2Bytes(c)
 
def resetChip():
    BUS.write_byte(RESET_ADDRESS, RESET_COMMAND)
    return
# Use BCM GPIO references
GPIO.setmode(GPIO.BCM)
GPIO.setup(ALERTPIN, GPIO.IN, pull_up_down=GPIO.PUD_UP) ## read mode, pull up resistor
 
 
class ADS1115Runner(cmd.Cmd):
    intro = '''usage: type following commands
          1    - one-shot measurement mode, timed
          2    - one-shot measurement mode, alerted through GPIO
          3    - continuous measurment mode, alerted through GPIO
          4  low high  - continuous mode, alerted when value out of range [low, high]
          q (quit)
          just hitting enter quits any mode 1-4. Enter 'y' to continue in modes 1 and 2.'''
    prompt = 'Enter 1,2,3,4 or q >>'
    file = None
 
#    __logfile = None
 
    def alerted(self, arg):        
        data_raw =  BUS.read_word_data(DEVICE_ADDRESS, POINTER_CONVERSION)
        print('alerted:' + str(LEtoBE(data_raw)))
        return
   
    def do_1(self, arg):
        '''One-shot, Read value from channel 0 with wait time'''
        resetChip()
       
        # compare with configuration settings from ADS115 datasheet
        # start single conversion - AIN2/GND - 4.096V - single shot - 8SPS - X
        # - X - X - disable comparator
        conf = prepareLEconf('1-110-001-1-000-0-0-0-11')
 
        go = 'y'
        while True and go in ['y','Y']:
            BUS.write_word_data(DEVICE_ADDRESS, POINTER_CONFIGURATION, conf)
            # long enough to be safe that data acquisition (conversion) has completed
            # may be calculated from data rate + some extra time for safety.
            # check accuracy in any case.
            time.sleep(0.2)
            value_raw = BUS.read_word_data(DEVICE_ADDRESS, POINTER_CONVERSION)
            value = LEtoBE(value_raw)
            print(value)
            #enter to break, repeat with 'y'
            go= input('continue: n/y')
            if (len(go)==0):
                go='n'
        return
   
    def do_2(self, arg):
        '''One-shot with GPIO alert'''
        # register callback for alerts
        GPIO.add_event_detect(ALERTPIN, GPIO.RISING, callback=self.alerted)
        # reset call
        resetChip()
        # compare with configuration settings from ADS115 datasheet:
        # start single conversion - AIN2/GND - 4.096V - single shot - 8SPS -
        # trad. comparator - active high - latching - assert after one conversion
        conf = prepareLEconf('1-110-001-1-000-0-1-1-00')
        BUS.write_byte(0b0000000,0b00000110) # reset call
        # set High and Low threshold for ALERT pin mode
        BUS.write_word_data(DEVICE_ADDRESS, POINTER_LOW_THRESHOLD, 0xFF7F) # 0x7FFF in BigEndian
        BUS.write_word_data(DEVICE_ADDRESS, POINTER_HIGH_THRESHOLD, 0x0080) # 0x8000 in BigEndian  
        go = 'y'
        while True and go in ['y','Y']:
            BUS.write_word_data(DEVICE_ADDRESS, POINTER_CONFIGURATION, conf)
            #enter to break, repeat with 'y'
            go= input('continue: n/y\n')
 
        # remove event listener
        GPIO.remove_event_detect(ALERTPIN)
        return
   
    def do_3(self, arg):
        '''Continuous mode with GPIO alert'''
        # register callback for alerts
        GPIO.add_event_detect(ALERTPIN, GPIO.RISING, callback=self.alerted)
        # reset call
        resetChip()
        # compare with configuration settings from ADS115 datasheet
        # X - AIN0/AIN1 - 2.048V - continuous mode - 64SPS -
        # window comparator - active high - nonlatching - assert after one conversion      
        conf = prepareLEconf('0-000-010-0-011-1-1-0-00')
        # set High and Low threshold for ALERT pin mode
        BUS.write_word_data(DEVICE_ADDRESS, POINTER_LOW_THRESHOLD, 0xFF7F) # 0x7FFF in BigEndian
        BUS.write_word_data(DEVICE_ADDRESS, POINTER_HIGH_THRESHOLD, 0x0080) # 0x8000 in BigEndian
        # write configuration ONCE
        BUS.write_word_data(DEVICE_ADDRESS, POINTER_CONFIGURATION, conf)
       
        # wait for input(), enter to break
        input('enter to stop\n' )
        # remove event listener to stop execution
        GPIO.remove_event_detect(ALERTPIN)
        return
   
    def do_4(self, arg):
        ''' Continuous measurements with latch and allowable data range'''
        largs = tuple(map(int, arg.split()))
        if len(largs) != 2:
            print('please call with exactly 2 integer arguments')
            return
        # reset call
        resetChip()
        # compare with configuration settings from ADS115 datasheet
        # X - AIN0/AIN1 - 2.048V - continuous mode - 8SPS -
        # window comparator - active high - latching - assert after one conversion      
        conf = prepareLEconf('0-000-010-0-000-1-1-1-00')
        # register callback for alerts
        GPIO.add_event_detect(ALERTPIN, GPIO.RISING, callback=self.alerted)
        # prepare for ALERT pin mode - define window
 
        low = min(largs) # Python BigEndian - RaspberryPi LittleEndian
        high = max(largs)
        low_val = BEtoLE(low)
        high_val = BEtoLE(high)
        logger.debug( "{:04X} {:04x} {:04x} {:04x} ".format(low, low_val, high, high_val))
        BUS.write_word_data(DEVICE_ADDRESS, POINTER_LOW_THRESHOLD, low_val)
        BUS.write_word_data(DEVICE_ADDRESS, POINTER_HIGH_THRESHOLD, high_val)
       
        # write configuration ONCE
        BUS.write_word_data(DEVICE_ADDRESS, POINTER_CONFIGURATION, conf)
       
        # wait for input(), enter to break
        input('enter to stop\n' )
        # remove event listener to stop execution
        GPIO.remove_event_detect(ALERTPIN)
        return
   
    def do_q(self, arg):
        '''Quit.'''
        return True
   
    def default(self, line):
        print('undefined key')
   
    def shutdown(self):
        GPIO.cleanup()
        BUS.close()
        pass    
 
if __name__ == "__main__":
    try:
        logging.basicConfig(
            level=logging.DEBUG,
            #format='%(name)-12s: %(levelname)-8s %(message)s')
            format='%(message)s')
        logger = logging.getLogger('ADS1115Runner')
        Runner = ADS1115Runner()
        Runner.cmdloop()
    finally:
        Runner.shutdown()
# © Copyright 2017-20 by Guido Lutterbach
# guido@smartypies.com
# / ADS1115Runner.p
#::::::::::textpak=>ADS1115Runner_pgmOnly.py
import cmd, time, logging, smbus, RPi.GPIO as GPIO
 
# ADS1115 + hardware constants
I2C_BUS = 1
#DEVICE_ADDRESS = 0x4B                      #DC
DEVICE_ADDRESS = 0x48                       #DC
POINTER_CONVERSION = 0x0
POINTER_CONFIGURATION = 0x1
POINTER_LOW_THRESHOLD = 0x2
POINTER_HIGH_THRESHOLD = 0x3
 
RESET_ADDRESS = 0b0000000
RESET_COMMAND = 0b00000110
 
# Open I2C device
BUS = smbus.SMBus(I2C_BUS)
BUS.open(I2C_BUS)
 
ALERTPIN =  27                #GPIO27       #DC
       
def swap2Bytes(c):
    '''Revert Byte order for Words (2 Bytes, 16 Bit).'''
    return (c>>8 |c<<8)&0xFFFF
 
def prepareLEconf(BEconf):
    '''Prepare LittleEndian Byte pattern from BigEndian configuration string, with separators.'''
    c = int(BEconf.replace('-',''), base=2)
    return swap2Bytes(c)
 
def LEtoBE(c):
    '''Little Endian to BigEndian conversion for signed 2Byte integers (2 complement).'''
    c = swap2Bytes(c)
    if(c >= 2**15):
        c= c-2**16
    return c
 
def BEtoLE(c):
    '''BigEndian to LittleEndian conversion for signed 2 Byte integers (2 complement).'''
    if(c < 0):
        c= 2**16 + c
    return swap2Bytes(c)
 
def resetChip():
    BUS.write_byte(RESET_ADDRESS, RESET_COMMAND)
    return
# Use BCM GPIO references
GPIO.setmode(GPIO.BCM)
GPIO.setup(ALERTPIN, GPIO.IN, pull_up_down=GPIO.PUD_UP) ## read mode, pull up resistor
 
 
class ADS1115Runner(cmd.Cmd):
    intro = '''usage: type following commands
          1    - one-shot measurement mode, timed
          2    - one-shot measurement mode, alerted through GPIO
          3    - continuous measurment mode, alerted through GPIO
          4  low high  - continuous mode, alerted when value out of range [low, high]
          q (quit)
          just hitting enter quits any mode 1-4. Enter 'y' to continue in modes 1 and 2.'''
    prompt = 'Enter 1,2,3,4 or q >>'
    file = None
 
#    __logfile = None
 
    def alerted(self, arg):        
        data_raw =  BUS.read_word_data(DEVICE_ADDRESS, POINTER_CONVERSION)
        print('alerted:' + str(LEtoBE(data_raw)))
        return
   
    def do_1(self, arg):
        '''One-shot, Read value from channel 0 with wait time'''
        resetChip()
       
        # compare with configuration settings from ADS115 datasheet
        # start single conversion - AIN2/GND - 4.096V - single shot - 8SPS - X
        # - X - X - disable comparator
        conf = prepareLEconf('1-110-001-1-000-0-0-0-11')
 
        go = 'y'
        while True and go in ['y','Y']:
            BUS.write_word_data(DEVICE_ADDRESS, POINTER_CONFIGURATION, conf)
            # long enough to be safe that data acquisition (conversion) has completed
            # may be calculated from data rate + some extra time for safety.
            # check accuracy in any case.
            time.sleep(0.2)
            value_raw = BUS.read_word_data(DEVICE_ADDRESS, POINTER_CONVERSION)
            value = LEtoBE(value_raw)
            print(value)
            #enter to break, repeat with 'y'
            go= input('continue: n/y')
            if (len(go)==0):
                go='n'
        return
   
    def do_2(self, arg):
        '''One-shot with GPIO alert'''
        # register callback for alerts
        GPIO.add_event_detect(ALERTPIN, GPIO.RISING, callback=self.alerted)
        # reset call
        resetChip()
        # compare with configuration settings from ADS115 datasheet:
        # start single conversion - AIN2/GND - 4.096V - single shot - 8SPS -
        # trad. comparator - active high - latching - assert after one conversion
        conf = prepareLEconf('1-110-001-1-000-0-1-1-00')
        BUS.write_byte(0b0000000,0b00000110) # reset call
        # set High and Low threshold for ALERT pin mode
        BUS.write_word_data(DEVICE_ADDRESS, POINTER_LOW_THRESHOLD, 0xFF7F) # 0x7FFF in BigEndian
        BUS.write_word_data(DEVICE_ADDRESS, POINTER_HIGH_THRESHOLD, 0x0080) # 0x8000 in BigEndian  
        go = 'y'
        while True and go in ['y','Y']:
            BUS.write_word_data(DEVICE_ADDRESS, POINTER_CONFIGURATION, conf)
            #enter to break, repeat with 'y'
            go= input('continue: n/y\n')
 
        # remove event listener
        GPIO.remove_event_detect(ALERTPIN)
        return
   
    def do_3(self, arg):
        '''Continuous mode with GPIO alert'''
        # register callback for alerts
        GPIO.add_event_detect(ALERTPIN, GPIO.RISING, callback=self.alerted)
        # reset call
        resetChip()
        # compare with configuration settings from ADS115 datasheet
        # X - AIN0/AIN1 - 2.048V - continuous mode - 64SPS -
        # window comparator - active high - nonlatching - assert after one conversion      
        conf = prepareLEconf('0-000-010-0-011-1-1-0-00')
        # set High and Low threshold for ALERT pin mode
        BUS.write_word_data(DEVICE_ADDRESS, POINTER_LOW_THRESHOLD, 0xFF7F) # 0x7FFF in BigEndian
        BUS.write_word_data(DEVICE_ADDRESS, POINTER_HIGH_THRESHOLD, 0x0080) # 0x8000 in BigEndian
        # write configuration ONCE
        BUS.write_word_data(DEVICE_ADDRESS, POINTER_CONFIGURATION, conf)
       
        # wait for input(), enter to break
        input('enter to stop\n' )
        # remove event listener to stop execution
        GPIO.remove_event_detect(ALERTPIN)
        return
   
    def do_4(self, arg):
        ''' Continuous measurements with latch and allowable data range'''
        largs = tuple(map(int, arg.split()))
        if len(largs) != 2:
            print('please call with exactly 2 integer arguments')
            return
        # reset call
        resetChip()
        # compare with configuration settings from ADS115 datasheet
        # X - AIN0/AIN1 - 2.048V - continuous mode - 8SPS -
        # window comparator - active high - latching - assert after one conversion      
        conf = prepareLEconf('0-000-010-0-000-1-1-1-00')
        # register callback for alerts
        GPIO.add_event_detect(ALERTPIN, GPIO.RISING, callback=self.alerted)
        # prepare for ALERT pin mode - define window
 
        low = min(largs) # Python BigEndian - RaspberryPi LittleEndian
        high = max(largs)
        low_val = BEtoLE(low)
        high_val = BEtoLE(high)
        logger.debug( "{:04X} {:04x} {:04x} {:04x} ".format(low, low_val, high, high_val))
        BUS.write_word_data(DEVICE_ADDRESS, POINTER_LOW_THRESHOLD, low_val)
        BUS.write_word_data(DEVICE_ADDRESS, POINTER_HIGH_THRESHOLD, high_val)
       
        # write configuration ONCE
        BUS.write_word_data(DEVICE_ADDRESS, POINTER_CONFIGURATION, conf)
       
        # wait for input(), enter to break
        input('enter to stop\n' )
        # remove event listener to stop execution
        GPIO.remove_event_detect(ALERTPIN)
        return
   
    def do_q(self, arg):
        '''Quit.'''
        return True
   
    def default(self, line):
        print('undefined key')
   
    def shutdown(self):
        GPIO.cleanup()
        BUS.close()
        pass    
 
if __name__ == "__main__":
    try:
        logging.basicConfig(
            level=logging.DEBUG,
            #format='%(name)-12s: %(levelname)-8s %(message)s')
            format='%(message)s')
        logger = logging.getLogger('ADS1115Runner')
        Runner = ADS1115Runner()
        Runner.cmdloop()
    finally:
        Runner.shutdown()
# © Copyright 2017-20 by Guido Lutterbach
# guido@smartypies.com
# / ADS1115Runner_pgmOnly.p
#::::::::::textpak=>adcRead_Pkg.py
# function Package adcRead_Pkg.py
import cmd, time, logging, smbus, RPi.GPIO as GPIO

#Source: https://smartypies.com/projects/ads1115-with-raspberrypi-and-python/ads1115runner/  #DC
#ADS1115 Datasheet: https://www.ti.com/lit/ds/symlink/ads1115.pdf?ts=1647366695082&ref_url=https%253A%252F%252Fwww.digchip.com%252F

#   Usage once:
#   define adcRead constants               # see the main program test_adcRead.py
#   BUS = adcReadInit(I2C_BUS,icNumber)    # create BUS class object
#   BUS.open(I2C_BUS)
#   . . . then repeatedly
#   value = adcRead(nChannel)              # read nChannel of the ADS1115 once
#   # no other functions need to be called
#   # the only externally callable functions are 
#         adcReadInit() 
#         adcRead()
#   # stop this program using ctrl+c       # how to stop the test    

def MUX(n):
    if n==0: m="00"
    if n==1: m="01"
    if n==2: m="10"
    if n==3: m="11"
    return m
#def end

def swap2Bytes(c):
    '''Revert Byte order for Words (2 Bytes, 16 Bit).'''
    return (c>>8 |c<<8)&0xFFFF
#def end
 
def prepareLEconf(BEconf):
    '''Prepare LittleEndian Byte pattern from BigEndian configuration string, with separators.'''
    c = int(BEconf.replace('-',''), base=2)
    return swap2Bytes(c)
#def end
 
def LEtoBE(c):
    '''Little Endian to BigEndian conversion for signed 2Byte integers (2 complement).'''
    c = swap2Bytes(c)
    if(c >= 2**15):
        c= c-2**16
    return c
#def end
 
def BEtoLE(c):
    '''BigEndian to LittleEndian conversion for signed 2 Byte integers (2 complement).'''
    if(c < 0):
        c= 2**16 + c
    return swap2Bytes(c)
#def end
 
def resetChip(RESET_ADDRESS, RESET_COMMAND):
    #BUS.write_byte(RESET_ADDRESS, RESET_COMMAND)
    return
#def end

class ADS1115Runner(cmd.Cmd):
    # this is the entry-point for  Runner.cmdloop() 
    # NB cmd.Cmd has been deprecated
    # cmd.Cmd will cause the self.cmdLoop() to return to the object's main method.
    # the ''' permits the definition of a string variable containing LFs
    #intro = '''usage: type following commands
    #     1    - one-shot measurement mode, timed
    #     2    - one-shot measurement mode, alerted through GPIO
    #     3    - continuous measurment mode, alerted through GPIO
    #     4  low high  - continuous mode, alerted when value out of range [low, high]
    #     q (quit)
    #     just hitting enter quits any mode 1-4. Enter 'y' to continue in modes 1 and 2.'''
    #prompt = 'Enter 1,2,3,4 or q >>'
    # if you enter 1 it will run do_1(), 2 . . . do_2() etc
    file = None
 
    __logfile = None
 
    def alerted(self, arg):  
        # deprecated      
        data_raw =  BUS.read_word_data(DEVICE_ADDRESS, POINTER_CONVERSION)
        print('alerted:' + str(LEtoBE(data_raw)))
        return
    #def end  alerted()
   
    def do_q(self, arg):
        exit
    #def end do_q()

    def mydo_1(self,BUS,AINn):
        RESET_ADDRESS = 0b0000000
        RESET_COMMAND = 0b00000110
        POINTER_CONVERSION = 0x0
        POINTER_CONFIGURATION  = 0x1
        POINTER_LOW_THRESHOLD  = 0x2
        POINTER_HIGH_THRESHOLD = 0x3
        DEVICE_ADDRESS = 0x48        # device address selected on the IC chip
        # replaces do_1 routine
        #print("into do_1 arg:",arg)
        #print("into do_1")
        '''One-shot, Read value from channel AINn with wait time'''
        #resetChip(RESET_ADDRESS, RESET_COMMAND)      #deprecated
        BUS.write_byte(RESET_ADDRESS, RESET_COMMAND)  #replace
       
        # compare with configuration settings from ADS1115 datasheet           #DC
        # start single conversion - AIN2/GND - 4.096V - single shot - 8SPS - X
        # - X - X - disable comparator
        # conf = prepareLEconf('1-110-001-1-000-0-0-0-11')                     #DC
        # AINn = 2 arg1 is AINn the nChannel to read
        ADSn = MUX(AINn)         #e.g. AINn=2 read AIN2  ( AIN2 to GND*)       #DC
        conf = prepareLEconf('1-1'+ADSn+'-001-1-000-0-0-0-11')                 #DC
        go = 'y'
        #while True and go in ['y','Y']:
        if True :           #only do this once
            BUS.write_word_data(DEVICE_ADDRESS, POINTER_CONFIGURATION, conf)
            # long enough to be safe that data acquisition (conversion) has completed
            # may be calculated from data rate + some extra time for safety.
            # check accuracy in any case.
            time.sleep(0.2)
            value_raw = BUS.read_word_data(DEVICE_ADDRESS, POINTER_CONVERSION)
            value = LEtoBE(value_raw)

            #print("mid do_1")

            global g_adcValue
            g_adcValue = value        # so adcRead() can see it

            #print(value)          # test_adcRead() will print it
            #enter to break, repeat with 'y'
            if False :             # deprecated
                go= input('continue: n/y')
                if (len(go)==0):
                    go='n'
            #time.sleep(sleepTime)
        #if end
        return value
    #def end mydo_1()

    def shutdown(self):
        #GPIO.cleanup()
        #BUS.close()
        pass 
    #def end shutdown()

#class end ADS1115Runner()

def adcRead(BUS,nChannel=0) :
    # nChannel is the number of the analog input to read i.e. 0 = AIN0

    # adcRead returns value 0 to ~11000 as the actual reading

    #by D@CC on 202CMar16 DC

    #must be preceded by 
    #    BUS.adcReadInit(I2C_BUS,icNumber)
    #    BUS.open(I2C_BUS)

    #Source: https://smartypies.com/projects/ads1115-with-raspberrypi-and-python/ads1115runner/  #DC
    #ADS1115 Datasheet: https://www.ti.com/lit/ds/symlink/ads1115.pdf?ts=1647366695082&ref_url=https%253A%252F%252Fwww.digchip.com%252F

    #Jumper S of KY-18 photo-cell to AIN2
    # invert the KY-18 3v3 and GND to measure the opposite [ light (not dark) ]
    # terminal strip is L-R  on the ADS1115 for RPi from SeeedStudios
    #  3V3,AIN3,AIN2,AIN1,AIN0,GND
    # Uses 3 objects:BUS.write_byte(RESET_ADDRESS, RESET_COMMAND)  #replace
    #   Runner.      for ADS1115 ADC
    #   BUS.         for ADS11#Jumper S of KY-18 photo-cell to AIN2  #DC

    #   GPIO.        for ALERTPIN  class is not used  #DC

    try:
        # I (D@CC) do not know anything about the logging
        logging.basicConfig(
            level=logging.DEBUG,
            #format='%(name)-12s: %(levelname)-8s %(message)s')
            format='%(message)s')
        logger = logging.getLogger('ADS1115Runner')
        #print("logger:",logger)
        #AINn=2                          # AINn=2 to read AIN2
        Runner = ADS1115Runner()    # create object Runner
        #print("before .cmdloop")
        Runner.mydo_1(BUS,nChannel)     # nChannel is 2 to read AIN2
        #Runner.cmdloop()            # will run the main Runner.method (cmd.Cmd)
                                    # which prompts for a response & invokes do_r(arg)
                                    # for a response of "r arg"
        #print("after .cmdloop")
  
        global g_adcValue
        returnValue = g_adcValue     # from mydo_1
        return returnValue  
    finally:
        Runner.shutdown()               #release this object
        #BUS.close()                     #release this object
#if end adcRead()

def adcReadInit(I2C_BUS=1,icNumber="ADS1115") :
    # arg1 is the BUS number used by the IC chip
    # arg2 is the number of the IC chip used on the Seeed ADS1115 4 channel RPi board
    # usage of global variables
    # global g_adcValue

    if icNumber=="ADS1115" :
        BUS=smbus.SMBus(I2C_BUS)
        #returns the BUS object , (usually BUS=smbus.SMBus(I2C_BUS) )
        # Open I2C device
        # I2C_BUS = 1
        # DEVICE_ADDRESS = 0x48

        return BUS
    else:
        print('ERROR025: ic supported is "ADS1115"')
        exit
#def end adcReadInit()

#   9 constants included in adcRead_Pkg.py
    RESET_ADDRESS = 0b0000000
    RESET_COMMAND = 0b00000110
    POINTER_CONVERSION = 0x0
    POINTER_CONFIGURATION  = 0x1
    POINTER_LOW_THRESHOLD  = 0x2
    POINTER_HIGH_THRESHOLD = 0x3
    DEVICE_ADDRESS = 0x48        # device address selected on the IC chip
    icNumber = "ADS1115"         # IC chip used
    I2C_BUS = 1                  # BUS number used by the IC chip

# end of adcRead_pkg.p
#::::::::::textpak=>test_adcRead.py
# test_adcRead.py   
# program to test adcRead() to read nChannel on the ADS1115 ADC RPi module from SeeedStuios
# by D@CC on 2022CMar16

# needs to have adcRead_Pkg.py in the same folder as test_adcRead.py
# needs import time
import time
# needs from adcRead_Pkg import adcRead,adcReadInit
from adcRead_Pkg import adcRead,adcReadInit

#needs to be run as >$ python3 test_adcRead.py


if __name__ == "__main__":
    # import adcRead_pkg.py      # is needed

    progName="test_adcRead.py"     #this is the main program to test adcRead()
    print("starting:"+progName)

    # These 9 parameters are also defined in 
    #    adcRead_pkg.py:
    #    mydo_1()
    RESET_ADDRESS = 0b0000000
    RESET_COMMAND = 0b00000110
    POINTER_CONVERSION = 0x0
    POINTER_CONFIGURATION  = 0x1
    POINTER_LOW_THRESHOLD  = 0x2
    POINTER_HIGH_THRESHOLD = 0x3
    DEVICE_ADDRESS = 0x48        # device address selected on the IC chip
    icNumber = "ADS1115"         # IC chip used
    I2C_BUS = 1                  # BUS number used by the IC chip
    # above constants are used with the ADS1115 IC chip:
    # [they could be defined as global variables in adcRead_init() instead]

    # These 2 constants must be defined in the test_adcRead.py program
    dT = 1                # sleep time between readings (set by the user of this program)
    nChannel = 2          # AINn is the analog pin # to read on the ADS1115 IC chip

    #                     # more than 1 channel can be read by the program 
    #                     # simply use adcRead(nChannel) where nChannel is the channel to read

    # usage of global variables
    # global g_adcValue

    # this variable can be referenced (seen) by any program using adcRead()
    # it always contains the most-recent-value read by adcRead()

    #create the BUS object

    BUS = adcReadInit(I2C_BUS,icNumber)
    BUS.open(I2C_BUS)

    while True :                            # loop
        value = adcRead(BUS,nChannel)           # reading nChannel of the ADS1115 once
        AINn="AIN"+str(nChannel)
        AINn=AINn.strip(" ")
        print ("value of "+AINn+" reading:", value)
        if dT==0 :
            break        #out of while loop # dT=0 will only read it once
        else:
            time.sleep(dT)                  # dT>0 will read it continuously
        #if end
    #while end
#end test_adcRead.p

::::::::::textpak=>adcValue.py.txt
*************************
adcValue.py
*************************
Date: 2022FJun10
adcValue variable is used in vMeterIXA_pico.py
to read the voltage
also used:
RAPasc()
readADC_pico(nn,cnvrt=5.035477e-05):

 stored in Raspberry Pi Pico & pi/pico_4f31_on_Fla53

also see readADC_pico.py  in 164.html

also see g_adcValue in 174.html
also see  n.py -a < adcRead_pkg.py

# 1 m adcRead_pkg.py
# 9  import cmd, time, logging, smbus, RPi.GPIO as GPIO
# 11   #Source: https://smartypies.com/projects/ads1115-with-raspberrypi-and-python/ads1115runner/  #DC
# 16   #   BUS = adcReadInit(I2C_BUS,icNumber)    # create BUS class object
# 26   def MUX(n):
# 34   def swap2Bytes(c):
# 39   def prepareLEconf(BEconf):
# 45   def LEtoBE(c):
# 53   def BEtoLE(c):
# 60   def resetChip(RESET_ADDRESS, RESET_COMMAND):
# 65   class ADS1115Runner(cmd.Cmd):
# 83       def alerted(self, arg):  
# 90       def do_q(self, arg):
# 94       def mydo_1(self,BUS,AINn):
# 129               global g_adcValue
# 143       def shutdown(self):
# 149   #class end ADS1115Runner()
# 151   def adcRead(BUS,nChannel=0) :
# 162       #Source: https://smartypies.com/projects/ads1115-with-raspberrypi-and-python/ads1115runner/  #DC
# 173       #   GPIO.        for ALERTPIN  class is not used  #DC
# 192           global g_adcValue
# 200   def adcReadInit(I2C_BUS=1,icNumber="ADS1115") :
# 203       # usage of global variables
# 204       # global g_adcValue
*************************
/adcValue.py.txt
::::::::::textpak=>ambLight_v00.py.txt
def ambLight(a,b,c):
    # Purpose: returns ambient light (measured by adc)
    #line 1
    #line 2
    return a*0
#def end
/ambLight_v00.py
::::::::::textpak=>ambLight_v01.py.txt
def ambLight(a,b,c):
    # Purpose: returns ambient light (measured by adc)
    #line 1
    #line 2
    return a*1
#def end
/ambLight_v01.py
::::::::::textpak=>ambLightB_v00.py.txt
def ambLightB(a,b,c):
    # Purpose: returns ambient light (measured by adc)
    #line 1
    #line 2
    return a*0+b
#def end
/ambLightB_v00.py
::::::::::textpak=>ambLightB_v01.py.txt
def ambLightB(a,b,c):
    # Purpose: returns ambient light (measured by adc)
    #line 1
    #line 2
    return a*1+b
#def end
/ambLightB_v01.py
::::::::::textpak=>ambLightB_v02.py.txt
def ambLightB(a,b,c):
    # Purpose: returns ambient light (measured by adc)
    #line 1
    #line 2
    return a*1+b
#def end
/ambLightB_v01.py
::::::::::textpak=>bChar_py.py.txt
def bChar(strB):
    #  given a string like b'z' this returns the "z"
    # tested by D@CC on 2021FJun15
    
    #strB=input("eg b'h' :")
    b=strB[2:]
    print("b:"+b)
    c=b[0]
    #c="zz"
    print("bChar("+'"'+strB+ '"):'+c)
    return c
#end def

while True:
    print(bChar(input("eg b'h' :")))
#end while
::::::::::textpak=>buttonAction_pico.py.txt
# IX_libr_pico.py

# This example works with Maker Pi Pico
# buttonAction()
# returns True when button Action is down i.e. pressed within 10 seconds
#    else returns False.

#imports for buttonAction
import machine
import utime

def buttonAction(gPnn,withinTime):

    if gPnn <0 or gPnn>25:
        print("Error in buttonAction: pin # is out of range")
        return
    #end if
    if withinTime <0 or withinTime>180:
        print("Error in buttonAction: withinTime is out of range")
        return
    #end if
    button = machine.Pin(gPnn, machine.Pin.IN)
    t0=utime.time()
    #print("t0:",t0)
    tDelta=0
    isDown=False
    while tDelta<withinTime:
        state=button.value()
        #print("button (active low) state:",state)
        tNow=utime.time()
        tDelta=tNow-t0
        #print("at:",tDelta,"button",gPnn, "is ", state)
        utime.sleep(0.5)
        if state==0:
            isDown=True
            break                 # out of loop
        #end if
    #end while
    return isDown #returns a Boolean result
#end def #buttonAction_pico.py
# by David at ColeCanada.com
# on 2021EMay25
#source: na
#end program IX_libr_pico.py

GPnn=22
tSecs=10
print("Press button GP"+str(GPnn),"within",tSecs,"secs")
isDown=buttonAction(GPnn,tSecs)
if isDown==None:
    print("Error: Aborted Execution")
else:
    print("buttonAction is",isDown)
#end if
#testButton_pico.py
::::::::::textpak=>deviceReset_pico.py.txt
# This example uses Maker Pi Pico
import machine
import utime
from machine import Pin

#by PicoLe-22
#on 2021EMay24
progName="deviceReset_pico.py"
print(progName)

print("Reset: program blinks leds 0- 25 on, then off")
print("       then sets every pin as input")
for GPnn in range(0,26):  #except 26
    ledPin = machine.Pin(GPnn, machine.Pin.OUT)
    ledPin.value(1)
    utime.sleep(.2)
    ledPin.value(0)
    ledPin = machine.Pin(GPnn, machine.Pin.IN)
#end for
print("after setting GP25 as IN")
for GPnn in range(26,30):  #except 31
    print("GP",GPnn," setting to IN")
    ledPin = machine.Pin(GPnn, machine.Pin.IN)
#end for
print(" Now GP20,21,22 LEDs all ON, ADC0(GP26) might be ON")
# deviceReset_pico.py
# source: none
# date: 2021EMay24

::::::::::textpak=>f3.py.txt
# f3()  formats as f999999.999 where f means float (See endnotes)
# MicroPython doesn't process complex numbers
import re    # to check for regular expressions in a string
def f3(x):
    isDone=False
    xFloat=3.14159
    xType="q"
    xReturn=""
    #print("into f3 xReturn:"+xReturn)
    # process a string
    #if isinstance(x,(float,int,str,list,dict,tuple)):
    
    if isinstance(x,(float,int,str)):
        if isinstance(x,str):
            if x.endswith("jJ"):
                isJend=True
            else:
                isJend=False
            #print("isJend:",isJend)
            #if(x.endswith("j)") or (x.endswith("J)"):
            #if((x.endswith("j")) or ((x.endswith("J")):
            if isJend:
                #almost complex but without the "(" and ")"
                xReturn="c" + "("+c+")"
                xType="c"
                isDone=True
            else:
                #not complex
                try:
                    xFloat=float(x)
                    xType="f"
                    isDone=True
                except:
                    xReturn="s"+x
                    isDone=True
                #end try
            #end if
        # process an integer value
        elif isinstance(x,int):
            xFloat=float(x)
            xType="i"
            isDone=True
        # process a float value
        elif isinstance(x,float):
            xFloat=x
            xType="f"
            isDone=True
        #end if instances of int,float,str,
    else:   #presume boolean
        if(bool(x)==1):
            xFloat=float(1)
            xType="b"
            isDone=True
        #end if
        if(bool(x)==0):
            xFloat=float(0)
            xType="b"
            isDone=True
        #end if
        #end of bool processing
    #end if    
    
    
    
  
    
    #process unknown type
    
    if isDone==False:
        #nothing was recognized
        xReturn="u??????.???"
    else:
        if xReturn=="":
            #create something to return
            xReturn=xType + str(xFloat)
        else:
            #something was created to be returned
            #doh="doh"
            pass
        #end if
    #end if

    #print("xReturn:"+xReturn)
    return xReturn
#end def
#returns in format f6.3 preceeded by a type character
#   "b     1.000"
#   "???????.???"
#   "s      .   "
#   "r    99.00 "
# f3(x)
#           test_f3.py
print("progName:test_f3.py")
print("Click in run window below, then:")
while True:
    strIn=input("input a number:")
    print("strIn:",strIn,f3(strIn))
#end while
#/f3.py.txt
::::::::::textpak=>f3_pyD.py.txt
# pi_IX_function_library (piIX_libr.py)
# by D@CC on 2021BFeb12 
# ver f3_pyD uses isDone() not isNotDone()
#
# f3(x)	converts the numerical variable to a f6.3 string
#for printing. Note: decimal points should ALL line up
# resolution of int, float are limited by device & Python vsn
#  by D@CC 2021EMay31 (c)ich180r2
#
# f"abc{floatA}." works in 3.7 but not yet in MicroPython
# print(("hi {floatA} bye"))
# strLine="hi %a. bye" % (floatA)
#python function l
def f3(x):
# prepares to print all numbers using format "-99999.999"  i.e. 6f3
# accepts types:int,str,float,complex,bool
# requires strToComplex(xStr)
# inspiration is to not print out more than 3 digits to the right of the decimal point
# returns S999999.999 after chopping off extra left and extra right digits
# stored in pi_IX_library.py   IX means "DC" if you connect the top & bottom serifs of the font letters
# errors appear as "??????.???" or ">999999.999" or "<-999999.999"
# by D@CC on 2021BFeb12 (c) ich180r2

    print("debug: starting f3",x)
    isError= False
    isDone=True
    floatX=x
    strFloatX=str(floatX)
#    #strFloat= f"abc{floatA}." works in 3.7 but not in MicroPython
    print(" cb means {  c means , P means pc sign")
    print("f 1. strFloatX:",strFloatX," bye")
    print(("  2. cb floatX cb bye"))
    strFloat="hi %s. bye" % (floatX)
    print("    strFloat= q hi pc s. bye q pc (floatX)")
    print("P 3. strFloat: c strFloat c  bye")
    pyVer="MPg" #MicroPython generic" code C testing
    #pyVer="Py3" #Python version 3 code B works
    
    #returns complex numbers as type "u" for sample & time
    # where "u" means u16 x1000
    # Note u12 with 4 bits of 0 on right = u16
    # u16 can even have more digits to the left
    # type "u" is compatible with Pico ADC raw readings
    # even allowing for more precision in the future.
    # To get Pico ADC reading; divide "u" value by 16000
    # i.e. lowest non-zero Pico ADC reading is 16000 in "u"
    # which converts to the actual ADC reading of "1"
    # this will work with future "16 bit" ADC on any device
    # & allowing more bits to the right of the decimal pnt.
    # 
    #test complex
    if type(x)=="complex" :
        xUse=x
        isDone=True
    #end if

    xInt=int(x)
    print("at error, xInt:",xInt)
    if  (abs(xInt)>999999) :
        isError=True
        str_floatX = ">999999.999"
        #print("line  27: strFloatX",strFloatX)
    else:
        #print("xInt:",xInt)
        floatX = 1.0 * xInt
        #strFloatX=f'{floatX:.3f}'
        #if pyVer=="Py3":strFloatX=f"{floatX:.3f}"
        if pyVer=="MPg":strFloatX="%s" % floatX 
        print("line  54: strFloatX",strFloatX)
    #end if
    isDone=True
    
    #fix too big but negative
    if  (abs(xInt)>999999) :
        isError=True
        str_floatX="<-999999.999"
    else:
        floatX= 1.0*xInt
        #if pyVer="Py3": strFloatX=f'{floatX:.3f}'
        if pyVer=="MPg": strFloat="%s" % floatX
    #end if
    isDone=True
    
    #float, str and int
    print("at 85: before xUse=0")
    xUse=x    #to define it
    print("type(x),x is",type(x),"=",x)
    
    # check if Float
    if (isDone==False):
        print("76: check if Float")
        isFloat=False
        isFloat=isinstance(x,float)
        #strType=type(x)
        print("isFloat?",isFloat)
        if (isFloat):
            print("82: x is type float")
            print("before xUse=x")
            xUse=x
        elif (type(x)=="str") :
            print("86 x is type str")
            print("should call strToComplex here")
            #xUse=parseFloat(x)
            xUse=float(x)
            print("str")
        elif (type(x)=="int") :
            print("92: x is type int")
            xUse=1.0*x
            print("int")
        #end if
        
        # fix magnitude of xUse
        print("xUse:",xUse)
        print("x type is known, test magnitude of xUse which is x")
        absX=abs(xUse)
        print("absX:",absX)
        if (abs(xUse)>999999.) and (xUse>0) :
            print("103: too big")
            isError=True
            str_floatX="> 999999.000"
        else:
            floatX= 1.0*xUse
            strFloatX=str(floatX)
        print("strFloatX:",strFloatX)
        
        #test too low and negative
        isDone=False
        if  (abs(xUse)>999999) and (xUse<0.) :
            isError=True
            str_floatX="<-999999.000"
        else:
            floatX= 1.0*xUse
            isDone=True
        #isDone=True
    #if end
    str_floatX=str(floatX)
    print("str_floatX:",str_floatX)
    
    
    #print("test bool")
    #bool
    #str_floatX=str(1.) # assign it
    print("isDone:",isDone)
    if (isDone==False) :
        print("check if bool")
        if(x==True): str_floatX="b    1.000"
        else: str_floatX="b    0.000"
        isDone=True
    else:
        print("not bool")
    #if end
    # final error and finish the function
    if (isDone==False): str_floatX="??????.???" #output that indicates an error (bad type)
    #if end
    print("debug: f3 of floatX: returning",str_floatX)
    return str_floatX
#end def f3
#end f3
#/f3_py.txt
print("start of test_f3.py")
while True:
    print("click into the 'execution window' below, then:")
    inNumb=input("type in something")
    print("inStr:",inNumb)
    oTxt=str(f3(inNumb))
    print("in f3 format:",inNumb)
#end while
#source:https://realpython.com/python-f-strings/
# test_f3_pyD.py
::::::::::textpak=>f3_v00.py.txt
# f3()  formats as f999999.999 where f means float (See endnotes)
# MicroPython doesn't process complex numbers
# described in 155.html
import re    # to check for regular expressions in a string
def f3(x):
    isDone=False
    xFloat=3.14159
    xType="q"
    xReturn=""
    #print("into f3 xReturn:"+xReturn)
    # process a string
    #if isinstance(x,(float,int,str,list,dict,tuple)):
    
    if isinstance(x,(float,int,str)):
        if isinstance(x,str):
            if x.endswith("jJ"):
                isJend=True
            else:
                isJend=False
            #print("isJend:",isJend)
            #if(x.endswith("j)") or (x.endswith("J)"):
            #if((x.endswith("j")) or ((x.endswith("J")):
            if isJend:
                #almost complex but without the "(" and ")"
                xReturn="c" + "("+c+")"
                xType="c"
                isDone=True
            else:
                #not complex
                try:
                    xFloat=float(x)
                    xType="f"
                    isDone=True
                except:
                    xReturn="s"+x
                    isDone=True
                #end try
            #end if
        # process an integer value
        elif isinstance(x,int):
            xFloat=float(x)
            xType="i"
            isDone=True
        # process a float value
        elif isinstance(x,float):
            xFloat=x
            xType="f"
            isDone=True
        #end if instances of int,float,str,
    else:   #presume boolean
        if(bool(x)==1):
            xFloat=float(1)
            xType="b"
            isDone=True
        #end if
        if(bool(x)==0):
            xFloat=float(0)
            xType="b"
            isDone=True
        #end if
        #end of bool processing
    #end if    
    
   
    #process unknown type
    
    if isDone==False:
        #nothing was recognized
        xReturn="u??????.???"
    else:
        if xReturn=="":
            #create something to return
            xReturn=xType + str(xFloat)
        else:
            #something was created to be returned
            #doh="doh"
            pass
        #end if
    #end if

    #print("xReturn:"+xReturn)
    return xReturn
#end def f3
#/f3_v00.py.txt
::::::::::textpak=>fadeLed_pico.py.txt
# Example of using PIO for PWM, and fading the brightness of an LED

from machine import Pin
from rp2 import PIO, StateMachine, asm_pio
from time import sleep

progName="fadeLed_pico.py"
print(progName)
#first example of PIO code

@asm_pio(sideset_init=PIO.OUT_LOW)
def pwm_prog():
    pull(noblock) .side(0)
    mov(x, osr) # Keep most recent pull data stashed in X, for recycling by noblock
    mov(y, isr) # ISR must be preloaded with PWM count max
    label("pwmloop")
    jmp(x_not_y, "skip")
    nop()         .side(1)
    label("skip")
    jmp(y_dec, "pwmloop")


class PIOPWM:
    def __init__(self, sm_id, pin, max_count, count_freq):
        self._sm = StateMachine(sm_id, pwm_prog, freq=2 * count_freq, sideset_base=Pin(pin))
        # Use exec() to load max count into ISR
        self._sm.put(max_count)
        self._sm.exec("pull()")
        self._sm.exec("mov(isr, osr)")
        self._sm.active(1)
        self._max_count = max_count

    def set(self, value):
        # Minimum value is -1 (completely turn off), 0 actually still produces narrow pulse
        value = max(value, -1)
        value = min(value, self._max_count)
        self._sm.put(value)


# Pin 25 is LED on Pico boards
pwm = PIOPWM(0, 25, max_count=(1 << 16) - 1, count_freq=10_000_000)

while True:
    for i in range(256):
        pwm.set(i ** 2)
        sleep(0.01)
#end program  #class PIOPWM pio_dac.py  mod by William
::::::::::textpak=>functionList_pkg.py.txt
# ToC of functionList_pkg.py
#  by D@CC on 2022CMar28   Use cmd -md to create ToC, suffix . to defs 
# 30 m posNxFnUsed.py
# 32   def. posNxFnUsed(inStr,posIn0) :
# 35   def. posNxFnUsed_v1(inStr,posIn0,v="v03") :
# 128 m functionList.py
# 129   def. functionList(testStr) :
# 132   def. functionList_v1(testStr) :
# 196 m posNxFnUsed.py
# 199   def. posNxFnUsed(inStr,posIn0) :
# 202   def. posNxFnUsed_v2(inStr,posIn0) :
# 342 m posNxFnUsed_test.py
# 343   def. t2() :
# 425 m functionList.py
# 427   def. functionList(testStr="#:::",v="v02") :
# 431   def. functionList_v02(testStr,v) :
# 474 m functionList_test.py
# 475   def. mainroutine() :
# 504 m posNxFnUsed.py
# 506   def. posNxFnUsed(inStr,posIn0,v=3) :
# 510   def. posNxFnUsed_v3(inStr,posIn0,v) :
# 616 m t03.py
# 617   def. mainroutine() :
# 669 m t16.py
# 683   def. mainroutine() :
# 702 eof

#::: end of list by n.py v03

#::::::::::textpak=>posNxFnUsed.py

def posNxFnUsed(inStr,posIn0) :
    return posNxFnUsed_v1(inStr,posIn0)

def posNxFnUsed_v1(inStr,posIn0,v="v03") :

    # by D@CC on 2022CMar15

    print("posNxFnUsed_v02 on line 24 in ...._pkg.py")

    # beginning of def. posNxFnUsed() definition
    import re
    #print("into posNFU")
    #print("posIn0:",posIn0)

    # globals: uses globals List, bList
    # import re
    # parameters
    # arg1: statement to be anayzed
    # arg2: position of previous function name -1 (or 0 to initialize)

    # find the pos of the first char ( less 1) of the next function used in the inStr
    # returns the pos of the next function name (less 1) in the inStr statement
    # WARNING: does NOT find any function name beginning in first char of the statement
    # FIX:     call it by preceding the statement with a space.

    # start searching at position
    # e.g. -3*(4+var+3.40+st2r4(27))+p2hi(35+a)+12b()  should return 15 pos of "str4("
    #      012345678901234567890123
    #      +0+(0+$$$+0+00+$$0$0(
    #                           00+++$0$$(00+$++00$(+
    #         (          +$$0$0(    +$0$$(         (
    #  valid regular pattern is "+$" any "0"  ????????????????

    # globals: uses globals List, bList
    # import re
    #
    if posIn0==0 :
        v1Patt="[_a-zA-Z]"       #"!" # valid first letter of a variable
        v2Patt="[_a-zA-Z0-9]"    #"0" # valid subseq. letter of a variable
        vxPatt="[^_a-zA-Z0-9(!]" #";" # invalid char. of a function name incl. "("
        #       the above vxPatt"-3*(4+var+3.40+st2r4(27))+p2hi(35+a)+12b()-a()"       # matches all char except those listed, I think
        vFPatt=";\$[0\$]\("    #print("                           ;!!0!0(    ;!0!!(           ;!( ")
        
        #print("inStr  :  "+inStr)
        pattStr=inStr    
        pattStr=re.sub(v1Patt,"!",pattStr)
        #print("pattStr:  "+pattStr)
        pattStr=re.sub(v2Patt,"0",pattStr)
        #print("pattStr:  "+pattStr)
        pattStr=re.sub(vxPatt,";",pattStr)
        #print("pattStr:  "+pattStr)

        #print("             -3*(4+var+3.40+st2r4(27))+p2hi(35+a)+12b()-a()")
        #print("                        ;!!0!0(    ;!0!!(           ;!( ")

        #print("             0123456789012345678901234567890123456789012345")
        #print("                       1         2         3         4")
        findPatt=";!{1}[!0]*\("  # find +$s  where s is any number of 0 or $ followed by (
        iter=re.finditer(findPatt,pattStr)
        global List
        List=[m.start(0) for m in iter]
        #print("List: ", List)
        global bList
        bList=[]
    #if end
    #print("b4 List")
    #print("List:",List)
    for n in List :
        #print("n:",n)
        item=testStr[n:].find("(") + n
        bList.append( item )
        #for end
        #print("bList:",bList)
        #print("posIn0:",posIn0)
        #  OK to here
    #for end                  --------------------------------
    for n in List :
        #print("n:",n)
        thisPos=n
        if posIn0==0:
            return thisPos   #returns and re-enters here
        else:
            if thisPos>posIn0:
                return thisPos
            else:
                continueDoh=True
                #keep looping
            #if end
        #if end
    #for end
    thisPos=-1
    #print("thisPos:",thisPos)
    return thisPos
#end def posNxFnUsed_v2
#                              #######################################

#::::::::::textpak=>functionList.py
def functionList(testStr) :
    return functionList_v1(testStr)

def functionList_v1(testStr) :
    # by D@CC on 2022CMar14

    # beginning of def. functionList.py definition in posNxFnUsed_test.py

    print("functionList on line 119 in ...._pkg.py")

    # or "$" "("  which is '+$[0$](' 
    # Use List=re.findall("+$[0functionList_test.py
    # Use List=re.search("+$[0$](", pattStr).start()
    #   will search for each matching pattern in the pattStr
    #     and return a list of the def. posNxFnUsed starting positions
    #procedure

    # replace "_a-ZA-Z0-9" with "0" where "0" is in "_a-ZA-Z0-9" ie valid subseq char equiv
    # replace "_a-ZA-Z" with "_"  wher  e "_" is in "_a-ZA-Z"    ie valid first char equiv
    # L-R find pos of first "0(""-3*(4+var+3.40+st2r4(27))+p2hi(35+a)+12b()-a()"
    # discard all to the right of "("
    # R-L find pos of first "_"
    # discard all to the left of "_"
    # fin what remains (it begins with a "_" first char equiv and ends with a "("
    # return the pos of what is found

    # beginning of def. functionList() definition

    # returns the next function name in an iteration list
    # of function calls in the given statment in arg1: testStr
    # calls posNxFnUsed()
    functionList=[]
    nPos=0

    many0s="000000000000000000000000000000"
    while nPos>=0 :
        #print("in main while")
        v="unknown"
        nex = posNxFnUsed(testStr, nPos,v)
        nextPos=int(nex)             #convert list element to string
        #print("in main af nextPos:",nextPos)
        if nextPos==-1 :
            # no more fNames found
            continueDoh=True
            break   #out of while loop
        else :
            textStr=testStr[0:]
            #print("textStr:  "+textStr)
            #textStr=testStr[0:]
            #print("textStr:  "+textStr)
            #print("          0123456789012345678901234567890123456789012345")
            nextFnPos =nextPos
            # ok   to here                          --------------------------
            #print("nextFnPos: ",nextFnPos)
            nextParPos = testStr[nextFnPos:].find("(")+nextFnPos
            #print("nextParPos: posNxFnUsed_test.py",nextParPos)
            fName=testStr[nextFnPos+1:nextParPos]
            functionList.append(fName)
            #print("fName:"+fName)
            nPos= nextParPos
            yield(fName)
        #if end
        #keep looping
    #while end
#def end functionList_v1
#                                          ###########################################

#::::::::::textpak=>posNxFnUsed.py
# originally was included in posNxFnUsed_test.py

def posNxFnUsed(inStr,posIn0) :
    return posNxFnUsed_v2(inStr,posIn0)

def posNxFnUsed_v2(inStr,posIn0) :

    import re

    print("posNxFnUsed_v2 on line 179 in ...._pkg.py")

    # by D@CC on 2022CMar15
    # find the pos of the first char of the next function used in the inStr
    # start searching at position
    # e.g. -3*(4+var+3.40+st2r4(27))+p2hi(35+a)+12b()  should return 15 pos of "str4("
    #      012345678901234567890123
    #      +0+(0+$$$+0+00+$$0$0(
    #                           00+++$0$$(00+$++00$(+
    #         (          +$$0$0(    +$0$$(         (
    #  valid regular pattern is "+$" any "0"  ????????????????
    v1Patt="[_a-zA-Z]"       #"$" # valid first letter of a variable
    v2Patt="[_a-zA-Z0-9]"    #"0" # valid subseq. letter of a variable
    vxPatt="[^_a-zA-Z0-9($]" #";" # invalid char. of a function name incl. "("
    #       the above vxPatt       # matches all char except those listed, I think
    vFPatt=";\$[0\$]*\("  
    # or "$" "("  which is '+$[0$](' 
    # Use List=re.findall("+$[0$](")
    # Use List=re.search("+$[0$](", pattStr).start()
    #   will search for each matching pattern in the pattStr
    #     and return a list of the starting positions
    #procedure

    # replace "_a-ZA-Z0-9" with "0" where "0" is in "_a-ZA-Z0-9" ie valid subseq char equiv
    # replace "_a-ZA-Z" with "_"  wher  e "_" is in "_a-ZA-Z"    ie valid first char equiv
    # L-R find pos of first "0("
    # discard all to the right of "("
    # R-L find pos of first "_"
    # discard all to the left of "_"
    # fin what remains (it begins with a "_" first char equiv and ends with a "("
    # return the pos of what is found



    #                               
    #    ( 2022CMar22 D@CC needs to test the above pattern matches. ) 

    outPos=-1
    pos0=posIn0

    if pos0>len(inStr): return outPos
    tStr=inStr[pos0:]
    print("tStr:"+tStr)
    if tStr.find('(')>-1 :
        print("found another (")
        isFn=True
        parPos=inStr[pos0:].find("(")    #parenthesis Position
        print("parPos:",parPos)
        while parPos > -1 :
            print("into while")
            isFn=False
            if parPos==-1 :
                print("no (")

                print("returning outPos:",outPos)
                return outPos
            else:
                #do the work
                pattStr=inStr[pos0:pos0+parPos+1]
                #::::::::::textpak=>functionList.py
                print("b4  pattStr:"+pattStr)
                pattStr=re.sub(v1Patt,"$",pattStr)
                print("md1 pattStr:"+pattStr)
                pattStr=re.sub(v2Patt,"0",pattStr)
                print("md2 pattStr:"+pattStr)
                pattStr=re.sub(vxPatt,";",pattStr)
                print("af  pattStr:"+pattStr)
                findPatt=";\$[0\$]*\("
                print("findPatt:"+findPatt)
                try:                                            #fix DC
                    #List=re.findall(findPatt, pattStr)         #fix DC
                    List=re.search(findPatt, pattStr).start()   #fix DC
                except:                                         #fix DC
                    print("exception occurred during .search") #fix DC
                    List=None                                   #fix DC
                finally:  
                    continueDoh=True                    #fix DC
                #try end
                if List==None : 
                    print("parPos: ",parPos) #parPos is parentheses Position
                    print("List=None")
                    print("breaking out of while loop")
                    break    # out of while loop
                print("List:", List)
                posFromList=List
                smallStr=pattStr[posFromList:]
                print("smallStr: "+smallStr)
                pInSmallPos= smallStr.find("(")
                print("pInSmallPos: ",pInSmallPos)
                zparPos= posFromList+pInSmallPos
                print("zparPos: ",zparPos)
                if zparPos >-1 :
                    #                          #working here
                    #              was ("0$")
                    findNonRePatt=";\$[0\$]*\("
                    print("in nonPosNx.... zparPos>-1")
                    print("findNonRePatt: "+findNonRePatt)
                    v1Pos =pattStr.find("0$")  #finds leftmost but
                    #                          need to search R-L
                    print("v1Pos:",v1Pos)
                    if v1Pos> -1 :
                        isFn=True
                        print ("Fn found ")
                        outPos=pos0+parPos-zparPos+v1Pos+1
                        FnStr=inStr[outPos:outPos+2]
                        print("FnStr:"+FnStr)
                        return outPos
                    #if end
                else:
                    print("zparPos:",zparPos)
                    isFn=False
                #if end
                if isFn==False :     # still not found, loop to try again
                    print("checked FN:"+pattStr[0:parPos+1])
                    print("of inStr  :"+inStr[pos0:pos0+parPos+1])
                    # new parPos will be
                    parPos=pos0+parPos
                    deltaparPos=inStr[pos0+parPos+1:].find("(")    #parenthesis Position
                    if deltaparPos>-1:     # keep looping
                        newparPos=pos0+parPos+1+deltaparPos
                        print("inStr[parPos:]:"+inStr[0:newparPos+1])
                        parPos=newparPos
                        print("parPos:",parPos)
                    else:
                        parPos=-1
                        # stop the while loop
                #if end
            #if end
            print("while end loop to try again")
        #while end
    else:
        return outPos
    #if end
#def end posNxFnUsed_v2
#                                         ##############################

#::::::::::textpak=>posNxFnUsed_test.py
def t2() :
    # beginning of actual posNxFnUsed_test.py
    # this is t2.py
    import re

    # body of t2 is missing doh!

    n=0
    testStr="-3*(4+var+3.40+st2r4(27))+p2hi(35+a)+12b()-a()"
    v1Patt="[_a-zA-Z]"       #"$" # valid first letter of a variable
    v2Patt="[_a-zA-Z0-9]"    #"0" # valid subseq. letter of a variable
    vxPatt="[^_a-zA-Z0-9($!]" #";" # invalid char. of a function name incl. "("
    #       the above vxPatt       # matches all char except those listed, I think
    vFPatt=";\$[0\$]\("   
    #        012345678901234567890123
    while n>-1 :
        if False :
            # start with string pos 0
            m=posNxFnUsed(testStr,n)
            print ("m:",m)
            if m>-1 :
                bracPos=testStr[m:].find("(")
                print("bracPos:",bracPos)
                FnStr=testStr[m:m+bracPos]
                print("FnStr:"+FnStr+":")
                n=bracPos
            #if end
        #if end
        pattStr=testStr    
        print("b4  pattStr: "+pattStr)
        pattStr=re.sub(v1Patt,"!",pattStr)
        print("md1 pattStr: "+pattStr)
        pattStr=re.sub(v2Patt,"0",pattStr)
        print("md2 pattStr: "+pattStr)
        pattStr=re.sub(vxPatt,";",pattStr)
        print("af  pattStr: af"+pattStr)
        print("                           ;!!0!0(    ;!0!!(           ;!( ")
        print("             0123456789012345678901234567890123456789012345")
        print("                       1         2         3         4")
        #findPatt="+$[0$]("
        findPatt="\+[0\$]\("
        findPatt="0.0"           #finds 0c0 #::::::::::textpak=>posNxFnUsed.py
# originally was included in posNxFnUsed_test.py

def posNxFnUsedZZ(inStr,posIn0) :
    return posNxFnUsed_v2(inStr,posIn0)

def posNxFnUsed_v2(inStr,posIn0) :

    import re

    print("posNxFnUsed_v2 on line 179 in ...._pkg.py")

    # by D@CC on 2022CMar15
    # find the pos of the first char of the next function used in the inStr
    # start searching at position
    # e.g. -3*(4+var+3.40+st2r4(27))+p2hi(35+a)+12b()  should return 15 pos of "str4("
    #      012345678901234567890123
    #      +0+(0+$$$+0+00+$$0$0(
    #                           00+++$0$$(00+$++00$(+
    #         (          +$$0$0(    +$0$$(         (
    #  valid regular pattern is "+$" any "0"  ????????????????
    v1Patt="[_a-zA-Z]"       #"$" # valid first letter of a variable
    v2Patt="[_a-zA-Z0-9]"    #"0" # valid subseq. letter of a variable
    vxPatt="[^_a-zA-Z0-9($]" #";" # invalid char. of a function name incl. "("
    #       the above vxPatt       # matches all char except those listed, I think
    vFPatt=";\$[0\$]*\("  
    # or "$" "("  which is '+$[0$](' 
    # Use List=re.findall("+$[0$](")
    # Use List=re.search("+$[0$](", pattStr).start()
    #   will search for each matching pattern in the pattStr
    #     and return a list of the starting positions
    #procedure

    # replace "_a-ZA-Z0-9" with "0" where "0" is in "_a-ZA-Z0-9" ie valid subseq char equiv
    # replace "_a-ZA-Z" with "_"  wher  e "_" is in "_a-ZA-Z"    ie valid first char equiv
    # L-R find pos of first "0("
    # discard all to the right of "("
    # R-L find pos of first "_"
    # discard all to the left of "_"
    # fin what remains (it begins with a "_" first char equiv and ends with a "("
    # return the pos of what is found



    #                               
    #    ( 2022CMar22 D@CC needs to test the above pattern matches. ) 

    outPos=-1
    pos0=posIn0

    if pos0>len(inStr): return outPos
    tStr=inStr[pos0:]
    print("tStr:"+tStr)
    if tStr.find('(')>-1 :
        print("found another (")
        isFn=True
        parPos=inStr[pos0:].find("(")    #parenthesis Position
        print("parPos:",parPos)
        while parPos > -1 :
            print("into while")
            isFn=False
            if parPos==-1 :
                print("no (")

                print("returning outPos:",outPos)
                return outPos
            else:
                #do the work
                pattStr=inStr[pos0:pos0+parPos+1]
                #::::::::::textpak=>functionList.py
                print("b4  pattStr:"+pattStr)
                pattStr=re.sub(v1Patt,"$",pattStr)
                print("md1 pattStr:"+pattStr)
                pattStr=re.sub(v2Patt,"0",pattStr)
                print("md2 pattStr:"+pattStr)
                pattStr=re.sub(vxPatt,";",pattStr)
                print("af  pattStr:"+pattStr)
                findPatt=";\$[0\$]*\("
                print("findPatt:"+findPatt)
                try:                                            #fix DC
                    #List=re.findall(findPatt, pattStr)         #fix DC
                    List=re.search(findPatt, pattStr).start()   #fix DC
                except:                                         #fix DC
                    print("exception occurred during .search") #fix DC
                    List=None                                   #fix DC
                finally:  
                    continueDoh=True                    #fix DC
                #try end
                if List==None : 
                    print("parPos: ",parPos) #parPos is parentheses Position
                    print("List=None")
                    print("breaking out of while loop")
                    break    # out of while loop
                print("List:", List)
                posFromList=List
                smallStr=pattStr[posFromList:]
                print("smallStr: "+smallStr)
                pInSmallPos= smallStr.find("(")
                print("pInSmallPos: ",pInSmallPos)
                zparPos= posFromList+pInSmallPos
                print("zparPos: ",zparPos)
                if zparPos >-1 :
                    #                          #working here
                    #              was ("0$")
                    findNonRePatt=";\$[0\$]*\("
                    print("in nonPosNx.... zparPos>-1")
                    print("findNonRePatt: "+findNonRePatt)
                    v1Pos =pattStr.find("0$")  #finds leftmost but
                    #                          need to search R-L
                    print("v1Pos:",v1Pos)
                    if v1Pos> -1 :
                        isFn=True
                        print ("Fn found ")
                        outPos=pos0+parPos-zparPos+v1Pos+1
                        FnStr=inStr[outPos:outPos+2]
                        print("FnStr:"+FnStr)
                        return outPos
                    #if end
                else:
                    print("zparPos:",zparPos)
                    isFn=False
                #if end
                if isFn==False :     # still not found, loop to try again
                    print("checked FN:"+pattStr[0:parPos+1])
                    print("of inStr  :"+inStr[pos0:pos0+parPos+1])
                    # new parPos will be
                    parPos=pos0+parPos
                    deltaparPos=inStr[pos0+parPos+1:].find("(")    #parenthesis Position
                    if deltaparPos>-1:     # keep looping
                        newparPos=pos0+parPos+1+deltaparPos
                        print("inStr[parPos:]:"+inStr[0:newparPos+1])
                        parPos=newparPos
                        print("parPos:",parPos)
                    else:
                        parPos=-1
                        # stop the while loop
                #if end
            #if end
            print("while end loop to try again")
        #while end
    else:
        return outPos
    #if end
#def end posNxFnUsed_v2


#::::::::::textpak=>t2.py
def t2() :
    while False :
        #where c is any character
        findPatt="\+\$\$0\$0\("  # finds +$$0$0(
        findPatt="\+[\$]"        # finds +$  +$$ etc
        findPatt="\+[\$]\+"      # finds +$+
        findPatt="\+[0\$]\+"     # finds +c+ where c must be either 0 or $
        findPatt="\+\$[\$0][\$0][\$0][\$0]\("   # finds +$ssss( where s must be either $ or 0  
        findPatt="\+\$+\+"       # finds +$+ where s must be any number(>0) of $
        findPatt="\+[\$0]+\+"    # finds +$+ where s must be any number(>0) of $ or 0
        #                                               #  but not a mixture of $ and 0
        findPatt="\+\${1}"      # find +$  where there is only 1$
        findPatt=";!{1}[!0]*\("  # find +$s  where s is any number of 0 or $ followed by (
        #                          \+ is "+"   ! is "!"  [\!0] is either ! or 0
        #                   af        [\!0]* is any number (0 or >0) of "!" or "0" in any order
        #                          \( is "("
        #                          So this matches "+!sssss("  where s is ! or 0 in any order
        # 
        #List=re.search(findPatt, pattStr).start()
        #findPatt=""
        # can find 0 but not $ nor (  returns len+1
        #pattStr="This was this is"
        iter=re.finditer(findPatt,pattStr)
        indices=[m.start(0) for m in iter]
        print("List: ", indices)
        bList=[]
        for n in indices :
            #print("n:",n)
            item=testStr[n:].find("(")+n
            bList.append( item )
        #for end
        print("bList:",bList)        
        break
    #while end
    print("done")
    # end of t2.py
#def end t2

if __name__ == '__main__' : t2( )

# end of actual posNxFnUsed_test.py

#                                 --------------------------------
#::::::::::textpak=>functionList.py
# beginning of def. functionList.py definition from functionList_test.py
def functionList(testStr="#:::",v="v02") :
    if v=="?" : return "v02"
    return functionList_v02(testStr,v="v02")

def functionList_v02(testStr,v) :
    # by D@CC on 2022CMar28
    # returns a list of function calls in the input statment: inStr

    #print("functionList on line 416 in ...._pkg.py")

    functionList=[]
    nPos=0
    many0s="000000000000000000000000000000"
    while nPos>=0 :
        #print("in main while")
        nex = posNxFnUsed(testStr, nPos)
        nextPos=nex             #convert list element to string
        #print("in fList af nextPos:",nextPos)
        isNextPosGood=True
        if nextPos==-1 :   isNextPosGood=False
        if nextPos==None : isNextPosGood=False
        if isNextPosGood==False :
            # no more fNames found
            continueDoh=True
            break   #out of while loop
        else :
            textStr=testStr[0:]
            #print("textStr:  "+textStr)
            #textStr=testStr[0:]
            #print("textStr:  "+textStr)
            #print("          0123456789012345678901234567890123456789012345")
            nextFnPos =nextPos
            # ok   to here                          --------------------------
            #print("nextFnPos: ",nextFnPos)
            nextParPos = testStr[nextFnPos:].find("(")+nextFnPos
            #print("nextParPos: ",nextParPos)
            fName=testStr[nextFnPos+1:nextParPos]
            functionList.append(fName)
            #print("fName:"+fName)
            nPos= nextParPos
            yield(fName)
        #if end
        #keep looping
    #while end

#def end functionList_v02.py definition

#::::::::::textpak=>functionList_test.py
def mainroutine() :
    # by D@CC on 2022CMar26
    # functionList_test.py
    from functionList_pkg import functionList, functionList_v
    from functionList_pkg import posNxFnUsed,  posNxFnUsed_v

    progName="functionList_test.py"
    #main program starts here
    #  calls:functionList.(
    # imports both functionList and posNxFnUsed from functionList_pkg.py

    print(" fL v:  "+functionList_v() )
    print(" pos v: "+posNxFnUsed_v()  )

    testStr="-3*(4+var+3.40+st2r4(27))+p2hi(35+a)+12b()-a()"
    print("testStr1:",testStr)
    for fName in functionList(testStr) :
        print("fName: "+fName)
    #for end
    #print("          012345678901234567890123456789012345678901234") #
    print("end of functionList_test.py v4")
    return
#def end mainroutine()
if __name__ == '__main__' : mainroutine( )



# end of functionList_test.py

#::::::::::textpak=>posNxFnUsed.py

def posNxFnUsed(inStr,posIn0,v=3) :
    if v=="?" :  return 3
    return posNxFnUsed_v3(inStr,posIn0,v=3)

def posNxFnUsed_v3(inStr,posIn0,v) :

    import re

    #if v=="?" : return 3

    # by D@CC on 2022CMar25
    #print("posNxFnUsed_v03 on line 501 in ...._pkg.py  v03")

    #print("into posNFU v03")
    #print("posIn0:",posIn0)
    # find the pos of the first char of the next function used in the inStr
    # start searching at position
    # e.g. -3*(4+var+3.40+st2r4(27))+p2hi(35+a)+12b()  should return 15 pos of "str4("
    #      012345678901234567890123
    #      +0+(0+$$$+0+00+$$0$0(
    #                           00+++$0$$(00+$++00$(+
    #         (          +$$0$0(    +$0$$(         (
    #  valid regular pattern is "+$" any "0"  ????????????????
    if posIn0==0 :
        v1Patt="[_a-zA-Z]"       #"!" # valid first letter of a variable
        v2Patt="[_a-zA-Z0-9]"    #"0" # valid subseq. letter of a variable
        vxPatt="[^_a-zA-Z0-9(!]" #";" # invalid char. of a function name incl. "("
        #       the above vxPatt"-3*(4+var+3.40+st2r4(27))+p2hi(35+a)+12b()-a()"       # matches all char except those listed, I think
        vFPatt="+$[0$]("    #print("                           ;!!0!0(    ;!0!!(           ;!( ")
        
        #print("inStr  :  "+inStr)
        pattStr=inStr    
        pattStr=re.sub(v1Patt,"!",pattStr)
        #print("pattStr:  "+pattStr)
        pattStr=re.sub(v2Patt,"0",pattStr)
        #print("pattStr:  "+pattStr)
        pattStr=re.sub(vxPatt,";",pattStr)
        #print("pattStr:  "+pattStr)

        #print("             -3*(4+var+3.40+st2r4(27))+p2hi(35+a)+12b()-a()")
        #print("                        ;!!0!0(    ;!0!!(           ;!( ")

        #print("             0123456789012345678901234567890123456789012345")
        #print("                       1         2         3         4")
        findPatt=";!{1}[!0]*\("  # find +$s  where s is any number of 0 or $ followed by (
        iter=re.finditer(findPatt,pattStr)
        global List
        List=[m.start(0) for m in iter]
        #print("List: ", List)
        global bList
        bList=[]
        #print("bList before gen")
        for n in List :
            #print("n:",n)
            #item=testStr[n:].find("(") + n                 # BAD
            item=inStr[n:].find("(") + n
            bList.append( item )
            #for end

            #print("posIn0:",posIn0)
            #  OK to here
        #for end
        #print("bList:",bList)


    #if end


    #print("b4 List")
    #print("List:",List)

    for n in List :
        #print("n:",n)
        thisPos=n
        if posIn0==0:
            return thisPos   #returns and re-enters here
        else:
            if thisPos>posIn0:
                return thisPos
            else:
                continueDoh=True
                #keep looping
            #if end
        #if end
    #for end
    thisPos=-1
    #print("thisPos:",thisPos)
    return thisPos



    # or "$" "("  which is '+$[0$](' 
    # Use List=re.findall("+$[0$](")
    # Use List=re.search("+$[0$](", pattStr).start()
    #   will search for each matching pattern in the pattStr
    #     and return a list of the starting positions
    #procedure

    # replace "_a-ZA-Z0-9" with "0" where "0" is in "_a-ZA-Z0-9" ie valid subseq char equiv
    # replace "_a-ZA-Z" with "_"  wher  e "_" is in "_a-ZA-Z"    ie valid first char equiv
    # L-R find pos of first "0(""-3*(4+var+3.40+st2r4(27))+p2hi(35+a)+12b()-a()"
    # discard all to the right of "("
    # R-L find pos of first "_"
    # discard all to the left of "_"
    # fin what remains (it begins with a "_" first char equiv and ends with a "("
    # return the pos of what is found

#def end posNxFnUsed_v03()


#::::::::::textpak=>t03.py
def mainroutine() :
    from functionList_pkg import posNxFnUsed

    #Purpose to test posNxFnUsed.py v04
    #Then I created functionList.py 
    #             (which contains all this code and calls posNxFnUsed() )

    # by D@CC on 2022CMar25

    #main program t03.py starts here
    testStr="-3*(4+var+3.40+st2r4(27))+p2hi(35+a)+12b()-a()"
    print("testStr1:",testStr)
    print("          012345678901234567890123456789012345678901234") #
    print("                    1         2         3         4    ")
    nPos=0
    many0s="000000000000000000000000000000"
    while nPos>=0 :
        #print("in main while")
        nex = posNxFnUsed(testStr, nPos)
        nextPos=int(nex)             #convert list element to string
        #print("in main af nextPos:",nextPos)
        if nextPos==-1 :
            continueDoh=True
            break   #out of while loop
        else :
            textStr=testStr[0:]
            #print("textStr:  "+textStr)
            #textStr=testStr[0:]
            #print("textStr:  "+textStr)

            nextFnPos =nextPos
            # ok   to here                          --------------------------
            #print("nextFnPos: ",nextFnPos)
            nextParPos = testStr[nextFnPos:].find("(")+nextFnPos
            #print("nextParPos: ",nextParPos)
            fName=testStr[nextFnPos+1:nextParPos]
            print("fName:"+fName)
            nPos= nextParPos
        #if end
        #keep looping
    #while end
    print("end of t3.py")

    print("done")
    # end of t3
#end def mainroutine()

if __name__ == '__main__' : mainroutine( )

#end def t03.py
#end of pkg on 2022CMar25    

#::::::::::textpak=>t16.py
#def functionList(testStr="",v="v02") :
    #if v=="?" : return "v02"
    #return functionList_v02(testStr,v)
#def end

#def functionList_v02(testStr, v) :
    # by D@CC on 2022CMar26
    #. . . .
    #. . . . function definition statements go here
    # . . . .
    #return anyValue
#def end functionList

def mainroutine() :
    #main program used to test the functionList function

    from functionList_pkg import functionList, posNxFnUsed

    line="abc = aStr(1000*unixTime() ) + bigI(333)"
    print("line:"+line+":")
    fList=functionList(line)
    for x in fList : 
        print(x, end=" " )
    #for end
    print()
    vsnStr=str( functionList("","?") )
    print( "vsn of functionList:  "+ vsnStr )
    vsnStr=str( posNxFnUsed("",0,"?") )
    print( "vsn of posNxFnUsed:  "+ vsnStr )
    return
#def end
if __name__ == '__main__'  : mainroutine()
#end of t.py v16

#::::::::::textpak=>posNxFnUsed.py

def posNxFnUsed(inStr,posIn0,v=4) :
    pass;                   vv=4
    returnValue = posNxFnUsed_v4(inStr,posIn0)
    # only need to edit the vsn # in 4 places (& at the end if desired)
    if v=="?" : return returnValue,vv
    else :      return returnValue
    #if end

def posNxFnUsed_v4(inStr,posIn0) :

    import re

    # by D@CC on 2022DApr02
    #print("posNxFnUsed_v04 on line 867 in ...._pkg.py  v04")

    #print("into posNFU v04")
    #print("posIn0:",posIn0)
    # find the pos of the first char of the next function used in the inStr
    # start searching at position
    # e.g. -3*(4+var+3.40+st2r4(27))+p2hi(35+a)+12b()  should return 15 pos of "str4("
    #      012345678901234567890123
    #      +0+(0+$$$+0+00+$$0$0(
    #                           00+++$0$$(00+$++00$(+
    #         (          +$$0$0(    +$0$$(         (
    #  valid regular pattern is "+$" any "0"  ????????????????
    if posIn0==0 :
        v1Patt="[_a-zA-Z]"       #"!" # valid first letter of a variable
        v2Patt="[_a-zA-Z0-9]"    #"0" # valid subseq. letter of a variable
        vxPatt="[^_a-zA-Z0-9(!]" #";" # invalid char. of a function name incl. "("
        #       the above vxPatt"-3*(4+var+3.40+st2r4(27))+p2hi(35+a)+12b()-a()"       # matches all char except those listed, I think
        vFPatt="+$[0$]("    #print("                           ;!!0!0(    ;!0!!(           ;!( ")
        
        #print("inStr  :  "+inStr)
        pattStr=inStr    
        pattStr=re.sub(v1Patt,"!",pattStr)
        #print("pattStr:  "+pattStr)
        pattStr=re.sub(v2Patt,"0",pattStr)
        #print("pattStr:  "+pattStr)
        pattStr=re.sub(vxPatt,";",pattStr)
        #print("pattStr:  "+pattStr)

        #print("             -3*(4+var+3.40+st2r4(27))+p2hi(35+a)+12b()-a()")
        #print("                        ;!!0!0(    ;!0!!(           ;!( ")

        #print("             0123456789012345678901234567890123456789012345")
        #print("                       1         2         3         4")
        findPatt=";!{1}[!0]*\("  # find +$s  where s is any number of 0 or $ followed by (
        iter=re.finditer(findPatt,pattStr)
        global List
        List=[m.start(0) for m in iter]
        #print("List: ", List)
        global bList
        bList=[]
        #print("bList before gen")
        for n in List :
            #print("n:",n)
            #item=testStr[n:].find("(") + n                 # BAD
            item=inStr[n:].find("(") + n
            bList.append( item )
            #for end

            #print("posIn0:",posIn0)
            #  OK to here
        #for end
        #print("bList:",bList)


    #if end


    #print("b4 List")
    #print("List:",List)

    for n in List :
        #print("n:",n)
        thisPos=n
        if posIn0==0:
            return thisPos   #returns and re-enters here
        else:
            if thisPos>posIn0:
                return thisPos
            else:
                continueDoh=True
                #keep looping
            #if end
        #if end
    #for end
    thisPos=-1
    #print("thisPos:",thisPos)
    return thisPos



    # or "$" "("  which is '+$[0$](' 
    # Use List=re.findall("+$[0$](")
    # Use List=re.search("+$[0$](", pattStr).start()
    #   will search for each matching pattern in the pattStr
    #     and return a list of the starting positions
    #procedure

    # replace "_a-ZA-Z0-9" with "0" where "0" is in "_a-ZA-Z0-9" ie valid subseq char equiv
    # replace "_a-ZA-Z" with "_"  wher  e "_" is in "_a-ZA-Z"    ie valid first char equiv
    # L-R find pos of first "0(""-3*(4+var+3.40+st2r4(27))+p2hi(35+a)+12b()-a()"
    # discard all to the right of "("
    # R-L find pos of first "_"
    # discard all to the left of "_"
    # fin what remains (it begins with a "_" first char equiv and ends with a "("
    # return the pos of what is found

#def end posNxFnUsed_v4()

#::::::::::textpak=>t17.py
#def functionList(testStr="",v="v02") :
    #if v=="?" : return "v02"
    #return functionList_v02(testStr,v)
#def end

#def functionList_v02(testStr, v) :
    # by D@CC on 2022CMar26
    #. . . .
    #. . . . function definition statements go here
    # . . . .
    #return anyValue
#def end functionList

def mainroutine() :
    #main program used to test the functionList function

    from functionList_pkg import functionList, posNxFnUsed

    line="abc = aStr(1000*unixTime() ) + bigI(333)"
    print("line:"+line+":")
    fList=functionList(line)
    for x in fList : 
        print(x, end=" " )
    #for end
    print()
    vMain=17
    print("vsn of t.py: ",vMain)
    vsnStr=str( functionList("","?") )
    print( "vsn of functionList:  "+ vsnStr )
    vsnStr=str( posNxFnUsed("",0,"?")[1] )
    print( "vsn of posNxFnUsed:  "+ vsnStr )
    return
#def end
if __name__ == '__main__'  : mainroutine()
#end of t17.py

#                                 --------------------------------
#::::::::::textpak=>functionList.py
# beginning of def. functionList.py definition 
def functionList(testStr="#:::",v=3) :
    pass;                      vv=3
    returnValue =  functionList_v03(testStr)
    if v=="?" : return returnValue,vv
    else :      return returnValue
    #if end

def functionList_v03(testStr) :
    # by D@CC on 2022DApr02
    # returns a list of function calls in the input statment: inStr

    #print("functionList v03 on line 1017 in ...._pkg.py")

    functionList=[]
    nPos=0
    many0s="000000000000000000000000000000"
    while nPos>=0 :
        #print("in main while")
        nex = posNxFnUsed(testStr, nPos)
        nextPos=nex             #convert list element to string
        #print("in fList af nextPos:",nextPos)
        isNextPosGood=True
        if nextPos==-1 :   isNextPosGood=False
        if nextPos==None : isNextPosGood=False
        if isNextPosGood==False :
            # no more fNames found
            continueDoh=True
            break   #out of while loop
        else :
            textStr=testStr[0:]
            #print("textStr:  "+textStr)
            #textStr=testStr[0:]
            #print("textStr:  "+textStr)
            #print("          0123456789012345678901234567890123456789012345")
            nextFnPos =nextPos
            # ok   to here                          --------------------------
            #print("nextFnPos: ",nextFnPos)
            nextParPos = testStr[nextFnPos:].find("(")+nextFnPos
            #print("nextParPos: ",nextParPos)
            fName=testStr[nextFnPos+1:nextParPos]
            functionList.append(fName)
            #print("fName:"+fName)
            nPos= nextParPos
            yield(fName)
        #if end
        #keep looping
    #while end

#def end functionList_v03.py definition

::::::::::textpak=>intRed_pico.py.txt
import machine
import utime

#program "intRed_pico.py" toggles the pico's main green LED
#        every 2 seconds using an interrupt routine
#        (not using an loop with a counter).
#        press button 21 to
#           turn ON led GP5 and to "interrupt"
#           the green LED's blinking for 4 sec

# external set up of GP Pins
# GP15 to red (n.o.) button to 3v3
# GP10 to 330 ohm resistor to greenLED anode from cathode to GND Pin phys 23
# GP11 to 330 ohm resistor to redLED   anode from cathode to GND Pin phys 23

# tested OK on 2021FJun15 with MPA by D@CC

progName="intRed_pico.py"
print("progName:"+progName)
bRedGP=18
#button_red = machine.Pin(bRedGP, machine.Pin.IN, machine.Pin.PULL_DOWN)
button_red = machine.Pin(bRedGP, machine.Pin.IN, machine.Pin.PULL_DOWN) #?no PULL_DOWN for MPA ADC0 to GP18
led_red  = machine.Pin(5, machine.Pin.OUT)
led_green  = machine.Pin(25, machine.Pin.OUT)

# inititialize red and green LEDs
led_red.value(0)
led_green.value(0)
print("waiting for press of button",bRedGP)

def int_handler(pin):
    button_red.irq(handler=None)
    print("Interrupt Detected! at time:",utime.time())
    led_red.value(1)
    led_green.value(0)
    print("sleeping for 4 secs")
    utime.sleep(4)     # seconds
    led_red.value(0)
    print("waiting for press of button",bRedGP)
    button_red.irq(handler=int_handler)
#end def

button_red.irq(trigger=machine.Pin.IRQ_RISING, handler=int_handler)

while True:
    led_green.toggle()
    utime.sleep(2)  # seconds
#while end

# source: https://www.youtube.com/watch?v=Zy64kZEM_bg
#/intRed.py     stored as intRed_pico.py

::::::::::textpak=>maker-pi-pico-rgb-led_pico.py.txt
# This example uses Maker Pi Pico
# Reference: https://www.cytron.io/p-maker-pi-pico
# -----
# to stop it completely RESET is useless, unplug from Pi instead

import array, time
from machine import Pin
import rp2
from rp2 import PIO, StateMachine, asm_pio

# Configure the number of WS2812 LEDs
# - There's 1x built-in RGB LED on Maker Pi Pico board
NUM_LEDS = 1

@asm_pio(sideset_init=PIO.OUT_LOW, out_shiftdir=PIO.SHIFT_LEFT,
autopull=True, pull_thresh=24)
def ws2812():
    T1 = 2
    T2 = 5
    T3 = 3
    label("bitloop")
    out(x, 1) .side(0) [T3 - 1]
    jmp(not_x, "do_zero") .side(1) [T1 - 1]
    jmp("bitloop") .side(1) [T2 - 1]
    label("do_zero")
    nop() .side(0) [T2 - 1]

# Create the StateMachine with the ws2812 program, outputting on pin GP28 (Maker Pi Pico).
sm = StateMachine(0, ws2812, freq=8000000, sideset_base=Pin(28))

# Start the StateMachine, it will wait for data on its FIFO.
sm.active(1)

# Display a pattern on the LEDs via an array of LED RGB values.
ar = array.array("I", [0 for _ in range(NUM_LEDS)])

while True:
    print("blue")
    for i in range(NUM_LEDS):
        ar[i] = 255
    sm.put(ar,8)
    time.sleep_ms(1000)

    print("red")
    for i in range(NUM_LEDS):
        ar[i] = 255<<8          # shift 8 bits to the left
    sm.put(ar,8)
    time.sleep_ms(1000)

    print("green")
    for i in range(NUM_LEDS):
        ar[i] = 255<<16         # shift 16 bits to the left
    sm.put(ar,8)
    time.sleep_ms(1000)

    print("white")
    for i in range(NUM_LEDS):
        ar[i] = 0xFFFFFF
    sm.put(ar,8)
    time.sleep_ms(1000)
# maker-pi-pico-rgb-led.py
# source: https://github.com/CytronTechnologies/MAKER-PI-PICO/blob/main/Example%20Code/MicroPython/maker-pi-pico-rgb-led.py
# date: 2021EMay24
#/maker-pi-pico-rgb-led_pico.py.txt

::::::::::textpak=>mid.py.txt
def mid(strIn,iFrom,iTo):
    # by D@CC
    # created  on 2022EMay30
    # improved on 2024BFeb12
    # Purpose: BASIC-like mid probably for pico
    #  returns  strType, midStr 
    # Comment: similar to Mid(strA,2,3) in BASIC
    #                          col:2,len:3
    # Issue: NOT YET FULLY TESTED
    #        BUT READY FOR TESTING
    # example of use: mid(strA,2,3)
    # mid returns same characters as
    #    the string splice of str(x)[1:4]
    # parmIn 01 strA  str eg "abcdef"
    # parmIn 02 iFrom int eg 2
    # parmIn 03 iTo   int eg 4
    # returns 
    #  parmOut 01 str strType eg "s" or "f" etc
    #  parmOut 02 str strA eg "bcd"
    # accepts types
    #   type     strA      print(Mid(strA,2,3)  BASIC
    #                      print(Mid(strA,a,b)  BASIC
    #                      print(mid(strA,a,b)  Python IX function
    #                      print(str(strA)[a-1:a+b-1] ) equivalent Python
    #   bool     "True"    "rue"
    #   Complex  "(-1+2j)" "-1+"
    #   int      12345     "234"
    #   float    12.34     "2.3"
    #   str      "abcdef"  "bcd"
    #
    # used in article 174
    # called by f3()
    #
    # Functions used:
    # isinstance()  # Issue: maybe "isInstance" instead
    # endswith()
    # float()
    # str()
    # bool()

    x=strIn
    if x == True:
        x="True"
    if x ==False:
        x="False"
    #if end
        
    if isinstance(x,(float,int,str)):
        #print("at 49 x:",x)
        if isinstance(x,str):
            #print("51 checking if complex")
            #print("at 52 x:",x)
            if x.endswith(("j","J")):
                isJend=True
            else:
                isJend=False
            #print("57 isJend:",isJend)
            
            #if(x.endswith("j)") or (x.endswith("J)"):
            #if((x.endswith("j")) or ((x.endswith("J")):
            if isJend:   #if x is probably complex
                print("Issue: Must check syntax of complex")
                print("complex is barely usable on pico")
                #almost complex but without the "(" and ")"
                xReturn="("+x+")"
                xType="sc"
                #print("66 xType:",xType)
                isDone=True
            else:
                #not complex, must be str
                #print("70 not complex, must be str or bool")
                if strIn in [True,False]:
                    print("72 is bool")
                    xType="b"
                    xReturn=x
                else:
                    #print("76 is str")
                    xType="s"
                    xReturn=x
                #if end
                #print("80 xReturn:",xReturn)
                return xType,str(xReturn)[iFrom-1:iFrom+iTo-1]
            #end if
            
            
        # process an integer value
        elif isinstance(x,int):
            print("87 saw int x",x)
            xType="i"
            xReturn=str(x)
            isDone=True
        elif isinstance(x,float):
            print("at 92, float x",x)
            xFloat=x
            xReturn=str(xFloat)
            xType="f"
            isDone=True
            
            
        elif isinstance(x,int):
            print("at 100 after elif x:",x)
            #xInt=int(x)
            xReturn=str(xInt)
            xType="i"
            isDone=True
            
            
            
        # process a float value
        #end if instances of int,float,str,
        
        
        
        
    else:   #presume boolean, not complex
        print("at 115 test Bool")
        if(bool(x)==1):
            xFloat=float(1)
            xReturn=str(xFloat)
            xType="b"
            isDone=True
        #end if
        if(bool(x)==0):
            xFloat=float(0)
            xReturn=str(xFloat)
            xType="b"
            isDone=True
        #end if
        #end of bool processing
    #end if
            
    if isDone:
        if False:
            y="abcdef"
            strY=str(y)[2:3]
            print("at 135 should be returning a value")
            print("136 iFrom:",iFrom)
            print("137 iLen:",iTo)
            print("138 y:",y)
            print("139 str(y)[2:3]:",str(y)[2:3])
        #if end
            
        #print("142 iFrom:",iFrom)
        #print("143 iLen:",iTo)
        #print("144 xType:",xType)
        #print("145 xReturn:",xReturn) 
        return xType,str(xReturn)[iFrom-1:iFrom+iTo-1]
    
    
    else:
        
        print("unknown type, presume s")
    #if end
        
        
    print("155 x:",x)
    xReturn=str(x)[a-1,a+b-1]
    print("157,xReturn:",xReturn)
    xType="s"
    
    
    print("at 161")
    return xType,str(xReturn)[iFrom-1:iFrom+iTo-1]
    #if end
#def end
#/mid_pico.py.txt

::::::::::textpak=>mid_old.py.txt
def mid_old(x,):
    #Issue: returnx xType,xFloat
    #Issue: xFloat is NOT a mid-string
    #WARNING: 2024BF11 D@CC improved this a little
    if isinstance(x,(float,int,str)):
        if isinstance(x,str):
            if x.endswith("jJ"):
                isJend==True
            else:
                isJend==False
            print("isJend:",isJend)
            #if(x.endswith("j)") or (x.endswith("J)"):
            #if((x.endswith("j")) or ((x.endswith("J")):
            if isJend:
                #almost complex but without the "(" and ")"
                xReturn="c" + "("+c+")"
                xType="cs"
                isDone=True
                return xType,xReturn
            else:
                #not complex
                try:
                    xFloat=float(x)
                    xType="f"
                    isDone=True
                except:
                    xReturn=x
                    xType="s"
                    isDone=True
                #end try
            #end if
        # process an integer value
        elif isinstance(x,int):
            xFloat=float(x)
            xType="i"
            isDone=True
        # process a float value
        elif isinstance(x,float):
            xFloat=x
            xType="f"
            isDone=True
        #end if instances of int,float,str,
    else:   #presume boolean
        if(bool(x)==1):
            xFloat=float(1)
            xType="b"
            isDone=True
        #end if
        if(bool(x)==0):
            xFloat=float(0)
            xType="b"
            isDone=True
        #end if
        #end of bool processing
    return xType,xFloat
    #end if
            

::::::::::textpak=>mid_test.py.txt
def mid(strIn,iFrom,iTo):
    # by D@CC
    # created  on 2022EMay30
    # improved on 2024BFeb12
    # Purpose: BASIC-like mid probably for pico
    #  returns  strType, midStr 
    # Comment: similar to Mid(strA,2,3) in BASIC
    #                          col:2,len:3
    # Issue: NOT YET FULLY TESTED
    #        BUT READY FOR TESTING
    # example of use: mid(strA,2,3)
    # mid returns same characters as
    #    the string splice of str(x)[1:4]
    # parmIn 01 strA  str eg "abcdef"
    # parmIn 02 iFrom int eg 2
    # parmIn 03 iTo   int eg 4
    # returns 
    #  parmOut 01 str strType eg "s" or "f" etc
    #  parmOut 02 str strA eg "bcd"
    # accepts types
    #   type     strA      print(Mid(strA,2,3)  BASIC
    #                      print(Mid(strA,a,b)  BASIC
    #                      print(mid(strA,a,b)  Python IX function
    #                      print(str(strA)[a-1:a+b-1] ) equivalent Python
    #   bool     "True"    "rue"
    #   Complex  "(-1+2j)" "-1+"
    #   int      12345     "234"
    #   float    12.34     "2.3"
    #   str      "abcdef"  "bcd"
    #
    # used in article 174
    # called by f3()
    #
    # Functions used:
    # isinstance()  # Issue: maybe "isInstance" instead
    # endswith()
    # float()
    # str()
    # bool()

    x=strIn
    if x == True:
        x="True"
    if x ==False:
        x="False"
    #if end
        
    if isinstance(x,(float,int,str)):
        #print("at 49 x:",x)
        if isinstance(x,str):
            #print("51 checking if complex")
            #print("at 52 x:",x)
            if x.endswith(("j","J")):
                isJend=True
            else:
                isJend=False
            #print("57 isJend:",isJend)
            
            #if(x.endswith("j)") or (x.endswith("J)"):
            #if((x.endswith("j")) or ((x.endswith("J")):
            if isJend:   #if x is probably complex
                print("Issue: Must check syntax of complex")
                print("complex is barely usable on pico")
                #almost complex but without the "(" and ")"
                xReturn="("+x+")"
                xType="sc"
                #print("66 xType:",xType)
                isDone=True
            else:
                #not complex, must be str
                #print("70 not complex, must be str or bool")
                if strIn in [True,False]:
                    print("72 is bool")
                    xType="b"
                    xReturn=x
                else:
                    #print("76 is str")
                    xType="s"
                    xReturn=x
                #if end
                #print("80 xReturn:",xReturn)
                return xType,str(xReturn)[iFrom-1:iFrom+iTo-1]
            #end if
            
            
        # process an integer value
        elif isinstance(x,int):
            print("87 saw int x",x)
            xType="i"
            xReturn=str(x)
            isDone=True
        elif isinstance(x,float):
            print("at 92, float x",x)
            xFloat=x
            xReturn=str(xFloat)
            xType="f"
            isDone=True
            
            
        elif isinstance(x,int):
            print("at 100 after elif x:",x)
            #xInt=int(x)
            xReturn=str(xInt)
            xType="i"
            isDone=True
            
            
            
        # process a float value
        #end if instances of int,float,str,
        
        
        
        
    else:   #presume boolean, not complex
        print("at 115 test Bool")
        if(bool(x)==1):
            xFloat=float(1)
            xReturn=str(xFloat)
            xType="b"
            isDone=True
        #end if
        if(bool(x)==0):
            xFloat=float(0)
            xReturn=str(xFloat)
            xType="b"
            isDone=True
        #end if
        #end of bool processing
    #end if
            
    if isDone:
        if False:
            y="abcdef"
            strY=str(y)[2:3]
            print("at 135 should be returning a value")
            print("136 iFrom:",iFrom)
            print("137 iLen:",iTo)
            print("138 y:",y)
            print("139 str(y)[2:3]:",str(y)[2:3])
        #if end
            
        #print("142 iFrom:",iFrom)
        #print("143 iLen:",iTo)
        #print("144 xType:",xType)
        #print("145 xReturn:",xReturn) 
        return xType,str(xReturn)[iFrom-1:iFrom+iTo-1]
    
    
    else:
        
        print("unknown type, presume s")
    #if end
        
        
    print("155 x:",x)
    xReturn=str(x)[a-1,a+b-1]
    print("157,xReturn:",xReturn)
    xType="s"
    
    
    print("at 161")
    return xType,str(xReturn)[iFrom-1:iFrom+iTo-1]
    #if end
#def end


def go():
    progName="mid_test.py"
    print("progName:",progName)
    print("test mid( ... ,2,3)")
    print("Issues:1")
    while True:
        strA=input("mid string?")
        
        #strA="1+23j"                      #for testing
        
        #print("at 176 strA:",strA)
        strKeep=strA
        #if strA in  :
        
        #if isinstance(strA,("True","False")):
        #print("at 181 strKeep:",strKeep)
        strB,strC = mid(strKeep,2,3)
        #print("at 183")
        print("184 strB,strC:",strB,strC)
    #while end
#def end
go()
#if __name__ == __main__ :
#    go()
#if end
#/mid_pico.py.txt

::::::::::textpak=>mod5.py.txt
# store this in Desktop/mod5 as __init__.py
# don't do sys.path.append('home/pi/Desktop/mod5')
# point Files to /home/pi/Desktop
# then run this with
# >>>import mod5
# >>>mod5.hello()
# This worked on 2021EMay28 by D@CC using Python3
# but not with microPython doh!
# Source: https://wiki.micropython.org/Importing-Modules
def hello():
    print('hello from mod5')
#end def
hello()

::::::::::textpak=>mpy_uart_pico.py.txt
import os
import utime
from machine import UART, Pin

progName="mpy_uart_pico.py"
print(progName)
print("Jumper GP04 to GP05")
#print sys info
print(os.uname())

#indicate program started visually
led_onboard = machine.Pin(25, machine.Pin.OUT)
led_onboard.value(0)     # onboard LED OFF for 0.5 sec
utime.sleep(0.5)
led_onboard.value(1)

#self.uart = UART(1, 115200, parity=None, stop=1, bits=8, rx=Pin(rxPin), tx=Pin(txPin))
# speed of 400 only reads 4 bytes . . Doh?
uart = machine.UART(1,600, parity=None, stop=1, bits=8, tx=Pin(4), rx=Pin(5))
#print uart info
#uart = machine.UART(1)
print(uart)

uart.write("hello")
utime.sleep(0.1)
while uart.any():
    print(uart.read(1))
#end while
print()
print("- bye -")
#Source:http://helloraspberrypi.blogspot.com/2021/01/raspberry-pi-picomicropython-simple.html
#program end
#/mpy_uart_pico.py.txt
::::::::::textpak=>n_v02.py.txt
#! /usr/bin/python3

# !/usr/local/bin/python  deprecated for Raspberry Pi
# IX_textnames.py  renamed and enhanced to n.py
# by D@CC on 2022CMar22
####################################################################
# first line (shebang) must be #! /usr/bin/python3                 #
# place the n.py and the package into Desktop                      #
#                                                                  #
# Usage:  >$ cd Desktop/                                           #
#         >sudo chmod +x n.py                                      #
#         >$ python3 ../n.py  < ../adcRead_pkg.py                  #
# or:     >$ cd Desktop                                            #
#         >$ ./n.py --acdhimgs < adcRead_pkg.py                    #
# NB In terminal, the above should list the names of the           #
#       files that exist in the package named in stdin.            #
#                                                                  #
# but due to the Unix trick line 1 "#!/usr...                      #
# and the last line if __name__ ...                                #
# the command line below works (afer chmod ...):                   #
# >$ ./n.py <adcRead_pkg.py                                        #
####################################################################
import sys
# from textpack import marker            # use common separator key but
marker = '#' + ':'*10 + 'textpak=>'      # the IX Marker is different
mlen = len(marker)                       # file names appear after markers

def names():
    cmdList0="[n]"  #default value
    argStr=str(sys.argv[1:])
    #print("argStr1:"+argStr)
    alen=len(argStr)
    argExt=argStr[alen-5:alen-2]
    #print("argExt:"+argExt)
    isBadArg=False
    if argExt==".py": isBadArg=True              #flag a Bad Argument
    if argExt.find("pkg")>-1 : isBadArg=True     #flag a Bad Argument
    #if end
    if isBadArg==True:
        continueDoh=True
        print('#::: Be sure to precede the Pkg name with a "<".')   
        return #from names    
    else:
        #print("argStr2:"+argStr)  
        #print("cmdList02:"+cmdList0)
        if False:
            continueDoh=True
        else:
            #print("argStr3:"+argStr)
            #for cmdList in sys.argv[1:]:
            if argStr=="[]": 
                cmdList=cmdList0
            else:
                cmdList=argStr
            #if end
            #print("cmdList3:"+cmdList)
            if cmdList.find("h")>-1 :
                print("#:::: Help for python n.py [IX pkg names list pgm]")
                print("#:::: Syntax: ./n.py [args] <pkg")
                print('#::::    args = -acdhimgs or null')
                print("#:::: a:all,c:class,d:def,h:help,i:import,m:marker,g:global,s:source:")
                print("#:::: NB use IX_textpack.py to create an IX package")
                print('#:::: NB marker is "#::::::::::'+'textpak=>"')
                print("#:::: (Cudos to:O'Reilly for textpack.py)")
                return   #from names 
            #if end
            if cmdList.find("a")>-1 :
               cmdList="-cdings"     #a means list all
            #endif
            if cmdList.find("<")>-1 :
                print("#:::: ERROR precede the < with a space")
                return   #from names 
            #if end
            print("#::: Enhanced n.py [IX pkg names list prg -h for help]:")
            
            if True:
                markCnt=0
                for line in sys.stdin.readlines(  ):     # for all input lines
                    #print("before first line")
                    #if line=="": break
                    #if line==None: break
                    markIn=line[0:mlen]

                    #if cmdList.find("m")>-1 :           # always show markers
                    if(line[:mlen]== marker):            # is it a marker line
                        markCnt+=1
                        llen=len(line)
                        filename=line[mlen:llen-1]       # get filename without LF
                        print(filename)
                    #if end
                    ##if end
                    isY=False
                    if cmdList.find("c")>-1 :
                        if line.find("class ")>-1: isY=True           # is it an class line
                        if isY :
                            llen=len(line)
                            pline="  "+line[:llen-1]       # get line without LF
                            print(pline)
                        #if end
                    #if end
                    isY=False
                    if cmdList.find("i")>-1 :
                        if line.find("import ")>-1: isY=True           # is it an import line
                        if isY :
                            llen=len(line)
                            pline=" "+line[:llen-1]       # get line without LF
                            print(pline)
                        #if end
                    #if end
                    isY=False
                    if cmdList.find("g")>-1 :
                        if line.find("global ")>-1: isY=True           # is it a global line
                        if line.find("global(")>-1: isY=True           # is it a global line
                        if isY :
                            llen=len(line)
                            pline="  "+line[:llen-1]       # get line without LF
                            print(pline)
                        #if end
                    #if end
                    isY=False
                    if cmdList.find("s")>-1 :
                        if line.find("source:")>-1: isY=True           # is it a source line
                        if line.find("Source:")>-1: isY=True           # is it a Source line
                        if isY :
                            llen=len(line)
                            pline="  "+line[:llen-1]       # get line without LF
                            print(pline)
                        #if end
                    #if end
                    isY=False
                    if cmdList.find("d")>-1 :
                        if line.find("def " )>-1: isY=True           # is it a def line
                        if line.find("#def ")>-1: isY=False
                        if isY :
                            llen=len(line)
                            pline="  "+line[:llen-1]       # get line without LF
                            print(pline)
                        #if end
                    #if end
                #for end
                if markCnt==0 : print("#::: WARNING: pkg has no markers")
            print("#::: end of list by n.py")
        #if end
    #if end
#def end names

if __name__ == '__main__' : names( )
#end of n.py
::::::::::textpak=>n_v03.py.txt
#! /usr/bin/python3

# !/usr/local/bin/python  deprecated for Raspberry Pi
# IX_textnames.py renamed and enhanced to n.py vsn
# by D@CC on 2022CMar26
# 2022CMar25 added lNo (input line numbers) & function uses: "calls"
####################################################################
# first line (shebang) must be #! /usr/bin/python3                 #
# place the n.py and the package into Desktop and Sandbox          #
#                                                                  #
# Usage:  >$ cd Desktop/                                           #
#         >sudo chmod +x n.py                                      #
#         >$ python3 ../n.py  < ../adcRead_pkg.py                  #
# or:     >$ cd Desktop                                            #
#         >$ ./n.py -acdghimosu < adcRead_pkg.py                   #
# NB In terminal, the above should list the names of the           #
#       files that exist in the package or file named in stdin.    #
# NB recently added is the listing of used-functions i.e. "calls"  #
# NB now, can also list packages using true O'Reilly markers       # 
#                    but excluding many std python functions       #
# Due to the Unix trick line 1 "#!/usr...                          #
#     and the last line if __name__ ...  mainroutine()             #
# the command line below works (afer chmod ...):                   #
# >$ ./n.py -all <adcRead_pkg.py                                   #
####################################################################


# from textpack import marker            # use common separator key but

def mainroutine():

    vsn="v03"    # of mainroutine
    import sys
    from functionList_pkg import functionList
    from functionList_pkg import posNxFnUsed

    # functionList_v & posNxFnUsed_v are called in -h (help)

    marker = '#' + ':'*10 + 'textpak=>'      # the IX Marker is different
    omarker = ':'*10 + 'textpak=>'           # the original O'Reilly Marker
    mlen = len(marker)                       # file names appear after markers
    olen = len(omarker)

    cmdList0="[n]"  #default value
    argStr=str(sys.argv[1:])
    #print("argStr1:"+argStr)
    alen=len(argStr)
    argExt=argStr[alen-5:alen-2]
    #print("argExt:"+argExt)
    isBadArg=False
    if argExt==".py": isBadArg=True              #flag a Bad Argument
    if argExt.find("pkg")>-1 : isBadArg=True     #flag a Bad Argument
    #if end
    if isBadArg==True:
        continueDoh=True
        print('#::: Be sure to precede the Pkg name with a "<".')   
        return #from names    
    else:
        #print("argStr2:"+argStr)  
        #print("cmdList02:"+cmdList0)
        if False:
            continueDoh=True
        else:
            #print("argStr3:"+argStr)
            #for cmdList in sys.argv[1:]:
            if argStr=="[]": 
                cmdList=cmdList0
            else:
                cmdList=argStr
            #if end
            #print("cmdList3:"+cmdList)
            if cmdList.find("h")>-1 :
                uS="_"
                print("#:::: Help for python n.py "+vsn+" [IX pkg names list pgm]")
                print("#:::: Syntax: ./n.py [args] <pkg")
                print('#:::: Enhanced args = -acdghimosu_ or null')
                print("#:::: a:all,c:class,d:def,g:global,h:help,i:import,m:marker,")
                print('#::::    o:oreillyMarkers,s:source:,u:usedfunctions,_:"_'+'_"')
                print("#:::: NB use IX_textpack.py to create an IX package")
                print('#:::: NB for more help info see: IX_textpack.txt')
                print('#:::: NB IX marker is "#::::::::::'+'textpak=>"')
                print("#:::: (Cudos to:O'Reilly for textpack.py)")
                print("#:::: Source: http://index-of.es/Programming/Python/O'Reilly%20-%20Programming%20Python,%203rd%20Ed%20Aug2006.pdf")
                print("#:::: NB not to be confused with the Textpack pkg")

                v="unknown"

                print("#::::   mainroutine:n.py:  "+vsn)
                print("#::::   posNxFnUsed  vsn:  v",posNxFnUsed("",0,"?") )
                print("#::::   functionList vsn:  "+functionList("","?") )
                return   #from names 
            #if end
            if cmdList.find("all")>-1 :
               cmdList="-cdimogsu"     #all means list all (except h_)
            #endif
            if cmdList.find("a")>-1 :
               cmdList="-cdimogs"     #a means list all (except hu)
            #endif
            if cmdList.find("<")>-1 :
                print("#:::: ERROR precede the < with a space")
                return   #from names 
            #if end
            print("#::: Enhanced n.py "+vsn+" [IX pkg names list prg -h for help]:")
            
            if True:
                lNo=0
                markCnt=0
                for line in sys.stdin.readlines(  ):     # for all input lines
                    lNo=lNo+1
                    #print("before first line")
                    #if line=="": break
                    #if line==None: break
                    markIn=line[0:mlen]

                    #if cmdList.find("m")>-1 :           # always show markers
                    #if markCnt==0:
                    if False :
                        print("mlen:",mlen)
                        print("line.mlen:"+line[:mlen])
                        print("mkr:"+marker)
                    #if end
                    if(line[:mlen]== marker):            # is it a marker line
                        markCnt+=1
                        llen=len(line)
                        filename=line[mlen:llen-1]       # get filename without LF
                        print("#",lNo, "m "+filename)
                    #if end
                    #if cmdList.find("o")>-1 functionList on line:           # also show oreilly markers
                    if(line[:olen]== omarker):            # is it a o-marker line
                        markCnt+=1
                        llen=len(line)
                        filename=line[olen:llen-1]       # get filename without LF
                        print()
                        print("#",lNo, "o "+filename+" oooooooo Oreilly marker oooooooo")
                        print()
                    #if end
                    ##if end
                    isY=False
                    if cmdList.find("c")>-1 :
                        if line.find("class ")>-1: isY=True           # is it an class line
                        if isY :
                            llen=len(line)
                            pline="  "+line[:llen-1]       # get line without LF
                            print("#",lNo,pline)
                        #if end
                    #if end 
                    isY=False
                    if cmdList.find("i")>-1 :
                        if line.find("import ")>-1: isY=True           # is it an import line
                        if isY :
                            llen=len(line)
                            pline=" "+line[:llen-1]       # get line without LF
                            print("#",lNo,pline)
                        #if end
                    #if end
                    isY=False
                    if cmdList.find("g")>-1 :
                        if line.find("global ")>-1: isY=True           # is it a global line
                        if line.find("global(")>-1: isY=True           # is it a global line
                        if isY :
                            llen=len(line)
                            pline="  "+line[:llen-1]       # get line without LF
                            print("#",lNo,pline)
                        #if end
                    #if end
                    isY=False
                    if cmdList.find("s")>-1 :
                        if line.find("source:"     )>-1: isY=True     # is it a source line
                        if line.find("Source:"     )>-1: isY=True     # is it a Source line
                        if line.find("Web Source M")>-1: isY=True     # is it a Source line
                        if isY :
                            llen=len(line)
                            pline="  "+line[:llen-1]       # get line without LF
                            print("#",lNo,pline)
                        #if end
                    #if end
                    isY=False
                    uS="_"
                    if cmdList.find("_")>-1 :
                        if line.find(uS+uS)>-1: isY=True           # is it a source line
                        if isY :
                            llen=len(line)
                            pline="  "+line[:llen-1]       # get line without LF
                            print("#",lNo,pline)
                        #if end
                    #if end
                    isY=False
                    if cmdList.find("u")>-1 :
                        #print("in n.py before calling functionListNew")
                        for fName in functionList(line,0):

                            isY=True                     # default is to print the function name
                            #                            # but don't print std python function names
                            pyL=    ",if,append,close,cleanup,exit,fltest,find,findall,finditer"
                            pyL=pyL+",globals,imorts,input,int,len,lstrip"
                            pyL=pyL+",names,number,not,open"
                            pyL=pyL+",output,pac,print,read,range,read,readline,readlines"
                            pyL=pyL+",remove,replace,rstrip,search,sleep,start,split,str"
                            pyL=pyL+",strip,system,time,type,sub,write,yield,"
                            if fName in pyL: isY=False
                            if False :
                                if  fName=="if"     :isY=False           # bad
                                #if  fName=="functionList" :isY=False    #in IX
                                if  fName=="globals" :isY=False          #IX main test
                                if  fName=="imports" :isY=False          #IX main test
                                if  fName=="mainroutine"  :isY=False     #IX main test
                                if  fName=="names"  :isY=False           #IX main test
                                #if  fName=="output"  :isY=False
                                #if  fName=="posNFnUsed" :isY=False      #in IX
                                #if  fName=="setup"  :isY=False
                                #if  fName=="setmode"  :isY=False
                                #if  fName=="SMBus" :isY=False           #in IX
                            #if end
                            if cmdList.find("d")>-1 :
                                if line.find("def ") >-1 :  #so "d" will also print it out
                                    isY=False               #so don't print it twice
                                #if end
                            #if end
                            if isY :
                                print("#",lNo,"   "+fName+"()")
                                #print("#",lNo,line)
                            #if end
                        #for end
                    #if end
                    isY=False
                    if cmdList.find("d")>-1 :
                        if line.find("def " )>-1:
                            isY=True           # is it a def line
                            #defList=defList+[1]
                        if line.find("#def ")>-1: isY=False
                        if line.find("#end def ")>-1: isY=False
                        if line.find("#def end ")>-1: isY=False
                        if isY :
                            llen=len(line)
                            pline="  "+line[:llen-1]       # get line without LF
                            print("#",lNo,pline)
                        #if end
                    #if end
                #for end
                if markCnt==0 : print("#::: WARNING: pkg has no markers")
            print("#",lNo,"eof")
            print("#::: end of list by n.py "+vsn)
        #if end
    #if end
#def end mainroutine

if __name__ == '__main__' : mainroutine( )
#end of n.py
::::::::::textpak=>n_v04.py.txt
#! /usr/bin/python3

# !/usr/local/bin/python  deprecated for Raspberry Pi
# IX_textnames.py renamed and enhanced to n.py vsn
# by D@CC on 2022CMar26
# 2022CMar25 added lNo (input line numbers) & function uses: "calls"
####################################################################
# first line (shebang) must be #! /usr/bin/python3                 #
# place the n.py and the package into Desktop and Sandbox          #
#                                                                  #
# Usage:  >$ cd Desktop/                                           #
#         >sudo chmod +x n.py                                      #
#         >$ python3 ../n.py  < ../adcRead_pkg.py                  #
# or:     >$ cd Desktop                                            #
#         >$ ./n.py -acdghimosu < adcRead_pkg.py                   #
# NB In terminal, the above should list the names of the           #
#       files that exist in the package or file named in stdin.    #
# NB recently added is the listing of used-functions i.e. "calls"  #
# NB now, can also list packages using true O'Reilly markers       # 
#                    but excluding many std python functions       #
# Due to the Unix trick line 1 "#!/usr...                          #
#     and the last line if __name__ ...  mainroutine()             #
# the command line below works (afer chmod ...):                   #
# >$ ./n.py -all <adcRead_pkg.py                                   #
####################################################################


# from textpack import marker            # use common separator key but

def mainroutine():

    vsn="v03"    # of mainroutine
    import sys
    from functionList_pkg import functionList
    from functionList_pkg import posNxFnUsed

    # functionList_v & posNxFnUsed_v are called in -h (help)

    marker = '#' + ':'*10 + 'textpak=>'      # the IX Marker is different
    omarker = ':'*10 + 'textpak=>'           # the original O'Reilly Marker
    mlen = len(marker)                       # file names appear after markers
    olen = len(omarker)

    cmdList0="[n]"  #default value
    argStr=str(sys.argv[1:])
    #print("argStr1:"+argStr)
    alen=len(argStr)
    argExt=argStr[alen-5:alen-2]
    #print("argExt:"+argExt)
    isBadArg=False
    if argExt==".py": isBadArg=True              #flag a Bad Argument
    if argExt.find("pkg")>-1 : isBadArg=True     #flag a Bad Argument
    #if end
    if isBadArg==True:
        continueDoh=True
        print('#::: Be sure to precede the Pkg name with a "<".')   
        return #from names    
    else:
        #print("argStr2:"+argStr)  
        #print("cmdList02:"+cmdList0)
        if False:
            continueDoh=True
        else:
            #print("argStr3:"+argStr)
            #for cmdList in sys.argv[1:]:
            if argStr=="[]": 
                cmdList=cmdList0
            else:
                cmdList=argStr
            #if end
            #print("cmdList3:"+cmdList)
            if cmdList.find("h")>-1 :
                uS="_"
                print("#:::: Help for python n.py "+vsn+" [IX pkg names list pgm]")
                print("#:::: Syntax: ./n.py [args] <pkg")
                print('#:::: Enhanced args = -acdghimosu_ or null')
                print("#:::: a:all,c:class,d:def,g:global,h:help,i:import,m:marker,")
                print('#::::    o:oreillyMarkers,s:source:,u:usedfunctions,_:"_'+'_"')
                print("#:::: NB use IX_textpack.py to create an IX package")
                print('#:::: NB for more help info see: IX_textpack.txt')
                print('#:::: NB IX marker is "#::::::::::'+'textpak=>"')
                print("#:::: (Cudos to:O'Reilly for textpack.py)")
                print("#:::: Source: http://index-of.es/Programming/Python/O'Reilly%20-%20Programming%20Python,%203rd%20Ed%20Aug2006.pdf")
                print("#:::: NB not to be confused with the Textpack pkg")

                v="unknown"

                print("#::::   mainroutine:n.py:  "+vsn)
                print("#::::   posNxFnUsed  vsn:  v",posNxFnUsed("",0,"?") )
                print("#::::   functionList vsn:  "+functionList("","?") )
                return   #from names 
            #if end
            if cmdList.find("all")>-1 :
               cmdList="-cdimogsu"     #all means list all (except h_)
            #endif
            if cmdList.find("a")>-1 :
               cmdList="-cdimogs"     #a means list all (except hu)
            #endif
            if cmdList.find("<")>-1 :
                print("#:::: ERROR precede the < with a space")
                return   #from names 
            #if end
            print("#::: Enhanced n.py "+vsn+" [IX pkg names list prg -h for help]:")
            
            if True:
                lNo=0
                markCnt=0
                for line in sys.stdin.readlines(  ):     # for all input lines
                    lNo=lNo+1
                    #print("before first line")
                    #if line=="": break
                    #if line==None: break
                    markIn=line[0:mlen]

                    #if cmdList.find("m")>-1 :           # always show markers
                    #if markCnt==0:
                    if False :
                        print("mlen:",mlen)
                        print("line.mlen:"+line[:mlen])
                        print("mkr:"+marker)
                    #if end
                    if(line[:mlen]== marker):            # is it a marker line
                        markCnt+=1
                        llen=len(line)
                        filename=line[mlen:llen-1]       # get filename without LF
                        print("#",lNo, "m "+filename)
                    #if end
                    #if cmdList.find("o")>-1 functionList on line:           # also show oreilly markers
                    if(line[:olen]== omarker):            # is it a o-marker line
                        markCnt+=1
                        llen=len(line)
                        filename=line[olen:llen-1]       # get filename without LF
                        print()
                        print("#",lNo, "o "+filename+" oooooooo Oreilly marker oooooooo")
                        print()
                    #if end
                    ##if end
                    isY=False
                    if cmdList.find("c")>-1 :
                        if line.find("class ")>-1: isY=True           # is it an class line
                        if isY :
                            llen=len(line)
                            pline="  "+line[:llen-1]       # get line without LF
                            print("#",lNo,pline)
                        #if end
                    #if end 
                    isY=False
                    if cmdList.find("i")>-1 :
                        if line.find("import ")>-1: isY=True           # is it an import line
                        if isY :
                            llen=len(line)
                            pline=" "+line[:llen-1]       # get line without LF
                            print("#",lNo,pline)
                        #if end
                    #if end
                    isY=False
                    if cmdList.find("g")>-1 :
                        if line.find("global ")>-1: isY=True           # is it a global line
                        if line.find("global(")>-1: isY=True           # is it a global line
                        if isY :
                            llen=len(line)
                            pline="  "+line[:llen-1]       # get line without LF
                            print("#",lNo,pline)
                        #if end
                    #if end
                    isY=False
                    if cmdList.find("s")>-1 :
                        if line.find("source:"     )>-1: isY=True     # is it a source line
                        if line.find("Source:"     )>-1: isY=True     # is it a Source line
                        if line.find("Web Source M")>-1: isY=True     # is it a Source line
                        if isY :
                            llen=len(line)
                            pline="  "+line[:llen-1]       # get line without LF
                            print("#",lNo,pline)
                        #if end
                    #if end
                    isY=False
                    uS="_"
                    if cmdList.find("_")>-1 :
                        if line.find(uS+uS)>-1: isY=True           # is it a source line
                        if isY :
                            llen=len(line)
                            pline="  "+line[:llen-1]       # get line without LF
                            print("#",lNo,pline)
                        #if end
                    #if end
                    isY=False
                    if cmdList.find("u")>-1 :
                        #print("in n.py before calling functionListNew")
                        for fName in functionList(line,0):

                            isY=True                     # default is to print the function name
                            #                            # but don't print std python function names
                            pyL=    ",if,append,close,cleanup,exit,fltest,find,findall,finditer"
                            pyL=pyL+",globals,imorts,input,int,len,lstrip"
                            pyL=pyL+",names,number,not,open"
                            pyL=pyL+",output,pac,print,read,range,read,readline,readlines"
                            pyL=pyL+",remove,replace,rstrip,search,sleep,start,split,str"
                            pyL=pyL+",strip,system,time,type,sub,write,yield,"
                            if fName in pyL: isY=False
                            if False :
                                if  fName=="if"     :isY=False           # bad
                                #if  fName=="functionList" :isY=False    #in IX
                                if  fName=="globals" :isY=False          #IX main test
                                if  fName=="imports" :isY=False          #IX main test
                                if  fName=="mainroutine"  :isY=False     #IX main test
                                if  fName=="names"  :isY=False           #IX main test
                                #if  fName=="output"  :isY=False
                                #if  fName=="posNFnUsed" :isY=False      #in IX
                                #if  fName=="setup"  :isY=False
                                #if  fName=="setmode"  :isY=False
                                #if  fName=="SMBus" :isY=False           #in IX
                            #if end
                            if cmdList.find("d")>-1 :
                                if line.find("def ") >-1 :  #so "d" will also print it out
                                    isY=False               #so don't print it twice
                                #if end
                            #if end
                            if isY :
                                print("#",lNo,"   "+fName+"()")
                                #print("#",lNo,line)
                            #if end
                        #for end
                    #if end
                    isY=False
                    if cmdList.find("d")>-1 :
                        if line.find("def " )>-1:
                            isY=True           # is it a def line
                            #defList=defList+[1]
                        if line.find("#def ")>-1: isY=False
                        if line.find("#end def ")>-1: isY=False
                        if line.find("#def end ")>-1: isY=False
                        if isY :
                            llen=len(line)
                            pline="  "+line[:llen-1]       # get line without LF
                            print("#",lNo,pline)
                        #if end
                    #if end
                #for end
                if markCnt==0 : print("#::: WARNING: pkg has no markers")
            print("#",lNo,"eof")
            print("#::: end of list by n.py "+vsn)
        #if end
    #if end
#def end mainroutine

if __name__ == '__main__' : mainroutine( )
#end of n.py
::::::::::textpak=>n_v05.py.txt
#! /usr/bin/python3

# !/usr/local/bin/python  deprecated for Raspberry Pi
# IX_textnames.py renamed and enhanced to n.py vsn
# by D@CC on 2022CMar26
# 2022CMar25 added lNo (input line numbers) & function uses: "calls"
####################################################################
# first line (shebang) must be #! /usr/bin/python3                 #
# place the n.py and the package into Desktop and Sandbox          #
# Version: v05 by D@CC on 2024BFeb08    2 edits                    #
#                                                                  #
# Usage:  >$ cd Desktop/                                           #
#         >sudo chmod +x n.py                                      #
#         >$ python3 ../n.py  < ../adcRead_pkg.py                  #
# or:     >$ cd Desktop                                            #
#         >$ ./n.py -acdghimosu < adcRead_pkg.py                   #
# NB In terminal, the above should list the names of the           #
#       files that exist in the package or file named in stdin.    #
# NB recently added is the listing of used-functions i.e. "calls"  #
# NB now, can also list packages using true O'Reilly markers       # 
#                    but excluding many std python functions       #
# Due to the Unix trick line 1 "#!/usr...                          #
#     and the last line if __name__ ...  mainroutine()             #
# the command line below works (afer chmod ...):                   #
# >$ ./n.py -all <adcRead_pkg.py                                   #
####################################################################


# from textpack import marker            # use common separator key but

def mainroutine():

    vsn="v05"    # of mainroutine
    import sys
    from functionList_pkg import functionList
    from functionList_pkg import posNxFnUsed

    # functionList_v & posNxFnUsed_v are called in -h (help)

    marker = '#' + ':'*10 + 'textpak=>'      # the IX Marker is different
    omarker = ':'*10 + 'textpak=>'           # the original O'Reilly Marker
    mlen = len(marker)                       # file names appear after markers
    olen = len(omarker)

    cmdList0="[n]"  #default value
    argStr=str(sys.argv[1:])
    #print("argStr1:"+argStr)
    alen=len(argStr)
    argExt=argStr[alen-5:alen-2]
    #print("argExt:"+argExt)
    isBadArg=False
    if argExt==".py": isBadArg=True              #flag a Bad Argument
    if argExt.find("pkg")>-1 : isBadArg=True     #flag a Bad Argument
    #if end
    if isBadArg==True:
        continueDoh=True
        print('#::: Be sure to precede the Pkg name with a "<".')   
        return #from names    
    else:
        #print("argStr2:"+argStr)  
        #print("cmdList02:"+cmdList0)
        if False:
            continueDoh=True
        else:
            #print("argStr3:"+argStr)
            #for cmdList in sys.argv[1:]:
            if argStr=="[]": 
                cmdList=cmdList0
            else:
                cmdList=argStr
            #if end
            #print("cmdList3:"+cmdList)
            if cmdList.find("h")>-1 :
                uS="_"
                print("#:::: Help for python n.py "+vsn+" [IX pkg names list pgm]")
                print("#:::: Syntax: ./n.py [args] <pkg")
                print('#:::: Enhanced args = -acdghimosu_ or null')
                print("#:::: a:all,c:class,d:def,g:global,h:help,i:import,m:marker,")
                print('#::::    o:oreillyMarkers,s:source:,u:usedfunctions,_:"_'+'_"')
                print("#:::: NB use IX_textpack.py to create an IX package")
                print('#:::: NB for more help info see: IX_textpack.txt')
                print('#:::: NB IX marker is "#::::::::::'+'textpak=>"')
                print("#:::: (Cudos to:O'Reilly for textpack.py)")
                print("#:::: Source: http://index-of.es/Programming/Python/O'Reilly%20-%20Programming%20Python,%203rd%20Ed%20Aug2006.pdf")
                print("#:::: NB not to be confused with the Textpack pkg")

                v="unknown"

                print("#::::   mainroutine:n.py:  "+vsn)
                print("#::::   posNxFnUsed  vsn:  v",posNxFnUsed("",0,"?") )
                print("#::::   functionList vsn:  "+str(functionList("","?") )) #v05
                return   #from names 
            #if end
            if cmdList.find("all")>-1 :
               cmdList="-cdimogsu"     #all means list all (except h_)
            #endif
            if cmdList.find("a")>-1 :
               cmdList="-cdimogs"     #a means list all (except hu)
            #endif
            if cmdList.find("<")>-1 :
                print("#:::: ERROR precede the < with a space")
                return   #from names 
            #if end
            print("#::: Enhanced n.py "+vsn+" [IX pkg names list prg -h for help]:")
            
            if True:
                lNo=0
                markCnt=0
                for line in sys.stdin.readlines(  ):     # for all input lines
                    lNo=lNo+1
                    #print("before first line")
                    #if line=="": break
                    #if line==None: break
                    markIn=line[0:mlen]

                    #if cmdList.find("m")>-1 :           # always show markers
                    #if markCnt==0:
                    if False :
                        print("mlen:",mlen)
                        print("line.mlen:"+line[:mlen])
                        print("mkr:"+marker)
                    #if end
                    if(line[:mlen]== marker):            # is it a marker line
                        markCnt+=1
                        llen=len(line)
                        filename=line[mlen:llen-1]       # get filename without LF
                        print("#",lNo, "m "+filename)
                    #if end
                    #if cmdList.find("o")>-1 functionList on line:           # also show oreilly markers
                    if(line[:olen]== omarker):            # is it a o-marker line
                        markCnt+=1
                        llen=len(line)
                        filename=line[olen:llen-1]       # get filename without LF
                        print()
                        print("#",lNo, "o "+filename+" oooooooo Oreilly marker oooooooo")
                        print()
                    #if end
                    ##if end
                    isY=False
                    if cmdList.find("c")>-1 :
                        if line.find("class ")>-1: isY=True           # is it an class line
                        if isY :
                            llen=len(line)
                            pline="  "+line[:llen-1]       # get line without LF
                            print("#",lNo,pline)
                        #if end
                    #if end 
                    isY=False
                    if cmdList.find("i")>-1 :
                        if line.find("import ")>-1: isY=True           # is it an import line
                        if isY :
                            llen=len(line)
                            pline=" "+line[:llen-1]       # get line without LF
                            print("#",lNo,pline)
                        #if end
                    #if end
                    isY=False
                    if cmdList.find("g")>-1 :
                        if line.find("global ")>-1: isY=True           # is it a global line
                        if line.find("global(")>-1: isY=True           # is it a global line
                        if isY :
                            llen=len(line)
                            pline="  "+line[:llen-1]       # get line without LF
                            print("#",lNo,pline)
                        #if end
                    #if end
                    isY=False
                    if cmdList.find("s")>-1 :
                        if line.find("source:"     )>-1: isY=True     # is it a source line
                        if line.find("Source:"     )>-1: isY=True     # is it a Source line
                        if line.find("Web Source M")>-1: isY=True     # is it a Source line
                        if isY :
                            llen=len(line)
                            pline="  "+line[:llen-1]       # get line without LF
                            print("#",lNo,pline)
                        #if end
                    #if end
                    isY=False
                    uS="_"
                    if cmdList.find("_")>-1 :
                        if line.find(uS+uS)>-1: isY=True           # is it a source line
                        if isY :
                            llen=len(line)
                            pline="  "+line[:llen-1]       # get line without LF
                            print("#",lNo,pline)
                        #if end
                    #if end
                    isY=False
                    if cmdList.find("u")>-1 :
                        #print("in n.py before calling functionListNew")
                        for fName in functionList(line,0):

                            isY=True                     # default is to print the function name
                            #                            # but don't print std python function names
                            pyL=    ",if,append,close,cleanup,exit,fltest,find,findall,finditer"
                            pyL=pyL+",globals,imports,input,int,len,lstrip" #v05
                            pyL=pyL+",names,number,not,open"
                            pyL=pyL+",output,pac,print,read,range,read,readline,readlines"
                            pyL=pyL+",remove,replace,rstrip,search,sleep,start,split,str"
                            pyL=pyL+",strip,system,time,type,sub,write,yield,"
                            if fName in pyL: isY=False
                            if False :
                                if  fName=="if"     :isY=False           # bad
                                #if  fName=="functionList" :isY=False    #in IX
                                if  fName=="globals" :isY=False          #IX main test
                                if  fName=="imports" :isY=False          #IX main test
                                if  fName=="mainroutine"  :isY=False     #IX main test
                                if  fName=="names"  :isY=False           #IX main test
                                #if  fName=="output"  :isY=False
                                #if  fName=="posNFnUsed" :isY=False      #in IX
                                #if  fName=="setup"  :isY=False
                                #if  fName=="setmode"  :isY=False
                                #if  fName=="SMBus" :isY=False           #in IX
                            #if end
                            if cmdList.find("d")>-1 :
                                if line.find("def ") >-1 :  #so "d" will also print it out
                                    isY=False               #so don't print it twice
                                #if end
                            #if end
                            if isY :
                                print("#",lNo,"   "+fName+"()")
                                #print("#",lNo,line)
                            #if end
                        #for end
                    #if end
                    isY=False
                    if cmdList.find("d")>-1 :
                        if line.find("def " )>-1:
                            isY=True           # is it a def line
                            #defList=defList+[1]
                        if line.find("#def ")>-1: isY=False
                        if line.find("#end def ")>-1: isY=False
                        if line.find("#def end ")>-1: isY=False
                        if isY :
                            llen=len(line)
                            pline="  "+line[:llen-1]       # get line without LF
                            print("#",lNo,pline)
                        #if end
                    #if end
                #for end
                if markCnt==0 : print("#::: WARNING: pkg has no markers")
            print("#",lNo,"eof")
            print("#::: end of list by n.py "+vsn)
        #if end
    #if end
#def end mainroutine

if __name__ == '__main__' : mainroutine( )
#end of n_v05.py
::::::::::textpak=>pack.py.txt
def pack():
    #by D@CC
    #on 7/2/2021  2021GJul02
    import sys                       # load the system module
    # must invoke on CLI followed by " >resultFileName"
    #move marker statement here
    #maybe: move marker statement into the pack function
    marker = ':'*10 + 'textpak=>'    # hopefully unique separator
    for name in sys.argv[1:]:        # for all command-line arguments
        input = open(name, 'r')      # open the next input file
        print marker + name          # write a separator line
        print input.read(  ),        # and write the file's contents
    #if __name__ == '__main__': pack(  )  # pack files listed on cmdline
    #Web Source:https://www.oreilly.com/library/view/programming-python-second/0596000855/ch04s05.html
    #end def textpack_py.py
    #/pack_py.py
#def end
******************************************************
/pack.py.txt
::::::::::textpak=>parseComplex.py.txt
#import cmath
def parseComplex(x,y):
    #Complex=('3+5j')
    xComplex=complex(x,y)
    print("xComplex:",xComplex)
    xReal=xComplex.real
    print("xReal:",xReal)
    #xImag=xComplex.imag
    #print("xImag:",xImag)
    y=2*xComplex
    print("y:",y)
    return
#end def

    
::::::::::textpak=>picoButton_pico.py.txt
# This example uses Maker Pi Pico
import machine
import utime


#by PicoLe-22  (D@CC)
#on 2021EMay24
progName="picoButton_pico.py"
print(progName)

button22 = machine.Pin(22, machine.Pin.IN)
while True:
	state=button22.value()
	print("GP22 button (active low) state:",state)
	utime.sleep(1)
#end while

# picoButton_pico.py
# source: https://github.com/CytronTechnologies/MAKER-PI-PICO/blob/main/Example%20Code/MicroPython/maker-pi-pico-rgb-led.py
# date: 2021EMay24
#/picoButton_pico.py.txt
::::::::::textpak=>PixObj.py.txt
#IXled_onboard.py
def value(s1):
    return
#/IXled_onboard.py
#IXmachine.py
def Pin(s1,s2):
    return
def machine_Pin_OUT():
    return
def Pin_OUT():
    return
def UART(s1,s2,parity=None,stop=None,bits=None,rx=None,tx=None):
    return
#/IXmachine.py
#uart.py
def any():
    return True
def read(s1):
    return "b'r'"
def write(aStr):
    print()
    print(" at 7 uart.write :"+aStr+":")
    return
#/IXuart.py
#IXutime.py
def sleep(s1):
    return
def time():
    return 0
#/IXutime.py
::::::::::textpak=>printPicoUniqueId.py.txt
#printPicoUniqueID.py
#by D@CC
#Date 2022EMay30

import machine
s = machine.unique_id()
for b in s:
    #print("b:",b,end=" ")
    print(hex(b)[2:],end=" ")
print()
#print("s:",s)
# MMBasic print mm.info(ID)
#List of Pico IDs owned by D@CC as of 2022AJan07
# Pico Unique ID          Item          from   Label        Use
# 36 60 58 38 83 3d 4f 31 Maker Pi Pico Cytron Pico_4f_31  MicroPython Examples
# E6605481DB4             Pi Pico       Cytron Pico_1DB4   MMBasic on picomite

#Source:
# https://forums.raspberrypi.com/viewtopic.php?p=1851234&hilit=read+pico+flash+unique+id#p1851234
#/printPicoUniqueId.py
::::::::::textpak=>printTemp.py.txt
import machine
import utime

#  this worked fine on 2021FJun09 with MPiADC board
#ADC0 with SW2 ON and CDS0 had no effect.
#blowing (w a straw) on the pico R2040 made temp go up 4 degrees.
sensor_temp = machine.ADC(4)
conversion_factor = 3.3 / (65535)
tim0=utime.time()
print("tim0:",tim0)
while True:
	reading = sensor_temp.read_u16() * conversion_factor
	temperature = 27 - (reading - 0.706)/0.001721
	tim=utime.time()-tim0
	print(tim,temperature)
	utime.sleep(2)
#while end
#printTemp.py

::::::::::textpak=>printTempQ.py.txt
import machine
from machine import *
import utime

sensor_temp = machine.ADC(0)
conversion_factor = 3.3 / (65535)
tim0=utime.time()
print("tim0:",tim0)
temp=ADC(ADC.CORE_TEMP)
conversion=3.3/65535
while True:
	reading = sensor_temp.read_u16() * conversion_factor
	temperature = 27 - (reading - 0.706)/0.001721
	tim=utime.time()-tim0
	print(tim,temperature)
	tempR=temp.read_u16()*conversion
	tempNow=tempR
	print("tempNow:",tempNow)
	utime.sleep(2)
#while end
#printTimTemp.py

::::::::::textpak=>printTimTemp_pico.py.txt
import machine
from machine import *
import utime

#by D@CC
#on 2022EMay30

#sensor_temp = machine.ADC(0)  #original code
sensor_temp = machine.ADC(0)
conversion_factor = 3.3 / (65535)
tim0=utime.time()
print("tim0:",tim0)
temp=ADC(ADC.CORE_TEMP)
conversion=3.3/65535
while True:
	reading = sensor_temp.read_u16() * conversion_factor
	temperature = 27 - (reading - 0.706)/0.001721
	tim=utime.time()-tim0
	print(tim,temperature)
	tempR=temp.read_u16()*conversion
	tempNow=tempR
	print("tempNow:",tempNow)
	utime.sleep(2)
#while end
#/printTimTemp_pico.py

::::::::::textpak=>serTxC_[pico_BU2021FJun18_2257.py.txt
import os
import utime
from machine import UART, Pin

#by D@CC
#Date: 2021FJun18
#Note: as of today, partially tested

# all functions and subroutines are at top of program
#  1. bChar()       converts 4 char byte into 1 char
#  2. serTx_pico()  transmits a full serial text message
#  3. txParse()     parses the outgoing text message and calls txChar
#  4. txChar()      adds the char to oP which is the output text packet queue
#  5. sendThisPack  actually transmits a full packet (wo any EOM)
#  6. sendLastPack  actually transmits text (with at least one EOM)
#  7. serRx_pico()  receives  a full serial text message
# testTx          transmits many test messages
# testRx          receives all test messages

#calling parms
#bChar(strB):
#serTx_pico(uartObject,bps=300, txtToBeSent="Hello,World",rxtxEndChar="]",pktSize=16):
#txParse(uartObject, thisMsg, bps=300, msgFormat="SMEPX", T5C=-1, pktSize=16,  eom="]"):
#txChar(char):
#sendThisPack(uartObject, oPIn, eom, pktSize):
#sendLastPack(oPIn, cntSent, cntUsed,  eom = "]", pktSize=16):
#serRx_pico(uartObject, bps=300, timeOut=-1, eom="]"):

def bChar(strB):                                                                   #bChar()
    #  given a string like b'z' this returns the "z"
    # tested by D@CC on 2021FJun15
    
    #strB=input("eg b'h' :")
    b=strB[2:]
    #print("b:"+b)
    c=b[0]
    #c="z"
    #print("bChar("+'"'+strB+ '"):'+c)
    return c
#end def


def serTx_pico(uartObject,bps=300, txtToBeSent="Hello,World",rxtxEndChar="]",pktSize=16):         #serTx_pico#

    print("txtToBeSent:",txtToBeSent,":")
    #every parameter has a default setting except the uartObject (which needs to be defined).
    t5c=50/bps          #   50 bit times = 5 character times
    t10c=100/bps        #  100 bit times = 10 character times
    t1000c=10000/bps    # 10000 bit times = 1000 character times
    
    # requires a uart object (below) to be created before this function is called
    #uart = machine.UART(1, 300, parity=None, stop=1, bits=8, tx=Pin(txPin), rx=Pin(rxPin))
    print("entering serTx_pico.py")
    if rxtxEndChar=="]":
        som = "["
        eom = "]"
    
    msgOut = """
    #S +
    #M +
    #E +
    #P +
    #C"""

    
    
    #where
    #A is the letter "A" meaning "16 bit packets (pktSize)"
    #S is SOM
    #M is Message text to be sent (will be followed by EOM)
    #E is EOM
    #P is the padding characters (enough EOMs to fill the packet)
    #X is t10c  (ten character time delay: "roman numeral X")
    #C is t100c  (100 character time delay: "roman numeral C")
        
    #Most messages will have   msgOut = "AC" "SMEPX"

    #Between messages, the transmitter will send "0" every minute indicating that its alive but
    #has no message to send.
    #Before sending each message the transmitter will send a single "A" which is 0x41 indicating
    #that the following message will be in packets of 16 characters.  In the future when the
    #packet size.
    #changes to 32 characters, the transmitter will precede each message with a single "B"
    #indicating the each packet will contain 32 characters.  This will allow future packet sizes
    #at least as big as 16x16x4 = 1024 characters and total message lengths of around 32768 without
    #using any control characters in the "ascii" preamble.

    #   Future versions will have msgOut = "DSNKMEPX"
    #    with packets having the format:
    #        AX SNKMV MV MV etc MEPX
    #The optional packet of 16 x D permits synchronization
    # 
    #where
    #D  is a full packet of Delete characters (optional for synchronization
    #N is the 2-character packet Number
    #K is the 2-character message character "Kount" including the only the first final EOM
    #V is t5c  (5 character time delay: "roman numeral V")


    #When a receiver starts up (and between messages) it should start by expecting packets of single
    #characters.  It will read a single 8-bit character expecting it to be a "0" meaning an idle transmitter.
    #If it is not a "0", it will read another single 8-bit character expecting it to be an "A".  If it is not an
    #"A",the character will be discarded, but the receiver will presume that it is reading a character
    #stream that is mid-message.  It will read single 8-bit characters searching for a "]" which will indicate
    #that this is the last packet of the message. It will keep reading and discarding all the "]" that it sees.
    #After the last "]", the
    #next 8-bit character should be a "0" or an "A".  The receiver should keep reading and discarding the "0"
    #characters.  When an "A" is finally received (while reading single 8-bit characters), the receiver knows that
    #this means subsequent packets will be packets of 16 characters.  The receiver is now fully
    #synchonized with the transmitter.  If something other than an "A" is received, the receiver should
    #begin looking for a "]" ()meaning "end of message" again.  If the state of "being in mid-message
    #continues 10 times, a human operator should be informed the that this ERROR is occuring.
    #
    #send the message
    txParse(uart,txtToBeSent)       #xyz
    return True
#end def serTx_pico()
def txParse(uartObject, thisMsg, bps=300, msgFormat="SMEPX", T5C=-1, pktSize=16,  eom="]"):    #txParse()
    show("thisMsg:",thisMsg)
#
#    uartObject is the uart being used
#    thisMsg is the full text message to be sent (It should not contain (EOM="]") they will become "?")
#                          (An EOM is added as the last character of a message, do not put the EOM in the msg)
#    bps is the baud rate (bits/sec)
#    msgFormat is the form of the Msg e.g. SMEPX  (first E is counted as last char of M)
#                                                (P is enough additional EOMs to pad to packetSize=16)
#                                               (t5c is interval between packets (-1 defaults to t5c)

#    t5c indicates time interval of 5 characters.  The transmitter will follow each packet with
#       this time delay
#    packetSize defaults to 16
#    eom is the definition of the 'EOM" character (usually "]")
    #oP is the full outgoing Packet that is sent by sendThisPack
    #                                      or by sendLastPack
    oP=""            # outgoing msg is initially empty
    if T5C==-1:    # if the calling routine doesn't specify
       t5c=50/bps
       t10c=100/bps
       t1000c=10000/bps
    else:
        t5c=T5C       #if the calling routine does specify T5C
        t10c=T5C*2
        t1000c=T5C*200
    #end if
    if eom=="]":
        som="["
    #end if

#    in 2021 msgOut="SMEPX"
    lenM=len(thisMsg)+1      #length of thisMsg -1  (+1 for the EOM character
    cntUsed=0                # number of characters in msgOut used so far
    cntSent=0                # number of character actually sent (incl all chars sent)
    isEOMsent=False          #EOM not sent yet
    show("msgFormat:",msgFormat)
    for msgPart in msgFormat:   # do each message segment
        if msgPart=="S":
            # send SOM
            print("send SOM")
            oP=oP+txChar(som)
            oP=oP+txChar("1")      # in future these 2 characters will contain parity or CRC
            oP=oP+txChar("6")      # today they contain the packet size (ie character count)
            cntSent=cntSent+3 #3 actually sent now
            print()
            print("oP:"+oP+":")
        #end if
        if msgPart=="X":     # time delay doesn't send any characters
            utime.sleep(t10c) 
        #end if
        if msgPart=="M":     # sends the msg followed by 1 eom
            print("sending M")
            isLastPack=True
            while (lenM-cntUsed) >= 1 : #lenM incl the EOM, cntUsed does also (after the EOM is sent)
                isLastPack=False
                #  the packet being sent should not include any EOM characters. (EOM is only in the last pk)
                #  send a packet of data w/o eom
                lastChar=cntUsed+pktSize
                show("lastChar",lastChar)
                #thisMsg="12345678901234567"
                print("thisMsg:"+thisMsg+":")
                show("cntUsed",cntUsed)
                show("lastChar",lastChar)
                show("thisMsg[cntUsed:lastChar]",thisMsg[cntUsed:lastChar])
                opToSend=thisMsg[cntUsed:lastChar]
                print("opToSend:"+opToSend+":")
                
                if len(opToSend)>=16 :
                    print()
                    print("before sendThisPack oP:"+oP+":")
                    cntUsedFromMsg=sendThisPack(uartObject,opToSend, eom, pktSize)
                                           #returns 16  should print the Pkt
                    oP=""
                    show("cntUsedFromMsg:",cntUsedFromMsg)
                    cntUsed=cntUsed+cntUsedFromMsg    # should be 16 ...... to verify
                    cntSent=cntSent+16
                    show("lenM",lenM)
                    show("cntUsed",cntUsed)
                    isLastPacket=False
                else:
                    print("need to send padded Packet")
                    isLastPacket=True
                #end if
                leftToSend=lenM-cntUsed-1
                show("leftToSend:",leftToSend)
            
                if isLastPacket==True :       # will send the Last Packet (containing at least 1 EOM)
                    print("isLastPack is True")
                    #useStr=thisStr
                    cntUsedFromMsg=len(opToSend)
                    toAdd=16-cntUsedFromMsg
                    show("toAdd:",toAdd)
                    for x in range(toAdd):      # must insert correct range !!!!!
                        oP=oP+txChar(eom)           # must insert correct char from fullMsg !!!!!
                        cntSent=cntSent+1
                    #end for
                    print()
                    print("before sendThisPack oP:"+oP+":")
                    cntSent=sendThisPack(uartObject,oP, eom, pktSize)
                    #returns 16  should print the Pkt
                    oP=""
                    cntUsed=cntUsed+cntUsedFromMsg
                    show("cntUsed:",cntUsed)
                #end if
                print("after Last Packet of Msg")
                toSend=lenM-cntUsed-1
                show("toSend:",toSend)
                print("end of while")
            #end while                 # the above sent all packets except the last one
            print("after end of while")
        #end if "M"
        print("after while")
        if False :
            if msgPart=="P":                # P means Padding (with more EOMs) if any needs to be sent
                print("msgPart=P")
                if False :
                    if True:     # to be decided
                        oP=oP+txChar(eom)        # how many eoms of padding  !!!!!
                        cntUsed=cntUsed+1
                        cntSent=cntSent+1
                    #end if
                    show("cntUsed",cntUsed)
                    strSent=thisMsg[cntUsed:cntUsed+16]
                    show("strSent:",strSent)
                    cntUsedFromMsg = sendLastPack(uartObject, strSent, eom, pktSize) # should print the Pkt
                    cntUsed=cntUsed+cntUsedFromMsg
                    cntSent=cntSent+pktSize   #pktSize is usually 16
                #end if
            #end if "P"
        #end if False
    #end for    # all msg parts have now been sent
    # should check that cntUsed = len(Msg) +1
    # should check that cntSent is a muliple of pktSize(eg 16)
    return #from parsing and transmitting
#end def
def txChar(char):                                                                       #txChar()        
    #simply records that "char" has been sent
    # just prints it during testing
    # doesn't actually send the char
    print(char, end='') #"end" suppresses the line feed
    return char
#end def

def sendThisPack(uartObject, opIn, eom, pktSize):                        #sendThisPack()
#

#actually sends the 16 characters in oP
    print()
    print("in sendThisPack")
    oP=opIn
    lenopIn=len(opIn)
    if (lenopIn==pktSize)==False:
        print("ERROR",pktSize, "is not the size of the packet to send:",lenopIn)
    #end if
    pos=opIn.find(eom)
    if pos==-1:              # -1 if not found
        pass
    else:
        print("WARNING E in serTx", eom, "found in message")
        oP=oP.replace(eom,"?")  
    #end if
    uartObject.write(oP)
    print("tx sent:"+oP+":")    #keep user informed during testing
    return pktSize
#end def

def mpyRead(uart):
    #keep read1 character packet until timeOut
    txtRead=""
    bRead=""
    while uart.any():

        aByte=str(uart.read(1))
        #show("aByte:",aByte)
        bRead=bChar(aByte)
        #show("bRead:",bRead)
        txtRead=txtRead+bRead
    #end while
    return txtRead
#end def

def sendLastPack(uartObject, opIn,  eom = "]", pktSize=16):                           #sendLastPack()   
#actually sends the character packet in oP
# but pads the packet with "eom"s first
    # replace any eom with "?"
    lenopIn=len(opIn)
    oP=opIn
    pos=oP.find(eom)
    if pos==-1:      # Good: eom not found
        pass
    else:
        print("ERROR E in serTx", eom, "found in message")
        oP.replace(eom,"?")  
    #end if
    len=len(oP)
    #pad packet with eoms
    show("lenOp",lenOp)
    for k in range(16,lenOp):
        oPtoSend=oPtoSend+eom    # add eoms for padding
    #end for    
    lenOp=len(oP)       # is the pktSize correct
    if (lenOp==pktSize)==False:
        print("ERROR",pktSize, "is not the size of the packet to send:",lenOp)
    #end if
    #send the 16 character packet
    uartObject.write(oPtoSend)
    print("tx padded (if needed) and sent:"+oP+":")
    return lenOpIn            # return # of chars used.
#end def

#  serRx_pico()   receives  a full serial text message               #serRx_pico()
def serRx_pico(uartObject, bps=600, timeOut=-1, eom="]"):
    #uart = machine.UART(1,bps, parity=None, stop=1, bits=8, rx=Pin(5), tx=Pin(4))
    print("my uart:",uart)
    #print("timeOut is set to:",timeOut)
    if timeOut==-1:
        t100c = 1000/bps
        timeOutUse=int(t100c+1.0)   #at least 1 sec
        #show("timeOutUse:",timeOutUse)
    else:
        timeOutUse=3   #in seconds
    #end if
    #timeOutUse=t100c
    time=utime.time()
    timeNow=time
    #show("timeNow:",timeNow)
    timeFail=timeNow+timeOutUse    # defaults to a 3 second TimeOut
    #print("waiting my:",timeOutUse," seconds for data receipt. . . . .")
    oP=""  # reset input buffer
    #show("time:",time)
    #show("timeFail:",timeFail)

    while time < timeFail :
        #keep reading any 1 character packets until timeOut
        #print("any")
        strA=mpyRead(uart)
        #show("strA:",strA)
        oP=oP+strA
        #show("oP:",oP)
        #end if
        time=utime.time()
    #end while
    #show("oP:",oP)
    lenOp=len(oP)
    if oP=="":
        print("ERROR T in serRx (): timeOut after",timeOutUse,"seconds")
        lenOp=len(oP)
    #end if
    if lenOp > 0:
        if oP.find("?")==-1:
            pass            # ? not found
        else:
            print("WARNING '?' seen in message received.")
        #end if
    #end if
    #print("serRx() received:"+oP+":")   #during testing
    return oP
#end def serRx_pico(uart,300,timeOut(in secs))

def show(strA,parmA):                                        # show
    print(strA,parmA)
    return
#end def

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

progName="testTxC_pico.py"
print("progName:"+progName)
if True:
    bps=600
    txPin=5
    rxPin=4
    #
    #print sys info
    print(os.uname())       #os, utime and machine were imported at top

    #indicate program started visually (by blinking the green LED)
    led_onboard = machine.Pin(25, machine.Pin.OUT)
    led_onboard.value(0)     # onboard LED OFF for 0.5 sec
    utime.sleep(0.5)
    led_onboard.value(1)    # leaving it ON

    #create uart object sample code
    if False :
        #self.uart = UART(1, 115200, parity=None, stop=1, bits=8, rx=Pin(rxPin), tx=Pin(txPin))
        pass
    #end if

    #create actual uart object
    uart = machine.UART(1,bps, parity=None, stop=1, bits=8, rx=Pin(5), tx=Pin(4))
    #print uart info
    #uart = machine.UART(1)
    print(uart)         # during testing


    #                     create uartObject
    #uart = machine.UART(1,bps, parity=None, stop=1, bits=8, tx=txPin, rx=rxPin)
    #    send a single "A"  which is 0x41 ("A"-0x40 * 16 is the packet length which is 16

    #                                         initialization is complete

    uart.write("A")     #every group of messages is preceeded by a single "A"
    # prior to the "A", the transmitter should send a synchronizing sequence to permit
    #               the (human) receiver to "guess" or "determine" the baud rate (the bps)
    # hopefully the operator of the transmitter and receiver is the same human.

    # the serRx_pico should be running in a separate thread.

    #def serTx_pico(uartObject,bps, txtToBeSent="[UUUUUUUU]",rxtxEndChar="]"):
    serTx_pico(uart,bps, txtToBeSent="Hello,JoeMaxRoyBob")

    if False:
        serTx_pico(uart,bps, txtToBeSent="H")
        serTx_pico(uart,bps, txtToBeSent="H")
        serTx_pico(uart,bps, txtToBeSent="H]")
        serTx_pico(uart,bps, txtToBeSent="[H]")
        serTx_pico(uart,bps, txtToBeSent="2.97")
        serTx_pico(uart,bps, txtToBeSent="99.987654")
        serTx_pico(uart,bps, txtToBeSent="ADC0:(0x4000,1622428309.000j)")
        serTx_pico(uart,bps, txtToBeSent="1234567890123")
        serTx_pico(uart,bps, txtToBeSent="12345678901234")
        serTx_pico(uart,bps, txtToBeSent="Hello,World")
        serTx_pico(uart,bps, txtToBeSent="1234567890123456789012345678901234567890")
    #end if

    if False:
        # the above is the current format of the rxtx protocol
        # The som,eom,t10c and are 1-character special codes
        #    each must be converted into outgoing text or actions or both
        #    all normal text does not need to be converted before transmission
        #
        # The txParse routine analyses the msgOut Format and separates it into
        # special codes (text and actions).  Each special code is sent to the txChar()
        # routine to be processed. Each character of outgoing text is sent to the
        # txChar() routine to be processed.
        #
        # The serTx_pico() routine is used to
        #   transmit a special code of text ("S" and "M")
        #   cause a time delay (V is "t5c X is "t10c  " and M is "t1000c")
        #   transmit msg as 16-byte packets (msg should not contain "]" which is replaced by "?" )
        #
        #   early testing Format is "SMEPX"
        #
        # Note that the "P" also inserts at least 1 "]" character and
        #   enough extra "]" characters (or none) to make a message with an exact multiple
        #   of 16 characters.  This is because there are always 16 characters sent per
        #   packet. Each packet is followed by a time delay of t5c.
        #   The last packet is always followed by a time delay of t10c.
        #   These time delays permit the receiver to resync with the transmitter.
        #   These time delays are never included in the character count of the
        #   message
        #   The serRx_pico() routine times out after an interval of 1000 character times: t1000c
        pass
    #end if

    # This should be run this as a separate thread
    # print whatever has been received
    bps=600
    t100c=1000/bps
    utime.sleep(t100c) #wait for an interval of 100 char times
#end if

#uart = machine.UART(1,bps, parity=None, stop=1, bits=8, tx=Pin(txPin), rx=Pin(rxPin))
bps=600
uart = machine.UART(1,bps, parity=None, stop=1, bits=8, tx=Pin(4), rx=Pin(5))
print("uart:",uart)
if False:
    uart.write("hello")
    t100c=1000/bps
    utime.sleep(t100c) #wait for an interval of 100 char times

    uart.write("Hello,World")
    utime.sleep(t100c) #wait for an interval of 100 char times
    utime.sleep(1)     #1 sec
#if end
if False:
    print("receiving mpy routine")
    while uart.any():
        print(uart.read(1))
    #end while
#end if
charIn=""
if False:
    print("receiving mpy routine")

    if uart.any() :
        #print("reading now")
        charIn=uart.read(1)
        #show("charIn:",charIn)
        #oP=oP+uartObject.read(1)
    #end if
    print("end of mpy routine")
#end if
show("charIn:",charIn)
#end if
print("receiving my routine")
msgIn=serRx_pico(uart,bps=600)   #times out after t100c seconds (100 char-times)
print("msgIn:",msgIn)

print("end of serRX()")

#end /testTxC_pico.py


::::::::::textpak=>serTxC_pico.py.txt
import os
import utime
from machine import UART, Pin

#by D@CC
#Date: 2021FJun18
#Note: as of today, partially tested

# all functions and subroutines are at top of program
#  1. bChar()       converts 4 char byte into 1 char
#  2. serTx_pico()  transmits a full serial text message
#  3. txParse()     parses the outgoing text message and calls txChar
#  4. txChar()      adds the char to oP which is the output text packet queue
#  5. sendThisPack  actually transmits a full packet (wo any EOM)
#  6. sendLastPack  actually transmits text (with at least one EOM)
#  7. serRx_pico()  receives  a full serial text message
# testTx          transmits many test messages
# testRx          receives all test messages

#calling parms
#bChar(strB):
#serTx_pico(uartObject,bps=300, txtToBeSent="Hello,World",rxtxEndChar="]",pktSize=16):
#txParse(uartObject, thisMsg, bps=300, msgFormat="SMEPX", T5C=-1, pktSize=16,  eom="]"):
#txChar(char):
#sendThisPack(uartObject, oPIn, eom, pktSize):
#sendLastPack(oPIn, cntSent, cntUsed,  eom = "]", pktSize=16):
#serRx_pico(uartObject, bps=300, timeOut=-1, eom="]"):

def bChar(strB):                                                                   #bChar()
    #  given a string like b'z' this returns the "z"
    # tested by D@CC on 2021FJun15
    
    #strB=input("eg b'h' :")
    b=strB[2:]
    #print("b:"+b)
    c=b[0]
    #c="z"
    #print("bChar("+'"'+strB+ '"):'+c)
    return c
#end def


def serTx_pico(uartObject,bps=300, txtToBeSent="Hello,World",rxtxEndChar="]",pktSize=16):         #serTx_pico#

    print("txtToBeSent:"+txtToBeSent+":")
    #every parameter has a default setting except the uartObject (which needs to be defined).
    t5c=50/bps          #   50 bit times = 5 character times
    t10c=100/bps        #  100 bit times = 10 character times
    t1000c=10000/bps    # 10000 bit times = 1000 character times
    
    # requires a uart object (below) to be created before this function is called
    #uart = machine.UART(1, 300, parity=None, stop=1, bits=8, tx=Pin(txPin), rx=Pin(rxPin))
    print("entering serTx_pico.py")
    if rxtxEndChar=="]":
        som = "["
        eom = "]"
    
    msgOut = """
    #S +
    #M +
    #E +
    #P +
    #C"""

    
    
    #where
    #A is the letter "A" meaning "16 bit packets (pktSize)"
    #S is SOM
    #M is Message text to be sent (will be followed by EOM)
    #E is EOM
    #P is the padding characters (enough EOMs to fill the packet)
    #X is t10c  (ten character time delay: "roman numeral X")
    #C is t100c  (100 character time delay: "roman numeral C")
        
    #Most messages will have   msgOut = "AC" "SMEPX"

    #Between messages, the transmitter will send "0" every minute indicating that its alive but
    #has no message to send.
    #Before sending each message the transmitter will send a single "A" which is 0x41 indicating
    #that the following message will be in packets of 16 characters.  In the future when the
    #packet size.
    #changes to 32 characters, the transmitter will precede each message with a single "B"
    #indicating the each packet will contain 32 characters.  This will allow future packet sizes
    #at least as big as 16x16x4 = 1024 characters and total message lengths of around 32768 without
    #using any control characters in the "ascii" preamble.

    #   Future versions will have msgOut = "DSNKMEPX"
    #    with packets having the format:
    #        AX SNKMV MV MV etc MEPX
    #The optional packet of 16 x D permits synchronization
    # 
    #where
    #D  is a full packet of Delete characters (optional for synchronization
    #N is the 2-character packet Number
    #K is the 2-character message character "Kount" including the only the first final EOM
    #V is t5c  (5 character time delay: "roman numeral V")


    #When a receiver starts up (and between messages) it should start by expecting packets of single
    #characters.  It will read a single 8-bit character expecting it to be a "0" meaning an idle transmitter.
    #If it is not a "0", it will read another single 8-bit character expecting it to be an "A".  If it is not an
    #"A",the character will be discarded, but the receiver will presume that it is reading a character
    #stream that is mid-message.  It will read single 8-bit characters searching for a "]" which will indicate
    #that this is the last packet of the message. It will keep reading and discarding all the "]" that it sees.
    #After the last "]", the
    #next 8-bit character should be a "0" or an "A".  The receiver should keep reading and discarding the "0"
    #characters.  When an "A" is finally received (while reading single 8-bit characters), the receiver knows that
    #this means subsequent packets will be packets of 16 characters.  The receiver is now fully
    #synchonized with the transmitter.  If something other than an "A" is received, the receiver should
    #begin looking for a "]" ()meaning "end of message" again.  If the state of "being in mid-message
    #continues 10 times, a human operator should be informed the that this ERROR is occuring.
    #
    #send the message
    txParse(uart,txtToBeSent)       #xyz
    print("end of serTx()")
    return True
#end def serTx_pico()
def txParse(uartObject, thisMsg, bps=300, msgFormat="SMEPX", T5C=-1, pktSize=16,  eom="]"):    #txParse()
    show("thisMsg:",thisMsg)
#
#    uartObject is the uart being used
#    thisMsg is the full text message to be sent (It should not contain (EOM="]") they will become "?")
#                          (An EOM is added as the last character of a message, do not put the EOM in the msg)
#    bps is the baud rate (bits/sec)
#    msgFormat is the form of the Msg e.g. SMEPX  (first E is counted as last char of M)
#                                                (P is enough additional EOMs to pad to packetSize=16)
#                                               (t5c is interval between packets (-1 defaults to t5c)

#    t5c indicates time interval of 5 characters.  The transmitter will follow each packet with
#       this time delay
#    packetSize defaults to 16
#    eom is the definition of the 'EOM" character (usually "]")
    #oP is the full outgoing Packet that is sent by sendThisPack
    #                                      or by sendLastPack
    oP=""            # outgoing msg is initially empty
    if T5C==-1:    # if the calling routine doesn't specify
       t5c=50/bps
       t10c=100/bps
       t1000c=10000/bps
    else:
        t5c=T5C       #if the calling routine does specify T5C
        t10c=T5C*2
        t1000c=T5C*200
    #end if
    if eom=="]":
        som="["
    #end if

#    in 2021 msgOut="SMEPX"
    lenM=len(thisMsg)+1      #length of thisMsg -1  (+1 for the EOM character
    cntUsed=0                # number of characters in msgOut used so far
    cntSent=0                # number of character actually sent (incl all chars sent)
    isEOMsent=False          #EOM not sent yet
    show("msgFormat:",msgFormat)
    for msgPart in msgFormat:   # do each message segment
        if msgPart=="S":
            # send SOM
            print("send SOM")
            oP=oP+txChar(som)
            oP=oP+txChar("1")      # in future these 2 characters will contain parity or CRC
            oP=oP+txChar("6")      # today they contain the packet size (ie character count)
            cntSent=cntSent+3 #3 actually sent now
            print()
            print("oP:"+oP+":")
            cntUsed=0
        #end if
        if msgPart=="X":     # time delay doesn't send any characters
            utime.sleep(t10c) 
        #end if
        if msgPart=="M":     # sends the msg followed by 1 eom
            print("sending M")
            #cntSent of the packet is already in oP
            #cntUsed is 0 going into the while
            # note that lenM also includes 1 eom
            # in the while loop, cntUsed will increase until cntUsed=lenM
            while (lenM-cntUsed) >= 1 : #lenM incl the EOM, cntUsed does also (after the EOM is sent)
                print("going into the M while")
                show("upon entry M-while cntUsed:",cntUsed)
                #  the packet being sent should not include any EOM characters. (EOM is only in the last pk)
                #  send a packet of data
                # lastChar is the lastChar of Msg to send in this packet
                cntCanAdd=pktSize-len(oP)
                print("cntCanAdd:",cntCanAdd,":")
                show("cntUsed:",cntUsed)  #should be 0 entering first loop

                cntRemainOfM=lenM-cntUsed-1   #this cnts the remaining chars of M 
                cntToAdd=pktSize-len(oP)    #this cnts the remaining space in oP
                # a packet is always sent in this next "if clause"
                show("cntRemainOfM:",cntRemainOfM)
                show("cntToAdd:",cntToAdd)
                if cntRemainOfM>cntToAdd :
                # this packet cannot hold rest of Msg plus an eom
                    isLastPack=False 
                    opToAdd=thisMsg[cntUsed:cntUsed+cntToAdd]  # to add to oP
                    opToSend=oP+opToAdd                        # to be sent
                    print("AopToSend:"+opToSend+":")
                    cntPadding=0
                    sendThisPack(uartObject, opToSend, cntPadding, eom, pktSize)
                    # that sent a full pkt without any padding
                    cntUsed=cntUsed+cntToAdd+1
                    # remember to count the first EOM as a character in cntUsed
                    show("cntUsed:",cntUsed)
                    show("lenM:",lenM)
                    oP=""
                    cntSent=0
                    #continue the while loop
                else :
                    isLastPack=True
                    # the pkt can hold the whole cntRemainOfM
                    opToAdd=thisMsg[cntUsed:cntUsed+cntRemainOfM]

                    #print("BopToSend:"+opToSend+":")
                    cntPadding=pktSize-cntSent-cntRemainOfM
                    strPadding=eom*cntPadding
                    opToSend=oP+opToAdd+strPadding
                    print("CopToSend:"+opToSend+":")
                    
                    sendLastPack(uartObject, opToSend, cntPadding, eom, pktSize)
                    # that sent a full pkt including the padding                        
                    cntUsed=cntUsed+len(opToAdd)
                    show("lenM:",lenM)
                    show("cntUsed:",cntUsed)
                    oP=""
                    cntSent=0
                    print("after Last Packet of Msg")
                    toSend=lenM-cntUsed
                    show("toSend:",toSend)
                    print("end of while")
                    break            #out of the while
                #if end
                cntUnsent=lenM-cntUsed-1
                show("cntUnsent:",cntUnsent)
                print("repeat the M while")
            #end while                 




            if False :
                # we need to send at least 1 more full packet
                isLastpack=False
                lastChar=cntUsed+(pktSize-len(oP)) #this is lastChar of Msg yet to send
                opToAdd=thisMsg[cntUsed:lastChar]  # to add to oP
                opTosend=oP+opToAdd
                print("opToSend:"+opToSend+":")
                sendThisPack(uartObject, opToSend, eom, pktSize)
                # no padding was necessary
                cntUsed=cntUsed+len(opToAdd)
                show("cntUsed:",cntUsed)
                # the while will loop once more
            #end if
            if False :
                lastChar=pktSize-cntSent
                show("lastChar",lastChar)
                #thisMsg="12345678901234567"
                print("thisMsg:"+thisMsg+":")
                show("cntUsed",cntUsed)
                show("lastChar",lastChar)
                show("thisMsg[cntSent:lastChar]",thisMsg[cntUsed:lastChar])
                opWasSent=thisMsg[cntUsed:lastChar]
                print("opWasSend:"+opWasSend+":")
                if len(opToSend)>=16 :
                    print()
                    print("before sendThisPack oP:"+oP+":")
                    cntSent=sendThisPack(uartObject,opToSend, eom, pktSize)
                                           #returns 16  should print the Pkt
                    oP=""
                    show("cntUsedFromMsg:",cntUsedFromMsg)
                    cntUsed=cntUsed+cntUsedFromMsg    # should be 16 ...... to verify
                    cntSent=cntSent+16
                    show("lenM",lenM)
                    show("cntUsed",cntUsed)
                    isLastPacket=False
                else:
                    print("need to send padded Packet")
                    isLastPacket=True
                #end if
            #end if False
            if False :
                # a packet has just been sent
                leftToSend=lenM-cntUsed-1
                show("leftToSend:",leftToSend)
                if False :
                    if isLastPacket==True :       # will send the Last Packet (containing at least 1 EOM)
                        print("isLastPack is True")
                        #useStr=thisStr
                        cntUsedFromMsg=len(opToSend)
                        oP=opToSend
                        toAdd=16-cntUsedFromMsg
                        show("toAdd:",toAdd)
                        for x in range(toAdd):      # must insert correct range !!!!!
                            oP=oP+txChar(eom)           # must insert correct char from fullMsg !!!!!
                            cntSent=cntSent+1
                        #end for
                        print()
                        print("before sendThisPack oP:"+oP+":")
                        cntSent=sendThisPack(uartObject,oP, eom, pktSize)
                        #returns 16  should print the Pkt
                        oP=""
                        cntUsed=cntUsed+cntUsedFromMsg
                        show("cntUsed:",cntUsed)
                    #end if
                #end if False
                # a packet was just sent
                print("M while might end now")
                print("after end of while")
            #end if False
        #end if "M"

        if False :
            if msgPart=="P":                # P means Padding (with more EOMs) if any needs to be sent
                print("msgPart=P")
                if False :
                    if True:     # to be decided
                        oP=oP+txChar(eom)        # how many eoms of padding  !!!!!
                        cntUsed=cntUsed+1
                        cntSent=cntSent+1
                    #end if
                    show("cntUsed",cntUsed)
                    strSent=thisMsg[cntUsed:cntUsed+16]
                    show("strSent:",strSent)
                    cntUsedFromMsg = sendLastPack(uartObject, strSent, eom, pktSize) # should print the Pkt
                    cntUsed=cntUsed+cntUsedFromMsg
                    cntSent=cntSent+pktSize   #pktSize is usually 16
                #end if
            #end if "P"
        #end if False
        
    #end for    # all msg parts have now been sent
    # should check that cntUsed = len(Msg) +1
    # should check that cntSent is a muliple of pktSize(eg 16)
    return #from parsing and transmitting
#end def
def txChar(char):                                                                       #txChar()        
    #simply records that "char" has been sent
    # just prints it during testing
    # doesn't actually send the char
    print(char, end='') #"end" suppresses the line feed
    return char
#end def

def sendThisPack(uartObject, opIn, cntPadding, eom, pktSize):                        #sendThisPack()
#

#actually sends the 16 characters in oP
    print()
    print("in sendThisPack")
    oP=opIn
    lenopIn=len(opIn)
    if (lenopIn==pktSize)==False:
        print("ERROR",pktSize, "is not the size of the packet to send:",lenopIn)
    #end if
    pos=opIn.find(eom)
    if pos==-1:              # -1 if not found
        pass
    else:
        print("WARNING E in serTx", eom, "found in message")
        oP=oP.replace(eom,"?")  
    #end if
    uartObject.write(oP)
    print("tx sent:"+oP+":")    #keep user informed during testing
    return pktSize
#end def

def sendLastPack(uartObject, opIn, cntPadding, eom, pktSize):                        #sendThisPack()
#

#actually sends the 16 characters in oP
    print()
    print("in sendLastPack")
    oP=opIn
    print("oP:"+oP+":")
    lenopIn=len(opIn)
    show("lenopIn:",lenopIn)
    if (lenopIn==pktSize)==False:
        print("ERROR",pktSize, "is not the size of the packet to send:",lenopIn)
    #end if
    #search for eom in the non-padding portion of oPIn
    suboPIn=opIn[0:pktSize-cntPadding]
    print("suboPIn:"+suboPIn+":")
    pos=suboPIn.find(eom)
    if pos==-1:              # -1 if not found
        pass
    else:
        print("WARNING E in serTx", eom, "found in message")
        oP=oP.replace(eom,"?")  
    #end if
    uartObject.write(oP)
    print("tx sent:"+oP+":")    #keep user informed during testing
    return pktSize
#end def
def mpyRead(uart):
    #keep read1 character packet until timeOut
    txtRead=""
    bRead=""
    while uart.any():

        aByte=str(uart.read(1))
        #show("aByte:",aByte)
        bRead=bChar(aByte)
        #show("bRead:",bRead)
        txtRead=txtRead+bRead
    #end while
    return txtRead
#end def



#  serRx_pico()   receives  a full serial text message               #serRx_pico()
def serRx_pico(uartObject, bps=600, timeOut=-1, eom="]"):
    #uart = machine.UART(1,bps, parity=None, stop=1, bits=8, rx=Pin(5), tx=Pin(4))
    print("my uart:",uart)
    #print("timeOut is set to:",timeOut)
    if timeOut==-1:
        t100c = 1000/bps
        timeOutUse=int(t100c+1.0)   #at least 1 sec
        #show("timeOutUse:",timeOutUse)
    else:
        timeOutUse=3   #in seconds
    #end if
    #timeOutUse=t100c
    time=utime.time()
    timeNow=time
    #show("timeNow:",timeNow)
    timeFail=timeNow+timeOutUse    # defaults to a 3 second TimeOut
    #print("waiting my:",timeOutUse," seconds for data receipt. . . . .")
    oP=""  # reset input buffer
    #show("time:",time)
    #show("timeFail:",timeFail)

    while time < timeFail :
        #keep reading any 1 character packets until timeOut
        #print("any")
        strA=mpyRead(uart)
        #show("strA:",strA)
        oP=oP+strA
        #show("oP:",oP)
        #end if
        time=utime.time()
    #end while
    #show("oP:",oP)
    lenOp=len(oP)
    if oP=="":
        print("ERROR T in serRx (): timeOut after",timeOutUse,"seconds")
        lenOp=len(oP)
    #end if
    if lenOp > 0:
        if oP.find("?")==-1:
            pass            # ? not found
        else:
            print("WARNING '?' seen in message received.")
        #end if
    #end if
    #print("serRx() received:"+oP+":")   #during testing
    return oP
#end def serRx_pico(uart,300,timeOut(in secs))

def show(strA,parmA):                                        # show
    print(strA,parmA)
    return
#end def

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

progName="testTxC_pico.py"
print("progName:"+progName)
if True:
    bps=600
    txPin=5
    rxPin=4
    #
    #print sys info
    print(os.uname())       #os, utime and machine were imported at top

    #indicate program started visually (by blinking the green LED)
    led_onboard = machine.Pin(25, machine.Pin.OUT)
    led_onboard.value(0)     # onboard LED OFF for 0.5 sec
    utime.sleep(0.5)
    led_onboard.value(1)    # leaving it ON

    #create uart object sample code
    if False :
        #self.uart = UART(1, 115200, parity=None, stop=1, bits=8, rx=Pin(rxPin), tx=Pin(txPin))
        pass
    #end if

    #create actual uart object
    uart = machine.UART(1,bps, parity=None, stop=1, bits=8, rx=Pin(5), tx=Pin(4))
    #print uart info
    #uart = machine.UART(1)
    print(uart)         # during testing


    #                     create uartObject
    #uart = machine.UART(1,bps, parity=None, stop=1, bits=8, tx=txPin, rx=rxPin)
    #    send a single "A"  which is 0x41 ("A"-0x40 * 16 is the packet length which is 16

    #                                         initialization is complete

    uart.write("A")     #every group of messages is preceeded by a single "A"
    # prior to the "A", the transmitter should send a synchronizing sequence to permit
    #               the (human) receiver to "guess" or "determine" the baud rate (the bps)
    # hopefully the operator of the transmitter and receiver is the same human.

    # the serRx_pico should be running in a separate thread.

    #def serTx_pico(uartObject,bps, txtToBeSent="[UUUUUUUU]",rxtxEndChar="]"):
    serTx_pico(uart,bps, txtToBeSent="Hello,JoeMaxRoyBob")

    if False:
        serTx_pico(uart,bps, txtToBeSent="H")
        serTx_pico(uart,bps, txtToBeSent="H")
        serTx_pico(uart,bps, txtToBeSent="H]")
        serTx_pico(uart,bps, txtToBeSent="[H]")
        serTx_pico(uart,bps, txtToBeSent="2.97")
        serTx_pico(uart,bps, txtToBeSent="99.987654")
        serTx_pico(uart,bps, txtToBeSent="ADC0:(0x4000,1622428309.000j)")
        serTx_pico(uart,bps, txtToBeSent="1234567890123")
        serTx_pico(uart,bps, txtToBeSent="12345678901234")
        serTx_pico(uart,bps, txtToBeSent="Hello,World")
        serTx_pico(uart,bps, txtToBeSent="1234567890123456789012345678901234567890")
    #end if

    if False:
        # the above is the current format of the rxtx protocol
        # The som,eom,t10c and are 1-character special codes
        #    each must be converted into outgoing text or actions or both
        #    all normal text does not need to be converted before transmission
        #
        # The txParse routine analyses the msgOut Format and separates it into
        # special codes (text and actions).  Each special code is sent to the txChar()
        # routine to be processed. Each character of outgoing text is sent to the
        # txChar() routine to be processed.
        #
        # The serTx_pico() routine is used to
        #   transmit a special code of text ("S" and "M")
        #   cause a time delay (V is "t5c X is "t10c  " and M is "t1000c")
        #   transmit msg as 16-byte packets (msg should not contain "]" which is replaced by "?" )
        #
        #   early testing Format is "SMEPX"
        #
        # Note that the "P" also inserts at least 1 "]" character and
        #   enough extra "]" characters (or none) to make a message with an exact multiple
        #   of 16 characters.  This is because there are always 16 characters sent per
        #   packet. Each packet is followed by a time delay of t5c.
        #   The last packet is always followed by a time delay of t10c.
        #   These time delays permit the receiver to resync with the transmitter.
        #   These time delays are never included in the character count of the
        #   message
        #   The serRx_pico() routine times out after an interval of 1000 character times: t1000c
        pass
    #end if

    # This should be run this as a separate thread
    # print whatever has been received
    bps=600
    t100c=1000/bps
    utime.sleep(t100c) #wait for an interval of 100 char times
#end if

#uart = machine.UART(1,bps, parity=None, stop=1, bits=8, tx=Pin(txPin), rx=Pin(rxPin))
bps=600
uart = machine.UART(1,bps, parity=None, stop=1, bits=8, tx=Pin(4), rx=Pin(5))
print("uart:",uart)
if False:
    uart.write("hello")
    t100c=1000/bps
    utime.sleep(t100c) #wait for an interval of 100 char times

    uart.write("Hello,World")
    utime.sleep(t100c) #wait for an interval of 100 char times
    utime.sleep(1)     #1 sec
#if end
if False:
    print("receiving mpy routine")
    while uart.any():
        print(uart.read(1))
    #end while
#end if
charIn=""
if False:
    print("receiving mpy routine")

    if uart.any() :
        #print("reading now")
        charIn=uart.read(1)
        #show("charIn:",charIn)
        #oP=oP+uartObject.read(1)
    #end if
    print("end of mpy routine")
#end if
show("charIn:",charIn)
#end if
print("receiving my routine")
msgIn=serRx_pico(uart,bps=600)   #times out after t100c seconds (100 char-times)
print("msgIn:",msgIn)

print("end of serRX()")

#end /testTxC_pico.py


::::::::::textpak=>serTxD3_pico.py.txt
import os
#import utime
#from machineIX import UART, Pin
import IXutime as utime
import IXmachine as machine
import IXled_onboard as IXled_onboard
import IXuart as uart

def Pin(s1):								#IX
    return									#IX

#uart.write("12 zyx")

#by D@CC
#Date: 2024BFeb13
#Note: as of today, partially tested

# all functions and subroutines are at top of program
#  1. bChar()       converts 4 char byte into 1 char
#  2. serTx_pico()  transmits a full serial text message
#  3. txParse()     parses the outgoing text message and calls txChar
#  4. txChar()      adds the char to oP which is the output text packet queue
#  5. sendThisPack  actually transmits a full packet (wo any EOM)
#  6. sendLastPack  actually transmits text (with at least one EOM)
#  7. serRx_pico()  receives  a full serial text message
# testTx          transmits many test messages
# testRx          receives all test messages

#calling parms
#bChar(strB):
#serTx_pico(uartObject,bps=300, txtToBeSent="Hello,World",rxtxEndChar="]",pktSize=16):
#txParse(uartObject, thisMsg, bps=300, msgFormat="SMEPX", T5C=-1, pktSize=16,  eom="]"):
#txChar(char):
#sendThisPack(uartObject, oPIn, eom, pktSize):
#sendLastPack(oPIn, cntSent, cntUsed,  eom = "]", pktSize=16):
#serRx_pico(uartObject, bps=300, timeOut=-1, eom="]"):

def bChar(strB):                                                                   #bChar()
    #  given a string like b'z' this returns the "z"
    # tested by D@CC on 2021FJun15
    
    #strB=input("eg b'h' :")
    b=strB[2:]
    #print("b:"+b)
    c=b[0]
    #c="z"
    #print("bChar("+'"'+strB+ '"):'+c)
    return c
#end def


def serTx_pico(uartObject,bps=300, txtToBeSent="Hello,World",rxtxEndChar="]",pktSize=16):         #serTx_pico#

    print("54 in serTx_pico txtToBeSent :"+txtToBeSent+":")
    #every parameter has a default setting except the uartObject (which needs to be defined).
    t5c=50/bps          #   50 bit times = 5 character times
    t10c=100/bps        #  100 bit times = 10 character times
    t1000c=10000/bps    # 10000 bit times = 1000 character times
    
    # requires a uart object (below) to be created before this function is called
    #uart = machine.UART(1, 300, parity=None, stop=1, bits=8, tx=Pin(txPin), rx=Pin(rxPin))
    #print("entering serTx_pico.py")
    if rxtxEndChar=="]":
        som = "["
        eom = "]"
    
    msgOut = """
    #S +
    #M +
    #E +
    #P +
    #C"""

    print("74 msgOut :",msgOut,":")
    
    #where
    #A is the letter "A" meaning "16 bit packets (pktSize)"
    #S is SOM
    #M is Message text to be sent (will be followed by EOM)
    #E is EOM
    #P is the padding characters (enough EOMs to fill the packet)
    #X is t10c  (ten character time delay: "roman numeral X")
    #C is t100c  (100 character time delay: "roman numeral C")
        
    #Most messages will have   msgOut = "AC" "SMEPX"

    #Between messages, the transmitter will send "0" every minute indicating that its alive but
    #has no message to send.
    #Before sending each message the transmitter will send a single "A" which is 0x41 indicating
    #that the following message will be in packets of 16 characters.  In the future when the
    #packet size.
    #changes to 32 characters, the transmitter will precede each message with a single "B"
    #indicating the each packet will contain 32 characters.  This will allow future packet sizes
    #at least as big as 16x16x4 = 1024 characters and total message lengths of around 32768 without
    #using any control characters in the "ascii" preamble.

    #   Future versions will have msgOut = "DSNKMEPX"
    #    with packets having the format:
    #        AX SNKMV MV MV etc MEPX
    #The optional packet of 16 x D permits synchronization
    # 
    #where
    #D  is a full packet of Delete characters (optional for synchronization
    #N is the 2-character packet Number
    #K is the 2-character message character "Kount" including the only the first final EOM
    #V is t5c  (5 character time delay: "roman numeral V")


    #When a receiver starts up (and between messages) it should start by expecting packets of single
    #characters.  It will read a single 8-bit character expecting it to be a "0" meaning an idle transmitter.
    #If it is not a "0", it will read another single 8-bit character expecting it to be an "A".  If it is not an
    #"A",the character will be discarded, but the receiver will presume that it is reading a character
    #stream that is mid-message.  It will read single 8-bit characters searching for a "]" which will indicate
    #that this is the last packet of the message. It will keep reading and discarding all the "]" that it sees.
    #After the last "]", the
    #next 8-bit character should be a "0" or an "A".  The receiver should keep reading and discarding the "0"
    #characters.  When an "A" is finally received (while reading single 8-bit characters), the receiver knows that
    #this means subsequent packets will be packets of 16 characters.  The receiver is now fully
    #synchonized with the transmitter.  If something other than an "A" is received, the receiver should
    #begin looking for a "]" ()meaning "end of message" again.  If the state of "being in mid-message
    #continues 10 times, a human operator should be informed the that this ERROR is occuring.
    #
    #send the message
    txParse(uart,txtToBeSent)       #IX
    #print("125 end of serTx()")
    #print("126 Hit ^C to stop!")
    #print()
    return True
#end def serTx_pico()
def txParse(uartObject, thisMsg, bps=300, msgFormat="SMEPX", T5C=-1, pktSize=16,  eom="]"):    #txParse()
    #show("thisMsg:",thisMsg)
#
#    uartObject is the uart being used
#    thisMsg is the full text message to be sent (It should not contain (EOM="]") they will become "?")
#                          (An EOM is added as the last character of a message, do not put the EOM in the msg)
#    bps is the baud rate (bits/sec)
#    msgFormat is the form of the Msg e.g. SMEPX  (first E is counted as last char of M)
#                                                (P is enough additional EOMs to pad to packetSize=16)
#                                               (t5c is interval between packets (-1 defaults to t5c)

#    t5c indicates time interval of 5 characters.  The transmitter will follow each packet with
#       this time delay
#    packetSize defaults to 16
#    eom is the definition of the 'EOM" character (usually "]")
    #oP is the full outgoing Packet that is sent by sendThisPack
    #                                      or by sendLastPack
    
    
    #print("149 into txParse")
    oP=""            # outgoing msg is initially empty
    if T5C==-1:    # if the calling routine doesn't specify
       t5c=50/bps
       t10c=100/bps
       t1000c=10000/bps
    else:
        t5c=T5C       #if the calling routine does specify T5C
        t10c=T5C*2
        t1000c=T5C*200
    #end if
    if eom=="]":
        som="["
    #end if

#    in 2021 msgOut="SMEPX"
    lenM=len(thisMsg)+1      #length of thisMsg -1  (+1 for the EOM character
    cntUsed=0                # number of characters in msgOut used so far
    cntSent=0                # number of character actually sent (incl all chars sent)
    isEOMsent=False          #EOM not sent yet
    #show("msgFormat:",msgFormat)
    for msgPart in msgFormat:   # do each message segment
        if msgPart=="S":
            # send SOM
            #print("send SOM")
            oP=oP+txChar(som)
            oP=oP+txChar("1")      # in future these 2 characters will contain parity or CRC
            oP=oP+txChar("6")      # today they contain the packet size (ie character count)
            cntSent=cntSent+3 #3 actually sent now
            #print()
            #print("oP:"+oP+":")
            cntUsed=0
        #end if
        if msgPart=="X":     # time delay doesn't send any characters
            utime.sleep(t10c) 
        #end if
        if msgPart=="M":     # sends the msg followed by 1 eom
            #print("sending M")
            #cntSent of the packet is already in oP
            #cntUsed is 0 going into the while
            # note that lenM also includes 1 eom
            # in the while loop, cntUsed will increase until cntUsed=lenM
            while (lenM-cntUsed) >= 1 : #lenM incl the EOM, cntUsed does also (after the EOM is sent)
                #print("going into the M while")
                #show("upon entry M-while cntUsed:",cntUsed)
                #  the packet being sent should not include any EOM characters. (EOM is only in the last pk)
                #  send a packet of data
                # lastChar is the lastChar of Msg to send in this packet
                cntCanAdd=pktSize-len(oP)
                #print("cntCanAdd:",cntCanAdd,":")
                #show("cntUsed:",cntUsed)  #should be 0 entering first loop

                cntRemainOfM=lenM-cntUsed-1   #this cnts the remaining chars of M 
                cntToAdd=pktSize-len(oP)    #this cnts the remaining space in oP
                # a packet is always sent in this next "if clause"
                #show("cntRemainOfM:",cntRemainOfM)
                #show("cntToAdd:",cntToAdd)
                if cntRemainOfM>cntToAdd :
                # this packet cannot hold rest of Msg plus an eom
                    isLastPack=False 
                    opToAdd=thisMsg[cntUsed:cntUsed+cntToAdd]  # to add to oP
                    opToSend=oP+opToAdd                        # to be sent
                    #print("AopToSend:"+opToSend+":")
                    cntPadding=0
                    sendThisPack(uartObject, opToSend, cntPadding, eom, pktSize)
                    # that sent a full pkt without any padding
                    cntUsed=cntUsed+cntToAdd+1
                    # remember to count the first EOM as a character in cntUsed
                    #show("cntUsed:",cntUsed)
                    #show("lenM:",lenM)
                    oP=""
                    cntSent=0
                    #continue the while loop
                else :
                    isLastPack=True
                    # the pkt can hold the whole cntRemainOfM
                    opToAdd=thisMsg[cntUsed:cntUsed+cntRemainOfM]

                    #print("BopToSend:"+opToSend+":")
                    cntPadding=pktSize-cntSent-cntRemainOfM
                    strPadding=eom*cntPadding
                    opToSend=oP+opToAdd+strPadding
                    #print("CopToSend:"+opToSend+":")
                    
                    sendLastPack(uartObject, opToSend, cntPadding, eom, pktSize)
                    # that sent a full pkt including the padding                        
                    cntUsed=cntUsed+len(opToAdd)
                    #show("lenM:",lenM)
                    #show("cntUsed:",cntUsed)
                    oP=""
                    cntSent=0
                    #print("after Last Packet of Msg")
                    toSend=lenM-cntUsed
                    #show("toSend:",toSend)
                    #print("end of while")
                    break            #out of the while
                #if end
                cntUnsent=lenM-cntUsed-1
                #show("cntUnsent:",cntUnsent)
                #print("repeat the M while")
            #end while                 




            if False :
                # we need to send at least 1 more full packet
                isLastpack=False
                lastChar=cntUsed+(pktSize-len(oP)) #this is lastChar of Msg yet to send
                opToAdd=thisMsg[cntUsed:lastChar]  # to add to oP
                opTosend=oP+opToAdd
                print("opToSend:"+opToSend+":")
                sendThisPack(uartObject, opToSend, eom, pktSize)
                # no padding was necessary
                cntUsed=cntUsed+len(opToAdd)
                show("cntUsed:",cntUsed)
                # the while will loop once more
            #end if
            if False :
                lastChar=pktSize-cntSent
                show("lastChar",lastChar)
                #thisMsg="12345678901234567"
                #print("thisMsg:"+thisMsg+":")
                show("cntUsed",cntUsed)
                show("lastChar",lastChar)
                show("thisMsg[cntSent:lastChar]",thisMsg[cntUsed:lastChar])
                opWasSent=thisMsg[cntUsed:lastChar]
                print("opWasSend:"+opWasSend+":")
                if len(opToSend)>=16 :
                    print()
                    print("before sendThisPack oP:"+oP+":")
                    cntSent=sendThisPack(uartObject,opToSend, eom, pktSize)
                                           #returns 16  should print the Pkt
                    oP=""
                    show("cntUsedFromMsg:",cntUsedFromMsg)
                    cntUsed=cntUsed+cntUsedFromMsg    # should be 16 ...... to verify
                    cntSent=cntSent+16
                    show("lenM",lenM)
                    show("cntUsed",cntUsed)
                    isLastPacket=False
                else:
                    print("need to send padded Packet")
                    isLastPacket=True
                #end if
            #end if False
            if False :
                # a packet has just been sent
                leftToSend=lenM-cntUsed-1
                show("leftToSend:",leftToSend)
                if False :
                    if isLastPacket==True :       # will send the Last Packet (containing at least 1 EOM)
                        print("isLastPack is True")
                        #useStr=thisStr
                        cntUsedFromMsg=len(opToSend)
                        oP=opToSend
                        toAdd=16-cntUsedFromMsg
                        show("toAdd:",toAdd)
                        for x in range(toAdd):      # must insert correct range !!!!!
                            oP=oP+txChar(eom)           # must insert correct char from fullMsg !!!!!
                            cntSent=cntSent+1
                        #end for
                        print()
                        print("before sendThisPack oP:"+oP+":")
                        cntSent=sendThisPack(uartObject,oP, eom, pktSize)
                        #returns 16  should print the Pkt
                        oP=""
                        cntUsed=cntUsed+cntUsedFromMsg
                        show("cntUsed:",cntUsed)
                    #end if
                #end if False
                # a packet was just sent
                print("M while might end now")
                print("after end of while")
            #end if False
        #end if "M"

        if False :
            if msgPart=="P":                # P means Padding (with more EOMs) if any needs to be sent
                print("msgPart=P")
                if False :
                    if True:     # to be decided
                        oP=oP+txChar(eom)        # how many eoms of padding  !!!!!
                        cntUsed=cntUsed+1
                        cntSent=cntSent+1
                    #end if
                    show("cntUsed",cntUsed)
                    strSent=thisMsg[cntUsed:cntUsed+16]
                    show("strSent:",strSent)
                    cntUsedFromMsg = sendLastPack(uartObject, strSent, eom, pktSize) # should print the Pkt
                    cntUsed=cntUsed+cntUsedFromMsg
                    cntSent=cntSent+pktSize   #pktSize is usually 16
                #end if
            #end if "P"
        #end if False
        
    #end for    # all msg parts have now been sent
    # should check that cntUsed = len(Msg) +1
    # should check that cntSent is a muliple of pktSize(eg 16)
    return #from parsing and transmitting
#end def txParse
def txChar(char):                                                                       #txChar()        
    #simply records that "char" has been sent
    # just prints it during testing
    # doesn't actually send the char
    #print("#")
    print(char, end='') #"end" suppresses the line feed       #IX
    return char
#end def txChar

def sendThisPack(uartObject, opIn, cntPadding, eom, pktSize):                        #sendThisPack()
#

#actually sends the 16 characters in oP
    #print()
    #print("in sendThisPack")
    oP=opIn
    lenopIn=len(opIn)
    if (lenopIn==pktSize)==False:
        print("ERROR",pktSize, "is not the size of the packet to send:",lenopIn)
    #end if
    pos=opIn.find(eom)
    if pos==-1:              # -1 if not found
        pass
    else:
        print("WARNING E in serTx", eom, "found in message")
        oP=oP.replace(eom,"?")  
    #end if
    uartObject.write(oP)
    print("377 tx sent :"+oP+":")    #keep user informed during testing
    return pktSize
#end def

def sendLastPack(uartObject, opIn, cntPadding, eom, pktSize):                        #sendThisPack()
#

#actually sends the 16 characters in oP
    #print()
    #print("in sendLastPack")
    oP=opIn
    #print("oP:"+oP+":")
    lenopIn=len(opIn)
    #show("lenopIn:",lenopIn)
    if (lenopIn==pktSize)==False:
        print("ERROR",pktSize, "is not the size of the packet to send:",lenopIn)
    #end if
    #search for eom in the non-padding portion of oPIn
    suboPIn=opIn[0:pktSize-cntPadding]
    #print("suboPIn:"+suboPIn+":")
    pos=suboPIn.find(eom)
    if pos==-1:              # -1 if not found
        pass
    else:
        print("WARNING E in serTx", eom, "found in message")
        oP=oP.replace(eom,"?")  
    #end if
    uartObject.write(oP)
    print("405 tx sent:"+oP+":")    #keep user informed during testing
    return pktSize
#end def




def mpyRead(uart):
    import IXuart as IXuart
    #keep read1 character packet until timeOut
    print("415 into mpyRead")
    txtRead=""
    bRead=""
    IXany=IXuart.any()
    while IXany:

        aByte=str(IXuart.read(1))
        show("aByte:",aByte)
        bRead=bChar(aByte)
        #show("bRead:",bRead)
        txtRead=txtRead+bRead
        IXany=False				#IX loop once
    #end while
    return txtRead
#end def



#  serRx_pico()   receives  a full serial text message               #serRx_pico()
def serRx_pico(uartObject, bps=600, timeOut=-1, eom="]"):
    uart = machine.UART(1,bps, parity=None, stop=1, bits=8, rx=Pin(5), tx=Pin(4))  #IX
    print("my uart:",uart)
    #print("timeOut is set to:",timeOut)
    if timeOut==-1:
        t100c = 1000/bps
        timeOutUse=int(t100c+1.0)   #at least 1 sec
        #show("timeOutUse:",timeOutUse)
    else:
        timeOutUse=timeOut   #in seconds
    #end if
    #timeOutUse=t100c
    time=utime.time()
    timeNow=time
    #show("timeNow:",timeNow)
    timeFail=timeNow+timeOutUse    # defaults to a 3 second TimeOut
    #print("waiting my:",timeOutUse," seconds for data receipt. . . . .")
    oP=""  # reset input buffer
    show("time:",time)
    show("timeFail:",timeFail)


    while time < timeFail :
        #keep reading any 1 character packets until timeOut
        print("458 I should be flashing the green LED while receiving")
        # I don't know if it is still receiving
        # it should write the received msg to a file.
        print("461 any")
        strA=mpyRead(uart)
        show("strA:",strA)
        oP=oP+strA
        show("465 oP:",oP)
        #end if
        time=utime.time()
        time=time+1         #IX
        show("time",time)
        if len(oP)>5 : break    #IX break out of while loop
    #end while
    #show("oP:",oP)
    lenOp=len(oP)
    if oP=="":
        print("ERROR T in serRx (): timeOut after",timeOutUse,"seconds")
        lenOp=len(oP)
    #end if
    if lenOp > 0:
        if oP.find("?")==-1:
            pass            # ? not found
        else:
            print("WARNING '?' seen in message received.")
        #end if
    #end if
    #print("serRx() received:"+oP+":")   #during testing
    return oP
#end def serRx_pico(uart,300,timeOut(in secs))

def show(strA,parmA):                                        # show
    print(strA,parmA)
    return
#end def

##########################################################################################
##########################################################################################
progName="testTxD3_pico.py"
print("496 progName:"+progName)


import IXuart as uart
uart.write("501 zzz")

if True:
    bps=60
    tPause=4 
    txPin=5
    rxPin=4
    #
    #print sys info
    print(os.uname())       #os, utime and machine were imported at top

    #indicate program started visually (by blinking the green LED)
    led_onboard = machine.Pin(25, machine.Pin_OUT)
    IXled_onboard.value(0)     # onboard LED OFF for 0.5 sec
    utime.sleep(0.5)
    IXled_onboard.value(1)    # leaving it ON

    #create uart object sample code
    if False :
        #self.uart = UART(1, 115200, parity=None, stop=1, bits=8, rx=Pin(rxPin), tx=Pin(txPin))
        pass
    #end if


    #create actual uart object
    #uart = machine.UART(1,bps, parity=None, stop=1, bits=8, rx=Pin(5), tx=Pin(4))   #IX
    #print uart info
    #uart = machine.UART(1)
    print(uart)         # during testing



    #                     create uartObject
    #uart = machine.UART(1,bps, parity=None, stop=1, bits=8, tx=txPin, rx=rxPin)
    #    send a single "A"  which is 0x41 ("A"-0x40 * 16 is the packet length which is 16
    #                                         initialization is complete
    #uart.write("A")     #every group of messages is preceeded by a single "A"
    # prior to the "A", the transmitter should send a synchronizing sequence to permit
    #               the (human) receiver to "guess" or "determine" the baud rate (the bps)
    # hopefully the operator of the transmitter and receiver is the same human.

    # the serRx_pico should be running in a separate thread.



    #def serTx_pico(uartObject,bps, txtToBeSent="[UUUUUUUU]",rxtxEndChar="]"):
    print("547 transmitting Hello msg on Pin(GP4) in 2 16 byte packets at")
    print("548 60 bps, continuously preceded by an 'A' at 2 sec intervals")
    print("549 Issue 01: it erroneously skips the 'o' in 'Roy'. Doh!")
    print("550 Issue 02: it includes the '[16' in the msg len count of 16. Doh!")
    #    [16Hello,JoeMaxR
    #    1234567890123456
    #    yBob]]]]]]]]]]]]



    print("557 Hit ^C to stop!")
    print()



    while True :
        try:
            #print("558 before write")
            uart.write("A")
            #print("566 before write")            
            utime.sleep(tPause)
            #print("568 before write")
            serTx_pico(uart,bps, txtToBeSent="Hello,JoeMaxRoyBob")
            #print( "570 before write")
            utime.sleep(tPause)
            #print("572 before except")
        except:
            print("574 interrupted by ^c")
            break
        finally:
            print("577 after finally")
            aReply=input("579 Hit Enter to Continue")
        #end try

    #end while

    
    if False:
        serTx_pico(uart,bps, txtToBeSent="H")
        serTx_pico(uart,bps, txtToBeSent="H")
        serTx_pico(uart,bps, txtToBeSent="H]")
        serTx_pico(uart,bps, txtToBeSent="[H]")
        serTx_pico(uart,bps, txtToBeSent="2.97")
        serTx_pico(uart,bps, txtToBeSent="99.987654")
        serTx_pico(uart,bps, txtToBeSent="ADC0:(0x4000,1622428309.000j)")
        serTx_pico(uart,bps, txtToBeSent="1234567890123")
        serTx_pico(uart,bps, txtToBeSent="12345678901234")
        serTx_pico(uart,bps, txtToBeSent="Hello,World")
        serTx_pico(uart,bps, txtToBeSent="1234567890123456789012345678901234567890")
    #end if


    if False:
        # the above is the current format of the rxtx protocol
        # The som,eom,t10c and are 1-character special codes
        #    each must be converted into outgoing text or actions or both
        #    all normal text does not need to be converted before transmission
        #
        # The txParse routine analyses the msgOut Format and separates it into
        # special codes (text and actions).  Each special code is sent to the txChar()
        # routine to be processed. Each character of outgoing text is sent to the
        # txChar() routine to be processed.
        #
        # The serTx_pico() routine is used to
        #   transmit a special code of text ("S" and "M")
        #   cause a time delay (V is "t5c X is "t10c  " and M is "t1000c")
        #   transmit msg as 16-byte packets (msg should not contain "]" which is replaced by "?" )
        #
        #   early testing Format is "SMEPX"
        #
        # Note that the "P" also inserts at least 1 "]" character and
        #   enough extra "]" characters (or none) to make a message with an exact multiple
        #   of 16 characters.  This is because there are always 16 characters sent per
        #   packet. Each packet is followed by a time delay of t5c.
        #   The last packet is always followed by a time delay of t10c.
        #   These time delays permit the receiver to resync with the transmitter.
        #   These time delays are never included in the character count of the
        #   message
        #   The serRx_pico() routine times out after an interval of 1000 character times: t1000c
        pass
    #end if


    # print whatever has been received
    bps=600
    t100c=1000/bps
    utime.sleep(t100c) #wait for an interval of 100 char times
#end if


# This should be run this as a separate thread

#uart = machine.UART(1,bps, parity=None, stop=1, bits=8, tx=Pin(txPin), rx=Pin(rxPin))
bps=600
#uart = machine.UART(1,bps, parity=None, stop=1, bits=8, tx=Pin(4), rx=Pin(5))
#uart="machine.uart"					#IX
print("636 machine.uart:",uart)
uart.write("642 yyy")
if True:                                #IX
    uart.write("hello")
    t100c=1000/bps
    utime.sleep(t100c) #wait for an interval of 100 char times

    uart.write("Hello,World")
    utime.sleep(t100c) #wait for an interval of 100 char times
    utime.sleep(1)     #1 sec
#if end
if False:
    print("receiving mpy routine")
    while uart.any():
        print(uart.read(1))
    #end while
#end if
charIn=""
if False:
    print("receiving mpy routine")

    if uart.any() :
        #print("663 reading now")
        charIn=uart.read(1)
        #show("charIn:",charIn)
        #oP=oP+uartObject.read(1)
    #end if
    print("end of mpy routine")
#end if
show("charIn:",charIn)
#end if
print("receiving my routine")
msgIn=serRx_pico(uart,bps=600)   #times out after t100c seconds (100 char-times)
print("msgIn:",msgIn)
print("675 end of serRX()")
print("676 end of:",progName)				#IX


#end /testTxD3_pico.py
::::::::::textpak=>serTxRx_Fast_pico.py.txt
import os
import utime
from machine import UART, Pin

#print("unfixed ERROR thinks msg is fully received at 1500 (sees a ']' at 35th byte")

progName="serTxRx_Fast_pico.py"
bps=1500  # baud (bits/sec) rate  First Att/ saw   Second Attp saw
#                            3000     32                  0
#                            1700     32                 all
#                            1525     32                 all
#                            1525     -                 hung
#                            1500     32      lost in mid  2
#                            1440    garbage            hung
#                            1440    all                 all
#                            1350    all                 all
#                            1000    all                 all
#                             500    all                 all
#                             300      -                hung
#                             300    all                 all
t10c=100/bps
t1000c=10000/bps
def setTBuff(bps,minTBuff=5,maxTBuff=15):
    tBuff=1000/bps
    if tBuff<minTBuff: tBuff=minTBuff
    if tBuff>maxTBuff: tBuff=maxTBuff
    return tBuff
#end def

tBuffer=setTBuff(bps)
print("tBuffer:",tBuffer)

errThreshold=99
rxtxEndChar="]"
isUsingFirstAttempt=True
isUsingSecondAttempt=True
# tested OK on 2021FJun15 by D@CC
# the b'H'<lf> has been converted to "H"
# backed up as serTxRx_pico_BU2021FJun15-1702.py

#based pm progName="mpy_uart_pico.py"
print("progName:"+progName)
print("Error occurs when using pins 8 and 9 as Rx and Tx")
txPin=4
rxPin=5
print("Jumper GP"+str(rxPin)+" to GP"+str(txPin))
#print sys info
print(os.uname())

#indicate program started visually
led_onboard = machine.Pin(25, machine.Pin.OUT)
led_onboard.value(0)     # onboard LED OFF for 0.5 sec
utime.sleep(0.5)
led_onboard.value(1)

#create uart object
if False :
    #self.uart = UART(1, 115200, parity=None, stop=1, bits=8, rx=Pin(rxPin), tx=Pin(txPin))
    # speed of 400 only reads 4 bytes . . Doh?
    # bps=9000
    pass
#end if

#tBuff=setTBuff(bps)
uart = machine.UART(1,bps, parity=None, stop=1, bits=8, tx=Pin(txPin), rx=Pin(rxPin))
#print uart info
#uart = machine.UART(1)
print(uart)

def bChar(strB):
    #  given a string like b'z' this returns the "z"
    # tested by D@CC on 2021FJun15
    
    #strB=input("eg b'h' :")
    b=strB[2:]
    #print("b:"+b)
    c=b[0]
    #c="zz"
    #print("bChar("+'"'+strB+ '"):'+c)
    return c
#end def

def serTxRx_pico(uartObject,bps, rOrT="R",txtToBeSent="[UUUUUUUU]",tBuff=3,rxtxEndChar="]"):
    t10c=100/bps
    t1000c=10000/bps
    # requires a uart object (below) to be created before this function is called
    #uart = machine.UART(1,600, parity=None, stop=1, bits=8, tx=Pin(txPin), rx=Pin(rxPin))
    #print("entering serTxRx")
    #print("rOrT:"+rOrT)

    #Note: there appears to be an internal error in either the Tx or the Rx function.  This
    # error causes messages (simple text strings) longer than 32 bytes to be chopped, resulting
    # in a loss of data no matter how long the program waits for the remainder of the message
    # to arrive.  What is really strange is that this issue is speed-dependant at both extremes
    # of speed.  The result is that the last character of the message ("]") might never arrive
    # or in some cases, characters in the middle of the message have been lost.  This issue
    # would dissappear if an ACK/NAK protocol were used, but this level of sophistication should
    # NOT be necessary for communication between two boards that are only inches apart.
    #
    # To further explore this issue, a wait count (called an "Error Threshold: errThreshold" is
    # used internally to count how many times the code receives an empty message before it
    # "gives up" and terminates with an error note.  As this Threshold is raised, a second
    # threshold (a time-out) is used after which an error note is received. This is complicated
    # by the fact that unix times on the pico do NOT seem to be measured in intervals less than
    # a second.
    # Precision in milliseconds would be needed to work on this issue. Exceeding a time
    # limit of 31.4159 seconds will also result in program termination with a different error message.
    # Another complication is that this issue is intermittent, and cannot always be reproduced.
    # This makes me wonder if something similar to "RAM garbage collection" might be in play.  We
    # have been told that "RAM garbage collection" does NOT occur in the Pico. Doh!

    #errThreshold of 99 works at low baud rates (even down to 200 bps)
    #   tested by D@CC with MPA board down to 20 with errThreshold=99
    #   sending longer messages (>32 characters) cause data loss by the receiver
    #      apparently very slow and very fast baud rates cause problems with 60 character msgs
    #   D@CC saw it fail at 450 bps sometimes (but "usually" works at 400)
    #     testing was done on an RPi model 4 with a RP4020 pico
    #   D@CC doesn't yet know what the high baud rate limit is

    isValidRorT=False
    txtIn=" mt "
    if rOrT=="T":
        isValidRorT=True
        txtOut=txtToBeSent
        #print("A transmitting:"+txtOut+":")
        if txtOut=="":
            txtOut="[HelloThere]"
        #end if
        print("B1 transmitting:"+txtOut+":")
        uartObject.write(txtOut)
        utime.sleep(0.1)
        print("transmission complete")
        return
    #end if
    if rOrT=="X":
        isValidRorT=True
        txtIn=""
        while uartObject.any():
            txtIn=uartObject.read(1)
        #end while
        if txtIn=="":
            pass
        else:
            print(txtIn)
        #end if
    #end if
    m=0
    if rOrT=="R" :
        #print("Receiving t10c:",t10c)
        isValidRorT=True
        #print("doing R")

        utime.sleep(t10c)      #wait for 10 char to be received

        txtMsg=""
        tBeg=utime.time()
        #print("tBeg:",tBeg)
        #
        # loop while the pico thinks that "any" more of the message is expected
        #    How can it know how long the message should be? unless it senses
        #    a non-empty "buffer queue" of unprocessed characters exists?
        while uart.any():
            m=m+1
            # this next statement reads "one character at a time"
            # If more than 1 character is requested to be read, the routine
            # will "wait" internally until the requested count of characters
            # has been received, essentially "hanging" the code until then.
            byteOne=uart.read(1)
            char1=str(byteOne)
            
            # the following routine named bChar() converts the message
            # containing the one  character (eg b'h') to the character "h"
            # by stripping the superfluous text surrounding the character.
            #txtMsg=txtMsg+str(m)+bChar(char1)
            
            txtMsg=txtMsg+bChar(char1)
            #print(m,char1)
            utime.sleep(0.01)
        #end while
        tNow=utime.time()
        dT=tNow-tBeg
        #print("dT:",dT,"txtMsg:"+txtMsg)
        #print("txtMsg:"+txtMsg)
        if txtMsg=="":
            # an empty txtIn messge will NOT be returned
            # this can result in a "hung" program if
            # data has been truly lost.
            txtIn=txtMsg
            if dT> 31.4159:
                print(" ERROR B wait time exceeds 31.4159 seconds")
                exit    #break out of this hung situation
            else:
                pass
            #end if
        else:
            txtIn=txtMsg
            return txtIn
        #end if
        #print("after R loop")

    #end if
    if isValidRorT :
        #print("returning")
        return txtIn
    else:
        txtIn="?"
        #print("returning")
        return txtIn
    #end if
#end def
def timeOut(t0,tOut):
    tNow=utime.time()
    dT=tNow-t0
    #print("q:",q,rxtxEndChar,"dT:",dT)
    if dT>tOut: return True     #print("ERROR E wait time exceeds",t1000c,"secs")
    else:
        return False
#end if
####################################################################################
#transmit the default text (then print and return any received text)
#serTxRx_pico(uart,bps,"T","[UUUUUUUUUUUUUUUUUUUUUUUUAUU30123456789UUUUUUUUUUU]")
if isUsingFirstAttempt :
    pass
#end if
#    the program executes so fast that we must wait for the message
#    to be fully sent before we start reading the message.
#    if we sleep(0), we will only see the final "o" Doh!

if False:
    while uart.any():
        print(uart.read(1))
    #end while
#end if


if isUsingFirstAttempt==False:
    print("skipping first attempt at coding this.")
else:
    print("First attempt at coding this.")
    serTxRx_pico(uart,bps, "T","[UUUUUUUUUUUUUUUUUUUUUUUUAUU301234567890abcdefghij]")
    #serTxRx_pico(uart,bps, "T","[UUUUUUUUUUUUUUUUUUUUUUUUAUU3012345678901234567890]")
    print("receiving 2 t10c:",t10c)
    utime.sleep(t10c)         # throttle transmission by 10 character pause
    kk=0
    partMsg=""
    tBeg=utime.time()
    dT=-1
    #print(kk,dT,"partMsg:"+partMsg+":")
    print("receiving 2 t10c:",t10c)
    while (len(partMsg)==0 or ((partMsg[-1:]==rxtxEndChar)==False)):
        #  leng==0        or   last char not "]"
        # keep reading characters
        msgStr="testing part Msg[-1:] :"
        #print(msgStr+partMsg[-1:])
        tNow=utime.time()
        dT=tNow-tBeg
        if dT>t1000c:
            print("dT:",dT)
            print("Error rX delay > ",t1000c,"secs")
            break     #out of while loop
        #end if
        kk=kk+1
        #print(kk,dT,"partMsg:"+partMsg+":")
        msgRecd=serTxRx_pico(uart,bps,"R",tBuff=tBuffer)
        partMsg=partMsg+msgRecd
        #print("XpartMsg:"+partMsg)

        #
        
        if kk>errThreshold:
            print("Error F -missing ']' at end of reading")
            break # out of the while loop
        else:
            pass
        #end if
        # get the result ready in case the while loop stops with a ")"
        
    #end while
    print("bps:",bps)
    print("Msg received 1st Try:"+partMsg+":")
#end if

# Reading
if False:
    for j in range(51):
        byteRecd=serTxRx_pico(uart,bps,"R",tBuff=tBuffer)
        strRecd=str(byteRecd)
        #print("strRecd:"+strRecd+":")
        if strRecd==" mt ":
            pass
        else:
            #strRecd=str(byteRecd)
            print(j,"txtRecd:"+strRecd+":")
        #end if
    #end for
#end if
#print("end of j loop")
print("bps:",bps)
pauseN=tBuffer                     #pause time set to 5 seconds
print("tBuffer:",tBuffer)
utime.sleep(t10c)               #let the buffers settle down (10 char delay)


if isUsingSecondAttempt :
    print()
    print("pausing to wait for buffers to settle:",pauseN,"secs")
    print("isUsingSecondAttempt")
    print("First . .  clear out any residual message:")
    while uart.any():
        inStr=str(uart.read(1))
        inStr=bChar(inStr)
        print(inStr, end='')
    #end while
    print()
    print("end of search for residual character(s)")
    print("transmitting")
    #serTxRx_pico(uart, bps,"T","[UUUUUUUUUUUUUUUUUUUUUUUUAUU3012345678901234567890]")
    serTxRx_pico(uart,bps, "T","[UUUUUUUUUUUUUUUUUUUUUUUUAUU301234567890abcdefghij]")
    print("t10c:",t10c)
    #utime.sleep(t10c)           #10 char delay to allow the transmission to be sent
    print("receiving 2nd attempt")
    q=0
    if True:
        partMsg=""
        leng=0
        tBeg=utime.time()
        print("rxtxEndChar:"+rxtxEndChar)
        #while (leng==0 or (partMsg[-1:]==rxtxEndChar)==False):
        if (partMsg[-1:]==rxtxEndChar) : isKeepChecking=False
        else: isKeepChecking=True
        #  or
        if (leng==0): isKeepChecking=True
        
        while isKeepChecking:
            #print("starting the while loop")
            # empty msg or last char not == "]"
            #print("q:",q, "before uart.any")
            isCheckUartAny=True
            if isCheckUartAny and uart.any():
                #print("after if uart any")
                inByte=uart.read(1)
                inStr=bChar(str(inByte))
                #print("inStr:",inStr)
                partMsg=partMsg+inStr
                isToTest=(partMsg[-1:]==rxtxEndChar)
                #print("isToTest:"+str(isToTest))
                if isToTest :
                    #That was the "end" character=="]"
                    print("        partMsg:"+partMsg+":")
                    #break      #out of the while loop
                    isKeepChecking=False
                #end if
                #print("end of uart.any")
            #end if
            if False:
                if False:                   # skipping this##########################
                    q=q+1
                    #print("q:",q,rxtxEndChar)
                    tNow=utime.time()
                    dT=tNow-tBeg
                    if dT>t1000c:
                        print("ERROR C wait time exceeds",t1000c, "secs")
                        break
                    else:
                        pass
                    #end if
                #end if                      ########################################
                inStr=str(uart.read(1))
                print("inStr:"+inStr)
                #leng=len(inStr)
                #leng=1
                #if leng>0 :
                #print("inStr:"+inStr)
                #for r in range(leng):
                chrStr=str(inStr)
                chrStr=bChar(chrStr)
                partMsg=partMsg+chrStr
                print("isToTest:"+str(partMsg[-1:]==rxtxEndChar))
                #end for
                #end if
            # end else:
            if False:
                #print("WARNING: still not any chars received")
                q=q+1
                print("q2:",q,rxtxEndChar)
                if timeOut(tBeg,t1000c):
                    print("     partMsg:"+partMsg+":")
                    print("timeOut exiting")
                    break     #out of while
                #end if
                utime.sleep(t10c)
            #end if    
        #end while
        print("endWhile")
        #print("     partMsg:"+partMsg+":")
    #end if
#end if
print()
print("- bye -")

#end def
#Source:http://helloraspberrypi.blogspot.com/2021/01/raspberry-pi-picomicropython-simple.html
#program end
#/serTxRx_Fast_pico.py
::::::::::textpak=>signalGenerator_pico.py.txt
# Example of using PIO for function generation using hacked PWM example

from machine import ADC
from time import sleep_us, sleep_ms
import _thread

#DC from pio_dac import PIOPWM

#DC copied PIOPWM from fadeLed_pico.py
from machine import Pin
from rp2 import PIO, StateMachine, asm_pio
from time import sleep

@asm_pio(sideset_init=PIO.OUT_LOW)
def pwm_prog():
    pull(noblock) .side(0)
    mov(x, osr) # Keep most recent pull data stashed in X, for recycling by noblock
    mov(y, isr) # ISR must be preloaded with PWM count max
    label("pwmloop")
    jmp(x_not_y, "skip")
    nop()         .side(1)
    label("skip")
    jmp(y_dec, "pwmloop")
    
class PIOPWM:
    def __init__(self, sm_id, pin, max_count, count_freq):
        self._sm = StateMachine(sm_id, pwm_prog, freq=2 * count_freq, sideset_base=Pin(pin))
        # Use exec() to load max count into ISR
        self._sm.put(max_count)
        self._sm.exec("pull()")
        self._sm.exec("mov(isr, osr)")
        self._sm.active(1)
        self._max_count = max_count

    def set(self, value):
        # Minimum value is -1 (completely turn off), 0 actually still produces narrow pulse
        value = max(value, -1)
        value = min(value, self._max_count)
        self._sm.put(value)
#DC end class PIOPWM copied from fadeLed_pico.py

#DC where is pio_dac ? [Answer: non-existant pot]
progName="signalGenerator_pico.py"
print(progName)
#DC suppressed use of pot [potentiometer on ADC(26) for frequency]

#DC Pin GP22 is output count_freq is generation interval not freq.
#DC pwm = PIOPWM(0, 22, max_count=250, count_freq=10_000_000)
pwm = PIOPWM(0, 18, max_count=250, count_freq=10_000_000)

#DC vector has 250 samples
sines = [
    124, 127, 130, 133, 136, 139, 142, 145, 148, 152,
    155, 158, 161, 164, 167, 170, 172, 175, 178, 181,
    184, 186, 189, 192, 194, 197, 200, 202, 204, 207,
    209, 211, 214, 216, 218, 220, 222, 224, 226, 227,
    229, 231, 232, 234, 235, 237, 238, 239, 240, 241,
    242, 243, 244, 245, 246, 246, 247, 247, 248, 248,
    248, 248, 249, 249, 248, 248, 248, 248, 247, 247,
    246, 246, 245, 244, 243, 242, 241, 240, 239, 238,
    237, 235, 234, 232, 231, 229, 227, 226, 224, 222,
    220, 218, 216, 214, 211, 209, 207, 204, 202, 200,
    197, 194, 192, 189, 186, 184, 181, 178, 175, 172,
    170, 167, 164, 161, 158, 155, 152, 148, 145, 142,
    139, 136, 133, 130, 127, 124, 120, 117, 114, 111,
    108, 105, 102, 99, 95, 92, 89, 86, 83, 80,
    77, 75, 72, 69, 66, 63, 61, 58, 55, 53,
    50, 48, 45, 43, 40, 38, 36, 33, 31, 29,
    27, 25, 23, 21, 20, 18, 16, 15, 13, 12,
    10, 9, 8, 7, 6, 5, 4, 3, 2, 1,
    1, 0, 0, -1, -1, -1, -1, -1, -1, -1,
    -1, -1, -1, 0, 0, 1, 1, 2, 3, 4,
    5, 6, 7, 8, 9, 10, 12, 13, 15, 16,
    18, 20, 21, 23, 25, 27, 29, 31, 33, 36,
    38, 40, 43, 45, 48, 50, 53, 55, 58, 61,
    63, 66, 69, 72, 75, 77, 80, 83, 86, 89,
    92, 95, 99, 102, 105, 108, 111, 114, 117, 120,
]


#DCx pot = ADC(26)
#DCpot = ADC(1)    #works with MPA ver1
DCpot = ADC(1)    #works with MPA ver1 (my pot is on 1)
delay = [400]


def read_pot():
    while True:
        #DCx v = pot.read_u16()
        #DC  v = pot.read_u16()   #works with MPA ver 1
        #DCx // is floor division (i.e. discard fractionary value)
        #DCx delay[0] = 20 + (400 * v)// 65000
        #DC delay[0] = 20 + (400 * v)// 65000 #works with MPA ver 1
        #DC delay[0] = 20 + 10 #200 is midpoint on pot
        #DC 20 + 10 is about 600 Hz
        sleep_ms(100)


_thread.start_new_thread(read_pot, ())

while True:
    for i in range(0, 250, 25):
        pwm.set(sines[i])
        sleep_us(delay[0])


#DC Source: http://blog.rareschool.com/2021/02/raspberry-pi-pico-simple-projects.html
#DC end program #signalGenerator_pico.py
#signalGenerator_pico.py
::::::::::textpak=>signalGenerator_w_Pot_pico.py.txt
*************************************
signalGenerator_w_Pot_pico.py
*************************************
by D@CC
on 2022EMay05

# Example of using PIO for function generation using hacked PWM example
#  with freq control using a potentiometer

#functions used
pwm_prog()
PIO statements_5
@asm_pio()
 pull()
 mov()
 label()
 jmp()
 nop()
 ._sm
 ._sm.put()
 ._sm.exec()
 ._sm.active()
 ._sm.mac_count
max()
min()
sm.put()
set()
PIOPWM()
ADC()
pot.read()
read_pot()
sleep_ms()
sleep_us()

from machine import ADC
from time import sleep_us, sleep_ms
import _thread

#DC from pio_dac import PIOPWM

#DC copied PIOPWM from fadeLed_pico.py
from machine import Pin
from rp2 import PIO, StateMachine, asm_pio
from time import sleep

@asm_pio(sideset_init=PIO.OUT_LOW)
def pwm_prog():
    pull(noblock) .side(0)
    mov(x, osr) # Keep most recent pull data stashed in X, for recycling by noblock
    mov(y, isr) # ISR must be preloaded with PWM count max
    label("pwmloop")
    jmp(x_not_y, "skip")
    nop()         .side(1)
    label("skip")
    jmp(y_dec, "pwmloop")
    
class PIOPWM:
    def __init__(self, sm_id, pin, max_count, count_freq):
        self._sm = StateMachine(sm_id, pwm_prog, freq=2 * count_freq, sideset_base=Pin(pin))
        # Use exec() to load max count into ISR
        self._sm.put(max_count)
        self._sm.exec("pull()")
        self._sm.exec("mov(isr, osr)")
        self._sm.active(1)
        self._max_count = max_count

    def set(self, value):
        # Minimum value is -1 (completely turn off), 0 actually still produces narrow pulse
        value = max(value, -1)
        value = min(value, self._max_count)
        self._sm.put(value)
#DC end class PIOPWM copied from fadeLed_pico.py

#DC where is pio_dac ? [Answer: non-existant pot]
progName="signalGenerator_w_Pot_pico.py"
print(progName)
#DC suppressed use of pot [potentiometer on ADC(26) for frequency]

#DC Pin GP22 is output count_freq is generation interval not freq.
#DC pwm = PIOPWM(0, 22, max_count=250, count_freq=10_000_000)
pwm = PIOPWM(0, 18, max_count=250, count_freq=10_000_000)

#DC vector has 250 samples
sines = [
    124, 127, 130, 133, 136, 139, 142, 145, 148, 152,
    155, 158, 161, 164, 167, 170, 172, 175, 178, 181,
    184, 186, 189, 192, 194, 197, 200, 202, 204, 207,
    209, 211, 214, 216, 218, 220, 222, 224, 226, 227,
    229, 231, 232, 234, 235, 237, 238, 239, 240, 241,
    242, 243, 244, 245, 246, 246, 247, 247, 248, 248,
    248, 248, 249, 249, 248, 248, 248, 248, 247, 247,
    246, 246, 245, 244, 243, 242, 241, 240, 239, 238,
    237, 235, 234, 232, 231, 229, 227, 226, 224, 222,
    220, 218, 216, 214, 211, 209, 207, 204, 202, 200,
    197, 194, 192, 189, 186, 184, 181, 178, 175, 172,
    170, 167, 164, 161, 158, 155, 152, 148, 145, 142,
    139, 136, 133, 130, 127, 124, 120, 117, 114, 111,
    108, 105, 102, 99, 95, 92, 89, 86, 83, 80,
    77, 75, 72, 69, 66, 63, 61, 58, 55, 53,
    50, 48, 45, 43, 40, 38, 36, 33, 31, 29,
    27, 25, 23, 21, 20, 18, 16, 15, 13, 12,
    10, 9, 8, 7, 6, 5, 4, 3, 2, 1,
    1, 0, 0, -1, -1, -1, -1, -1, -1, -1,
    -1, -1, -1, 0, 0, 1, 1, 2, 3, 4,
    5, 6, 7, 8, 9, 10, 12, 13, 15, 16,
    18, 20, 21, 23, 25, 27, 29, 31, 33, 36,
    38, 40, 43, 45, 48, 50, 53, 55, 58, 61,
    63, 66, 69, 72, 75, 77, 80, 83, 86, 89,
    92, 95, 99, 102, 105, 108, 111, 114, 117, 120,
]


pot = ADC(26)
delay = [400]


def read_pot():
    while True:
        # potentiometer is 4K8 (4800 ohms)
        v = pot.read_u16()
        #DC // is floor division (i.e. discard fractionary value)
        delay[0] = 20 + (400 * v)// 65000
        #DC delay[0] = 20 + 10 #200 is midpoint on pot
        #DC 20 + 10 is about 600 Hz
        sleep_ms(100)


_thread.start_new_thread(read_pot, ())

while True:
    for i in range(0, 250, 25):
        pwm.set(sines[i])
        sleep_us(delay[0])

#DC Source: http://blog.rareschool.com/2021/02/raspberry-pi-pico-simple-projects.html
#DC end program #signalGenerator_w_Pot_pico.py
::::::::::textpak=>signalGenerator_w_PotOn1_pico.py.txt
# Example of using PIO for function generation using hacked PWM example

from machine import ADC
from time import sleep_us, sleep_ms
import _thread

#DC from pio_dac import PIOPWM
# worked with MakPiADC board with pot on 2021FJun09

#DC copied PIOPWM from fadeLed_pico.py
from machine import Pin
from rp2 import PIO, StateMachine, asm_pio
from time import sleep

@asm_pio(sideset_init=PIO.OUT_LOW)
def pwm_prog():
    pull(noblock) .side(0)
    mov(x, osr) # Keep most recent pull data stashed in X, for recycling by noblock
    mov(y, isr) # ISR must be preloaded with PWM count max
    label("pwmloop")
    jmp(x_not_y, "skip")
    nop()         .side(1)
    label("skip")
    jmp(y_dec, "pwmloop")
    
class PIOPWM:
    def __init__(self, sm_id, pin, max_count, count_freq):
        self._sm = StateMachine(sm_id, pwm_prog, freq=2 * count_freq, sideset_base=Pin(pin))
        # Use exec() to load max count into ISR
        self._sm.put(max_count)
        self._sm.exec("pull()")
        self._sm.exec("mov(isr, osr)")
        self._sm.active(1)
        self._max_count = max_count

    def set(self, value):
        # Minimum value is -1 (completely turn off), 0 actually still produces narrow pulse
        value = max(value, -1)
        value = min(value, self._max_count)
        self._sm.put(value)
#DC end class PIOPWM copied from fadeLed_pico.py

#DC where is pio_dac ? [Answer: non-existant pot]
progName="signalGenerator_w_Pot_pico.py"
print(progName)
#DC suppressed use of pot [potentiometer on ADC(26) for frequency]

#DC Pin GP22 is output count_freq is generation interval not freq.
#DC pwm = PIOPWM(0, 22, max_count=250, count_freq=10_000_000)
pwm = PIOPWM(0, 18, max_count=250, count_freq=10_000_000)

#DC vector has 250 samples
sines = [
    124, 127, 130, 133, 136, 139, 142, 145, 148, 152,
    155, 158, 161, 164, 167, 170, 172, 175, 178, 181,
    184, 186, 189, 192, 194, 197, 200, 202, 204, 207,
    209, 211, 214, 216, 218, 220, 222, 224, 226, 227,
    229, 231, 232, 234, 235, 237, 238, 239, 240, 241,
    242, 243, 244, 245, 246, 246, 247, 247, 248, 248,
    248, 248, 249, 249, 248, 248, 248, 248, 247, 247,
    246, 246, 245, 244, 243, 242, 241, 240, 239, 238,
    237, 235, 234, 232, 231, 229, 227, 226, 224, 222,
    220, 218, 216, 214, 211, 209, 207, 204, 202, 200,
    197, 194, 192, 189, 186, 184, 181, 178, 175, 172,
    170, 167, 164, 161, 158, 155, 152, 148, 145, 142,
    139, 136, 133, 130, 127, 124, 120, 117, 114, 111,
    108, 105, 102, 99, 95, 92, 89, 86, 83, 80,
    77, 75, 72, 69, 66, 63, 61, 58, 55, 53,
    50, 48, 45, 43, 40, 38, 36, 33, 31, 29,
    27, 25, 23, 21, 20, 18, 16, 15, 13, 12,
    10, 9, 8, 7, 6, 5, 4, 3, 2, 1,
    1, 0, 0, -1, -1, -1, -1, -1, -1, -1,
    -1, -1, -1, 0, 0, 1, 1, 2, 3, 4,
    5, 6, 7, 8, 9, 10, 12, 13, 15, 16,
    18, 20, 21, 23, 25, 27, 29, 31, 33, 36,
    38, 40, 43, 45, 48, 50, 53, 55, 58, 61,
    63, 66, 69, 72, 75, 77, 80, 83, 86, 89,
    92, 95, 99, 102, 105, 108, 111, 114, 117, 120,
]


#DCx pot = ADC(26)
#DC  pot = ADC(1)   # my pot in MPA is on ADC1
#DC  pot = ADC(0)   # my CDS0 in MPA is on ADC0
#DC                 # CDS0 doesn't control freq very well
#DC                 # the calc needs adjustment
pot = ADC(1)   # my pot in MPA is on ADC1
delay = [400]


def read_pot():
    while True:
        # potentiometer is 4K8 (4800 ohms)
        v = pot.read_u16()
        #DC // is floor division (i.e. discard fractionary value)
        delay[0] = 20 + (400 * v)// 65000
        #DC delay[0] = 20 + 10 #200 is midpoint on pot
        #DC 20 + 10 is about 600 Hz
        sleep_ms(100)


_thread.start_new_thread(read_pot, ())

while True:
    for i in range(0, 250, 25):
        pwm.set(sines[i])
        sleep_us(delay[0])

#DC Source: http://blog.rareschool.com/2021/02/raspberry-pi-pico-simple-projects.html
#DC end program #signalGenerator_w_Pot_pico.py
::::::::::textpak=>signalGenerator_wo_Pot_pico.py.txt
# Example of using PIO for function generation using hacked PWM example

from machine import ADC
from time import sleep_us, sleep_ms
import _thread

#DC from pio_dac import PIOPWM

#DC copied PIOPWM from fadeLed_pico.py
from machine import Pin
from rp2 import PIO, StateMachine, asm_pio
from time import sleep

@asm_pio(sideset_init=PIO.OUT_LOW)
def pwm_prog():
    pull(noblock) .side(0)
    mov(x, osr) # Keep most recent pull data stashed in X, for recycling by noblock
    mov(y, isr) # ISR must be preloaded with PWM count max
    label("pwmloop")
    jmp(x_not_y, "skip")
    nop()         .side(1)
    label("skip")
    jmp(y_dec, "pwmloop")
    
class PIOPWM:
    def __init__(self, sm_id, pin, max_count, count_freq):
        self._sm = StateMachine(sm_id, pwm_prog, freq=2 * count_freq, sideset_base=Pin(pin))
        # Use exec() to load max count into ISR
        self._sm.put(max_count)
        self._sm.exec("pull()")
        self._sm.exec("mov(isr, osr)")
        self._sm.active(1)
        self._max_count = max_count

    def set(self, value):
        # Minimum value is -1 (completely turn off), 0 actually still produces narrow pulse
        value = max(value, -1)
        value = min(value, self._max_count)
        self._sm.put(value)
#DC end class PIOPWM copied from fadeLed_pico.py

#DC where is pio_dac ? [Answer: non-existant pot]
progName="signalGenerator_wo_Pot_pico.py"
print(progName)
#DC suppressed use of pot [potentiometer on ADC(26) for frequency]

#DC Pin GP22 is output count_freq is generation interval not freq.
#DC pwm = PIOPWM(0, 22, max_count=250, count_freq=10_000_000)
pwm = PIOPWM(0, 18, max_count=250, count_freq=10_000_000)

#DC vector has 250 samples
sines = [
    124, 127, 130, 133, 136, 139, 142, 145, 148, 152,
    155, 158, 161, 164, 167, 170, 172, 175, 178, 181,
    184, 186, 189, 192, 194, 197, 200, 202, 204, 207,
    209, 211, 214, 216, 218, 220, 222, 224, 226, 227,
    229, 231, 232, 234, 235, 237, 238, 239, 240, 241,
    242, 243, 244, 245, 246, 246, 247, 247, 248, 248,
    248, 248, 249, 249, 248, 248, 248, 248, 247, 247,
    246, 246, 245, 244, 243, 242, 241, 240, 239, 238,
    237, 235, 234, 232, 231, 229, 227, 226, 224, 222,
    220, 218, 216, 214, 211, 209, 207, 204, 202, 200,
    197, 194, 192, 189, 186, 184, 181, 178, 175, 172,
    170, 167, 164, 161, 158, 155, 152, 148, 145, 142,
    139, 136, 133, 130, 127, 124, 120, 117, 114, 111,
    108, 105, 102, 99, 95, 92, 89, 86, 83, 80,
    77, 75, 72, 69, 66, 63, 61, 58, 55, 53,
    50, 48, 45, 43, 40, 38, 36, 33, 31, 29,
    27, 25, 23, 21, 20, 18, 16, 15, 13, 12,
    10, 9, 8, 7, 6, 5, 4, 3, 2, 1,
    1, 0, 0, -1, -1, -1, -1, -1, -1, -1,
    -1, -1, -1, 0, 0, 1, 1, 2, 3, 4,
    5, 6, 7, 8, 9, 10, 12, 13, 15, 16,
    18, 20, 21, 23, 25, 27, 29, 31, 33, 36,
    38, 40, 43, 45, 48, 50, 53, 55, 58, 61,
    63, 66, 69, 72, 75, 77, 80, 83, 86, 89,
    92, 95, 99, 102, 105, 108, 111, 114, 117, 120,
]


#DCx pot = ADC(26)    # deleted pot reference here for wo Pot
delay = [400]


def read_pot():
    while True:
        #DCx v = pot.read_u16()
        #DCx // is floor division (i.e. discard fractionary value)
        #DCx delay[0] = 20 + (400 * v)// 65000
        delay[0] = 20 + 10 #200 is midpoint on pot
        #DC 20 + 10 is about 600 Hz
        sleep_ms(100)


_thread.start_new_thread(read_pot, ())

while True:
    for i in range(0, 250, 25):
        pwm.set(sines[i])
        sleep_us(delay[0])

#DC Source: http://blog.rareschool.com/2021/02/raspberry-pi-pico-simple-projects.html
#DC end program #signalGenerator_pico.py
::::::::::textpak=>Test_readCD2works.py.txt
import sys, time
#sys.path.append("/home/pi/Desktop/IX_assets/ix")
###########################

def initCD2(PPin):
    import RPi.GPIO as GPIO
    #By D@CC on 2023KNov01
    #PPin-2 is PPout  (tested with PPin = 40)
    GPIO.setmode(GPIO.BOARD) #physical Board numbers
    #GPIO.setmode(GPIO.BMB)   #BroadCoM numbering eg GPIO #s
    print("PPin-2:",PPin-2)
    isBadPin= ((PPin-2==1) or (PPin-2==17))  # they are 3v3
    # Ground pins won't work either, nor 5v0 pins
    print("isBadPin:",isBadPin)
    if not isBadPin:
        GPIO.setup(PPin-2,GPIO.OUT)
        print("turn On phys pin:", PPin-2)
        GPIO.output(PPin-2, True)
    #if end

    # on a Raspberry Pi, PullUpDown is a 10k resistor
    # a photoresistor photocell (CD) when  lit is   100.
    #                                when dark is >10k0.
    return
#def end initCD2(PPin)
#::::::::::textpak=>readCD2.py
def readCD2(PPin):
    import RPi.GPIO as GPIO
    #By D@CC on 2023KNov01

    #Purpose: to return True if both CDs are covered
    #HW: my device "CD2_Dongle(c)"
    #Tested with PPin=40
    GPIO.setmode(GPIO.BOARD) #physical Board numbers
    GPIO.setup(PPin, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
    reading=GPIO.input(PPin)
    # reading is True if the CD photoCells are Dark
    # Make them dark by covering them with a finger
    if reading:                                                                                                                                                                                                    
        state=False
    else:
        state=True
    #if end
    return state
#def end

progName="Test_readCD2works.py"
PPin=40	#works as GPIO21 on Maker pHAT
#PPin=21  #for Maker pHAT
#Purpose: test my device "CD2_Dongle(c)"
#By: D@CC on 2023KNov01
#Issue: SW uses RPi.GPIO which is deprecated on RPi 5
#Warning: Ignore RuntimeWarning: . . . in use . . .
#Status: HW & SW are both working
#Functions Used: initCD2,readCD2
#Packages Used: Desktop/ix/ix_pkg.py
#Python Packages Used: sys,time
#Future: should use GPIO ZERO SW
# Use Phy Pin 40 on the Pi400
# But when also using the Cytron Maker pHAT:
#   other devices are attached to various pins
#   so, use Phy Pin 21 as input (with Phy pin 19)
# Closing Maker pHAT button 21 makes Phys Pin 40:
#  "Dark" equivalent to CD2 Dark between 38 & 40
print("progName:",progName,"Phys Pin:",PPin)
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BOARD) #physical Board numbers																																																		GPIO.setup(PPin, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
#Purpose: to sense if 2CD photocells "see" Light or Dark
#          using an internal pulldown resistor
#By D@CC on 2023JOct30
# tested with PPin=40 on a Raspberrry Pi400
#Cover the CDs with a thumb to "Make it Dark"
print("uses RPi.GPIO (fails on RPi 5B)")
print("always works with 2 CD in series (covering both), ")
print("works with 1 CD sometimes. . . ")
print("CDs from phys pin 38 (with output High).")
#                        19
print("  to phys pin 40 (as input with PUD_DOWN)")
#                    21
#PPout=38  #phys pin 38 #GPIO 20  output
#PPin =40  #phys pin 40 #GPIO 21  input

#This also works with PPin = 37 (But not PPin=3 nor 19)
# It probably works with some other adjacent pin pairs
initCD2(PPin)
while True:
    print("PPin:",PPin)
    if readCD2(PPin):
        print("Dark")
    else:
        print("Light")
    #if end
    time.sleep(1)
#while end
#/Test_readCD2works.py.txt
::::::::::textpak=>test_TxG_pico.py.txt
# test_TxG_pico.py
# stored in Raspberry Pi Pico/
#   and  in /home/pi/Desktop/Python_new/ix_pico_test/

import os
import utime
from machine import UART, Pin

#by D@CC
#Date: 2021FJun21
#Note: as of today, no known errors  ver F is first to work successfully

# all functions and subroutines are at top of program
#  1. bChar()       converts 4 char byte into 1 char
#  2. serTx_pico()  transmits a full serial text message
#  3. txParse()     parses the outgoing text message and calls txChar
#  4. txChar()      adds the char to oP which is the output text packet queue
#  5. sendThisPack()actually transmits a full packet (wo any EOM)
#  6. sendLastPack()actually transmits text (with at least one EOM)
#  7. serRx_pico()  receives  a full serial text message
# testTx          transmits many test messages
# testRx          receives all test messages

#calling parms
#bChar(strB):
#serTx_pico(uartObject,bps=300, txtToBeSent="Hello,World",rxtxEndChar="]",pktSize=16):
#txParse(uartObject, thisMsg, bps=300, msgFormat="SMEPX", T5C=-1, pktSize=16,  eom="]"):
#txChar(char):
#sendThisPack(uartObject, oPIn, eom, pktSize):
#sendLastPack(oPIn, cntSent, cntUsed,  eom = "]", pktSize=16):
#serRx_pico(uartObject, bps=300, timeOut=-1, eom="]"):
#
#   test_pktixRx_pi.py   OUTLINE
#
#All Use: int,str,time,strip,hex,float

#txToBeSent->|1.test_TxG_pico
#               ------------
#               1.RAPasc(->strRAPasc
#                 -------
#                 1.readADC_pico(->adcVoltage
#                 2.serTx_pico(->True
#                   -----------
#                   1.txParse(
#
#
#            |a.txParse(->a.sendThisPack(->|
#            |            b.sendLastPack(->|->a.uart.write(->GP5
#            |  --------  --------------
#            |  1.txchar(   
#            |  2.sleep(
#            
#
#
#            |0.testpktixRx(
#            |  ------------
#txIncoming->|1.machine.UART(
#            |2.serRx_pico(->oP
#            |  -----------
#            |  1.mpyRead(->strA
#                 --------                    
#                 1.bChar(->txtRead))))))))))))))
               
               
#Debugging notes:
#"tx sent:" is what is actually sent

# Errors and Warnings are embedded in the text transmitted. 
def readADC_pico(nn,cnvrt=5.035477e-05):
    #nn is the pico GPnn (ADCnn) to read
    #cnvrt = 5.035477e-05 converts the reading to volts.
    # that is the default cnvrt factor.
    adcFirst = machine.ADC(nn)
    adcValue=adcFirst.read_u16()
    #print("The value of ADC0 is", adcValue)

    #conversion_factor = 3.3 / (65535)
    #print("conversion_factor:",conversion_factor)
    adcVoltage=adcValue * cnvrt
    #print("The voltage at ADC0 is", adcVoltage)
    #print("-bye- from readADC_pico.py")
    return adcVoltage
#end def

def bChar(strB):                                                                   #bChar()
    #  given a string like b'z' this returns the "z"
    # tested by D@CC on 2021FJun15
    
    #strB=input("eg b'h' :")
    b=strB[2:]
    #print("b:"+b)
    c=b[0]
    #c="z"
    #print("bChar("+'"'+strB+ '"):'+c)
    return c
#end def


def serTx_pico(uartObject,bps=300, txtToBeSent="Hello,World",rxtxEndChar="]",pktSize=16):         #serTx_pico#

    #print("txtToBeSent:"+txtToBeSent+":")
    #every parameter has a default setting except the uartObject (which needs to be defined).
    t5c=50/bps          #   50 bit times = 5 character times
    t10c=100/bps        #  100 bit times = 10 character times
    t1000c=10000/bps    # 10000 bit times = 1000 character times
    
    # requires a uart object (below) to be created before this function is called
    #uart = machine.UART(1, 300, parity=None, stop=1, bits=8, tx=Pin(txPin), rx=Pin(rxPin))
    #print("entering serTx_pico.py")
    if rxtxEndChar=="]":
        som = "["
        eom = "]"
    
    msgOut = """
    #S +
    #M +
    #E +
    #P +
    #C"""

    
    
    #where
    #A is the letter "A" meaning "16 bit packets (pktSize)"
    #S is SOM
    #M is Message text to be sent (will be followed by EOM)
    #E is EOM
    #P is the padding characters (enough EOMs to fill the packet)
    #X is t10c  (ten character time delay: "roman numeral X")
    #C is t100c  (100 character time delay: "roman numeral C")
        
    #Most messages will have   msgOut = "AC" "SMEPX"

    #Between messages, the transmitter will send "0" every minute indicating that its alive but
    #has no message to send.
    #Before sending each message the transmitter will send a single "A" which is 0x41 indicating
    #that the following message will be in packets of 16 characters.  In the future when the
    #packet size.
    #changes to 32 characters, the transmitter will precede each message with a single "B"
    #indicating the each packet will contain 32 characters.  This will allow future packet sizes
    #at least as big as 16x16x4 = 1024 characters and total message lengths of around 32768 without
    #using any control characters in the "ascii" preamble.

    #   Future versions will have msgOut = "DSNKMEPX"
    #    with packets having the format:
    #        AX SNKMV MV MV etc MEPX
    #The optional packet of 16 x D permits synchronization
    # 
    #where
    #D  is a full packet of Delete characters (optional for synchronization
    #N is the 2-character packet Number
    #K is the 2-character message character "Kount" including the only the first final EOM
    #V is t5c  (5 character time delay: "roman numeral V")


    #When a receiver starts up (and between messages) it should start by expecting packets of single
    #characters.  It will read a single 8-bit character expecting it to be a "0" meaning an idle transmitter.
    #If it is not a "0", it will read another single 8-bit character expecting it to be an "A".  If it is not an
    #"A",the character will be discarded, but the receiver will presume that it is reading a character
    #stream that is mid-message.  It will read single 8-bit characters searching for a "]" which will indicate
    #that this is the last packet of the message. It will keep reading and discarding all the "]" that it sees.
    #After the last "]", the
    #next 8-bit character should be a "0" or an "A".  The receiver should keep reading and discarding the "0"
    #characters.  When an "A" is finally received (while reading single 8-bit characters), the receiver knows that
    #this means subsequent packets will be packets of 16 characters.  The receiver is now fully
    #synchonized with the transmitter.  If something other than an "A" is received, the receiver should
    #begin looking for a "]" ()meaning "end of message" again.  If the state of "being in mid-message
    #continues 10 times, a human operator should be informed the that this ERROR is occuring.
    #
    #send the message
    txParse(uart,txtToBeSent)       #xyz
    #print("end of serTx()")
    #print("Hit ^C to stop!")
    #print()
    return True
#end def serTx_pico()
def txParse(uartObject, thisMsg, bps=300, msgFormat="SMEPX", T5C=-1, pktSize=16,  eom="]"):    #txParse()
    #show("thisMsg:",thisMsg)
#
#    uartObject is the uart being used
#    thisMsg is the full text message to be sent (It should not contain (EOM="]") they will become "?")
#                          (An EOM is added as the last character of a message, do not put the EOM in the msg)
#    bps is the baud rate (bits/sec)
#    msgFormat is the form of the Msg e.g. SMEPX  (first E is counted as last char of M)
#                                                (P is enough additional EOMs to pad to packetSize=16)
#                                               (t5c is interval between packets (-1 defaults to t5c)

#    t5c indicates time interval of 5 characters.  The transmitter will follow each packet with
#       this time delay
#    packetSize defaults to 16
#    eom is the definition of the 'EOM" character (usually "]")
    #oP is the full outgoing Packet that is sent by sendThisPack
    #                                      or by sendLastPack
    oP=""            # outgoing msg is initially empty
    if T5C==-1:    # if the calling routine doesn't specify
       t5c=50/bps
       t10c=100/bps
       t1000c=10000/bps
    else:
        t5c=T5C       #if the calling routine does specify T5C
        t10c=T5C*2
        t1000c=T5C*200
    #end if
    if eom=="]":
        som="["
    #end if

#    in 2021 msgOut="SMEPX"
    lenM=len(thisMsg)+1      #length of thisMsg -1  (+1 for the EOM character
    cntUsed=0                # number of characters in msgOut used so far
    cntSent=0                # number of character actually sent (incl all chars sent)
    isEOMsent=False          #EOM not sent yet
    #show("msgFormat:",msgFormat)
    for msgPart in msgFormat:   # do each message segment
        if msgPart=="S":
            # send SOM
            #print("send SOM")
            oP=oP+txChar(som)
            oP=oP+txChar("1")      # in future these 2 characters will contain parity or CRC
            oP=oP+txChar("6")      # today they contain the packet size (ie character count)
            cntSent=cntSent+3 #3 actually sent now
            #print()
            #print("oP:"+oP+":")
            cntUsed=0
        #end if
        if msgPart=="X":     # time delay doesn't send any characters
            utime.sleep(t10c) 
        #end if
        if msgPart=="M":     # sends the msg followed by 1 eom
            #print("sending M")
            #cntSent of the packet is already in oP
            #cntUsed is 0 going into the while
            # note that lenM also includes 1 eom
            # in the while loop, cntUsed will increase until cntUsed=lenM
            while (lenM-cntUsed) >= 1 : #lenM incl the EOM, cntUsed does also (after the EOM is sent)
                #print("going into the M while")
                #show("upon entry M-while cntUsed:",cntUsed)
                #  the packet being sent should not include any EOM characters. (EOM is only in the last pk)
                #  send a packet of data
                # lastChar is the lastChar of Msg to send in this packet
                cntCanAdd=pktSize-len(oP)
                #print("cntCanAdd:",cntCanAdd,":")
                #show("cntUsed:",cntUsed)  #should be 0 entering first loop

                cntRemainOfM=lenM-cntUsed-1   #this cnts the remaining chars of M 
                cntToAdd=pktSize-len(oP)    #this cnts the remaining space in oP
                # a packet is always sent in this next "if clause"
                #show("cntRemainOfM:",cntRemainOfM)
                #show("cntToAdd:",cntToAdd)
                #if (cntRemainOfM)>cntToAdd :   #{for debugging}
                if (cntRemainOfM+1)>cntToAdd :  #{for debugging} ver F +1
                # this packet cannot hold rest of Msg plus an eom
                    isLastPack=False 
                    opToAdd=thisMsg[cntUsed:cntUsed+cntToAdd]  # to add to oP
                    opToSend=oP+opToAdd                        # to be sent
                    #print("AopToSend:"+opToSend+":")
                    cntPadding=0
                    sendThisPack(uartObject, opToSend, cntPadding, eom, pktSize)
                    # that sent a full pkt without any padding
                    #cntUsed=cntUsed+cntToAdd+1
                    cntUsed=cntUsed+cntToAdd    #{for debugging} ver F del "+1"
                    # remember to count the first EOM as a character in cntUsed
                    #show("cntUsed:",cntUsed)
                    #show("lenM:",lenM)
                    oP=""
                    cntSent=0
                    #continue the while loop
                else :
                    isLastPack=True
                    # the pkt can hold the whole cntRemainOfM
                    opToAdd=thisMsg[cntUsed:cntUsed+cntRemainOfM]

                    #print("BopToSend:"+opToSend+":")
                    cntPadding=pktSize-cntSent-cntRemainOfM
                    strPadding=eom*cntPadding
                    opToSend=oP+opToAdd+strPadding
                    #print("CopToSend:"+opToSend+":")
                    
                    sendLastPack(uartObject, opToSend, cntPadding, eom, pktSize)
                    # that sent a full pkt including the padding                        
                    cntUsed=cntUsed+len(opToAdd)
                    #show("lenM:",lenM)
                    #show("cntUsed:",cntUsed)
                    oP=""
                    cntSent=0
                    #print("after Last Packet of Msg")
                    toSend=lenM-cntUsed
                    #show("toSend:",toSend)
                    #print("end of while")
                    break            #out of the while
                #if end
                cntUnsent=lenM-cntUsed-1
                #show("cntUnsent:",cntUnsent)
                #print("repeat the M while")
            #end while                 




            if False :
                # we need to send at least 1 more full packet
                isLastpack=False
                lastChar=cntUsed+(pktSize-len(oP)) #this is lastChar of Msg yet to send
                opToAdd=thisMsg[cntUsed:lastChar]  # to add to oP
                opTosend=oP+opToAdd
                print("opToSend:"+opToSend+":")
                sendThisPack(uartObject, opToSend, eom, pktSize)
                # no padding was necessary
                cntUsed=cntUsed+len(opToAdd)
                show("cntUsed:",cntUsed)
                # the while will loop once more
            #end if
            if False :
                lastChar=pktSize-cntSent
                show("lastChar",lastChar)
                #thisMsg="12345678901234567"
                #print("thisMsg:"+thisMsg+":")
                show("cntUsed",cntUsed)
                show("lastChar",lastChar)
                show("thisMsg[cntSent:lastChar]",thisMsg[cntUsed:lastChar])
                opWasSent=thisMsg[cntUsed:lastChar]
                print("opWasSend:"+opWasSend+":")
                if len(opToSend)>=16 :
                    print()
                    print("before sendThisPack oP:"+oP+":")
                    cntSent=sendThisPack(uartObject,opToSend, eom, pktSize)
                                           #returns 16  should print the Pkt
                    oP=""
                    show("cntUsedFromMsg:",cntUsedFromMsg)
                    cntUsed=cntUsed+cntUsedFromMsg    # should be 16 ...... to verify
                    cntSent=cntSent+16
                    show("lenM",lenM)
                    show("cntUsed",cntUsed)
                    isLastPacket=False
                else:
                    print("need to send padded Packet")
                    isLastPacket=True
                #end if
            #end if False
            if False :
                # a packet has just been sent
                leftToSend=lenM-cntUsed-1
                show("leftToSend:",leftToSend)
                if False :
                    if isLastPacket==True :       # will send the Last Packet (containing at least 1 EOM)
                        print("isLastPack is True")
                        #useStr=thisStr
                        cntUsedFromMsg=len(opToSend)
                        oP=opToSend
                        toAdd=16-cntUsedFromMsg
                        show("toAdd:",toAdd)
                        for x in range(toAdd):      # must insert correct range !!!!!
                            oP=oP+txChar(eom)           # must insert correct char from fullMsg !!!!!
                            cntSent=cntSent+1
                        #end for
                        print()
                        print("before sendThisPack oP:"+oP+":")
                        cntSent=sendThisPack(uartObject,oP, eom, pktSize)
                        #returns 16  should print the Pkt
                        oP=""
                        cntUsed=cntUsed+cntUsedFromMsg
                        show("cntUsed:",cntUsed)
                    #end if
                #end if False
                # a packet was just sent
                print("M while might end now")
                print("after end of while")
            #end if False
        #end if "M"

        if False :
            if msgPart=="P":                # P means Padding (with more EOMs) if any needs to be sent
                print("msgPart=P")
                if False :
                    if True:     # to be decided
                        oP=oP+txChar(eom)        # how many eoms of padding  !!!!!
                        cntUsed=cntUsed+1
                        cntSent=cntSent+1
                    #end if
                    show("cntUsed",cntUsed)
                    strSent=thisMsg[cntUsed:cntUsed+16]
                    show("strSent:",strSent)
                    cntUsedFromMsg = sendLastPack(uartObject, strSent, eom, pktSize) # should print the Pkt
                    cntUsed=cntUsed+cntUsedFromMsg
                    cntSent=cntSent+pktSize   #pktSize is usually 16
                #end if
            #end if "P"
        #end if False
        
    #end for    # all msg parts have now been sent
    # should check that cntUsed = len(Msg) +1
    # should check that cntSent is a muliple of pktSize(eg 16)
    return #from parsing and transmitting
#end def
def txChar(char):                                                                       #txChar()        
    #simply records that "char" has been sent
    # just prints it during testing
    # doesn't actually send the char
    #print(char, end='') #"end" suppresses the line feed
    return char
#end def

def sendThisPack(uartObject, opIn, cntPadding, eom, pktSize):                        #sendThisPack()
#

#actually sends the 16 characters in oP
    #print()
    #print("in sendThisPack")
    oP=opIn
    lenopIn=len(opIn)
    if (lenopIn==pktSize)==False:
        print("ERROR",pktSize, "is not the size of the packet to send:",lenopIn)
    #end if
    pos=opIn.find(eom)
    if pos==-1:              # -1 if not found
        pass
    else:
        print("WARNING E1 in serTx", eom, "found eom in message")
        #oP=oP.replace(eom,"?")   
        oP=oP.replace(eom,"?",1)   #{for debugging} ver F  replace once
    #end if
    uartObject.write(oP)
    #print("tx sent:"
    # in sendThisPack
    print(oP, end='')    #this actually sends the text to the Shell
    #                    because in this early version, what is shown
    #                    in the Shell is actually sent.
    #print()              #{for debugging}
    return pktSize
#end def

def sendLastPack(uartObject, opIn, cntPadding, eom, pktSize):                        #sendThisPack()
#

#actually sends the 16 characters in oP
    #print()
    #print("in sendLastPack")
    oP=opIn
    #print("oP:"+oP+":")
    lenopIn=len(opIn)
    #show("lenopIn:",lenopIn)
    if (lenopIn==pktSize)==False:
        print("ERROR",pktSize, "is not the size of the packet to send:",lenopIn)
    #end if
    #search for eom in the non-padding portion of oPIn
    suboPIn=opIn[0:pktSize-cntPadding]
    #print("suboPIn:"+suboPIn+":")
    pos=suboPIn.find(eom)
    if pos==-1:              # -1 if not found
        pass
    else:
        print("WARNING E2 in serTx", eom, "found in message")
        oPleft=opIn[0:pos]          #{for debugging} ver F fix
        #print("oPleft:"+oPleft+":")
        lenOp=len(opIn)             #{for debugging} ver F fix
        oPright=opIn[pos+1:lenOp]   #{for debugging} ver F fix
        #print("oPright:"+oPright+":")        
        #oP=oP.replace(eom,"?")
        #oP=oP.replace(eom,"?",1)   #{for debugging} replace once didn't work
        oP=oPleft+"?"+oPright       #{for debugging} ver F fix
    #end if
    uartObject.write(oP)
    # in sendLastPack():
    #print("tx sent:"+
    print(oP, end='')    #keep user informed during testing
    #print()              #{for debugging}
    return pktSize
#end def
def mpyRead(uart):
    #keep read1 character packet until timeOut
    txtRead=""
    bRead=""
    while uart.any():

        aByte=str(uart.read(1))
        #show("aByte:",aByte)
        bRead=bChar(aByte)
        #show("bRead:",bRead)
        txtRead=txtRead+bRead
    #end while
    return txtRead
#end def



#  serRx_pico()   receives  a full serial text message               #serRx_pico()
def serRx_pico(uartObject, bps=600, timeOut=-1, eom="]"):
    #uart = machine.UART(1,bps, parity=None, stop=1, bits=8, rx=Pin(5), tx=Pin(4))
    print("my uart:",uart)
    #print("timeOut is set to:",timeOut)
    if timeOut==-1:
        t100c = 1000/bps
        timeOutUse=int(t100c+1.0)   #at least 1 sec
        #show("timeOutUse:",timeOutUse)
    else:
        timeOutUse=timeOut   #in seconds
    #end if
    #timeOutUse=t100c
    time=utime.time()
    time=str(int(time)+secsToAdd)#{for debugging}
    #time=time+secsToAdd
    timeNow=time
    #show("timeNow:",timeNow)
    timeFail=timeNow+timeOutUse    # defaults to a 3 second TimeOut
    #print("waiting my:",timeOutUse," seconds for data receipt. . . . .")
    oP=""  # reset input buffer
    #show("time:",time)
    #show("timeFail:",timeFail)

    while time < timeFail :
        #keep reading any 1 character packets until timeOut
        print("I should be flashing the green LED while receiving")
        # I don't know if it is still receiving
        # it should write the received msg to a file.
        #print("any")
        strA=mpyRead(uart)
        #show("strA:",strA)
        oP=oP+strA
        #show("oP:",oP)
        #end if
        time=utime.time()
        time=str(int(time)+secsToAdd)#{for debugging}
        time=time+secsToAdd
    #end while
    #show("oP:",oP)
    lenOp=len(oP)
    if oP=="":
        print("ERROR T in serRx (): timeOut after",timeOutUse,"seconds")
        lenOp=len(oP)
    #end if
    if lenOp > 0:
        if oP.find("?")==-1:
            pass            # ? not found
        else:
            print("WARNING '?' seen in message received.")
        #end if
    #end if
    #print("serRx() received:"+oP+":")   #during testing
    return oP
#end def serRx_pico(uart,300,timeOut(in secs))

def show(strA,parmA):                                        # show
    print(strA,parmA)
    return
#end def
def readADC_pico(nn,cnvrt=5.035477e-05):
    #nn is the pico GPnn (ADCnn) to read
    #cnvrt = 5.035477e-05 converts the reading to volts.
    # that is the default cnvrt factor.
    adcFirst = machine.ADC(nn)
    adcValue=adcFirst.read_u16()
    #print("The value of ADC0 is", adcValue)

    #conversion_factor = 3.3 / (65535)
    #print("conversion_factor:",conversion_factor)
    adcVoltage=adcValue * cnvrt
    #print("The voltage at ADC0 is", adcVoltage)
    #print("-bye- from readADC_pico.py")
    return adcVoltage
#end def
def RAPasc(reading,nnIn,rFormat):
    #returns the RAPasc packet
    #print("nnIn:",nnIn)
    if nnIn==0 :
        nn=0      #ADC number = 0 or 1 usually
        strNN=str(nn)
    #end if
    if nnIn==1 :
        nn=1      #ADC number = 0 or 1 usually
        strNN=str(nn)
    #end if
    if nnIn==26 :
        nn=26      #ADC number = 0 or 1 or 26 usually
        strNN=str(nn)
    #end if
    # prepare the time
    timeNow=utime.time()
    intTime=int(timeNow)
    #print("intTime:",intTime)
    intTime=intTime+secsToAdd      #{for debugging}
    timeNow=str(intTime)           #{for debugging}
    #timeNow=timeNow+secsToAdd     #{for debugging}
    strTime=str(timeNow)+".000"
    strReading="???"
    #print("rFormat:"+rFormat)
    if rFormat=="X":
        # use strReading as Hex # (It comes as a Hex #)
        # I need to improve this by receiving the #
        # as a string and using f3() to convert it to float
        hexNumber=readADC_pico(nn,cnvrt=1.000)
        #print("hexNumber:",hexNumber)
        strReading=str(hexNumber)
        #print("|"+strReading+"|")
        strReading=strReading.strip()
        #h = str(hex(i))[2:]
        #h = h.upper()
        hexNumber=int(hexNumber)
        #print("hexNumber:",hexNumber)
        strReading=str(hex(hexNumber))[2:]
        #print("strReading:"+strReading)
        strReading="0x"+strReading.upper()
    #end if
    if rFormat=="F":
        # use strReading as Float # (It comes as a Hex #)
        strReading=str(float(readADC_pico(nn,cnvrt=5.035477e-05)))
        #print("|"+strReading+"|")
        strReading=strReading.strip()
    #end if
    #print("strNN:"+strNN)
    strRAPasc="ADC"+strNN+":("+strReading+"+"+strTime+"j)"
    return strRAPasc
#end def RAPasc

##########################################################################################
##########################################################################################
progName="test_TxG_pico.py"
print("progName:"+progName)


if True:
    bps=600
    print("tx bps:",600)
    tPause=1 
    txPin=5
    rxPin=4
    #
    #print sys info
    print(os.uname())       #os, utime and machine were imported at top

    #indicate program started visually (by blinking the green LED)
    led_onboard = machine.Pin(25, machine.Pin.OUT)
    led_onboard.value(0)     # onboard LED OFF for 0.5 sec
    utime.sleep(0.5)
    led_onboard.value(1)    # leaving it ON

    #create uart object sample code
    if False :
        #self.uart = UART(1, 115200, parity=None, stop=1, bits=8, rx=Pin(rxPin), tx=Pin(txPin))
        pass
    #end if

    #create actual uart object
    uart = machine.UART(1,bps, parity=None, stop=1, bits=8, rx=Pin(5), tx=Pin(4))
    #print uart info
    #uart = machine.UART(1)
    print(uart)         # during testing


    # verifying and adjusting localtime and gmtime
    timeLocal=utime.localtime()
    strLocal=str(timeLocal)
    print("strLocal:"+strLocal)
    timeGMT=utime.gmtime()
    strGMT=str(timeGMT)
    print("strGMT  :"+strGMT)
    strAnsw=input("Are these Correct?:")
    if "nN".find(strAnsw)==-1 :
        pass
    else:
        addToGMT=input("what N (hours) should we add to GMT?")
    #end if
    print("this routine will add",addToGMT,"hours to GMT")
    secsToAdd=3600*int(addToGMT)  #convert hrs to secs
    #                     create uartObject
    #uart = machine.UART(1,bps, parity=None, stop=1n, bits=8, tx=txPin, rx=rxPin)
    #    send a single "A"  which is 0x41 ("A"-0x40 * 16 is the packet length which is 16

    #                                         initialization is complete

    #uart.write("A")     #every group of messages is preceeded by a single "A"
    # prior to the "A", the transmitter should send a synchronizing sequence to permit
    #               the (human) receiver to "guess" or "determine" the baud rate (the bps)
    # hopefully the operator of the transmitter and receiver is the same human.

    # the serRx_pico should be running in a separate thread.

    #def serTx_pico(uartObject,bps, txtToBeSent="[UUUUUUUU]",rxtxEndChar="]"):
    print("transmitting Hello msg on Pin(GP4) in 2 16 byte packets at")
    print("60 bps, continuously preceded by an 'A' at 2 sec intervals")
    print("the 'A' is not seen by the receiver") 
    #print("it erroneously skips the 'o' in 'Roy'. Doh!") #fixed in ver F
    print("it erroneously skips a full packet of ']' when needed") 

    print("Hit ^C to stop!")
    print()

    while True :
        uart.write("A")
        utime.sleep(tPause)
        #read and create format RAPasc using the following function call
        #strRAPasc=RAPasc(readADC_pico(n1,cnvrt=5.035477e-05),1,"F")
        #           readADC_pico() reads ADC[nn], by default cvrts to volts
        #                          and returns the reading in volts
        #                    but can read ADC[nn], cvrts using another factor
        #                          and returns the converted reading
        #                    but can read ADC[nn], do no conversion (cnvrt=1.000)
        #                          and return the unconverted reading
        #    RAPasc(accepts the reading, followed by the time into the format
        #           ADC1:(56.789+875678.000j) if 2nd parm is "F"
        #    RAPasc(accepts the reading, followed by the time into the format
        #           ADC1:(0xffff+875678.000j) if 2nd parm is "X" 
        

#        *************************************************************
        strRAPasc=RAPasc(readADC_pico(0,cnvrt=5.035477e-05),0,"F")
        #finally the the ADC1:(reading+timej) string is ready
        # to be converted into serial packets
        serTx_pico(uart,bps, txtToBeSent=strRAPasc)
        utime.sleep(tPause)

        strRAPasc=RAPasc(readADC_pico(1,cnvrt=1.0000),1,"X")
        #finally the the ADC1:(reading+timej) string is ready
        # to be converted into serial packets
        serTx_pico(uart,bps, txtToBeSent=strRAPasc)
        utime.sleep(tPause)

        strRAPasc=RAPasc(readADC_pico(26,cnvrt=5.035477e-05),1,"X")
        #finally the the ADC1:(reading+timej) string is ready
        # to be converted into serial packets
        serTx_pico(uart,bps, txtToBeSent=strRAPasc)
        utime.sleep(tPause)
        
        print()


        try:
            utime.sleep(tPause)                    #{for debugging}
        except:
            # this try/except code permits the tester to stop here using ^C
            print("interrupted by ^c")
            break
        finally:
            pass
        #end try
    #end while
#end if True
##########################################################################
#   everything after here is old deprecated code                         #

###########################################################################
# testpktixRx()
if False:
    if False:
        # the above is the current format of the rxtx protocol
        # The som,eom,t10c and are 1-character special codes
        #    each must be converted into outgoing text or actions or both
        #    all normal text does not need to be converted before transmission
        #
        # The txParse routine analyses the msgOut Format and separates it into
        # special codes (text and actions).  Each special code is sent to the txChar()
        # routine to be processed. Each character of outgoing text is sent to the
        # txChar() routine to be processed.
        #
        # The serTx_pico() routine is used to
        #   transmit a special code of text ("S" and "M")
        #   cause a time delay (V is "t5c X is "t10c  " and M is "t1000c")
        #   transmit msg as 16-byte packets (msg should not contain "]" which is replaced by "?" )
        #
        #   early testing Format is "SMEPX"
        #
        # Note that the "P" also inserts at least 1 "]" character and
        #   enough extra "]" characters (or none) to make a message with an exact multiple
        #   of 16 characters.  This is because there are always 16 characters sent per
        #   packet. Each packet is followed by a time delay of t5c.
        #   The last packet is always followed by a time delay of t10c.
        #   These time delays permit the receiver to resync with the transmitter.
        #   These time delays are never included in the character count of the
        #   message
        #   The serRx_pico() routine times out after an interval of 1000 character times: t1000c
        pass
    #end if

    # This should be run this as a separate thread
    # print whatever has been received
    bps=600
    t100c=1000/bps
    utime.sleep(t100c) #wait for an interval of 100 char times
#end if False

#uart = machine.UART(1,bps, parity=None, stop=1, bits=8, tx=Pin(txPin), rx=Pin(rxPin))
bps=600
uart = machine.UART(1,bps, parity=None, stop=1, bits=8, tx=Pin(4), rx=Pin(5))
print("uart:",uart)
if False:
    uart.write("hello")
    t100c=1000/bps
    utime.sleep(t100c) #wait for an interval of 100 char times

    uart.write("Hello,World")
    utime.sleep(t100c) #wait for an interval of 100 char times
    utime.sleep(1)     #1 sec
#if end False
if False:
    print("receiving mpy routine")
    while uart.any():
        print(uart.read(1))
    #end while
#end if False
charIn=""
if False:
    print("receiving mpy routine")

    if uart.any() :
        #print("reading now")
        charIn=uart.read(1)
        #show("charIn:",charIn)
        #oP=oP+uartObject.read(1)
    #end if
    print("end of mpy routine")
#end if False
show("charIn:",charIn)
#end if
print("receiving my routine")
msgIn=serRx_pico(uart,bps=600)   #times out after t100c seconds (100 char-times)
print("msgIn:",msgIn)

print("end of serRX()")

#end /test_TxG_pico.py
# stored in Raspberry Pi Pico/
# stored in /home/pi/Desktop/Python_new/ix_pico_test/

::::::::::textpak=>test_TxH_pico.py.txt
# test_TxH_pico.py
# stored in Raspberry Pi Pico/
#   and  in /home/pi/Desktop/Python_new/ix_pico_test/

import os
import utime
from machine import UART, Pin

#by D@CC
#Date: 2021FJun21
#Note: as of today, no known errors  ver F is first to work successfully

# all functions and subroutines are at top of program
#  1. bChar()       converts 4 char byte into 1 char
#  2. serTx_pico()  transmits a full serial text message
#  3. txParse()     parses the outgoing text message and calls txChar
#  4. txChar()      adds the char to oP which is the output text packet queue
#  5. sendThisPack()actually transmits a full packet (wo any EOM)
#  6. sendLastPack()actually transmits text (with at least one EOM)
#  7. serRx_pico()  receives  a full serial text message
# testTx          transmits many test messages
# testRx          receives all test messages

#calling parms
#bChar(strB):
#serTx_pico(uartObject,bps=300, txtToBeSent="Hello,World",rxtxEndChar="]",pktSize=16):
#txParse(uartObject, thisMsg, bps=300, msgFormat="SMEPX", T5C=-1, pktSize=16,  eom="]"):
#txChar(char):
#sendThisPack(uartObject, oPIn, eom, pktSize):
#sendLastPack(oPIn, cntSent, cntUsed,  eom = "]", pktSize=16):
#serRx_pico(uartObject, bps=300, timeOut=-1, eom="]"):
#
#   test_pktixRx_pi.py   OUTLINE
#
#All Use: int,str,time,strip,hex,float

#txToBeSent->|1.test_TxG_pico
#               ------------
#               1.RAPasc(->strRAPasc
#                 -------
#                 1.readADC_pico(->adcVoltage
#                 2.serTx_pico(->True
#                   -----------
#                   1.txParse(
#
#
#            |a.txParse(->a.sendThisPack(->|
#            |            b.sendLastPack(->|->a.uart.write(->GP5
#            |  --------  --------------
#            |  1.txchar(   
#            |  2.sleep(
#            
#
#
#            |0.testpktixRx(
#            |  ------------
#txIncoming->|1.machine.UART(
#            |2.serRx_pico(->oP
#            |  -----------
#            |  1.mpyRead(->strA
#                 --------                    
#                 1.bChar(->txtRead))))))))))))))
               
               
#Debugging notes:
#"tx sent:" is what is actually sent

# Errors and Warnings are embedded in the text transmitted.

#for pin 29
if False:
    if VSYS_ADC_INPUT == 3:
      Pin = machine.Pin
      Pin(29, Pin.IN)
      vsysChannel = machine.ADC(3)
    else:
      vsysChannel = machine.ADC(29)
    #end if
    while True:
      adcReading  = vsysChannel.read_u16()
      adcVoltage  = (adcReading * 3.3) / 65535
      vsysVoltage = adcVoltage * 3
    #end while
#end if False
      
def readADC_pico(nn,cnvrt=5.035477e-05):
    # this is the good version
    # the X prevents it from being used
    #nn is the pico GPnn (ADCnn) to read
    #cnvrt = 5.035477e-05 converts the reading to volts.
    # that is the default cnvrt factor.
    #print("in readADC_pico nn:",nn)
    adcFirst = machine.ADC(nn)
    adcValue=adcFirst.read_u16()
    #print("The value of ADC0 is", adcValue)
    convertedValue=888.88
    print("96 convertedValue:",convertedValue)
    if nn==4 :
        adcVoltage=adcValue*5.035477e-05
        #print("adcVoltage:",adcVoltage)
        convertedVoltage=adcVoltage
        #print("convertedVoltage:",convertedVoltage)
        #temperature = 27 - (reading - 0.706)/0.001721
        convertedValue = 27 - (convertedVoltage - 0.706)/0.001721
        print("104 convertedValue:",convertedValue)
    #end if
    if nn==3:
        if nn==3:
              VSYS_ADC_INPUT = 3
              Pin = machine.Pin
              Pin(29, Pin.IN)
              vsysChannel = machine.ADC(3)
        else:
            vsysChannel = machine.ADC(29)
        #end if
        adcReading  = vsysChannel.read_u16()
        adcVoltage  = (adcReading * 3.3) / 65535
        vsysVoltage = adcVoltage * 3
        #print("vsysVoltage:",vsysVoltage)
        convertedValue=vsysVoltage
        print("120 convertedValue:",convertedValue)
    else:
        pass
        #conversion_factor = 3.3 / (65535)
        #print("conversion_factor:",conversion_factor)
        #convertedValue=adcValue * cnvrt
        print("126 convertedValue:",convertedValue)
        #print("The voltage at ADC0 is", convertedValue)
    #end if
    #print("-bye- from readADC_pico.py")
    return convertedValue
#end def

def bChar(strB):                                                                   #bChar()
    #  given a string like b'z' this returns the "z"
    # tested by D@CC on 2021FJun15
    
    #strB=input("eg b'h' :")
    b=strB[2:]
    #print("b:"+b)
    c=b[0]
    #c="z"
    #print("bChar("+'"'+strB+ '"):'+c)
    return c
#end def


def serTx_pico(uartObject,bps=300, txtToBeSent="Hello,World",rxtxEndChar="]",pktSize=16):         #serTx_pico#

    #print("txtToBeSent:"+txtToBeSent+":")
    #every parameter has a default setting except the uartObject (which needs to be defined).
    t5c=50/bps          #   50 bit times = 5 character times
    t10c=100/bps        #  100 bit times = 10 character times
    t1000c=10000/bps    # 10000 bit times = 1000 character times
    
    # requires a uart object (below) to be created before this function is called
    #uart = machine.UART(1, 300, parity=None, stop=1, bits=8, tx=Pin(txPin), rx=Pin(rxPin))
    #print("entering serTx_pico.py")
    if rxtxEndChar=="]":
        som = "["
        eom = "]"
    
    msgOut = """
    #S +
    #M +
    #E +
    #P +
    #C"""

    
    
    #where
    #A is the letter "A" meaning "16 bit packets (pktSize)"
    #S is SOM
    #M is Message text to be sent (will be followed by EOM)
    #E is EOM
    #P is the padding characters (enough EOMs to fill the packet)
    #X is t10c  (ten character time delay: "roman numeral X")
    #C is t100c  (100 character time delay: "roman numeral C")
        
    #Most messages will have   msgOut = "AC" "SMEPX"

    #Between messages, the transmitter will send "0" every minute indicating that its alive but
    #has no message to send.
    #Before sending each message the transmitter will send a single "A" which is 0x41 indicating
    #that the following message will be in packets of 16 characters.  In the future when the
    #packet size.
    #changes to 32 characters, the transmitter will precede each message with a single "B"
    #indicating the each packet will contain 32 characters.  This will allow future packet sizes
    #at least as big as 16x16x4 = 1024 characters and total message lengths of around 32768 without
    #using any control characters in the "ascii" preamble.

    #   Future versions will have msgOut = "DSNKMEPX"
    #    with packets having the format:
    #        AX SNKMV MV MV etc MEPX
    #The optional packet of 16 x D permits synchronization
    # 
    #where
    #D  is a full packet of Delete characters (optional for synchronization
    #N is the 2-character packet Number
    #K is the 2-character message character "Kount" including the only the first final EOM
    #V is t5c  (5 character time delay: "roman numeral V")


    #When a receiver starts up (and between messages) it should start by expecting packets of single
    #characters.  It will read a single 8-bit character expecting it to be a "0" meaning an idle transmitter.
    #If it is not a "0", it will read another single 8-bit character expecting it to be an "A".  If it is not an
    #"A",the character will be discarded, but the receiver will presume that it is reading a character
    #stream that is mid-message.  It will read single 8-bit characters searching for a "]" which will indicate
    #that this is the last packet of the message. It will keep reading and discarding all the "]" that it sees.
    #After the last "]", the
    #next 8-bit character should be a "0" or an "A".  The receiver should keep reading and discarding the "0"
    #characters.  When an "A" is finally received (while reading single 8-bit characters), the receiver knows that
    #this means subsequent packets will be packets of 16 characters.  The receiver is now fully
    #synchonized with the transmitter.  If something other than an "A" is received, the receiver should
    #begin looking for a "]" ()meaning "end of message" again.  If the state of "being in mid-message
    #continues 10 times, a human operator should be informed the that this ERROR is occuring.
    #
    #send the message
    txParse(uart,txtToBeSent)       #xyz
    #print("end of serTx()")
    #print("Hit ^C to stop!")
    #print()
    return True
#end def serTx_pico()
def txParse(uartObject, thisMsg, bps=300, msgFormat="SMEPX", T5C=-1, pktSize=16,  eom="]"):    #txParse()
    #show("thisMsg:",thisMsg)
#
#    uartObject is the uart being used
#    thisMsg is the full text message to be sent (It should not contain (EOM="]") they will become "?")
#                          (An EOM is added as the last character of a message, do not put the EOM in the msg)
#    bps is the baud rate (bits/sec)
#    msgFormat is the form of the Msg e.g. SMEPX  (first E is counted as last char of M)
#                                                (P is enough additional EOMs to pad to packetSize=16)
#                                               (t5c is interval between packets (-1 defaults to t5c)

#    t5c indicates time interval of 5 characters.  The transmitter will follow each packet with
#       this time delay
#    packetSize defaults to 16
#    eom is the definition of the 'EOM" character (usually "]")
    #oP is the full outgoing Packet that is sent by sendThisPack
    #                                      or by sendLastPack
    oP=""            # outgoing msg is initially empty
    if T5C==-1:    # if the calling routine doesn't specify
       t5c=50/bps
       t10c=100/bps
       t1000c=10000/bps
    else:
        t5c=T5C       #if the calling routine does specify T5C
        t10c=T5C*2
        t1000c=T5C*200
    #end if
    if eom=="]":
        som="["
    #end if

#    in 2021 msgOut="SMEPX"
    lenM=len(thisMsg)+1      #length of thisMsg -1  (+1 for the EOM character
    cntUsed=0                # number of characters in msgOut used so far
    cntSent=0                # number of character actually sent (incl all chars sent)
    isEOMsent=False          #EOM not sent yet
    #show("msgFormat:",msgFormat)
    for msgPart in msgFormat:   # do each message segment
        if msgPart=="S":
            # send SOM
            #print("send SOM")
            oP=oP+txChar(som)
            oP=oP+txChar("1")      # in future these 2 characters will contain parity or CRC
            oP=oP+txChar("6")      # today they contain the packet size (ie character count)
            cntSent=cntSent+3 #3 actually sent now
            #print()
            #print("oP:"+oP+":")
            cntUsed=0
        #end if
        if msgPart=="X":     # time delay doesn't send any characters
            utime.sleep(t10c) 
        #end if
        if msgPart=="M":     # sends the msg followed by 1 eom
            #print("sending M")
            #cntSent of the packet is already in oP
            #cntUsed is 0 going into the while
            # note that lenM also includes 1 eom
            # in the while loop, cntUsed will increase until cntUsed=lenM
            while (lenM-cntUsed) >= 1 : #lenM incl the EOM, cntUsed does also (after the EOM is sent)
                #print("going into the M while")
                #show("upon entry M-while cntUsed:",cntUsed)
                #  the packet being sent should not include any EOM characters. (EOM is only in the last pk)
                #  send a packet of data
                # lastChar is the lastChar of Msg to send in this packet
                cntCanAdd=pktSize-len(oP)
                #print("cntCanAdd:",cntCanAdd,":")
                #show("cntUsed:",cntUsed)  #should be 0 entering first loop

                cntRemainOfM=lenM-cntUsed-1   #this cnts the remaining chars of M 
                cntToAdd=pktSize-len(oP)    #this cnts the remaining space in oP
                # a packet is always sent in this next "if clause"
                #show("cntRemainOfM:",cntRemainOfM)
                #show("cntToAdd:",cntToAdd)
                #if (cntRemainOfM)>cntToAdd :   #{for debugging}
                if (cntRemainOfM+1)>cntToAdd :  #{for debugging} ver F +1
                # this packet cannot hold rest of Msg plus an eom
                    isLastPack=False 
                    opToAdd=thisMsg[cntUsed:cntUsed+cntToAdd]  # to add to oP
                    opToSend=oP+opToAdd                        # to be sent
                    #print("AopToSend:"+opToSend+":")
                    cntPadding=0
                    sendThisPack(uartObject, opToSend, cntPadding, eom, pktSize)
                    # that sent a full pkt without any padding
                    #cntUsed=cntUsed+cntToAdd+1
                    cntUsed=cntUsed+cntToAdd    #{for debugging} ver F del "+1"
                    # remember to count the first EOM as a character in cntUsed
                    #show("cntUsed:",cntUsed)
                    #show("lenM:",lenM)
                    oP=""
                    cntSent=0
                    #continue the while loop
                else :
                    isLastPack=True
                    # the pkt can hold the whole cntRemainOfM
                    opToAdd=thisMsg[cntUsed:cntUsed+cntRemainOfM]

                    #print("BopToSend:"+opToSend+":")
                    cntPadding=pktSize-cntSent-cntRemainOfM
                    strPadding=eom*cntPadding
                    opToSend=oP+opToAdd+strPadding
                    #print("CopToSend:"+opToSend+":")
                    
                    sendLastPack(uartObject, opToSend, cntPadding, eom, pktSize)
                    # that sent a full pkt including the padding                        
                    cntUsed=cntUsed+len(opToAdd)
                    #show("lenM:",lenM)
                    #show("cntUsed:",cntUsed)
                    oP=""
                    cntSent=0
                    #print("after Last Packet of Msg")
                    toSend=lenM-cntUsed
                    #show("toSend:",toSend)
                    #print("end of while")
                    break            #out of the while
                #if end
                cntUnsent=lenM-cntUsed-1
                #show("cntUnsent:",cntUnsent)
                #print("repeat the M while")
            #end while                 




            if False :
                # we need to send at least 1 more full packet
                isLastpack=False
                lastChar=cntUsed+(pktSize-len(oP)) #this is lastChar of Msg yet to send
                opToAdd=thisMsg[cntUsed:lastChar]  # to add to oP
                opTosend=oP+opToAdd
                print("opToSend:"+opToSend+":")
                sendThisPack(uartObject, opToSend, eom, pktSize)
                # no padding was necessary
                cntUsed=cntUsed+len(opToAdd)
                show("cntUsed:",cntUsed)
                # the while will loop once more
            #end if
            if False :
                lastChar=pktSize-cntSent
                show("lastChar",lastChar)
                #thisMsg="12345678901234567"
                #print("thisMsg:"+thisMsg+":")
                show("cntUsed",cntUsed)
                show("lastChar",lastChar)
                show("thisMsg[cntSent:lastChar]",thisMsg[cntUsed:lastChar])
                opWasSent=thisMsg[cntUsed:lastChar]
                print("opWasSend:"+opWasSend+":")
                if len(opToSend)>=16 :
                    print()
                    print("before sendThisPack oP:"+oP+":")
                    cntSent=sendThisPack(uartObject,opToSend, eom, pktSize)
                                           #returns 16  should print the Pkt
                    oP=""
                    show("cntUsedFromMsg:",cntUsedFromMsg)
                    cntUsed=cntUsed+cntUsedFromMsg    # should be 16 ...... to verify
                    cntSent=cntSent+16
                    show("lenM",lenM)
                    show("cntUsed",cntUsed)
                    isLastPacket=False
                else:
                    print("need to send padded Packet")
                    isLastPacket=True
                #end if
            #end if False
            if False :
                # a packet has just been sent
                leftToSend=lenM-cntUsed-1
                show("leftToSend:",leftToSend)
                if False :
                    if isLastPacket==True :       # will send the Last Packet (containing at least 1 EOM)
                        print("isLastPack is True")
                        #useStr=thisStr
                        cntUsedFromMsg=len(opToSend)
                        oP=opToSend
                        toAdd=16-cntUsedFromMsg
                        show("toAdd:",toAdd)
                        for x in range(toAdd):      # must insert correct range !!!!!
                            oP=oP+txChar(eom)           # must insert correct char from fullMsg !!!!!
                            cntSent=cntSent+1
                        #end for
                        print()
                        print("before sendThisPack oP:"+oP+":")
                        cntSent=sendThisPack(uartObject,oP, eom, pktSize)
                        #returns 16  should print the Pkt
                        oP=""
                        cntUsed=cntUsed+cntUsedFromMsg
                        show("cntUsed:",cntUsed)
                    #end if
                #end if False
                # a packet was just sent
                print("M while might end now")
                print("after end of while")
            #end if False
        #end if "M"

        if False :
            if msgPart=="P":                # P means Padding (with more EOMs) if any needs to be sent
                print("msgPart=P")
                if False :
                    if True:     # to be decided
                        oP=oP+txChar(eom)        # how many eoms of padding  !!!!!
                        cntUsed=cntUsed+1
                        cntSent=cntSent+1
                    #end if
                    show("cntUsed",cntUsed)
                    strSent=thisMsg[cntUsed:cntUsed+16]
                    show("strSent:",strSent)
                    cntUsedFromMsg = sendLastPack(uartObject, strSent, eom, pktSize) # should print the Pkt
                    cntUsed=cntUsed+cntUsedFromMsg
                    cntSent=cntSent+pktSize   #pktSize is usually 16
                #end if
            #end if "P"
        #end if False
        
    #end for    # all msg parts have now been sent
    # should check that cntUsed = len(Msg) +1
    # should check that cntSent is a muliple of pktSize(eg 16)
    return #from parsing and transmitting
#end def
def txChar(char):                                                                       #txChar()        
    #simply records that "char" has been sent
    # just prints it during testing
    # doesn't actually send the char
    #print(char, end='') #"end" suppresses the line feed
    return char
#end def

def sendThisPack(uartObject, opIn, cntPadding, eom, pktSize):                        #sendThisPack()
#

#actually sends the 16 characters in oP
    #print()
    #print("in sendThisPack")
    oP=opIn
    lenopIn=len(opIn)
    if (lenopIn==pktSize)==False:
        print("ERROR",pktSize, "is not the size of the packet to send:",lenopIn)
    #end if
    pos=opIn.find(eom)
    if pos==-1:              # -1 if not found
        pass
    else:
        print("WARNING E1 in serTx", eom, "found eom in message")
        #oP=oP.replace(eom,"?")   
        oP=oP.replace(eom,"?",1)   #{for debugging} ver F  replace once
    #end if
    uartObject.write(oP)
    #print("tx sent:"
    # in sendThisPack
    print(oP, end='')    #this actually sends the text to the Shell
    #                    because in this early version, what is shown
    #                    in the Shell is actually sent.
    #print()              #{for debugging}
    return pktSize
#end def

def sendLastPack(uartObject, opIn, cntPadding, eom, pktSize):                        #sendThisPack()
#

#actually sends the 16 characters in oP
    #print()
    #print("in sendLastPack")
    oP=opIn
    #print("oP:"+oP+":")
    lenopIn=len(opIn)
    #show("lenopIn:",lenopIn)
    if (lenopIn==pktSize)==False:
        print("ERROR",pktSize, "is not the size of the packet to send:",lenopIn)
    #end if
    #search for eom in the non-padding portion of oPIn
    suboPIn=opIn[0:pktSize-cntPadding]
    #print("suboPIn:"+suboPIn+":")
    pos=suboPIn.find(eom)
    if pos==-1:              # -1 if not found
        pass
    else:
        print("WARNING E2 in serTx", eom, "found in message")
        oPleft=opIn[0:pos]          #{for debugging} ver F fix
        #print("oPleft:"+oPleft+":")
        lenOp=len(opIn)             #{for debugging} ver F fix
        oPright=opIn[pos+1:lenOp]   #{for debugging} ver F fix
        #print("oPright:"+oPright+":")        
        #oP=oP.replace(eom,"?")
        #oP=oP.replace(eom,"?",1)   #{for debugging} replace once didn't work
        oP=oPleft+"?"+oPright       #{for debugging} ver F fix
    #end if
    uartObject.write(oP)
    # in sendLastPack():
    #print("tx sent:"+
    print(oP, end='')    #keep user informed during testing
    #print()              #{for debugging}
    return pktSize
#end def
def mpyRead(uart):
    #keep read1 character packet until timeOut
    txtRead=""
    bRead=""
    while uart.any():

        aByte=str(uart.read(1))
        #show("aByte:",aByte)
        bRead=bChar(aByte)
        #show("bRead:",bRead)
        txtRead=txtRead+bRead
    #end while
    return txtRead
#end def



#  serRx_pico()   receives  a full serial text message               #serRx_pico()
def serRx_pico(uartObject, bps=600, timeOut=-1, eom="]"):
    #not a duplicate
    #uart = machine.UART(1,bps, parity=None, stop=1, bits=8, rx=Pin(5), tx=Pin(4))
    print("my uart:",uart)
    #print("timeOut is set to:",timeOut)
    if timeOut==-1:
        t100c = 1000/bps
        timeOutUse=int(t100c+1.0)   #at least 1 sec
        #show("timeOutUse:",timeOutUse)
    else:
        timeOutUse=timeOut   #in seconds
    #end if
    #timeOutUse=t100c
    time=utime.time()
    time=str(int(time)+secsToAdd)#{for debugging}
    #time=time+secsToAdd
    timeNow=time
    #show("timeNow:",timeNow)
    timeFail=timeNow+timeOutUse    # defaults to a 3 second TimeOut
    #print("waiting my:",timeOutUse," seconds for data receipt. . . . .")
    oP=""  # reset input buffer
    #show("time:",time)
    #show("timeFail:",timeFail)

    while time < timeFail :
        #keep reading any 1 character packets until timeOut
        print("I should be flashing the green LED while receiving")
        # I don't know if it is still receiving
        # it should write the received msg to a file.
        #print("any")
        strA=mpyRead(uart)
        #show("strA:",strA)
        oP=oP+strA
        #show("oP:",oP)
        #end if
        time=utime.time()
        time=str(int(time)+secsToAdd)#{for debugging}
        time=time+secsToAdd
    #end while
    #show("oP:",oP)
    lenOp=len(oP)
    if oP=="":
        print("ERROR T in serRx (): timeOut after",timeOutUse,"seconds")
        lenOp=len(oP)
    #end if
    if lenOp > 0:
        if oP.find("?")==-1:
            pass            # ? not found
        else:
            print("WARNING '?' seen in message received.")
        #end if
    #end if
    #print("serRx() received:"+oP+":")   #during testing
    return oP
#end def serRx_pico(uart,300,timeOut(in secs))

def show(strA,parmA):                                        # show
    print(strA,parmA)
    return
#end def show
if False :
    #def readADC_pico(nn,cnvrt=5.035477e-05):
    # this is the bad version
    #nn is the pico GPnn (ADCnn) to read
    #cnvrt = 5.035477e-05 converts the reading to volts.
    # that is the default cnvrt factor.
    print("in other readADC_pico")
    adcFirst = machine.ADC(nn)
    adcValue=adcFirst.read_u16()
    #print("The value of ADC0 is", adcValue)

    #conversion_factor = 3.3 / (65535)
    #print("conversion_factor:",conversion_factor)
    adcVoltage=adcValue * cnvrt
    #print("The voltage at ADC0 is", adcVoltage)
    #print("-bye- from readADC_pico.py")
    return adcVoltage
#end def
#end if
def RAPasc(reading,nnIn,rFormat):
    #returns the RAPasc packet
    #print("nnIn:",nnIn)
    if nnIn==0 :
        nn=0      #ADC number = 0 or 1 usually
        strNN=str(nn)
    #end if
    if nnIn==1 :
        nn=1      #ADC number = 0 or 1 usually
        strNN=str(nn)
    #end if
    if nnIn==4 :
        nn=4      #ADC number = 0 or 1 or 4 usually
        strNN=str(nn)
    #end if
    if nnIn==3 :
        nn=3
        strNN=str(nn)
    #end if
    if nnIn==29 :
        nn=29
        strNN=str(nn)
    #end if
#end if
    # prepare the time
    timeNow=utime.time()
    intTime=int(timeNow)
    #print("intTime:",intTime)
    intTime=intTime+secsToAdd      #{for debugging}
    timeNow=str(intTime)           #{for debugging}
    #timeNow=timeNow+secsToAdd     #{for debugging}
    strTime=str(timeNow)+".000"
    strReading="???"
    #print("rFormat:"+rFormat)
    if rFormat=="X":
        # use strReading as Hex # (It comes as a Hex #)
        # I need to improve this by receiving the #
        # as a string and using f3() to convert it to float
        #show("603 before readADC_pico, nn:",nn)
        hexNumber=readADC_pico(nn,cnvrt=1.000)
        print("hexNumber:",hexNumber)
        strReading=str(hexNumber)
        print("|"+strReading+"|")
        strReading=strReading.strip()
        #h = str(hex(i))[2:]
        #h = h.upper()
        hexNumber=int(hexNumber)
        #print("hexNumber:",hexNumber)
        strReading=str(hex(hexNumber))[2:]
        #print("strReading:"+strReading)
        strReading="0x"+strReading.upper()
    #end if
    if rFormat=="F":
        if nn==4 :
            #show("619 before readADC_pico, nn:",nn)
            strReading=str(readADC_pico(nn,cnvrt=1.000))
            print("in 667 strReading:"+strReading)
        else:
            # use strReading as Float # (It comes as a Hex #)
            #show("623 before readADC_pico, nn:",nn)
            strReading=str(float(readADC_pico(nn,cnvrt=5.035477e-05)))
            #print("|"+strReading+"|")
            strReading=strReading.strip()
        #end if
    #end if
    #print("strNN:"+strNN)
    strRAPasc="ADC"+strNN+":("+strReading+"+"+strTime+"j)"
    return strRAPasc
#end def RAPasc

##########################################################################################
##########################################################################################
progName="test_TxH_pico.py"
print("progName:"+progName)


if True:
    bps=600
    print("tx bps:",600)
    tPause=1 
    txPin=5
    rxPin=4
    #
    #print sys info
    print(os.uname())       #os, utime and machine were imported at top

    #indicate program started visually (by blinking the green LED)
    led_onboard = machine.Pin(25, machine.Pin.OUT)
    led_onboard.value(0)     # onboard LED OFF for 0.5 sec
    utime.sleep(0.5)
    led_onboard.value(1)    # leaving it ON

    #create uart object sample code
    if False :
        #self.uart = UART(1, 115200, parity=None, stop=1, bits=8, rx=Pin(rxPin), tx=Pin(txPin))
        pass
    #end if

    #create actual uart object
    uart = machine.UART(1,bps, parity=None, stop=1, bits=8, rx=Pin(5), tx=Pin(4))
    #print uart info
    #uart = machine.UART(1)
    print(uart)         # during testing


    # verifying and adjusting localtime and gmtime
    timeLocal=utime.localtime()
    strLocal=str(timeLocal)
    print("strLocal:"+strLocal)
    timeGMT=utime.gmtime()
    strGMT=str(timeGMT)
    print("strGMT  :"+strGMT)
    strAnsw=input("Are these Correct?:")
    if "nN".find(strAnsw)==-1 :
        pass
    else:
        addToGMT=input("what N (hours) should we add to GMT?")
    #end if
    print("this routine will add",addToGMT,"hours to GMT")
    secsToAdd=3600*int(addToGMT)  #convert hrs to secs
    #                     create uartObject
    #uart = machine.UART(1,bps, parity=None, stop=1n, bits=8, tx=txPin, rx=rxPin)
    #    send a single "A"  which is 0x41 ("A"-0x40 * 16 is the packet length which is 16

    #                                         initialization is complete

    #uart.write("A")     #every group of messages is preceeded by a single "A"
    # prior to the "A", the transmitter should send a synchronizing sequence to permit
    #               the (human) receiver to "guess" or "determine" the baud rate (the bps)
    # hopefully the operator of the transmitter and receiver is the same human.

    # the serRx_pico should be running in a separate thread.

    #def serTx_pico(uartObject,bps, txtToBeSent="[UUUUUUUU]",rxtxEndChar="]"):
    print("transmitting Hello msg on Pin(GP4) in 2 16 byte packets at")
    print("60 bps, continuously preceded by an 'A' at 2 sec intervals")
    print("the 'A' is not seen by the receiver") 
    #print("it erroneously skips the 'o' in 'Roy'. Doh!") #fixed in ver F
    print("it erroneously skips a full packet of ']' when needed") 

    print("Hit ^C to stop!")
    print()

    while True :
        uart.write("A")
        utime.sleep(tPause)
        #read and create format RAPasc using the following function call
        #strRAPasc=RAPasc(readADC_pico(n1,cnvrt=5.035477e-05),1,"F")
        #           readADC_pico() reads ADC[nn], by default cvrts to volts
        #                          and returns the reading in volts
        #                    but can read ADC[nn], cvrts using another factor
        #                          and returns the converted reading
        #                    but can read ADC[nn], do no conversion (cnvrt=1.000)
        #                          and return the unconverted reading
        #    RAPasc(accepts the reading, followed by the time into the format
        #           ADC1:(56.789+875678.000j) if 2nd parm is "F"
        #    RAPasc(accepts the reading, followed by the time into the format
        #           ADC1:(0xffff+875678.000j) if 2nd parm is "X" 
        

#        *************************************************************
        nn=0
        #show("726 before readADC_pico, nn:",nn)
        strRAPasc=RAPasc(readADC_pico(nn,cnvrt=5.035477e-05),nn,"F")
        #finally the the ADC1:(reading+timej) string is ready
        # to be converted into serial packets
        serTx_pico(uart,bps, txtToBeSent=strRAPasc)
        utime.sleep(tPause)

        nn=1
        #show("734 before readADC_pico, nn:",nn)
        strRAPasc=RAPasc(readADC_pico(nn,cnvrt=1.0000),nn,"X")
        #finally the the ADC1:(reading+timej) string is ready
        # to be converted into serial packets
        serTx_pico(uart,bps, txtToBeSent=strRAPasc)
        utime.sleep(tPause)


        nn=3
        #temperature = 27 - (reading - 0.706)/0.001721
        #print()
        #show("744 before readADC_pico, nn:",nn)
        strRAPasc=RAPasc(readADC_pico(nn,cnvrt=1.000),nn,"F")
        #finally the the ADC1:(reading+timej) string is ready
        # to be converted into serial packets
        serTx_pico(uart,bps, txtToBeSent=strRAPasc)
        utime.sleep(tPause)

        nn=4
        #temperature = 27 - (reading - 0.706)/0.001721
        print()
        show("802 before readADC_pico, nn:",nn)
        strFromReadADC_pico=str(readADC_pico(nn,cnvrt=1.000))
        print("804 strFromReadADC_pico"+strFromReadADC_pico)
        strRAPasc=RAPasc(strFromReadADC_pico,nn,"F")
        print("in 806 strRAPasc:"+strRAPasc)
        #finally the the ADC1:(reading+timej) string is ready
        # to be converted into serial packets
        serTx_pico(uart,bps, txtToBeSent=strRAPasc)
        utime.sleep(tPause)

        
        print()


        try:
            utime.sleep(tPause)                    #{for debugging}
        except:
            # this try/except code permits the tester to stop here using ^C
            print("interrupted by ^c")
            break
        finally:
            pass
        #end try
    #end while
#end if True
##########################################################################
#   everything after here is old deprecated code                         #

###########################################################################
# testpktixRx()
if False:
    if False:
        # the above is the current format of the rxtx protocol
        # The som,eom,t10c and are 1-character special codes
        #    each must be converted into outgoing text or actions or both
        #    all normal text does not need to be converted before transmission
        #
        # The txParse routine analyses the msgOut Format and separates it into
        # special codes (text and actions).  Each special code is sent to the txChar()
        # routine to be processed. Each character of outgoing text is sent to the
        # txChar() routine to be processed.
        #
        # The serTx_pico() routine is used to
        #   transmit a special code of text ("S" and "M")
        #   cause a time delay (V is "t5c X is "t10c  " and M is "t1000c")
        #   transmit msg as 16-byte packets (msg should not contain "]" which is replaced by "?" )
        #
        #   early testing Format is "SMEPX"
        #
        # Note that the "P" also inserts at least 1 "]" character and
        #   enough extra "]" characters (or none) to make a message with an exact multiple
        #   of 16 characters.  This is because there are always 16 characters sent per
        #   packet. Each packet is followed by a time delay of t5c.
        #   The last packet is always followed by a time delay of t10c.
        #   These time delays permit the receiver to resync with the transmitter.
        #   These time delays are never included in the character count of the
        #   message
        #   The serRx_pico() routine times out after an interval of 1000 character times: t1000c
        pass
    #end if

    # This should be run this as a separate thread
    # print whatever has been received
    bps=600
    t100c=1000/bps
    utime.sleep(t100c) #wait for an interval of 100 char times
#end if False

#uart = machine.UART(1,bps, parity=None, stop=1, bits=8, tx=Pin(txPin), rx=Pin(rxPin))
bps=600
uart = machine.UART(1,bps, parity=None, stop=1, bits=8, tx=Pin(4), rx=Pin(5))
print("uart:",uart)
if False:
    uart.write("hello")
    t100c=1000/bps
    utime.sleep(t100c) #wait for an interval of 100 char times

    uart.write("Hello,World")
    utime.sleep(t100c) #wait for an interval of 100 char times
    utime.sleep(1)     #1 sec
#if end False
if False:
    print("receiving mpy routine")
    while uart.any():
        print(uart.read(1))
    #end while
#end if False
charIn=""
if False:
    print("receiving mpy routine")

    if uart.any() :
        #print("reading now")
        charIn=uart.read(1)
        #show("charIn:",charIn)
        #oP=oP+uartObject.read(1)
    #end if
    print("end of mpy routine")
#end if False
show("charIn:",charIn)
#end if
print("receiving my routine")
msgIn=serRx_pico(uart,bps=600)   #times out after t100c seconds (100 char-times)
print("msgIn:",msgIn)

print("end of serRX()")

#end /test_TxH_pico.py
# stored in Raspberry Pi Pico/
# stored in /home/pi/Desktop/Python_new/ix_pico_test/

::::::::::textpak=>test_VSYS_pico.py.txt
# test_VSYS_pico.py

import machine
import time

print("Example output        VBUS       VSYS")
VSYS_ADC_INPUT = 3      # 3 or 29

# Using ADC(3)  - Pin 29 needs to be set as input with no pulls.
# Using ADC(29) - Pin 29 is automatically set as required.

if VSYS_ADC_INPUT == 3:
  Pin = machine.Pin
  Pin(29, Pin.IN)
  vsysChannel = machine.ADC(3)
else:
  vsysChannel = machine.ADC(29)
  
while True:
  adcReading  = vsysChannel.read_u16()
  adcVoltage  = (adcReading * 3.3) / 65535
  vsysVoltage = adcVoltage * 3
  vbusVoltage = vsysVoltage + 0.275 # At 100mA
  print(adcReading >> 4, adcReading, adcVoltage, "|", vbusVoltage, "|", vsysVoltage)
  time.sleep(1)
# end while

#Source:https://www.raspberrypi.org/forums/viewtopic.php?t=301152
#        See near end by hippy 
# test_VSYS_pico.py
::::::::::textpak=>testButton_pico.py.txt
# IX_libr_pico.py

# This example works with Maker Pi Pico
# buttonAction()
# returns True when button Action is down i.e. pressed within 10 seconds
#    else returns False.

#imports for buttonAction
import machine
import utime

def buttonAction(gPnn,withinTime):

    if gPnn <0 or gPnn>25:
        print("Error in buttonAction: pin # is out of range")
        return
    #end if
    if withinTime <0 or withinTime>180:
        print("Error in buttonAction: withinTime is out of range")
        return
    #end if
    button = machine.Pin(gPnn, machine.Pin.IN)
    t0=utime.time()
    #print("t0:",t0)
    tDelta=0
    isDown=False
    while tDelta<withinTime:
        state=button.value()
        #print("button (active low) state:",state)
        tNow=utime.time()
        tDelta=tNow-t0
        #print("at:",tDelta,"button",gPnn, "is ", state)
        utime.sleep(0.5)
        if state==0:
            isDown=True
            break                 # out of loop
        #end if
    #end while
    return isDown #returns a Boolean result
#end def #buttonAction_pico.py
# by David at ColeCanada.com
# on 2021EMay25
#source: na
#end program IX_libr_pico.py

GPnn=22
tSecs=10
print("Press button GP"+str(GPnn),"within",tSecs,"secs")
isDown=buttonAction(GPnn,tSecs)
if isDown==None:
    print("Error: Aborted Execution")
else:
    print("buttonAction is",isDown)
#end if
#testButton_pico.py
::::::::::textpak=>testLeds.py.txt
from machine import Pin
import time

#by D@CC
#on 2022EMay30

# need to modify it for RPi Pi (not pico)

print("testLeds.py")
print("by PiCole22 on 2021EMay20")
print(" pronounced 'pickle 22'")
print("testing the Maker Pi Pico board by Cytron")
print("The small green 3V3 led should always be ON")
led=Pin(25,Pin.OUT)
led.value(1)
print("turning green pico led ON")
i=0
print("turning each GPxx blue led ON (1/sec)")
while i<28:
    i=i+1
    led1=Pin(i,Pin.OUT)
    led1.value(1)
    time.sleep(1) # 1sec
#end while
print("Please check if all leds are ON")
i=0
print("turning each GPxx blue led OFF (1/sec)")
while i<28:
    i=i+1
    led1=Pin(i,Pin.OUT)
    led1.value(0)
    time.sleep(1) # 1sec
#end while
print("Please check if all leds are OFF")
led=Pin(25,Pin.OUT)
led.value(1)
print("turning green pico led ON")
time.sleep(1) # 1sec
led=Pin(25,Pin.OUT)
led.value(0)
print("turning green pico led OFF")
print("end of testLeds.py")
#end testLeds.py
::::::::::textpak=>testLeds_pico.py.txt
from machine import Pin
import time

print("testLeds_pico.py")
print("by PiCole22 on 2021EMay20")
print(" pronounced 'pickle 22'")
print("testing the Maker Pi Pico board by Cytron")
print("The small green 3V3 led should always be ON")
led=Pin(25,Pin.OUT)
led.value(1)
print("turning green pico led ON")
i=0
print("turning each GPxx blue led ON (1/sec)")
while i<28:
    i=i+1
    led1=Pin(i,Pin.OUT)
    led1.value(1)
    time.sleep(1) # 1sec
#end while
print("Please check if all leds are ON")
i=0
print("turning each GPxx blue led OFF (1/sec)")
while i<28:
    i=i+1
    led1=Pin(i,Pin.OUT)
    led1.value(0)
    time.sleep(1) # 1sec
#end while
print("Please check if all leds are OFF")
led=Pin(25,Pin.OUT)
led.value(1)
print("turning green pico led ON")
time.sleep(1) # 1sec
led=Pin(25,Pin.OUT)
led.value(0)
print("turning green pico led OFF")
print("end of testLeds.py")
#end testLeds.py
::::::::::textpak=>testPlot.py.txt
def plot(vector):
# by D@CC
# on 2021EMay22

# vector is a list of values to be plotted
# values between 0 and 255 inclusive
# the number of values should be less than 64

samples = [1,2,3,4,5,6]
vlen = len(samples) #actual length -1
vmin = min(samples)
vmax = max(samples)
ncols = 60
nrows = 10
colThickness = 1 + ncols//vlen  (e.g. 10)
rowThickness = 1 + nrows//(vmax-vmin)
# 2 dim array is shown below
matrix = [[0,1,2],[2,4,6]]
for i = 0,1:
    print matrix[i,0], matrix[i,1],matrix[i,2]
#end def plot

progName="testPlot.py"
print(progName)

plot(a)
        
#source: https://www.educba.com/list-operations-in-python/
#end program testPlot.py
::::::::::textpak=>testRxD_pico.py.txt
import os
import utime
from machine import UART, Pin



#by D@CC
#Date: 2021FJun19
#Note: as of today, partially tested
##########################################################################################
#  1. serRx_pico()  receives  a full serial text message
#  2. show()        shows (displays) an object or variable
#  3. mpyread()     reads a character (borrowed routine)
# testRx          receives all test messages (TimeOut=t1000c)

progName="testRxD_pico.py"
print("progName:"+progName)
if True:
    bps=600
    txPin=5
    rxPin=4
    rxtxEndChar="]"
    #
    #print sys info
    print(os.uname())       #os, utime and machine were imported at top
#end if
    
    #every parameter has a default setting except the uartObject (which needs to be defined).
    t5c=50/bps          #   50 bit times = 5 character times
    t10c=100/bps        #  100 bit times = 10 character times
    t1000c=10000/bps    # 10000 bit times = 1000 character times
    t9999c=10000/bps    # 100000 bit times
    t60=60              # 60 seconds
    t10=10
    
    # requires a uart object (below) to be created before this function is called
    #uart = machine.UART(1, 300, parity=None, stop=1, bits=8, tx=Pin(txPin), rx=Pin(rxPin))
    print("entering serTx_pico.py")
    if rxtxEndChar=="]":
        som = "["
        eom = "]"
    #end if
        
    #create uart object sample code
    if False :
        #self.uart = UART(1, 115200, parity=None, stop=1, bits=8, rx=Pin(rxPin), tx=Pin(txPin))
        pass
    #end if

    #create actual uart object
    uart = machine.UART(1,bps, parity=None, stop=1, bits=8, rx=Pin(5), tx=Pin(4))
    #print uart info
    #uart = machine.UART(1)
    print(uart)         # during testing

def mpyRead(uart):
    print("in mpyRead")
    #keep read1 character packet until not any characters
    txtRead=""
    bRead=""
    while uart.any():

        aByte=str(uart.read(1))
        #show("aByte:",aByte)
        bRead=bChar(aByte)
        #show("bRead:",bRead)
        txtRead=txtRead+bRead
    #end while
    return txtRead
#end def

#  serRx_pico()   receives  a full serial text message               #serRx_pico()
def serRx_pico(uartObject, bps=600, timeOut=-1, eom="]"):
    #uart = machine.UART(1,bps, parity=None, stop=1, bits=8, rx=Pin(5), tx=Pin(4))
    print("my uart:",uart)
    #print("timeOut is set to:",timeOut)
    if timeOut==-1:
        t100c = 1000/bps
        timeOutUse=int(t100c+1.0)   #at least 1 sec
        #show("timeOutUse:",timeOutUse)
    else:
        timeOutUse=timeOut   #in seconds
    #end if
    #timeOutUse=t100c
    time=utime.time()
    timeNow=time
    #show("timeNow:",timeNow)
    timeFail=timeNow+timeOutUse    # defaults to a 3 second TimeOut
    #print("waiting my:",timeOutUse," seconds for data receipt. . . . .")
    oP=""  # reset input buffer
    #show("time:",time)
    #show("timeFail:",timeFail)
    k=0
    while time < timeFail :
        k=k+1
        #keep reading any 1 character packets until timeOut
        print(k,"waiting for any characters to arrive")
        strA=mpyRead(uart)
        #show("strA:",strA)
        oP=oP+strA
        #show("oP:",oP)
        #end if
        time=utime.time()
        utime.sleep(.5)
    #end while
    #show("oP:",oP)
    lenOp=len(oP)
    if oP=="":
        print("ERROR T in serRx (): timeOut after",timeOutUse,"seconds")
        lenOp=len(oP)
    #end if
    if lenOp > 0:
        if oP.find("?")==-1:
            pass            # ? not found
        else:
            print("WARNING '?' seen in message received.")
        #end if
    #end if
    #print("serRx() received:"+oP+":")   #during testing
    return oP
#end def serRx_pico(uart,300,timeOut(in secs))

def show(strA,parmA):                                        # show
    print(strA,parmA)
    return
#end def

print("receiving my routine")
timeNow=utime.time()
tOut=60
print("waiting", tOut,"seconds to receive data, time:",0)
#msgIn=serRx_pico(uart,bps=600)   #times out after t100c seconds (100 char-times)
msgIn=serRx_pico(uart,bps=600,timeOut=tOut)   #times out after t10 seconds (100 char-times)
print("msgIn:",msgIn)
time=utime.time()-timeNow
print("time:",time)

print("end of serRX()")

#end /testRxD_pico.py
::::::::::textpak=>testTxE_pico.py.txt
# testTxE_pico.py
# stored in Raspberry Pi Pico/
#   and  in /home/pi/Desktop/Python_new/ix_pico_test/

import os
import utime
from machine import UART, Pin

#by D@CC
#Date: 2021FJun18
#Note: as of today, partially tested

# all functions and subroutines are at top of program
#  1. bChar()       converts 4 char byte into 1 char
#  2. serTx_pico()  transmits a full serial text message
#  3. txParse()     parses the outgoing text message and calls txChar
#  4. txChar()      adds the char to oP which is the output text packet queue
#  5. sendThisPack  actually transmits a full packet (wo any EOM)
#  6. sendLastPack  actually transmits text (with at least one EOM)
#  7. serRx_pico()  receives  a full serial text message
# testTx          transmits many test messages
# testRx          receives all test messages

#calling parms
#bChar(strB):
#serTx_pico(uartObject,bps=300, txtToBeSent="Hello,World",rxtxEndChar="]",pktSize=16):
#txParse(uartObject, thisMsg, bps=300, msgFormat="SMEPX", T5C=-1, pktSize=16,  eom="]"):
#txChar(char):
#sendThisPack(uartObject, oPIn, eom, pktSize):
#sendLastPack(oPIn, cntSent, cntUsed,  eom = "]", pktSize=16):
#serRx_pico(uartObject, bps=300, timeOut=-1, eom="]"):
#
#Debugging notes:
#"tx sent:" is what is actually sent

def bChar(strB):                                                                   #bChar()
    #  given a string like b'z' this returns the "z"
    # tested by D@CC on 2021FJun15
    
    #strB=input("eg b'h' :")
    b=strB[2:]
    #print("b:"+b)
    c=b[0]
    #c="z"
    #print("bChar("+'"'+strB+ '"):'+c)
    return c
#end def


def serTx_pico(uartObject,bps=300, txtToBeSent="Hello,World",rxtxEndChar="]",pktSize=16):         #serTx_pico#

    #print("txtToBeSent:"+txtToBeSent+":")
    #every parameter has a default setting except the uartObject (which needs to be defined).
    t5c=50/bps          #   50 bit times = 5 character times
    t10c=100/bps        #  100 bit times = 10 character times
    t1000c=10000/bps    # 10000 bit times = 1000 character times
    
    # requires a uart object (below) to be created before this function is called
    #uart = machine.UART(1, 300, parity=None, stop=1, bits=8, tx=Pin(txPin), rx=Pin(rxPin))
    #print("entering serTx_pico.py")
    if rxtxEndChar=="]":
        som = "["
        eom = "]"
    
    msgOut = """
    #S +
    #M +
    #E +
    #P +
    #C"""

    
    
    #where
    #A is the letter "A" meaning "16 bit packets (pktSize)"
    #S is SOM
    #M is Message text to be sent (will be followed by EOM)
    #E is EOM
    #P is the padding characters (enough EOMs to fill the packet)
    #X is t10c  (ten character time delay: "roman numeral X")
    #C is t100c  (100 character time delay: "roman numeral C")
        
    #Most messages will have   msgOut = "AC" "SMEPX"

    #Between messages, the transmitter will send "0" every minute indicating that its alive but
    #has no message to send.
    #Before sending each message the transmitter will send a single "A" which is 0x41 indicating
    #that the following message will be in packets of 16 characters.  In the future when the
    #packet size.
    #changes to 32 characters, the transmitter will precede each message with a single "B"
    #indicating the each packet will contain 32 characters.  This will allow future packet sizes
    #at least as big as 16x16x4 = 1024 characters and total message lengths of around 32768 without
    #using any control characters in the "ascii" preamble.

    #   Future versions will have msgOut = "DSNKMEPX"
    #    with packets having the format:
    #        AX SNKMV MV MV etc MEPX
    #The optional packet of 16 x D permits synchronization
    # 
    #where
    #D  is a full packet of Delete characters (optional for synchronization
    #N is the 2-character packet Number
    #K is the 2-character message character "Kount" including the only the first final EOM
    #V is t5c  (5 character time delay: "roman numeral V")


    #When a receiver starts up (and between messages) it should start by expecting packets of single
    #characters.  It will read a single 8-bit character expecting it to be a "0" meaning an idle transmitter.
    #If it is not a "0", it will read another single 8-bit character expecting it to be an "A".  If it is not an
    #"A",the character will be discarded, but the receiver will presume that it is reading a character
    #stream that is mid-message.  It will read single 8-bit characters searching for a "]" which will indicate
    #that this is the last packet of the message. It will keep reading and discarding all the "]" that it sees.
    #After the last "]", the
    #next 8-bit character should be a "0" or an "A".  The receiver should keep reading and discarding the "0"
    #characters.  When an "A" is finally received (while reading single 8-bit characters), the receiver knows that
    #this means subsequent packets will be packets of 16 characters.  The receiver is now fully
    #synchonized with the transmitter.  If something other than an "A" is received, the receiver should
    #begin looking for a "]" ()meaning "end of message" again.  If the state of "being in mid-message
    #continues 10 times, a human operator should be informed the that this ERROR is occuring.
    #
    #send the message
    txParse(uart,txtToBeSent)       #xyz
    #print("end of serTx()")
    #print("Hit ^C to stop!")
    #print()
    return True
#end def serTx_pico()
def txParse(uartObject, thisMsg, bps=300, msgFormat="SMEPX", T5C=-1, pktSize=16,  eom="]"):    #txParse()
    #show("thisMsg:",thisMsg)
#
#    uartObject is the uart being used
#    thisMsg is the full text message to be sent (It should not contain (EOM="]") they will become "?")
#                          (An EOM is added as the last character of a message, do not put the EOM in the msg)
#    bps is the baud rate (bits/sec)
#    msgFormat is the form of the Msg e.g. SMEPX  (first E is counted as last char of M)
#                                                (P is enough additional EOMs to pad to packetSize=16)
#                                               (t5c is interval between packets (-1 defaults to t5c)

#    t5c indicates time interval of 5 characters.  The transmitter will follow each packet with
#       this time delay
#    packetSize defaults to 16
#    eom is the definition of the 'EOM" character (usually "]")
    #oP is the full outgoing Packet that is sent by sendThisPack
    #                                      or by sendLastPack
    oP=""            # outgoing msg is initially empty
    if T5C==-1:    # if the calling routine doesn't specify
       t5c=50/bps
       t10c=100/bps
       t1000c=10000/bps
    else:
        t5c=T5C       #if the calling routine does specify T5C
        t10c=T5C*2
        t1000c=T5C*200
    #end if
    if eom=="]":
        som="["
    #end if

#    in 2021 msgOut="SMEPX"
    lenM=len(thisMsg)+1      #length of thisMsg -1  (+1 for the EOM character
    cntUsed=0                # number of characters in msgOut used so far
    cntSent=0                # number of character actually sent (incl all chars sent)
    isEOMsent=False          #EOM not sent yet
    #show("msgFormat:",msgFormat)
    for msgPart in msgFormat:   # do each message segment
        if msgPart=="S":
            # send SOM
            #print("send SOM")
            oP=oP+txChar(som)
            oP=oP+txChar("1")      # in future these 2 characters will contain parity or CRC
            oP=oP+txChar("6")      # today they contain the packet size (ie character count)
            cntSent=cntSent+3 #3 actually sent now
            #print()
            #print("oP:"+oP+":")
            cntUsed=0
        #end if
        if msgPart=="X":     # time delay doesn't send any characters
            utime.sleep(t10c) 
        #end if
        if msgPart=="M":     # sends the msg followed by 1 eom
            #print("sending M")
            #cntSent of the packet is already in oP
            #cntUsed is 0 going into the while
            # note that lenM also includes 1 eom
            # in the while loop, cntUsed will increase until cntUsed=lenM
            while (lenM-cntUsed) >= 1 : #lenM incl the EOM, cntUsed does also (after the EOM is sent)
                #print("going into the M while")
                #show("upon entry M-while cntUsed:",cntUsed)
                #  the packet being sent should not include any EOM characters. (EOM is only in the last pk)
                #  send a packet of data
                # lastChar is the lastChar of Msg to send in this packet
                cntCanAdd=pktSize-len(oP)
                #print("cntCanAdd:",cntCanAdd,":")
                #show("cntUsed:",cntUsed)  #should be 0 entering first loop

                cntRemainOfM=lenM-cntUsed-1   #this cnts the remaining chars of M 
                cntToAdd=pktSize-len(oP)    #this cnts the remaining space in oP
                # a packet is always sent in this next "if clause"
                #show("cntRemainOfM:",cntRemainOfM)
                #show("cntToAdd:",cntToAdd)
                if cntRemainOfM>cntToAdd :
                # this packet cannot hold rest of Msg plus an eom
                    isLastPack=False 
                    opToAdd=thisMsg[cntUsed:cntUsed+cntToAdd]  # to add to oP
                    opToSend=oP+opToAdd                        # to be sent
                    #print("AopToSend:"+opToSend+":")
                    cntPadding=0
                    sendThisPack(uartObject, opToSend, cntPadding, eom, pktSize)
                    # that sent a full pkt without any padding
                    #cntUsed=cntUsed+cntToAdd+1
                    cntUsed=cntUsed+cntToAdd    #{for debugging} del "+1"
                    # remember to count the first EOM as a character in cntUsed
                    show("cntUsed:",cntUsed)
                    show("lenM:",lenM)
                    oP=""
                    cntSent=0
                    #continue the while loop
                else :
                    isLastPack=True
                    # the pkt can hold the whole cntRemainOfM
                    opToAdd=thisMsg[cntUsed:cntUsed+cntRemainOfM]

                    #print("BopToSend:"+opToSend+":")
                    cntPadding=pktSize-cntSent-cntRemainOfM
                    strPadding=eom*cntPadding
                    opToSend=oP+opToAdd+strPadding
                    #print("CopToSend:"+opToSend+":")
                    
                    sendLastPack(uartObject, opToSend, cntPadding, eom, pktSize)
                    # that sent a full pkt including the padding                        
                    cntUsed=cntUsed+len(opToAdd)
                    #show("lenM:",lenM)
                    #show("cntUsed:",cntUsed)
                    oP=""
                    cntSent=0
                    #print("after Last Packet of Msg")
                    toSend=lenM-cntUsed
                    #show("toSend:",toSend)
                    #print("end of while")
                    break            #out of the while
                #if end
                cntUnsent=lenM-cntUsed-1
                #show("cntUnsent:",cntUnsent)
                #print("repeat the M while")
            #end while                 




            if False :
                # we need to send at least 1 more full packet
                isLastpack=False
                lastChar=cntUsed+(pktSize-len(oP)) #this is lastChar of Msg yet to send
                opToAdd=thisMsg[cntUsed:lastChar]  # to add to oP
                opTosend=oP+opToAdd
                print("opToSend:"+opToSend+":")
                sendThisPack(uartObject, opToSend, eom, pktSize)
                # no padding was necessary
                cntUsed=cntUsed+len(opToAdd)
                show("cntUsed:",cntUsed)
                # the while will loop once more
            #end if
            if False :
                lastChar=pktSize-cntSent
                show("lastChar",lastChar)
                #thisMsg="12345678901234567"
                #print("thisMsg:"+thisMsg+":")
                show("cntUsed",cntUsed)
                show("lastChar",lastChar)
                show("thisMsg[cntSent:lastChar]",thisMsg[cntUsed:lastChar])
                opWasSent=thisMsg[cntUsed:lastChar]
                print("opWasSend:"+opWasSend+":")
                if len(opToSend)>=16 :
                    print()
                    print("before sendThisPack oP:"+oP+":")
                    cntSent=sendThisPack(uartObject,opToSend, eom, pktSize)
                                           #returns 16  should print the Pkt
                    oP=""
                    show("cntUsedFromMsg:",cntUsedFromMsg)
                    cntUsed=cntUsed+cntUsedFromMsg    # should be 16 ...... to verify
                    cntSent=cntSent+16
                    show("lenM",lenM)
                    show("cntUsed",cntUsed)
                    isLastPacket=False
                else:
                    print("need to send padded Packet")
                    isLastPacket=True
                #end if
            #end if False
            if False :
                # a packet has just been sent
                leftToSend=lenM-cntUsed-1
                show("leftToSend:",leftToSend)
                if False :
                    if isLastPacket==True :       # will send the Last Packet (containing at least 1 EOM)
                        print("isLastPack is True")
                        #useStr=thisStr
                        cntUsedFromMsg=len(opToSend)
                        oP=opToSend
                        toAdd=16-cntUsedFromMsg
                        show("toAdd:",toAdd)
                        for x in range(toAdd):      # must insert correct range !!!!!
                            oP=oP+txChar(eom)           # must insert correct char from fullMsg !!!!!
                            cntSent=cntSent+1
                        #end for
                        print()
                        print("before sendThisPack oP:"+oP+":")
                        cntSent=sendThisPack(uartObject,oP, eom, pktSize)
                        #returns 16  should print the Pkt
                        oP=""
                        cntUsed=cntUsed+cntUsedFromMsg
                        show("cntUsed:",cntUsed)
                    #end if
                #end if False
                # a packet was just sent
                print("M while might end now")
                print("after end of while")
            #end if False
        #end if "M"

        if False :
            if msgPart=="P":                # P means Padding (with more EOMs) if any needs to be sent
                print("msgPart=P")
                if False :
                    if True:     # to be decided
                        oP=oP+txChar(eom)        # how many eoms of padding  !!!!!
                        cntUsed=cntUsed+1
                        cntSent=cntSent+1
                    #end if
                    show("cntUsed",cntUsed)
                    strSent=thisMsg[cntUsed:cntUsed+16]
                    show("strSent:",strSent)
                    cntUsedFromMsg = sendLastPack(uartObject, strSent, eom, pktSize) # should print the Pkt
                    cntUsed=cntUsed+cntUsedFromMsg
                    cntSent=cntSent+pktSize   #pktSize is usually 16
                #end if
            #end if "P"
        #end if False
        
    #end for    # all msg parts have now been sent
    # should check that cntUsed = len(Msg) +1
    # should check that cntSent is a muliple of pktSize(eg 16)
    return #from parsing and transmitting
#end def
def txChar(char):                                                                       #txChar()        
    #simply records that "char" has been sent
    # just prints it during testing
    # doesn't actually send the char
    #print(char, end='') #"end" suppresses the line feed
    return char
#end def

def sendThisPack(uartObject, opIn, cntPadding, eom, pktSize):                        #sendThisPack()
#

#actually sends the 16 characters in oP
    #print()
    #print("in sendThisPack")
    oP=opIn
    lenopIn=len(opIn)
    if (lenopIn==pktSize)==False:
        print("ERROR",pktSize, "is not the size of the packet to send:",lenopIn)
    #end if
    pos=opIn.find(eom)
    if pos==-1:              # -1 if not found
        pass
    else:
        print("WARNING E in serTx", eom, "found in message")
        oP=oP.replace(eom,"?")  
    #end if
    uartObject.write(oP)
    #print("tx sent:"
    # in sendThisPack
    print(oP, end='')    #this actually sends the text to the Shell
    #                    because in this early version, what is shown
    #                    in the Shell is actually sent.
    print()              #{for debugging}
    return pktSize
#end def

def sendLastPack(uartObject, opIn, cntPadding, eom, pktSize):                        #sendThisPack()
#

#actually sends the 16 characters in oP
    #print()
    #print("in sendLastPack")
    oP=opIn
    #print("oP:"+oP+":")
    lenopIn=len(opIn)
    #show("lenopIn:",lenopIn)
    if (lenopIn==pktSize)==False:
        print("ERROR",pktSize, "is not the size of the packet to send:",lenopIn)
    #end if
    #search for eom in the non-padding portion of oPIn
    suboPIn=opIn[0:pktSize-cntPadding]
    #print("suboPIn:"+suboPIn+":")
    pos=suboPIn.find(eom)
    if pos==-1:              # -1 if not found
        pass
    else:
        print("WARNING E in serTx", eom, "found in message")
        oP=oP.replace(eom,"?")  
    #end if
    uartObject.write(oP)
    # in sendLastPack():
    #print("tx sent:"+
    print(oP, end='')    #keep user informed during testing
    print()              #{for debugging}
    return pktSize
#end def
def mpyRead(uart):
    #keep read1 character packet until timeOut
    txtRead=""
    bRead=""
    while uart.any():

        aByte=str(uart.read(1))
        #show("aByte:",aByte)
        bRead=bChar(aByte)
        #show("bRead:",bRead)
        txtRead=txtRead+bRead
    #end while
    return txtRead
#end def



#  serRx_pico()   receives  a full serial text message               #serRx_pico()
def serRx_pico(uartObject, bps=600, timeOut=-1, eom="]"):
    #uart = machine.UART(1,bps, parity=None, stop=1, bits=8, rx=Pin(5), tx=Pin(4))
    print("my uart:",uart)
    #print("timeOut is set to:",timeOut)
    if timeOut==-1:
        t100c = 1000/bps
        timeOutUse=int(t100c+1.0)   #at least 1 sec
        #show("timeOutUse:",timeOutUse)
    else:
        timeOutUse=timeOut   #in seconds
    #end if
    #timeOutUse=t100c
    time=utime.time()
    timeNow=time
    #show("timeNow:",timeNow)
    timeFail=timeNow+timeOutUse    # defaults to a 3 second TimeOut
    #print("waiting my:",timeOutUse," seconds for data receipt. . . . .")
    oP=""  # reset input buffer
    #show("time:",time)
    #show("timeFail:",timeFail)

    while time < timeFail :
        #keep reading any 1 character packets until timeOut
        print("I should be flashing the green LED while receiving")
        # I don't know if it is still receiving
        # it should write the received msg to a file.
        #print("any")
        strA=mpyRead(uart)
        #show("strA:",strA)
        oP=oP+strA
        #show("oP:",oP)
        #end if
        time=utime.time()
    #end while
    #show("oP:",oP)
    lenOp=len(oP)
    if oP=="":
        print("ERROR T in serRx (): timeOut after",timeOutUse,"seconds")
        lenOp=len(oP)
    #end if
    if lenOp > 0:
        if oP.find("?")==-1:
            pass            # ? not found
        else:
            print("WARNING '?' seen in message received.")
        #end if
    #end if
    #print("serRx() received:"+oP+":")   #during testing
    return oP
#end def serRx_pico(uart,300,timeOut(in secs))

def show(strA,parmA):                                        # show
    print(strA,parmA)
    return
#end def

##########################################################################################
##########################################################################################
progName="testTxE_pico.py"
print("progName:"+progName)


if True:
    bps=60
    tPause=4 
    txPin=5
    rxPin=4
    #
    #print sys info
    print(os.uname())       #os, utime and machine were imported at top

    #indicate program started visually (by blinking the green LED)
    led_onboard = machine.Pin(25, machine.Pin.OUT)
    led_onboard.value(0)     # onboard LED OFF for 0.5 sec
    utime.sleep(0.5)
    led_onboard.value(1)    # leaving it ON

    #create uart object sample code
    if False :
        #self.uart = UART(1, 115200, parity=None, stop=1, bits=8, rx=Pin(rxPin), tx=Pin(txPin))
        pass
    #end if

    #create actual uart object
    uart = machine.UART(1,bps, parity=None, stop=1, bits=8, rx=Pin(5), tx=Pin(4))
    #print uart info
    #uart = machine.UART(1)
    print(uart)         # during testing


    #                     create uartObject
    #uart = machine.UART(1,bps, parity=None, stop=1, bits=8, tx=txPin, rx=rxPin)
    #    send a single "A"  which is 0x41 ("A"-0x40 * 16 is the packet length which is 16

    #                                         initialization is complete

    #uart.write("A")     #every group of messages is preceeded by a single "A"
    # prior to the "A", the transmitter should send a synchronizing sequence to permit
    #               the (human) receiver to "guess" or "determine" the baud rate (the bps)
    # hopefully the operator of the transmitter and receiver is the same human.

    # the serRx_pico should be running in a separate thread.

    #def serTx_pico(uartObject,bps, txtToBeSent="[UUUUUUUU]",rxtxEndChar="]"):
    print("transmitting Hello msg on Pin(GP4) in 2 16 byte packets at")
    print("60 bps, continuously preceded by an 'A' at 2 sec intervals")
    print("it erroneously skips the 'o' in 'Roy'. Doh!")
    print("Hit ^C to stop!")
    print()

    while True :
        try:
            uart.write("A")
            utime.sleep(tPause)
            serTx_pico(uart,bps, txtToBeSent="Hello,JoeMaxRoyBob")
            utime.sleep(tPause)
        except:
            print("interrupted by ^c")
            break
        #end try
    #end while
    if False:
        serTx_pico(uart,bps, txtToBeSent="H")
        serTx_pico(uart,bps, txtToBeSent="H")
        serTx_pico(uart,bps, txtToBeSent="H]")
        serTx_pico(uart,bps, txtToBeSent="[H]")
        serTx_pico(uart,bps, txtToBeSent="2.97")
        serTx_pico(uart,bps, txtToBeSent="99.987654")
        serTx_pico(uart,bps, txtToBeSent="ADC0:(0x4000,1622428309.000j)")
        serTx_pico(uart,bps, txtToBeSent="1234567890123")
        serTx_pico(uart,bps, txtToBeSent="12345678901234")
        serTx_pico(uart,bps, txtToBeSent="Hello,World")
        serTx_pico(uart,bps, txtToBeSent="1234567890123456789012345678901234567890")
    #end if

    if False:
        # the above is the current format of the rxtx protocol
        # The som,eom,t10c and are 1-character special codes
        #    each must be converted into outgoing text or actions or both
        #    all normal text does not need to be converted before transmission
        #
        # The txParse routine analyses the msgOut Format and separates it into
        # special codes (text and actions).  Each special code is sent to the txChar()
        # routine to be processed. Each character of outgoing text is sent to the
        # txChar() routine to be processed.
        #
        # The serTx_pico() routine is used to
        #   transmit a special code of text ("S" and "M")
        #   cause a time delay (V is "t5c X is "t10c  " and M is "t1000c")
        #   transmit msg as 16-byte packets (msg should not contain "]" which is replaced by "?" )
        #
        #   early testing Format is "SMEPX"
        #
        # Note that the "P" also inserts at least 1 "]" character and
        #   enough extra "]" characters (or none) to make a message with an exact multiple
        #   of 16 characters.  This is because there are always 16 characters sent per
        #   packet. Each packet is followed by a time delay of t5c.
        #   The last packet is always followed by a time delay of t10c.
        #   These time delays permit the receiver to resync with the transmitter.
        #   These time delays are never included in the character count of the
        #   message
        #   The serRx_pico() routine times out after an interval of 1000 character times: t1000c
        pass
    #end if

    # This should be run this as a separate thread
    # print whatever has been received
    bps=600
    t100c=1000/bps
    utime.sleep(t100c) #wait for an interval of 100 char times
#end if

#uart = machine.UART(1,bps, parity=None, stop=1, bits=8, tx=Pin(txPin), rx=Pin(rxPin))
bps=600
uart = machine.UART(1,bps, parity=None, stop=1, bits=8, tx=Pin(4), rx=Pin(5))
print("uart:",uart)
if False:
    uart.write("hello")
    t100c=1000/bps
    utime.sleep(t100c) #wait for an interval of 100 char times

    uart.write("Hello,World")
    utime.sleep(t100c) #wait for an interval of 100 char times
    utime.sleep(1)     #1 sec
#if end
if False:
    print("receiving mpy routine")
    while uart.any():
        print(uart.read(1))
    #end while
#end if
charIn=""
if False:
    print("receiving mpy routine")

    if uart.any() :
        #print("reading now")
        charIn=uart.read(1)
        #show("charIn:",charIn)
        #oP=oP+uartObject.read(1)
    #end if
    print("end of mpy routine")
#end if
show("charIn:",charIn)
#end if
print("receiving my routine")
msgIn=serRx_pico(uart,bps=600)   #times out after t100c seconds (100 char-times)
print("msgIn:",msgIn)

print("end of serRX()")

#end /testTxE_pico.py
# stored in Raspberry Pi Pico/

::::::::::textpak=>testTxF_pico.py.txt
# testTxF_pico.py
# stored in Raspberry Pi Pico/
#   and  in /home/pi/Desktop/Python_new/ix_pico_test/

import os
import utime
from machine import UART, Pin

#by D@CC
#Date: 2021FJun20
#Note: as of today, no known errors  ver F is first to work successfully

# all functions and subroutines are at top of program
#  1. bChar()       converts 4 char byte into 1 char
#  2. serTx_pico()  transmits a full serial text message
#  3. txParse()     parses the outgoing text message and calls txChar
#  4. txChar()      adds the char to oP which is the output text packet queue
#  5. sendThisPack  actually transmits a full packet (wo any EOM)
#  6. sendLastPack  actually transmits text (with at least one EOM)
#  7. serRx_pico()  receives  a full serial text message
# testTx          transmits many test messages
# testRx          receives all test messages

#calling parms
#bChar(strB):
#serTx_pico(uartObject,bps=300, txtToBeSent="Hello,World",rxtxEndChar="]",pktSize=16):
#txParse(uartObject, thisMsg, bps=300, msgFormat="SMEPX", T5C=-1, pktSize=16,  eom="]"):
#txChar(char):
#sendThisPack(uartObject, oPIn, eom, pktSize):
#sendLastPack(oPIn, cntSent, cntUsed,  eom = "]", pktSize=16):
#serRx_pico(uartObject, bps=300, timeOut=-1, eom="]"):
#
#Debugging notes:
#"tx sent:" is what is actually sent
# Errors and Warnings are embedded in the text transmitted. 

def bChar(strB):                                                                   #bChar()
    #  given a string like b'z' this returns the "z"
    # tested by D@CC on 2021FJun15
    
    #strB=input("eg b'h' :")
    b=strB[2:]
    #print("b:"+b)
    c=b[0]
    #c="z"
    #print("bChar("+'"'+strB+ '"):'+c)
    return c
#end def


def serTx_pico(uartObject,bps=300, txtToBeSent="Hello,World",rxtxEndChar="]",pktSize=16):         #serTx_pico#

    #print("txtToBeSent:"+txtToBeSent+":")
    #every parameter has a default setting except the uartObject (which needs to be defined).
    t5c=50/bps          #   50 bit times = 5 character times
    t10c=100/bps        #  100 bit times = 10 character times
    t1000c=10000/bps    # 10000 bit times = 1000 character times
    
    # requires a uart object (below) to be created before this function is called
    #uart = machine.UART(1, 300, parity=None, stop=1, bits=8, tx=Pin(txPin), rx=Pin(rxPin))
    #print("entering serTx_pico.py")
    if rxtxEndChar=="]":
        som = "["
        eom = "]"
    
    msgOut = """
    #S +
    #M +
    #E +
    #P +
    #C"""

    
    
    #where
    #A is the letter "A" meaning "16 bit packets (pktSize)"
    #S is SOM
    #M is Message text to be sent (will be followed by EOM)
    #E is EOM
    #P is the padding characters (enough EOMs to fill the packet)
    #X is t10c  (ten character time delay: "roman numeral X")
    #C is t100c  (100 character time delay: "roman numeral C")
        
    #Most messages will have   msgOut = "AC" "SMEPX"

    #Between messages, the transmitter will send "0" every minute indicating that its alive but
    #has no message to send.
    #Before sending each message the transmitter will send a single "A" which is 0x41 indicating
    #that the following message will be in packets of 16 characters.  In the future when the
    #packet size.
    #changes to 32 characters, the transmitter will precede each message with a single "B"
    #indicating the each packet will contain 32 characters.  This will allow future packet sizes
    #at least as big as 16x16x4 = 1024 characters and total message lengths of around 32768 without
    #using any control characters in the "ascii" preamble.

    #   Future versions will have msgOut = "DSNKMEPX"
    #    with packets having the format:
    #        AX SNKMV MV MV etc MEPX
    #The optional packet of 16 x D permits synchronization
    # 
    #where
    #D  is a full packet of Delete characters (optional for synchronization
    #N is the 2-character packet Number
    #K is the 2-character message character "Kount" including the only the first final EOM
    #V is t5c  (5 character time delay: "roman numeral V")


    #When a receiver starts up (and between messages) it should start by expecting packets of single
    #characters.  It will read a single 8-bit character expecting it to be a "0" meaning an idle transmitter.
    #If it is not a "0", it will read another single 8-bit character expecting it to be an "A".  If it is not an
    #"A",the character will be discarded, but the receiver will presume that it is reading a character
    #stream that is mid-message.  It will read single 8-bit characters searching for a "]" which will indicate
    #that this is the last packet of the message. It will keep reading and discarding all the "]" that it sees.
    #After the last "]", the
    #next 8-bit character should be a "0" or an "A".  The receiver should keep reading and discarding the "0"
    #characters.  When an "A" is finally received (while reading single 8-bit characters), the receiver knows that
    #this means subsequent packets will be packets of 16 characters.  The receiver is now fully
    #synchonized with the transmitter.  If something other than an "A" is received, the receiver should
    #begin looking for a "]" ()meaning "end of message" again.  If the state of "being in mid-message
    #continues 10 times, a human operator should be informed the that this ERROR is occuring.
    #
    #send the message
    txParse(uart,txtToBeSent)       #xyz
    #print("end of serTx()")
    #print("Hit ^C to stop!")
    #print()
    return True
#end def serTx_pico()
def txParse(uartObject, thisMsg, bps=300, msgFormat="SMEPX", T5C=-1, pktSize=16,  eom="]"):    #txParse()
    #show("thisMsg:",thisMsg)
#
#    uartObject is the uart being used
#    thisMsg is the full text message to be sent (It should not contain (EOM="]") they will become "?")
#                          (An EOM is added as the last character of a message, do not put the EOM in the msg)
#    bps is the baud rate (bits/sec)
#    msgFormat is the form of the Msg e.g. SMEPX  (first E is counted as last char of M)
#                                                (P is enough additional EOMs to pad to packetSize=16)
#                                               (t5c is interval between packets (-1 defaults to t5c)

#    t5c indicates time interval of 5 characters.  The transmitter will follow each packet with
#       this time delay
#    packetSize defaults to 16
#    eom is the definition of the 'EOM" character (usually "]")
    #oP is the full outgoing Packet that is sent by sendThisPack
    #                                      or by sendLastPack
    oP=""            # outgoing msg is initially empty
    if T5C==-1:    # if the calling routine doesn't specify
       t5c=50/bps
       t10c=100/bps
       t1000c=10000/bps
    else:
        t5c=T5C       #if the calling routine does specify T5C
        t10c=T5C*2
        t1000c=T5C*200
    #end if
    if eom=="]":
        som="["
    #end if

#    in 2021 msgOut="SMEPX"
    lenM=len(thisMsg)+1      #length of thisMsg -1  (+1 for the EOM character
    cntUsed=0                # number of characters in msgOut used so far
    cntSent=0                # number of character actually sent (incl all chars sent)
    isEOMsent=False          #EOM not sent yet
    #show("msgFormat:",msgFormat)
    for msgPart in msgFormat:   # do each message segment
        if msgPart=="S":
            # send SOM
            #print("send SOM")
            oP=oP+txChar(som)
            oP=oP+txChar("1")      # in future these 2 characters will contain parity or CRC
            oP=oP+txChar("6")      # today they contain the packet size (ie character count)
            cntSent=cntSent+3 #3 actually sent now
            #print()
            #print("oP:"+oP+":")
            cntUsed=0
        #end if
        if msgPart=="X":     # time delay doesn't send any characters
            utime.sleep(t10c) 
        #end if
        if msgPart=="M":     # sends the msg followed by 1 eom
            #print("sending M")
            #cntSent of the packet is already in oP
            #cntUsed is 0 going into the while
            # note that lenM also includes 1 eom
            # in the while loop, cntUsed will increase until cntUsed=lenM
            while (lenM-cntUsed) >= 1 : #lenM incl the EOM, cntUsed does also (after the EOM is sent)
                #print("going into the M while")
                #show("upon entry M-while cntUsed:",cntUsed)
                #  the packet being sent should not include any EOM characters. (EOM is only in the last pk)
                #  send a packet of data
                # lastChar is the lastChar of Msg to send in this packet
                cntCanAdd=pktSize-len(oP)
                #print("cntCanAdd:",cntCanAdd,":")
                #show("cntUsed:",cntUsed)  #should be 0 entering first loop

                cntRemainOfM=lenM-cntUsed-1   #this cnts the remaining chars of M 
                cntToAdd=pktSize-len(oP)    #this cnts the remaining space in oP
                # a packet is always sent in this next "if clause"
                #show("cntRemainOfM:",cntRemainOfM)
                #show("cntToAdd:",cntToAdd)
                #if (cntRemainOfM)>cntToAdd :   #{for debugging}
                if (cntRemainOfM+1)>cntToAdd :  #{for debugging} ver F +1
                # this packet cannot hold rest of Msg plus an eom
                    isLastPack=False 
                    opToAdd=thisMsg[cntUsed:cntUsed+cntToAdd]  # to add to oP
                    opToSend=oP+opToAdd                        # to be sent
                    #print("AopToSend:"+opToSend+":")
                    cntPadding=0
                    sendThisPack(uartObject, opToSend, cntPadding, eom, pktSize)
                    # that sent a full pkt without any padding
                    #cntUsed=cntUsed+cntToAdd+1
                    cntUsed=cntUsed+cntToAdd    #{for debugging} ver F del "+1"
                    # remember to count the first EOM as a character in cntUsed
                    #show("cntUsed:",cntUsed)
                    #show("lenM:",lenM)
                    oP=""
                    cntSent=0
                    #continue the while loop
                else :
                    isLastPack=True
                    # the pkt can hold the whole cntRemainOfM
                    opToAdd=thisMsg[cntUsed:cntUsed+cntRemainOfM]

                    #print("BopToSend:"+opToSend+":")
                    cntPadding=pktSize-cntSent-cntRemainOfM
                    strPadding=eom*cntPadding
                    opToSend=oP+opToAdd+strPadding
                    #print("CopToSend:"+opToSend+":")
                    
                    sendLastPack(uartObject, opToSend, cntPadding, eom, pktSize)
                    # that sent a full pkt including the padding                        
                    cntUsed=cntUsed+len(opToAdd)
                    #show("lenM:",lenM)
                    #show("cntUsed:",cntUsed)
                    oP=""
                    cntSent=0
                    #print("after Last Packet of Msg")
                    toSend=lenM-cntUsed
                    #show("toSend:",toSend)
                    #print("end of while")
                    break            #out of the while
                #if end
                cntUnsent=lenM-cntUsed-1
                #show("cntUnsent:",cntUnsent)
                #print("repeat the M while")
            #end while                 




            if False :
                # we need to send at least 1 more full packet
                isLastpack=False
                lastChar=cntUsed+(pktSize-len(oP)) #this is lastChar of Msg yet to send
                opToAdd=thisMsg[cntUsed:lastChar]  # to add to oP
                opTosend=oP+opToAdd
                print("opToSend:"+opToSend+":")
                sendThisPack(uartObject, opToSend, eom, pktSize)
                # no padding was necessary
                cntUsed=cntUsed+len(opToAdd)
                show("cntUsed:",cntUsed)
                # the while will loop once more
            #end if
            if False :
                lastChar=pktSize-cntSent
                show("lastChar",lastChar)
                #thisMsg="12345678901234567"
                #print("thisMsg:"+thisMsg+":")
                show("cntUsed",cntUsed)
                show("lastChar",lastChar)
                show("thisMsg[cntSent:lastChar]",thisMsg[cntUsed:lastChar])
                opWasSent=thisMsg[cntUsed:lastChar]
                print("opWasSend:"+opWasSend+":")
                if len(opToSend)>=16 :
                    print()
                    print("before sendThisPack oP:"+oP+":")
                    cntSent=sendThisPack(uartObject,opToSend, eom, pktSize)
                                           #returns 16  should print the Pkt
                    oP=""
                    show("cntUsedFromMsg:",cntUsedFromMsg)
                    cntUsed=cntUsed+cntUsedFromMsg    # should be 16 ...... to verify
                    cntSent=cntSent+16
                    show("lenM",lenM)
                    show("cntUsed",cntUsed)
                    isLastPacket=False
                else:
                    print("need to send padded Packet")
                    isLastPacket=True
                #end if
            #end if False
            if False :
                # a packet has just been sent
                leftToSend=lenM-cntUsed-1
                show("leftToSend:",leftToSend)
                if False :
                    if isLastPacket==True :       # will send the Last Packet (containing at least 1 EOM)
                        print("isLastPack is True")
                        #useStr=thisStr
                        cntUsedFromMsg=len(opToSend)
                        oP=opToSend
                        toAdd=16-cntUsedFromMsg
                        show("toAdd:",toAdd)
                        for x in range(toAdd):      # must insert correct range !!!!!
                            oP=oP+txChar(eom)           # must insert correct char from fullMsg !!!!!
                            cntSent=cntSent+1
                        #end for
                        print()
                        print("before sendThisPack oP:"+oP+":")
                        cntSent=sendThisPack(uartObject,oP, eom, pktSize)
                        #returns 16  should print the Pkt
                        oP=""
                        cntUsed=cntUsed+cntUsedFromMsg
                        show("cntUsed:",cntUsed)
                    #end if
                #end if False
                # a packet was just sent
                print("M while might end now")
                print("after end of while")
            #end if False
        #end if "M"

        if False :
            if msgPart=="P":                # P means Padding (with more EOMs) if any needs to be sent
                print("msgPart=P")
                if False :
                    if True:     # to be decided
                        oP=oP+txChar(eom)        # how many eoms of padding  !!!!!
                        cntUsed=cntUsed+1
                        cntSent=cntSent+1
                    #end if
                    show("cntUsed",cntUsed)
                    strSent=thisMsg[cntUsed:cntUsed+16]
                    show("strSent:",strSent)
                    cntUsedFromMsg = sendLastPack(uartObject, strSent, eom, pktSize) # should print the Pkt
                    cntUsed=cntUsed+cntUsedFromMsg
                    cntSent=cntSent+pktSize   #pktSize is usually 16
                #end if
            #end if "P"
        #end if False
        
    #end for    # all msg parts have now been sent
    # should check that cntUsed = len(Msg) +1
    # should check that cntSent is a muliple of pktSize(eg 16)
    return #from parsing and transmitting
#end def
def txChar(char):                                                                       #txChar()        
    #simply records that "char" has been sent
    # just prints it during testing
    # doesn't actually send the char
    #print(char, end='') #"end" suppresses the line feed
    return char
#end def

def sendThisPack(uartObject, opIn, cntPadding, eom, pktSize):                        #sendThisPack()
#

#actually sends the 16 characters in oP
    #print()
    #print("in sendThisPack")
    oP=opIn
    lenopIn=len(opIn)
    if (lenopIn==pktSize)==False:
        print("ERROR",pktSize, "is not the size of the packet to send:",lenopIn)
    #end if
    pos=opIn.find(eom)
    if pos==-1:              # -1 if not found
        pass
    else:
        print("WARNING E1 in serTx", eom, "found eom in message")
        #oP=oP.replace(eom,"?")   
        oP=oP.replace(eom,"?",1)   #{for debugging} ver F  replace once
    #end if
    uartObject.write(oP)
    #print("tx sent:"
    # in sendThisPack
    print(oP, end='')    #this actually sends the text to the Shell
    #                    because in this early version, what is shown
    #                    in the Shell is actually sent.
    #print()              #{for debugging}
    return pktSize
#end def

def sendLastPack(uartObject, opIn, cntPadding, eom, pktSize):                        #sendThisPack()
#

#actually sends the 16 characters in oP
    #print()
    #print("in sendLastPack")
    oP=opIn
    #print("oP:"+oP+":")
    lenopIn=len(opIn)
    #show("lenopIn:",lenopIn)
    if (lenopIn==pktSize)==False:
        print("ERROR",pktSize, "is not the size of the packet to send:",lenopIn)
    #end if
    #search for eom in the non-padding portion of oPIn
    suboPIn=opIn[0:pktSize-cntPadding]
    #print("suboPIn:"+suboPIn+":")
    pos=suboPIn.find(eom)
    if pos==-1:              # -1 if not found
        pass
    else:
        print("WARNING E2 in serTx", eom, "found in message")
        oPleft=opIn[0:pos]          #{for debugging} ver F fix
        #print("oPleft:"+oPleft+":")
        lenOp=len(opIn)             #{for debugging} ver F fix
        oPright=opIn[pos+1:lenOp]   #{for debugging} ver F fix
        #print("oPright:"+oPright+":")        
        #oP=oP.replace(eom,"?")
        #oP=oP.replace(eom,"?",1)   #{for debugging} replace once didn't work
        oP=oPleft+"?"+oPright       #{for debugging} ver F fix
    #end if
    uartObject.write(oP)
    # in sendLastPack():
    #print("tx sent:"+
    print(oP, end='')    #keep user informed during testing
    #print()              #{for debugging}
    return pktSize
#end def
def mpyRead(uart):
    #keep read1 character packet until timeOut
    txtRead=""
    bRead=""
    while uart.any():

        aByte=str(uart.read(1))
        #show("aByte:",aByte)
        bRead=bChar(aByte)
        #show("bRead:",bRead)
        txtRead=txtRead+bRead
    #end while
    return txtRead
#end def



#  serRx_pico()   receives  a full serial text message               #serRx_pico()
def serRx_pico(uartObject, bps=600, timeOut=-1, eom="]"):
    #uart = machine.UART(1,bps, parity=None, stop=1, bits=8, rx=Pin(5), tx=Pin(4))
    print("my uart:",uart)
    #print("timeOut is set to:",timeOut)
    if timeOut==-1:
        t100c = 1000/bps
        timeOutUse=int(t100c+1.0)   #at least 1 sec
        #show("timeOutUse:",timeOutUse)
    else:
        timeOutUse=timeOut   #in seconds
    #end if
    #timeOutUse=t100c
    time=utime.time()
    timeNow=time
    #show("timeNow:",timeNow)
    timeFail=timeNow+timeOutUse    # defaults to a 3 second TimeOut
    #print("waiting my:",timeOutUse," seconds for data receipt. . . . .")
    oP=""  # reset input buffer
    #show("time:",time)
    #show("timeFail:",timeFail)

    while time < timeFail :
        #keep reading any 1 character packets until timeOut
        print("I should be flashing the green LED while receiving")
        # I don't know if it is still receiving
        # it should write the received msg to a file.
        #print("any")
        strA=mpyRead(uart)
        #show("strA:",strA)
        oP=oP+strA
        #show("oP:",oP)
        #end if
        time=utime.time()
    #end while
    #show("oP:",oP)
    lenOp=len(oP)
    if oP=="":
        print("ERROR T in serRx (): timeOut after",timeOutUse,"seconds")
        lenOp=len(oP)
    #end if
    if lenOp > 0:
        if oP.find("?")==-1:
            pass            # ? not found
        else:
            print("WARNING '?' seen in message received.")
        #end if
    #end if
    #print("serRx() received:"+oP+":")   #during testing
    return oP
#end def serRx_pico(uart,300,timeOut(in secs))

def show(strA,parmA):                                        # show
    print(strA,parmA)
    return
#end def

##########################################################################################
##########################################################################################
progName="testTxF_pico.py"
print("progName:"+progName)


if True:
    bps=60
    tPause=4 
    txPin=5
    rxPin=4
    #
    #print sys info
    print(os.uname())       #os, utime and machine were imported at top

    #indicate program started visually (by blinking the green LED)
    led_onboard = machine.Pin(25, machine.Pin.OUT)
    led_onboard.value(0)     # onboard LED OFF for 0.5 sec
    utime.sleep(0.5)
    led_onboard.value(1)    # leaving it ON

    #create uart object sample code
    if False :
        #self.uart = UART(1, 115200, parity=None, stop=1, bits=8, rx=Pin(rxPin), tx=Pin(txPin))
        pass
    #end if

    #create actual uart object
    uart = machine.UART(1,bps, parity=None, stop=1, bits=8, rx=Pin(5), tx=Pin(4))
    #print uart info
    #uart = machine.UART(1)
    print(uart)         # during testing


    #                     create uartObject
    #uart = machine.UART(1,bps, parity=None, stop=1, bits=8, tx=txPin, rx=rxPin)
    #    send a single "A"  which is 0x41 ("A"-0x40 * 16 is the packet length which is 16

    #                                         initialization is complete

    #uart.write("A")     #every group of messages is preceeded by a single "A"
    # prior to the "A", the transmitter should send a synchronizing sequence to permit
    #               the (human) receiver to "guess" or "determine" the baud rate (the bps)
    # hopefully the operator of the transmitter and receiver is the same human.

    # the serRx_pico should be running in a separate thread.

    #def serTx_pico(uartObject,bps, txtToBeSent="[UUUUUUUU]",rxtxEndChar="]"):
    print("transmitting Hello msg on Pin(GP4) in 2 16 byte packets at")
    print("60 bps, continuously preceded by an 'A' at 2 sec intervals")
    print("the 'A' is not seen by the receiver") 
    #print("it erroneously skips the 'o' in 'Roy'. Doh!") #fixed in ver F
    print("it erroneously skips a full packet of ']' when needed") 

    print("Hit ^C to stop!")
    print()

    while True :
        uart.write("A")
        utime.sleep(tPause)
        serTx_pico(uart,bps, txtToBeSent="Hello,JoeMaxRoyBob")
        utime.sleep(tPause)
        serTx_pico(uart,bps, txtToBeSent="H")  #{for debugging}
        utime.sleep(tPause)                    #{for debugging}
        #serTx_pico(uart,bps, txtToBeSent="H]") #{for debugging}
        #utime.sleep(tPause)   
        serTx_pico(uart,bps, txtToBeSent="2.97")
        utime.sleep(tPause)                    #{for debugging}
        serTx_pico(uart,bps, txtToBeSent="99.987654")
        utime.sleep(tPause)                    #{for debugging}
        serTx_pico(uart,bps, txtToBeSent="ADC0:(0x4000,1622428309.000j)")
        # recv'd                          ADC0:(0x4000,1622428309.0  b''
        utime.sleep(tPause)
        serTx_pico(uart,bps, txtToBeSent="1234567890123456789012345678901234567890")
        # recv'd                          1234567890123456789012345  b'01234567890'
        try:
            utime.sleep(tPause)                    #{for debugging}
        except:
            print("interrupted by ^c")
            break
        finally:
            pass
        #end try
    #end while
    if False:


        serTx_pico(uart,bps, txtToBeSent="2.97")
        serTx_pico(uart,bps, txtToBeSent="99.987654")
        serTx_pico(uart,bps, txtToBeSent="ADC0:(0x4000,1622428309.000j)")
        serTx_pico(uart,bps, txtToBeSent="1234567890123")
        serTx_pico(uart,bps, txtToBeSent="12345678901234")
        serTx_pico(uart,bps, txtToBeSent="Hello,World")
        serTx_pico(uart,bps, txtToBeSent="1234567890123456789012345678901234567890")
    #end if

    if False:
        # the above is the current format of the rxtx protocol
        # The som,eom,t10c and are 1-character special codes
        #    each must be converted into outgoing text or actions or both
        #    all normal text does not need to be converted before transmission
        #
        # The txParse routine analyses the msgOut Format and separates it into
        # special codes (text and actions).  Each special code is sent to the txChar()
        # routine to be processed. Each character of outgoing text is sent to the
        # txChar() routine to be processed.
        #
        # The serTx_pico() routine is used to
        #   transmit a special code of text ("S" and "M")
        #   cause a time delay (V is "t5c X is "t10c  " and M is "t1000c")
        #   transmit msg as 16-byte packets (msg should not contain "]" which is replaced by "?" )
        #
        #   early testing Format is "SMEPX"
        #
        # Note that the "P" also inserts at least 1 "]" character and
        #   enough extra "]" characters (or none) to make a message with an exact multiple
        #   of 16 characters.  This is because there are always 16 characters sent per
        #   packet. Each packet is followed by a time delay of t5c.
        #   The last packet is always followed by a time delay of t10c.
        #   These time delays permit the receiver to resync with the transmitter.
        #   These time delays are never included in the character count of the
        #   message
        #   The serRx_pico() routine times out after an interval of 1000 character times: t1000c
        pass
    #end if

    # This should be run this as a separate thread
    # print whatever has been received
    bps=600
    t100c=1000/bps
    utime.sleep(t100c) #wait for an interval of 100 char times
#end if

#uart = machine.UART(1,bps, parity=None, stop=1, bits=8, tx=Pin(txPin), rx=Pin(rxPin))
bps=600
uart = machine.UART(1,bps, parity=None, stop=1, bits=8, tx=Pin(4), rx=Pin(5))
print("uart:",uart)
if False:
    uart.write("hello")
    t100c=1000/bps
    utime.sleep(t100c) #wait for an interval of 100 char times

    uart.write("Hello,World")
    utime.sleep(t100c) #wait for an interval of 100 char times
    utime.sleep(1)     #1 sec
#if end
if False:
    print("receiving mpy routine")
    while uart.any():
        print(uart.read(1))
    #end while
#end if
charIn=""
if False:
    print("receiving mpy routine")

    if uart.any() :
        #print("reading now")
        charIn=uart.read(1)
        #show("charIn:",charIn)
        #oP=oP+uartObject.read(1)
    #end if
    print("end of mpy routine")
#end if
show("charIn:",charIn)
#end if
print("receiving my routine")
msgIn=serRx_pico(uart,bps=600)   #times out after t100c seconds (100 char-times)
print("msgIn:",msgIn)

print("end of serRX()")

#end /testTxF_pico.py
# stored in Raspberry Pi Pico/

::::::::::textpak=>testTxRxB_pico.py.txt
import os
import utime
from machine import UART, Pin

#by D@CC
#Date: 2021FJun18
#Note: as of today, fully untested

# all functions and subroutines are at top of program
#  1. bChar()       converts 4 char byte into 1 char
#  2. serTx_pico()  transmits a full serial text message
#  3. txParse()     parses the outgoing text message and calls txChar
#  4. txChar()      adds the char to oP which is the output text packet queue
#  5. sendThisPack  actually transmits a full packet (wo any EOM)
#  6. sendLastPack  actually transmits text (with at least one EOM)
#  7. serRx_pico()  receives  a full serial text message
# testTx()          transmits many test messages
# testRx()          receives all test messages

def bChar(strB):                                                                   #bChar()
    #  given a string like b'z' this returns the "z"
    # tested by D@CC on 2021FJun15
    
    #strB=input("eg b'h' :")
    b=strB[2:]
    #print("b:"+b)
    c=b[0]
    #c="z"
    #print("bChar("+'"'+strB+ '"):'+c)
    return c
#end def


def serTx_pico(uartObject,bps=300, txtToBeSent="Hello,World",rxtxEndChar="]",pktSize):         #serTx_pico#

    #every parameter has a default setting except the uartObject (which needs to be defined).
    t5c=50/bps          #   50 bit times = 5 character times
    t10c=100/bps        #  100 bit times = 10 character times
    t1000c=10000/bps    # 10000 bit times = 1000 character times
    
    # requires a uart object (below) to be created before this function is called
    #uart = machine.UART(1, 300, parity=None, stop=1, bits=8, tx=Pin(txPin), rx=Pin(rxPin))
    print("entering serTx_pico.py")
    if rxtxEndChar=="]":
        som = "["
        eom = "]"
    
    msgOut = """
    S +
    M +
    E +
    P +
    X"""

    
    
    where
    A is the letter "A" meaning "16 bit packets (pktSize)"
    S is SOM
    M is Message text to be sent (will be followed by EOM)
    E is EOM
    P is the padding characters (enough EOMs to fill the packet)
    X is t10c  (ten character time delay: "roman numeral X")
    C is t100c  (100 character time delay: "roman numeral C")
        
    Most messages will have   msgOut = "AC" "SMEPX"

    Between messages, the transmitter will send "0" every minute indicating that its alive but
    has no message to send.
    Before sending each message the transmitter will send a single "A" which is 0x41 indicating
    that the following message will be in packets of 16 characters.  In the future when the
    packet size.
    changes to 32 characters, the transmitter will precede each message with a single "B"
    indicating the each packet will contain 32 characters.  This will allow future packet sizes
    at least as big as 16x16x4 = 1024 characters and total message lengths of around 32768 without
    using any control characters in the "ascii" preamble.

        Future versions will have msgOut = "DSNKMEPX"
        with packets having the format:
            AX SNKMV MV MV etc MEPX
    The optional packet of 16 x D permits synchronization
    
    where
    D  is a full packet of Delete characters (optional for synchronization
    N is the 2-character packet Number
    K is the 2-character message character "Kount" including the only the first final EOM
    V is t5c  (5 character time delay: "roman numeral V")


    When a receiver starts up (and between messages) it should start by expecting packets of single
    characters.  It will read a single 8-bit character expecting it to be a "0" meaning an idle transmitter.
    If it is not a "0", it will read another single 8-bit character expecting it to be an "A".  If it is not an
    "A",the character will be discarded, but the receiver will presume that it is reading a character
    stream that is mid-message.  It will read single 8-bit characters searching for a "]" which will indicate
    that this is the last packet of the message. It will keep reading and discarding all the "]" that it sees.
    After the last "]", the
    next 8-bit character should be a "0" or an "A".  The receiver should keep reading and discarding the "0"
    characters.  When an "A" is finally received (while reading single 8-bit characters), the receiver knows that
    this means subsequent packets will be packets of 16 characters.  The receiver is now fully
    synchonized with the transmitter.  If something other than an "A" is received, the receiver should
    begin looking for a "]" ()meaning "end of message" again.  If the state of "being in mid-message
    continues 10 times, a human operator should be informed the that this ERROR is occuring.
    
    #send the message
def txParse(uartObject, fullMsg, bps=300, msgFormat="SMEPX", T5C=-1, packetSize=16,  eom="]"):    #txParse()
#
#    uartObject is the uart being used
#    fullMsg is the full text message to be sent (It should not contain (EOM="]") they will become "?")
#                          (An EOM is added as the last character of a message, do not put the EOM in the msg)
#    bps is the baud rate (bits/sec)
#    msgFormat is the form of the Msg e.g. SMEPX  (first E is counted as last char of M)
#                                                (P is enough additional EOMs to pad to packetSize=16)
#                                               (t5c is interval between packets (-1 defaults to t5c)

#    t5c indicates time interval of 5 characters.  The transmitter will follow each packet with
#       this time delay
#    packetSize defaults to 16
#    eom is the definition of the 'EOM" character (usually "]")
    #oP is the full outgoing Packet that is sent by sendThisPack
    #                                      or by sendLastPack
    oP=""            # outgoing msg is initially empty
    if T5C==-1:    # if the calling routine doesn't specify
       t5c=50/bps
       t10c=100/bps
       t1000c=10000/bps
    else:
        t5c=T5C       #if the calling routine does specify T5C
        t10c=T5C*2
        t1000c=T5C*200
    #end if
    
#    in 2021 msgOut="SMEPX"
    lenM=len(fullMsg)+1      #length of fullMsg -1  (+1 for the EOM character
    cntUsed=0                # number of characters in msgOut used so far
    cntSent=0                # number of character actually sent (incl all chars sent)
    isEOMsent=False          #EOM not sent yet
    for msgPart in msgFormat:   # do each message segment
        if msgPart=="S":
            # send SOM
            oP=oP+txChar(som)
            oP=oP+txChar("1")      # in future these 2 characters will contain parity or CRC
            oP=oP+txChar("6")      # today they contain the packet size (ie character count)
            cntSent=cntSent+3 #3 actually sent now
        #end if
        if msgPart=="X":     # time delay doesn't send any characters
            utime.sleep(t10c) 
        #end if
        if msgPart=="M":     # sends the msg followed by 1 eom
            isLastPack=True
            while (lenM-cntUsed) >= 1 : #lenM incl the EOM, cntUsed does also (after the EOM is sent)
                isLastPack=False
                #  the packet being sent should not include any EOM characters. (EOM is only in the last pk)
                #  send a packet of data w/o eom
                cntUsedFromMsg=sendThisPack(fullMsg,cntUsed,cntUsed+pktSize, cntSent ,cntUsed,pktSize)
                                                        #returns 16  should print the Pkt
                cntUsed=cntUsed+cntUsedFromMsg    # should be 16 ...... to verify
                cntSent=cntSent+16
            #end while                 # the above sent all packets except the last one
                
            if isLastPack==True        # will send the Last Packet (containing at least 1 EOM)
                for x in range():      # must insert correct range !!!!!
                    oP=oP+txChar(?)           # must insert correct char from fullMsg !!!!!
                    cntUsed=cntUsed+?     
                    cntSent=cntSent+1
                #end for
                oP=oP+txChar(eom)            # send the first eom

                #cntUsed should be = lenMsg +1 (for the eom)

            #end if
        #end if
        if msgPart=="P"                # P means Padding (with more EOMs) if any needs to be sent
                if (True or False)     # to be decided
                    oP=oP+txChar(eom)        # how many eoms of padding  !!!!!
                    cntUsed=cntUsed+1
                    cntSent=cntSent+1
                #end if
                cntUsedFromMsg = sendLastPack(fullMsg, cntSent ,cntUsed, eom) # should print the Pkt
                cntUsed=cntUsed+cntUsedFromMsg
                cntSent=cntSent+pktSize   #pktSize is usually 16
        #end if
    #end for    # all msg parts have now been sent
    # should check that cntUsed = len(Msg) +1
    # should check that cntSent is a muliple of pktSize(eg 16)
    return #from parsing and transmitting
#end def
def txChar(char):                                                                       #txChar()        
    #simply records that "char" has been sent
    # just prints it during testing
    # doesn't actually send the char
    print(char end='') #"end" suppresses the line feed
    return char
#end def

def sendThisPack(uartObject, oPIn, pktSize):                                    #sendThisPack()
#
#actually sends the 16 characters in oP
    oP=opIn
    lenOpIn=len(oPIn)
    if (lenOpIn==pktSize)==False:
        print("ERROR",pktSize, "is not the size of the packet to send:",lenOpIn)
    #end if
    pos=oPIn.find(eom)
    if pos=-1:              # -1 if not found
        pass
    else:
        print("WARNING E in serTx", eom, "found in message")
        oP.replace(eom,"?")  
    #end if
    uartObject.write(oPIn)
    print("tx sent:"+oPIn+":")    #keep user informed during testing
    return pktSize
#end def

def sendLastPack(uartObject, oPIn, eom = "]")                           #sendLastPack()   
#actually sends the character packet in oP
# but pads the packet with "eom"s first
    # replace any eom with "?"
    lenOpIn=len(oPIn)
    oP=opIn
    pos=oP.find(eom)
    if pos=-1:      # Good: eom not found
        pass
    else:
        print("ERROR E in serTx", eom, "found in message")
        oP.replace(eom,"?")  
    #end if
    len=len(oP)
    #pad packet with eoms
    for k in range(16-lenOp):
        oPtoSend=oPtoSend+eom
    #end for
    
    lenOp=len(oP)       # is the pktSize correct
    if (lenOp==pktSize)==False:
        print("ERROR",pktSize, "is not the size of the packet to send:",lenOp)
    #end if
    #send the 16 character packet
    uartObject.write(oP)
    print("tx padded (if needed) and sent:"+oP+":")
    return lenOpIn            # return # of chars used.
#end def

#  serRx_pico()   receives  a full serial text message               #serRx_pico()
def serRx_pico(uartObject,bps=300, timeOut, eom="]"):
    if timeOut="":
        t100c= 1000/bps
    else:
        t100c=timeOut
    #end if
    timeOutUse=t100c
    timeNow=unix.time()
    timeFail=timeNow+timeOutUse    # defaults to a 3 second TimeOut
    print("waiting",timeOutUse," seconds for data receipt. . . . .")
    oP=""  # reset input buffer
    while time < timeFail :
        #keep reading any 1 character packets until timeOut
        if uartObject.any() :
            oP=oP+uartObject.read(1)
        #end if
    #end while
        print("ERROR T in serRx((): timeOut after",timeOutUse,"seconds")
        #end if
    #end while
    lenOp=len(oP)
    if lenOp > 0:
        if oP.find("?")==-1:
            pass            # ? not found
        else:
            print("WARNING '?' seen in message received. )
        #end if
    #end if
    print("serRx() received:"+oP+":")   #during testing
    return lenOp
#end def serRx_pico(uart,300,timeOut(in secs))

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

progName="testTxB_pico.py"
print("progName:"+progName)
bps=300
txPin=5
rxPin=4
#
#print sys info
print(os.uname())       #os, utime and machine were imported at top

#indicate program started visually (by blinking the green LED)
led_onboard = machine.Pin(25, machine.Pin.OUT)
led_onboard.value(0)     # onboard LED OFF for 0.5 sec
utime.sleep(0.5)
led_onboard.value(1)    # leaving it ON

#create uart object sample code
if False :
    #self.uart = UART(1, 115200, parity=None, stop=1, bits=8, rx=Pin(rxPin), tx=Pin(txPin))
    pass
#end if

create actual uart object
uart = machine.UART(1,bps, parity=None, stop=1, bits=8, tx=Pin(txPin), rx=Pin(rxPin))
#print uart info
#uart = machine.UART(1)
print(uart)         # during testing


#                     create uartObject
uart = machine.UART(1,bps, parity=None, stop=1, bits=8, tx=Pin(txPin), rx=Pin(rxPin))
#    send a single "A"  which is 0x41 ("A"-0x40 * 16 is the packet length which is 16

#                                         initialization is complete

uartObject.write("A")     #every group of messages is preceeded by a single "A"
# prior to the "A", the transmitter should send a synchronizing sequence to permit
#               the (human) receiver to "guess" or "determine" the baud rate (the bps)
# hopefully the operator of the transmitter and receiver is the same human.

# the serRx_pico should be running in a separate thread.

#def serTx_pico(uartObject,bps, txtToBeSent="[UUUUUUUU]",rxtxEndChar="]"):
serTx_pico(uartObject,bps, txtToBeSent="")
serTx_pico(uartObject,bps, txtToBeSent="H")
serTx_pico(uartObject,bps, txtToBeSent="H]")
serTx_pico(uartObject,bps, txtToBeSent="[H]")
serTx_pico(uartObject,bps, txtToBeSent="2.97")
serTx_pico(uartObject,bps, txtToBeSent="99.987654")
serTx_pico(uartObject,bps, txtToBeSent="ADC0:(0x4000,1622428309.000j)"")
serTx_pico(uartObject,bps, txtToBeSent="1234567890123")
serTx_pico(uartObject,bps, txtToBeSent="12345678901234")
serTx_pico(uartObject,bps, txtToBeSent="Hello,World")
serTx_pico(uartObject,bps, txtToBeSent="1234567890123456789012345678901234567890")

if False:
    # the above is the current format of the rxtx protocol
    # The som,eom,t10c and are 1-character special codes
    #    each must be converted into outgoing text or actions or both
    #    all normal text does not need to be converted before transmission
    #
    # The txParse routine analyses the msgOut Format and separates it into
    # special codes (text and actions).  Each special code is sent to the txChar()
    # routine to be processed. Each character of outgoing text is sent to the
    # txChar() routine to be processed.
    #
    # The serTx_pico() routine is used to
    #   transmit a special code of text ("S" and "M")
    #   cause a time delay (V is "t5c X is "t10c  " and M is "t1000c")
    #   transmit msg as 16-byte packets (msg should not contain "]" which is replaced by "?" )
    #
    #   early testing Format is "SMEPX"
    #
    # Note that the "P" also inserts at least 1 "]" character and
    #   enough extra "]" characters (or none) to make a message with an exact multiple
    #   of 16 characters.  This is because there are always 16 characters sent per
    #   packet. Each packet is followed by a time delay of t5c.
    #   The last packet is always followed by a time delay of t10c.
    #   These time delays permit the receiver to resync with the transmitter.
    #   These time delays are never included in the character count of the
    #   message
    #   The serRx_pico() routine times out after an interval of 1000 character times: t1000c
    pass
#end if

# This should be run this as a separate thread
# print whatever has been received
bps=300
t100c=1000/bps
#uart = machine.UART(1,bps, parity=None, stop=1, bits=8, tx=Pin(txPin), rx=Pin(rxPin))
uart = machine.UART(1,bps, parity=None, stop=1, bits=8, tx=5, rx=4))
print(serRx(uart,300,t1000c))   #times out after t1000c seconds (1000 char-times)
print("end of serRX()")

#/testTxRxB_pico.py

::::::::::textpak=>testTxRxC_pico.py.txt
import os
import utime
from machine import UART, Pin

#by D@CC
#Date: 2021FJun18
#Note: as of today, partially tested

# all functions and subroutines are at top of program
#  1. bChar()       converts 4 char byte into 1 char
#  2. serTx_pico()  transmits a full serial text message
#  3. txParse()     parses the outgoing text message and calls txChar
#  4. txChar()      adds the char to oP which is the output text packet queue
#  5. sendThisPack  actually transmits a full packet (wo any EOM)
#  6. sendLastPack  actually transmits text (with at least one EOM)
#  7. serRx_pico()  receives  a full serial text message
# testTx          transmits many test messages
# testRx          receives all test messages

#calling parms
#bChar(strB):
#serTx_pico(uartObject,bps=300, txtToBeSent="Hello,World",rxtxEndChar="]",pktSize=16):
#txParse(uartObject, thisMsg, bps=300, msgFormat="SMEPX", T5C=-1, pktSize=16,  eom="]"):
#txChar(char):
#sendThisPack(uartObject, oPIn, eom, pktSize):
#sendLastPack(oPIn, cntSent, cntUsed,  eom = "]", pktSize=16):
#serRx_pico(uartObject, bps=300, timeOut=-1, eom="]"):

def bChar(strB):                                                                   #bChar()
    #  given a string like b'z' this returns the "z"
    # tested by D@CC on 2021FJun15
    
    #strB=input("eg b'h' :")
    b=strB[2:]
    #print("b:"+b)
    c=b[0]
    #c="z"
    #print("bChar("+'"'+strB+ '"):'+c)
    return c
#end def


def serTx_pico(uartObject,bps=300, txtToBeSent="Hello,World",rxtxEndChar="]",pktSize=16):         #serTx_pico#

    print("txtToBeSent:",txtToBeSent,":")
    #every parameter has a default setting except the uartObject (which needs to be defined).
    t5c=50/bps          #   50 bit times = 5 character times
    t10c=100/bps        #  100 bit times = 10 character times
    t1000c=10000/bps    # 10000 bit times = 1000 character times
    
    # requires a uart object (below) to be created before this function is called
    #uart = machine.UART(1, 300, parity=None, stop=1, bits=8, tx=Pin(txPin), rx=Pin(rxPin))
    print("entering serTx_pico.py")
    if rxtxEndChar=="]":
        som = "["
        eom = "]"
    
    msgOut = """
    #S +
    #M +
    #E +
    #P +
    #C"""

    
    
    #where
    #A is the letter "A" meaning "16 bit packets (pktSize)"
    #S is SOM
    #M is Message text to be sent (will be followed by EOM)
    #E is EOM
    #P is the padding characters (enough EOMs to fill the packet)
    #X is t10c  (ten character time delay: "roman numeral X")
    #C is t100c  (100 character time delay: "roman numeral C")
        
    #Most messages will have   msgOut = "AC" "SMEPX"

    #Between messages, the transmitter will send "0" every minute indicating that its alive but
    #has no message to send.
    #Before sending each message the transmitter will send a single "A" which is 0x41 indicating
    #that the following message will be in packets of 16 characters.  In the future when the
    #packet size.
    #changes to 32 characters, the transmitter will precede each message with a single "B"
    #indicating the each packet will contain 32 characters.  This will allow future packet sizes
    #at least as big as 16x16x4 = 1024 characters and total message lengths of around 32768 without
    #using any control characters in the "ascii" preamble.

    #   Future versions will have msgOut = "DSNKMEPX"
    #    with packets having the format:
    #        AX SNKMV MV MV etc MEPX
    #The optional packet of 16 x D permits synchronization
    # 
    #where
    #D  is a full packet of Delete characters (optional for synchronization
    #N is the 2-character packet Number
    #K is the 2-character message character "Kount" including the only the first final EOM
    #V is t5c  (5 character time delay: "roman numeral V")


    #When a receiver starts up (and between messages) it should start by expecting packets of single
    #characters.  It will read a single 8-bit character expecting it to be a "0" meaning an idle transmitter.
    #If it is not a "0", it will read another single 8-bit character expecting it to be an "A".  If it is not an
    #"A",the character will be discarded, but the receiver will presume that it is reading a character
    #stream that is mid-message.  It will read single 8-bit characters searching for a "]" which will indicate
    #that this is the last packet of the message. It will keep reading and discarding all the "]" that it sees.
    #After the last "]", the
    #next 8-bit character should be a "0" or an "A".  The receiver should keep reading and discarding the "0"
    #characters.  When an "A" is finally received (while reading single 8-bit characters), the receiver knows that
    #this means subsequent packets will be packets of 16 characters.  The receiver is now fully
    #synchonized with the transmitter.  If something other than an "A" is received, the receiver should
    #begin looking for a "]" ()meaning "end of message" again.  If the state of "being in mid-message
    #continues 10 times, a human operator should be informed the that this ERROR is occuring.
    #
    #send the message
    txParse(uart,txtToBeSent)       #xyz
    return True
#end def serTx_pico()
def txParse(uartObject, thisMsg, bps=300, msgFormat="SMEPX", T5C=-1, pktSize=16,  eom="]"):    #txParse()
    show("thisMsg",thisMsg)
#
#    uartObject is the uart being used
#    thisMsg is the full text message to be sent (It should not contain (EOM="]") they will become "?")
#                          (An EOM is added as the last character of a message, do not put the EOM in the msg)
#    bps is the baud rate (bits/sec)
#    msgFormat is the form of the Msg e.g. SMEPX  (first E is counted as last char of M)
#                                                (P is enough additional EOMs to pad to packetSize=16)
#                                               (t5c is interval between packets (-1 defaults to t5c)

#    t5c indicates time interval of 5 characters.  The transmitter will follow each packet with
#       this time delay
#    packetSize defaults to 16
#    eom is the definition of the 'EOM" character (usually "]")
    #oP is the full outgoing Packet that is sent by sendThisPack
    #                                      or by sendLastPack
    oP=""            # outgoing msg is initially empty
    if T5C==-1:    # if the calling routine doesn't specify
       t5c=50/bps
       t10c=100/bps
       t1000c=10000/bps
    else:
        t5c=T5C       #if the calling routine does specify T5C
        t10c=T5C*2
        t1000c=T5C*200
    #end if
    if eom=="]":
        som="["
    #end if

#    in 2021 msgOut="SMEPX"
    lenM=len(thisMsg)+1      #length of thisMsg -1  (+1 for the EOM character
    cntUsed=0                # number of characters in msgOut used so far
    cntSent=0                # number of character actually sent (incl all chars sent)
    isEOMsent=False          #EOM not sent yet
    for msgPart in msgFormat:   # do each message segment
        if msgPart=="S":
            # send SOM
            oP=oP+txChar(som)
            oP=oP+txChar("1")      # in future these 2 characters will contain parity or CRC
            oP=oP+txChar("6")      # today they contain the packet size (ie character count)
            cntSent=cntSent+3 #3 actually sent now
        #end if
        if msgPart=="X":     # time delay doesn't send any characters
            utime.sleep(t10c) 
        #end if
        if msgPart=="M":     # sends the msg followed by 1 eom
            isLastPack=True
            while (lenM-cntUsed) >= 1 : #lenM incl the EOM, cntUsed does also (after the EOM is sent)
                isLastPack=False
                #  the packet being sent should not include any EOM characters. (EOM is only in the last pk)
                #  send a packet of data w/o eom
                lastChar=cntUsed+pktSize
                show("lastChar",lastChar)
                thisMsg="12345678901234567"
                show("thisMsg",thisMsg)
                show("cntUsed",cntUsed)
                show("lastChar",lastChar)
                show("thisMsg[cntUsed:lastChar]",thisMsg[cntUsed:lastChar])
                opSent=thisMsg[cntUsed:lastChar]
                show("opSent",opSent)
                cntUsedFromMsg=sendThisPack(uartObject,opSent, eom, pktSize)
                                                        #returns 16  should print the Pkt
                cntUsed=cntUsed+cntUsedFromMsg    # should be 16 ...... to verify
                cntSent=cntSent+16
            #end while                 # the above sent all packets except the last one
                
            if isLastPack==True :       # will send the Last Packet (containing at least 1 EOM)
                #useStr=thisStr
                for x in thisStr:      # must insert correct range !!!!!
                    oP=oP+txChar(x)           # must insert correct char from fullMsg !!!!!
                    cntUsed=cntUsed+1  # ??????     
                    cntSent=cntSent+1
                #end for
                oP=oP+txChar(eom)            # send the first eom

                #cntUsed should be = lenMsg +1 (for the eom)

            #end if
        #end if
        if msgPart=="P":                # P means Padding (with more EOMs) if any needs to be sent
            if False :
                if True:     # to be decided
                    oP=oP+txChar(eom)        # how many eoms of padding  !!!!!
                    cntUsed=cntUsed+1
                    cntSent=cntSent+1
                #end if
                show("cntUsed",cntUsed)
                strSent=thisMsg[cntUsed:cntUsed+16]
                show("strSent:",strSent)
                cntUsedFromMsg = sendLastPack(uartObject, strSent, eom, pktSize) # should print the Pkt
                cntUsed=cntUsed+cntUsedFromMsg
                cntSent=cntSent+pktSize   #pktSize is usually 16
            #end if
        #end if
    #end for    # all msg parts have now been sent
    # should check that cntUsed = len(Msg) +1
    # should check that cntSent is a muliple of pktSize(eg 16)
    return #from parsing and transmitting
#end def
def txChar(char):                                                                       #txChar()        
    #simply records that "char" has been sent
    # just prints it during testing
    # doesn't actually send the char
    print(char, end='') #"end" suppresses the line feed
    return char
#end def

def sendThisPack(uartObject, opIn, eom, pktSize):                        #sendThisPack()
#

#actually sends the 16 characters in oP
    oP=opIn
    lenopIn=len(opIn)
    if (lenopIn==pktSize)==False:
        print("ERROR",pktSize, "is not the size of the packet to send:",lenopIn)
    #end if
    pos=opIn.find(eom)
    if pos==-1:              # -1 if not found
        pass
    else:
        print("WARNING E in serTx", eom, "found in message")
        oP=oP.replace(eom,"?")  
    #end if
    uartObject.write(oP)
    print("tx sent:"+oP+":")    #keep user informed during testing
    return pktSize
#end def

def mpyRead(uart):
    #keep read1 character packet until timeOut
    txtRead=""
    bRead=""
    while uart.any():

        aByte=str(uart.read(1))
        #show("aByte:",aByte)
        bRead=bChar(aByte)
        #show("bRead:",bRead)
        txtRead=txtRead+bRead
    #end while
    return txtRead
#end def

def sendLastPack(uartObject, opIn,  eom = "]", pktSize=16):                           #sendLastPack()   
#actually sends the character packet in oP
# but pads the packet with "eom"s first
    # replace any eom with "?"
    lenopIn=len(opIn)
    oP=opIn
    pos=oP.find(eom)
    if pos==-1:      # Good: eom not found
        pass
    else:
        print("ERROR E in serTx", eom, "found in message")
        oP.replace(eom,"?")  
    #end if
    len=len(oP)
    #pad packet with eoms
    show("lenOp",lenOp)
    for k in range(16,lenOp):
        oPtoSend=oPtoSend+eom    # add eoms for padding
    #end for    
    lenOp=len(oP)       # is the pktSize correct
    if (lenOp==pktSize)==False:
        print("ERROR",pktSize, "is not the size of the packet to send:",lenOp)
    #end if
    #send the 16 character packet
    uartObject.write(oPtoSend)
    print("tx padded (if needed) and sent:"+oP+":")
    return lenOpIn            # return # of chars used.
#end def

#  serRx_pico()   receives  a full serial text message               #serRx_pico()
def serRx_pico(uartObject, bps=600, timeOut=-1, eom="]"):
    #uart = machine.UART(1,bps, parity=None, stop=1, bits=8, rx=Pin(5), tx=Pin(4))
    print("my uart:",uart)
    #print("timeOut is set to:",timeOut)
    if timeOut==-1:
        t100c = 1000/bps
        timeOutUse=int(t100c+1.0)   #at least 1 sec
        #show("timeOutUse:",timeOutUse)
    else:
        timeOutUse=3   #in seconds
    #end if
    #timeOutUse=t100c
    time=utime.time()
    timeNow=time
    #show("timeNow:",timeNow)
    timeFail=timeNow+timeOutUse    # defaults to a 3 second TimeOut
    #print("waiting my:",timeOutUse," seconds for data receipt. . . . .")
    oP=""  # reset input buffer
    #show("time:",time)
    #show("timeFail:",timeFail)

    while time < timeFail :
        #keep reading any 1 character packets until timeOut
        #print("any")
        strA=mpyRead(uart)
        #show("strA:",strA)
        oP=oP+strA
        #show("oP:",oP)
        #end if
        time=utime.time()
    #end while
    #show("oP:",oP)
    lenOp=len(oP)
    if oP=="":
        print("ERROR T in serRx (): timeOut after",timeOutUse,"seconds")
        lenOp=len(oP)
    #end if
    if lenOp > 0:
        if oP.find("?")==-1:
            pass            # ? not found
        else:
            print("WARNING '?' seen in message received.")
        #end if
    #end if
    #print("serRx() received:"+oP+":")   #during testing
    return oP
#end def serRx_pico(uart,300,timeOut(in secs))

def show(strA,parmA):                                        # show
    print(strA,parmA)
    return
#end def

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

progName="testTxB_pico.py"
print("progName:"+progName)
if True:
    bps=600
    txPin=5
    rxPin=4
    #
    #print sys info
    print(os.uname())       #os, utime and machine were imported at top

    #indicate program started visually (by blinking the green LED)
    led_onboard = machine.Pin(25, machine.Pin.OUT)
    led_onboard.value(0)     # onboard LED OFF for 0.5 sec
    utime.sleep(0.5)
    led_onboard.value(1)    # leaving it ON

    #create uart object sample code
    if False :
        #self.uart = UART(1, 115200, parity=None, stop=1, bits=8, rx=Pin(rxPin), tx=Pin(txPin))
        pass
    #end if

    #create actual uart object
    uart = machine.UART(1,bps, parity=None, stop=1, bits=8, rx=Pin(5), tx=Pin(4))
    #print uart info
    #uart = machine.UART(1)
    print(uart)         # during testing


    #                     create uartObject
    #uart = machine.UART(1,bps, parity=None, stop=1, bits=8, tx=txPin, rx=rxPin)
    #    send a single "A"  which is 0x41 ("A"-0x40 * 16 is the packet length which is 16

    #                                         initialization is complete

    uart.write("A")     #every group of messages is preceeded by a single "A"
    # prior to the "A", the transmitter should send a synchronizing sequence to permit
    #               the (human) receiver to "guess" or "determine" the baud rate (the bps)
    # hopefully the operator of the transmitter and receiver is the same human.

    # the serRx_pico should be running in a separate thread.

    #def serTx_pico(uartObject,bps, txtToBeSent="[UUUUUUUU]",rxtxEndChar="]"):
    serTx_pico(uart,bps, txtToBeSent="Hello,Joe")

    if False:
        serTx_pico(uart,bps, txtToBeSent="H")
        serTx_pico(uart,bps, txtToBeSent="H")
        serTx_pico(uart,bps, txtToBeSent="H]")
        serTx_pico(uart,bps, txtToBeSent="[H]")
        serTx_pico(uart,bps, txtToBeSent="2.97")
        serTx_pico(uart,bps, txtToBeSent="99.987654")
        serTx_pico(uart,bps, txtToBeSent="ADC0:(0x4000,1622428309.000j)")
        serTx_pico(uart,bps, txtToBeSent="1234567890123")
        serTx_pico(uart,bps, txtToBeSent="12345678901234")
        serTx_pico(uart,bps, txtToBeSent="Hello,World")
        serTx_pico(uart,bps, txtToBeSent="1234567890123456789012345678901234567890")
    #end if

    if False:
        # the above is the current format of the rxtx protocol
        # The som,eom,t10c and are 1-character special codes
        #    each must be converted into outgoing text or actions or both
        #    all normal text does not need to be converted before transmission
        #
        # The txParse routine analyses the msgOut Format and separates it into
        # special codes (text and actions).  Each special code is sent to the txChar()
        # routine to be processed. Each character of outgoing text is sent to the
        # txChar() routine to be processed.
        #
        # The serTx_pico() routine is used to
        #   transmit a special code of text ("S" and "M")
        #   cause a time delay (V is "t5c X is "t10c  " and M is "t1000c")
        #   transmit msg as 16-byte packets (msg should not contain "]" which is replaced by "?" )
        #
        #   early testing Format is "SMEPX"
        #
        # Note that the "P" also inserts at least 1 "]" character and
        #   enough extra "]" characters (or none) to make a message with an exact multiple
        #   of 16 characters.  This is because there are always 16 characters sent per
        #   packet. Each packet is followed by a time delay of t5c.
        #   The last packet is always followed by a time delay of t10c.
        #   These time delays permit the receiver to resync with the transmitter.
        #   These time delays are never included in the character count of the
        #   message
        #   The serRx_pico() routine times out after an interval of 1000 character times: t1000c
        pass
    #end if

    # This should be run this as a separate thread
    # print whatever has been received
    bps=600
    t100c=1000/bps
    utime.sleep(t100c) #wait for an interval of 100 char times
#end if

#uart = machine.UART(1,bps, parity=None, stop=1, bits=8, tx=Pin(txPin), rx=Pin(rxPin))
bps=600
uart = machine.UART(1,bps, parity=None, stop=1, bits=8, tx=Pin(4), rx=Pin(5))
print("uart:",uart)
if False:
    uart.write("hello")
    t100c=1000/bps
    utime.sleep(t100c) #wait for an interval of 100 char times

    uart.write("Hello,World")
    utime.sleep(t100c) #wait for an interval of 100 char times
    utime.sleep(1)     #1 sec
#if end
if False:
    print("receiving mpy routine")
    while uart.any():
        print(uart.read(1))
    #end while
#end if
charIn=""
if False:
    print("receiving mpy routine")

    if uart.any() :
        #print("reading now")
        charIn=uart.read(1)
        #show("charIn:",charIn)
        #oP=oP+uartObject.read(1)
    #end if
    print("end of mpy routine")
#end if
show("charIn:",charIn)
#end if
print("receiving my routine")
msgIn=serRx_pico(uart,bps=600)   #times out after t100c seconds (100 char-times)
print("msgIn:",msgIn)

print("end of serRX()")

#end /testTxRxC_pico.py


::::::::::textpak=>textpack_py.py.txt
#!/usr/local/bin/python
#by D@CC
#on 7/2/2021  2021GJul02

import sys                           # load the system module
marker = ':'*10 + 'textpak=>'     # hopefully unique separator

def pack(  ):
    for name in sys.argv[1:]:        # for all command-line arguments
        input = open(name, 'r')      # open the next input file
        print marker + name          # write a separator line
        print input.read(  ),        # and write the file's contents
if __name__ == '__main__': pack(  )  # pack files listed on cmdline
#Web Source:https://www.oreilly.com/library/view/programming-python-second/0596000855/ch04s05.html
#end def textpack_py.py
#/textpack_py.py
::::::::::textpak=>tickLed.py.txt
from machine import Pin,Timer

#create class led and class tim
led = Pin(25, Pin.OUT)
tim = Timer()

def tick(timer):
	global led
	led.toggle()

tim.init(freq=2.5, mode=Timer.PERIODIC, callback=tick)

#/tickLed.py   tickLed_py.txt
::::::::::textpak=>tickLed_pi.py.txt
from machine import Pin,Timer

#worked fine on 2021FJun09
#create class led and class tim
led = Pin(25, Pin.OUT)
tim = Timer()

def tick(timer):
	global led
	led.toggle()

tim.init(freq=2.5, mode=Timer.PERIODIC, callback=tick)

#/tickLed.py   tickLed_pi.py
::::::::::textpak=>ws2812_pico.py.txt
def ws2812():
#used in maker-pi-pico-rgb-led_pico()d
#in-line code
    T1 = 2
    T2 = 5
    T3 = 3
    label("bitloop")
    out(x, 1) .side(0) [T3 - 1]
    jmp(not_x, "do_zero") .side(1) [T1 - 1]
    jmp("bitloop") .side(1) [T2 - 1]
    label("do_zero")
    nop() .side(0) [T2 - 1]
#def end
/ws2812.py.txt
