[Tutor] newbie bragging about code
Eur van Andel
eur at fiwihex.nl
Wed Nov 12 19:05:39 EST 2003
Hi
I sent the prog hereunder to my father with comments. Maybe these comments will
help others or draw better comments.
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
More information about the Tutor
mailing list