[Tutor] newbie bragging about code
Bob Gailer
bgailer at alum.rpi.edu
Thu Nov 13 15:42:47 EST 2003
At 05:05 PM 11/12/2003, Eur van Andel wrote:
>Hi
>
>I sent the prog hereunder to my father with comments. Maybe these comments
>will
>help others or draw better comments.
I notice you are not using classes, and that's OK. I will show one way to
use classes in the hopes of giving you a "leg up" on OOP.
One indication of a need for classes is when you are doing the same thing
twice (creating files in this case). Consider:
class File:
def __init__(self, kind):
self.fileName = strftime("%d-%m-%Y_%H-%M." + kind, localtime())
self.file = file(self.fileName, 'w')
def write(self.txt):
self.file.write(txt)
# everything that's common to the 2 file types is encapsulated in one class
definition. Then you proceed to create 2 instances of File, each dedicated
to a unique purpose:
...
logfile = File('log')
logfile.write('temperatures and pump duty cycles\n')
logfile.write('from six fans and pump controller\n')
if raw_output:
rawfile = File('raw')
I factored out the initial writing to the log file to keep the class
definition simple.
There are numerous other options here, including creating subclasses for
the 2 types, and using __call__ instead of write (in which case you'd write
to the file thus: logfile('temperatures and pump duty cycles\n')
>The program sends data to and from a string of PIC microcontrollers that
>measure 4 temperatures of a water to air heat exchanger. These messages leave
>the PC as hex strings like ;0123FAFAFAFACC where ; is the delimiter, 01 the
>address, 23 the command, FA the four data bytes and CC the checksum. They get
>cnverted by a PIC converter board to pulse duration code msgs on a two signal
>wire bus with hardware node costs of $2 (two RJ 6/6 amp connectors and
>74HC14).
>The bus carries power too. I need to connect several 1000's of these later.
>
>The PIC controllers (16F819) have a bootloader that allows reprogramming
>of the
>application program in flash memory. The program hereunder deals just with
>receiving and sending temperatures.
>
>
>Output first:
>
> >/home/eur # cd xwisp/
> >/home/eur/xwisp # python almeria4.py
> >Run
>all PICs run (from bootloader to app)
>
> >1 0x4E4D4E4E 2 0x4B464A49 3 0x4C4D4F4E 4 0x4C4A4B4C
> >5 0x53534F53 6 0x4B4D544F 7 0x53515152 8 0x4F4E4E54
>raw-output, nice debugging. Only data in recvd msgs shown
>
> >
> >1 15.6 15.4 15.6 15.6 2 15.0 14.0 14.8 14.6 3 15.2 15.4 15.8 15.6
> >4 15.2 14.8 15.0 15.2 5 16.6 16.6 15.8 16.6 6 15.0 15.4 16.8 15.8
> >7 16.6 16.2 16.2 16.4 8 15.8 15.6 15.6 16.8 15.6 15.4 15.7 15.7
>8 PICs with board number and 4 temps each. last four are average temps
>that get
>send to first PIC (which has no sensors, it controls the water flow)
>
> >
> >
> >1 0x4E4D4E4E 2 0x4B464A49 3 0x4C4D4F4E 4 0x4C4A4B4C
> >5 0x52535053 6 0x4B4D544F 7 0x53515152 8 0x4F4E4E54
> >
> >1 15.6 15.4 15.6 15.6 2 15.0 14.0 14.8 14.6 3 15.2 15.4 15.8 15.6
> >4 15.2 14.8 15.0 15.2 5 16.4 16.6 16.0 16.6 6 15.0 15.4 16.8 15.8
> >7 16.6 16.2 16.2 16.4 8 15.8 15.6 15.6 16.8 15.6 15.4 15.8 15.7
>Quite cold in here. Netherlands in winter, Pythoneer to cheap to turn on
>heating after office hours.
> >
> >
> >1 0x4D4D4E4E 2 0x4B464A4A 3 0x4C4D4F4E 4 0x4C4A4B4C
> >5 0x52534E53 6 0x4C4D544F 7 0x53515151 8 0x4E4D4D54
> >
> >1 15.4 15.4 15.6 15.6 2 15.0 14.0 14.8 14.8 3 15.2 15.4 15.8 15.6
> >4 15.2 14.8 15.0 15.2 5 16.4 16.6 15.6 16.6 6 15.2 15.4 16.8 15.8
> >7 16.6 16.2 16.2 16.2 8 15.6 15.4 15.4 16.8 15.6 15.4 15.7 15.7
> >
>
>
>Code follows, inline bragging after that:
>
>
>
>####################################################################
>#
># program almeria3.py
># makes logfile
># polls boards for temperatures
># writes temperatures to screen
># records temperatures in logfile
># makes new logfile every midnight
># can output raw packets
>#
># to do: config file, separate data routine for msgs
># fault-tolerant: no output (or the lack of output)
># may NOT crash the program
># re-boot boards if necessary
># send average temps to pump board
>#
>###################################################################
>
>from time import strftime, localtime, sleep
>import random, fpformat
>import sys
>from xwisp_fwx3 import fwx
>import string
>
>def make_logfile():
> logfile = open(strftime("%d-%m-%Y_%H-%M.log", localtime()),'w')
> #logfile = open(strftime("%d_%H%M.log", localtime()),'w') # MSDOS
> logfile.write('temperatures and pump duty cycles\n')
> logfile.write('from six fans and pump controller\n')
> return(logfile)
>
>def make_rawfile():
> rawfile = open(strftime("%d-%m-%Y_%H-%M.raw", localtime()),'w')
> #logfile = open(strftime("%d_%H%M.log", localtime()),'w') # MSDOS
> logfile.write('raw msgs from fwx boards\n')
> return(rawfile)
>
>def data_send_X(B3,B2,B1, B0): # makes integer that is a 8-char in hex
> data = '%02X' % B3 + '%02X' % B2 + '%02X' % B1 + '%02X' % B0
> data = long(data, 16)
> #print '%08X' % data
> return data
>
>
>def send_temps_to_pumpcontr(Tai, Tao, Twl, Twh):
> Response = f.Send_Receive(75, data_send_X(Tai*5, Tao*5, Twl*5, Twh*5),
> 1) #
>pump_controller has address 1
> #print Response
>
>############################ START OF PROGRAM #######################
>
>
>number_of_boards = 8 # should be in config file
>raw_output = True
>
>T = [ [None] * 5 for i in range(1,number_of_boards+2) ] # array of
>[0..num][0..4]
>
>f = fwx( '/dev/cuaa0' )
>Errors = 0
>f.CMD_RUN()
>
>date = localtime()[2]
>
>logfile = make_logfile()
>if raw_output:
> rawfile = make_rawfile()
>
>
># $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ START OF MAIN LOOP $$$$$$$$$$$$$$
>
>while True:
> minutes, seconds = localtime()[4], localtime()[5]
>
> if date != localtime()[2]: # a new day has dawned, open a new logfile
> logfile = make_logfile()
> date = localtime()[2]
>
> if minutes % 1 == 0:
> if seconds % 10 == 0:
> if raw_output:
> rawfile.write(strftime('"%d-%m-%Y %H:%M:%S" ', localtime()))
>
> for n in range(1, number_of_boards + 1):
> Response = f.Send_Receive(33, Address = n)
> if Response == None:
> if raw_output:
> print '%1d None ' % n,
> rawfile.write('%1d None ')
> if n % 4 == 0: # after 4 raw packets
> print '\n',
> Response = 825307441L
> else:
> if raw_output:
> print '%1d 0x%08X' % (n,Response),
> rawfile.write('%1d 0x%08X ' % (n, Response))
> if n % 4 == 0: # after 4 raw packets
> print '\n',
>
> D = '%08X' % Response
> T[n][1] = int(D[0:2],16)/5.0 # T air in
> T[n][2] = int(D[2:4],16)/5.0 # T air out
> T[n][3] = int(D[4:6],16)/5.0 # T water high
> T[n][4] = int(D[6:8],16)/5.0 # T water low
> # end of looping over boards
>
> if raw_output:
> print '\n',
> rawfile.write('\n')
>
> logfile.write(strftime('"%d-%m-%Y %H:%M:%S" ', localtime()))
> Tai = Tao = Twl = Twh = 0
> print Tai, Tao, Twl, Twh
> for n in range(1, number_of_boards+1):
> print '%1d' % n,
> logfile.write('%1d' % n)
> if n > 1 and n < number_of_boards: # 1 = pump, last= control
> group
> Tai = Tai + T[n][1]
> Tao = Tao + T[n][2]
> Twl = Twl + T[n][3]
> Twh = Twh + T[n][4]
>
> for i in range(1,5):
> print '%4.1f' % T[n][i],
> logfile.write('%4.1f' % T[n][i])
> if n % 3 == 0: # after three temperature quads
> print '\n',
>
> Tai = Tai / (number_of_boards - 2) # 1 pump board, 1 control group
>board
> Tao = Tao / (number_of_boards - 2)
> Twl = Twl / (number_of_boards - 2)
> Twh = Twh / (number_of_boards - 2)
>
> print '%4.1f %4.1f %4.1f %4.1f' % (Tai, Tao, Twl, Twh)
>
> print '\n'
>
> logfile.write('\n')
> logfile.flush()
>
> send_temps_to_pumpcontr(Tai, Tao, Twl, Twh)
>
> sleep(2)
># if seconds < 55:
># sleep(55 - seconds)
>
>
>
>
>
>
>
> >####################################################################
> >#
> ># program almeria3.py
> ># makes logfile
> ># polls boards for temperatures
> ># writes temperatures to screen
> ># records temperatures in logfile
> ># makes new logfile every midnight
> ># can output raw packets
> >#
> ># to do: config file, separate data routine for msgs
>needs work
>
> ># fault-tolerant: no output (or the lack of output)
> ># may NOT crash the program
>works.
>
> ># re-boot boards if necessary
>needs work
>
> ># send average temps to pump board
>works
>
> >#
> >###################################################################
> >
> >from time import strftime, localtime, sleep
> >import random, fpformat
> >import sys
>several libs, but I'll have to check if still needed
>
> >from xwisp_fwx3 import fwx
>wouter's msg routines
>
> >import string
> >
> >def make_logfile():
>def: define function
>(): no arguments
>
> > logfile = open(strftime("%d-%m-%Y_%H-%M.log", localtime()),'w')
>12-11-2003_23-59.log, open for writing, the 'w'
>
>
> > #logfile = open(strftime("%d_%H%M.log", localtime()),'w') # MSDOS
> > logfile.write('temperatures and pump duty cycles\n')
> > logfile.write('from six fans and pump controller\n')
> > return(logfile)
>so function returns logfile object. Call function with
>
>logfile = make_logfile()
>
>after that, you can do things like:
>
>logfile.close()
>logfile.flush()
>
>
> >
> >def make_rawfile():
> > rawfile = open(strftime("%d-%m-%Y_%H-%M.raw", localtime()),'w')
> > #logfile = open(strftime("%d_%H%M.log", localtime()),'w') # MSDOS
>12_23-59.log, 8-char MSDOS compatible file name. This code snippet was
>developed under DOS.
>
> > logfile.write('raw msgs from fwx boards\n')
> > return(rawfile)
> >
> >def data_send_X(B3,B2,B1, B0): # makes integer that is a 8-char
> in hex
> > data = '%02X' % B3 + '%02X' % B2 + '%02X' % B1 + '%02X' % B0
>
>'02X' % 255 means: write 255 as hexadecimal (X) string ('..'), two chars wide
>(2) with leading zeroes (0). Yes, Python is powerful. I took 3 days to
>understand this.
>
> > data = long(data, 16)
> > #print '%08X' % data
>debugging :-)
>
> > return data
>as 8-char hex string from 4 integers. If integers are 199498535 or other
>useless number >255, hex string will always be 8 char wide. Very robust.
>
> >
> >
> >def send_temps_to_pumpcontr(Tai, Tao, Twl, Twh):
> > Response = f.Send_Receive(75, data_send_X(Tai*5, Tao*5, Twl*5,
> Twh*5), 1) # pump_controller has address 1
> > #print Response
>remember: internal byte representation of temps in PIC is degree celsius * 5
>
>75 is bad: needs to be replaced by cmd_set_av_temps constant.
>
> >
> >############################ START OF PROGRAM #######################
> >
> >
> >number_of_boards = 8 # should be in config file
>indeed.
>
> >raw_output = True
>idem, in config file
>
> >
> >T = [ [None] * 5 for i in range(1,number_of_boards+2) ] # array of
> [0..num][0..4]
>clumsy array of stupid newbie that wants arrays like T[1..n][1..4] instead of
>Python way T[0..n-1][0..3]. Array should be replaced with nice set of fourfold
>tuples.
>
> >
> >f = fwx( '/dev/cuaa0' )
>FreeBSD serial port 1
>
> >Errors = 0
> >f.CMD_RUN()
>run boards
> >
> >date = localtime()[2]
> >
> >logfile = make_logfile()
> >if raw_output:
> > rawfile = make_rawfile()
> >
> >
> ># $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ START OF MAIN LOOP $$$$$$$$$$$$$$
> >
> >while True:
> > minutes, seconds = localtime()[4], localtime()[5]
>powerful Python tuple (data set) value setting.
>
>a,b,c,d = 1,2,3,4
>
>is normal Python. Typically T = [a,b,c,d] should be used
>
> >
> > if date != localtime()[2]: # a new day has dawned, open a new logfile
> > logfile = make_logfile()
> > date = localtime()[2]
> >
> > if minutes % 1 == 0:
> > if seconds % 10 == 0:
>for fast response
>
>Note that Python has no begin...end, only indentation. One space off and the
>compilers hurls abuse at you, rightly so. Even one tab and 8 spaces on
>different lines are not accepted. ":" is "then"
>
> > if raw_output:
> > rawfile.write(strftime('"%d-%m-%Y %H:%M:%S" ', localtime()))
>Writing time to raw log, to match the raw packets later to the
>temperatures.
>
> >
> > for n in range(1, number_of_boards + 1):
>stupid newbie counting from 1 to n. Python way is
>
>for n in range(number_of_boards)
>
>n will be 0...8
>
> > Response = f.Send_Receive(33, Address = n)
>get 4 temperatures
>
> > if Response == None:
> > if raw_output:
> > print '%1d None ' % n,
> > rawfile.write('%1d None ')
> > if n % 4 == 0: # after 4 raw packets
> > print '\n',
> > Response = 825307441L
>is 0x31313131 is 49 49 49 49 is 4 times 9.8*5
>which will thoroughly confuse pump_controller. Bad.
>
> > else:
> > if raw_output:
> > print '%1d 0x%08X' % (n,Response),
>print n as 1 digit integer, Response as 0xXXXXXXXX 8-digit hex number
>trailing comma means no newline after print
>
>print '\n'
>
>with no trailing comma means TWO newlines
>
> > rawfile.write('%1d 0x%08X ' % (n, Response))
>note middle and trailing space in format string: chunk.write() will not spaced
>numbers like print does
>
> > if n % 4 == 0: # after 4 raw packets
> > print '\n',
>to the screen, not to the file
> >
> > D = '%08X' % Response
>D now 8 (hex) char long string
>
> > T[n][1] = int(D[0:2],16)/5.0 # T air in
>T[n][1] is integer of first two chars of string, with base number 16, divided
>by 5. 5.0 is written so Python will understand T[n][1] is a float
>
> > T[n][2] = int(D[2:4],16)/5.0 # T air out
> > T[n][3] = int(D[4:6],16)/5.0 # T water high
> > T[n][4] = int(D[6:8],16)/5.0 # T water low
> > # end of looping over boards
> >
> > if raw_output:
> > print '\n',
> > rawfile.write('\n')
>Now a newline to the raw file
>
> >
> > logfile.write(strftime('"%d-%m-%Y %H:%M:%S" ', localtime()))
> > Tai = Tao = Twl = Twh = 0
>resetting the values for averaging
>
> > print Tai, Tao, Twl, Twh
>debugging
>
> > for n in range(1, number_of_boards+1):
>clueless newbie loops again over boards, sigh
>
> > print '%1d' % n,
> > logfile.write('%1d' % n)
>
> > if n > 1 and n < number_of_boards: # 1 = pump, last=
> control group
>first board is pump_contr, last board is control_group, both should not be
>used
>for calculating average
>
> > Tai = Tai + T[n][1]
> > Tao = Tao + T[n][2]
> > Twl = Twl + T[n][3]
> > Twh = Twh + T[n][4]
>Real Pythoneers would combine these statements:
>
> T[n][1] = int(D[0:2],16)/5.0 # T air in
> Tai = Tai + T[n][1]
>
>to
>
> Tai = Tai + T[n][1] = int(D[0:2],16)/5.0 # T air in
>
>in a single loop
> >
> > for i in range(1,5):
> > print '%4.1f' % T[n][i],
> > logfile.write('%4.1f' % T[n][i])
>no space, bad
>
> > if n % 3 == 0: # after three temperature quads
> > print '\n',
>print board number and temperatures in line of three
> >
> > Tai = Tai / (number_of_boards - 2) # 1 pump board, 1 control
> group board
> > Tao = Tao / (number_of_boards - 2)
> > Twl = Twl / (number_of_boards - 2)
> > Twh = Twh / (number_of_boards - 2)
>averaging
> >
> > print '%4.1f %4.1f %4.1f %4.1f' % (Tai, Tao, Twl, Twh)
>debugging
> >
> > print '\n'
> >
> > logfile.write('\n')
> > logfile.flush()
>flush data stream to logfile so no data loss when power failure
> >
> > send_temps_to_pumpcontr(Tai, Tao, Twl, Twh)
>ha! This took me a full day to get this single statement working!
>
> >
> > sleep(2)
>so not 6 times in the same second. Yes, Python is that fast.
>
> ># if seconds < 55:
> ># sleep(55 - seconds)
>To minimize system load?
>
>
>--
>Ir. E.E. van Andel, Fine Wire Heat Exchangers, Fiwihex B.V. www.fiwihex.com
>Wierdensestraat 74, NL-7604 BK Almelo, The Netherlands eur at fiwihex.nl
>phone +31-546-491106 fax +31-546-491107 mobile +31-653-286573
>
>_______________________________________________
>Tutor maillist - Tutor at python.org
>http://mail.python.org/mailman/listinfo/tutor
>
>
>
>---
>Incoming mail is certified Virus Free.
>Checked by AVG anti-virus system (http://www.grisoft.com).
>Version: 6.0.538 / Virus Database: 333 - Release Date: 11/10/2003
Bob Gailer
bgailer at alum.rpi.edu
303 442 2625
-------------- next part --------------
---
Outgoing mail is certified Virus Free.
Checked by AVG anti-virus system (http://www.grisoft.com).
Version: 6.0.538 / Virus Database: 333 - Release Date: 11/10/2003
More information about the Tutor
mailing list