#!/usr/bin/python
import sys
from datetime import datetime
import getopt
usage = """
This is a simple free program to process the output of the
Mighty Ohm geiger counter connected through an FTDI
usb/serial adapter.
See http://www-cs-faculty.stanford.edu/~nick/mrgeiger/
This is free software released under the Apache v2 license
Version 1.0
Nick Parlante
nick.parlante@cs.stanford.edu
Usage:
-i -- *required*
Using the very common FTDI serial chip, the input filenames look like:
/dev/ttyUSB0 on Linux
/dev/cu.usbserial-XXXXXXXX on the Mac
Something like "com1" or "com2" on Windows
-o -- write to named output file
-a -- auto output filename, e.g. 2012.04.01-23.14.12.csv (implies -o)
-e -- echo the raw lines from the geiger counter
-g N -- group into samples of N seconds
Output will be CSV format: seconds, count, cpm, uSv/hr
-t N -- timed stop after N seconds
-u X -- specify X as cpm to uSv/hr conversion factor
Use Ctrl-c to stop if not using -t N to stop after a number
of seconds.
Example:
Group data by 20 seconds, ending at 120 seconds,
write the csv data to afile.csv as well as stdout:
mrgeiger.py -i /dev/cu.usbserial-A9007CPG -g 20 -t 120 -o afile.csv
See the README.txt for more details.
"""
class MrGeiger:
def __init__(self, argv):
if len(argv) == 1:
print usage
sys.exit(1)
optlist, args = getopt.getopt(argv[1:], 'i:o:g:t:u:ae')
opts = dict(optlist)
# Here get string value or None
self.in_fname = opts.get('-i')
if not self.in_fname:
sys.stderr.write('-i required, typically:\n' +
' /dev/cu.usbserial-XXXXXXXX on the Mac\n' +
' /dev/ttyUSB0 on Linux\n' +
' com1 or com2 ... on Windows\n')
sys.exit(1)
# writing to output, and what is the filename
self.out_on = '-a' in opts
self.out_fname = opts.get('-o')
if self.out_fname:
self.out_on = 1
self.outf = None
self.echo = '-e' in opts
# ints: group end group_mode
self.group = int(opts.get('-g', 0))
self.group_mode = self.group > 0
self.end = int(opts.get('-t', 0))
# conversion of cpm to uSv/hr
# 0.0057 is the factor for a SBM-20 tube
self.usv_factor = float(opts.get('-u', 0.0057))
header_csv = 'seconds, count, cpm, uSv/hr\n'
def open_output(self):
"Opens up self.outf as appropriate"
if self.out_on:
suffix = '.geiger'
if self.group_mode:
suffix = '.csv'
if self.out_fname:
outfilename = self.out_fname
else:
outfilename = datetime.now().strftime('%Y.%m.%d-%H.%M.%S') + suffix
self.outf = open(outfilename, 'w')
def print_both_data(self, seconds, count):
"Prints one csv data line to output and stdout as appropriate."
cpm = count * 60.0 / self.group
s = '%d, %d, %g, %g\n' % (seconds, count, cpm, self.usv_factor * cpm)
self.print_both(s)
def print_both(self, s):
"Prints to file output and stdout as appropriate."
if self.outf:
self.outf.write(s)
sys.stdout.write(s)
def readloop(self):
"Read from device, gathering stats, writing output to file and stdout."
count_inner = 0
seconds_inner = 0
count_total = 0
seconds_total = 0
self.open_output() # sets self.outf for writing
inf = open(self.in_fname, 'rU')
if self.group_mode:
self.print_both(self.header_csv)
while True:
try:
line = inf.readline()
if line == '': break
if line == '\n': continue
# like this:
# CPS, 1, CPM, 22, uSv/hr, 0.12, SLOW
parts = line.split(',')
# This catches obvious serial garbled data, and if it's not in SLOW mode.
# Skip the garbled line.
# The second line read is all garbled for some reason on the mac.
if len(parts) != 7 or not 'SLOW' in parts[6]:
sys.stderr.write('ERROR line ignored:' + line + '\n')
continue
if self.group_mode:
if self.echo:
sys.stdout.write(line)
# accumulate to the "inner" vars
count_inner += int(parts[1])
seconds_inner += 1
if seconds_inner == self.group:
count_total += count_inner
seconds_total += seconds_inner
self.print_both_data(seconds_total, count_inner)
count_inner = 0
seconds_inner = 0
else:
count_total += int(parts[1])
seconds_total += 1
self.print_both(line)
if self.end and seconds_total >= self.end:
break
except KeyboardInterrupt:
print
break
# print summary to stdout, but not to the output file.
cpm = count_total * 60.0 / seconds_total
print 'total seconds:%d count:%d cpm:%g uSv/hr:%g' % (seconds_total, count_total,
cpm, self.usv_factor * cpm)
def main():
geiger = MrGeiger(sys.argv)
geiger.readloop()
if __name__ == '__main__':
main()