223 lines
7.5 KiB
Python
223 lines
7.5 KiB
Python
# Sample script showing how to loop through the Roster entries and export
|
|
# specific information to a .csv file.
|
|
#
|
|
# Now includes a simple FileChooser, information message dialogs and
|
|
# output of specific CV values
|
|
#
|
|
# Inspired by Bob Jacobsen's 'RosterLoop' and 'CsvToTurnouts'
|
|
#
|
|
# Note: this will replace any existing file
|
|
#
|
|
# Author: Matthew Harris, copyright 2010, 2016
|
|
# Part of the JMRI distribution
|
|
|
|
import jmri
|
|
import jmri.jmrit.roster
|
|
import org.apache.commons.csv
|
|
from javax.swing import JFileChooser, JOptionPane
|
|
from jmri.jmrit.symbolicprog import CvTableModel
|
|
import java
|
|
import java.awt
|
|
import java.io
|
|
|
|
# Define some default values
|
|
|
|
# Default filename - located in the same location as the Roster itself
|
|
# The script does show a pop-up 'Save As' dialog allowing this to be
|
|
# changed when executed
|
|
outFile = jmri.jmrit.roster.Roster.getDefault().getRosterLocation()+"roster.csv"
|
|
print "Default output file:", outFile
|
|
|
|
# Determine if to output the header or not
|
|
# Set to 'True' if required; 'False' if not
|
|
outputHeader = True
|
|
|
|
# Define functions for later use
|
|
|
|
# Write the header
|
|
# Make sure that the headers match the detail!!
|
|
def writeHeader(csvFile):
|
|
# Write the header line
|
|
# Entries from the Basic roster entry
|
|
csvFile.print("RosterID")
|
|
csvFile.print("RoadName")
|
|
csvFile.print("RoadNumber")
|
|
csvFile.print("Manufacturer")
|
|
csvFile.print("Owner")
|
|
csvFile.print("Model")
|
|
csvFile.print("Address")
|
|
csvFile.print("Is Long?")
|
|
csvFile.print("Speed Limit")
|
|
csvFile.print("Comment")
|
|
csvFile.print("Decoder Family")
|
|
csvFile.print("Decoder Model")
|
|
csvFile.print("Decoder Comment")
|
|
|
|
# Function labels
|
|
for func in range(0,28+1):
|
|
csvFile.print("Fn%02d" % func)
|
|
|
|
# Now add some CV values
|
|
csvFile.print("CV19")
|
|
csvFile.print("CV7")
|
|
csvFile.print("CV8")
|
|
|
|
# Lastly, add some single bits from CV29
|
|
csvFile.print("Speed Steps (CV29.1)")
|
|
csvFile.print("DC mode (CV29.2)")
|
|
|
|
# Notify the writer of the end of the header record
|
|
csvFile.println();
|
|
print "Header written"
|
|
|
|
# Write the value of the specified CV in the specified format
|
|
# If the CV doesn't exist, a blank is written
|
|
def writeCvValue(cvValue, format):
|
|
if cvValue != None:
|
|
return format % cvValue.getValue()
|
|
else:
|
|
return ""
|
|
|
|
# Write the details of each roster entry
|
|
# Make sure that the details match the header!!
|
|
def writeDetails(csvFile):
|
|
# Get a list of matched roster entries;
|
|
# the list of None's means match everything
|
|
rosterlist = jmri.jmrit.roster.Roster.getDefault().matchingList(None, None, None, None, None, None, None)
|
|
|
|
# now loop through the matched entries, outputing things
|
|
for entry in rosterlist.toArray() :
|
|
# Most parameters are text-based, so can be output directly
|
|
csvFile.print(entry.getId())
|
|
csvFile.print(entry.getRoadName())
|
|
csvFile.print(entry.getRoadNumber())
|
|
csvFile.print(entry.getMfg())
|
|
csvFile.print(entry.getOwner())
|
|
csvFile.print(entry.getModel())
|
|
csvFile.print(entry.getDccAddress())
|
|
|
|
# 'isLongAddress' is a boolean function so we need
|
|
# to deal with outputting that in this way
|
|
if entry.longAddress:
|
|
csvFile.print("Yes")
|
|
else:
|
|
csvFile.print("No")
|
|
|
|
# Max Speed is a number - we need to convert to a string
|
|
csvFile.print("%d%%" % entry.getMaxSpeedPCT())
|
|
|
|
csvFile.print(entry.getComment())
|
|
csvFile.print(entry.getDecoderFamily())
|
|
csvFile.print(entry.getDecoderModel())
|
|
csvFile.print(entry.getDecoderComment())
|
|
|
|
# Now output function labels
|
|
for func in range(0,28+1):
|
|
csvFile.print(entry.getFunctionLabel(func))
|
|
|
|
# Finally, we deal with reading in the CV values and
|
|
# outputing those we're interested in
|
|
|
|
# First we need to create and populate the CV tables - remember
|
|
# to call the readFile method before trying to populate the CV tables
|
|
cvTable = CvTableModel(None, None)
|
|
entry.readFile()
|
|
entry.loadCvModel(None, cvTable) # no variables, just load CVs
|
|
|
|
# Now we can grab the CV values we're interested in
|
|
# Bear in mind that these need to be converted from
|
|
# integers into strings so we use the 'writeCvValue'
|
|
# function defined earlier.
|
|
# These examples are all in decimal - if you require
|
|
# hex, change "%d" to "0x%x" or "0x%X"
|
|
csvFile.print(writeCvValue(cvTable.getCvByNumber("19"), "%d"))
|
|
csvFile.print(writeCvValue(cvTable.getCvByNumber("7"), "%d"))
|
|
csvFile.print(writeCvValue(cvTable.getCvByNumber("8"), "%d"))
|
|
|
|
# Lastly, we deal with examining specific bits of CV29.
|
|
#
|
|
# First, we read CV29 and store it temporarily as we will then use
|
|
# bitwise comparisons later.
|
|
#
|
|
# For the bitwise comparisons, use the following pattern to read the
|
|
# individual bits:
|
|
#
|
|
# if (cv29Value & {value}) == {value}:
|
|
# csvFile.print("bit set")
|
|
# else:
|
|
# csvFile.print("bit clear")
|
|
#
|
|
# where {value} is one of the following:
|
|
#
|
|
# Pos Bit Value
|
|
# 1st 0 1
|
|
# 2nd 1 2
|
|
# 3rd 2 4
|
|
# 4th 3 8
|
|
# 5th 4 16
|
|
# 6th 5 32
|
|
# 7th 6 64
|
|
# 8th 7 128
|
|
|
|
# OK, read the value of CV29
|
|
cv29Value = 0;
|
|
if cvTable.getCvByNumber("29") != None:
|
|
cv29Value = cvTable.getCvByNumber("29").getValue()
|
|
else:
|
|
print "Did not find a CV29 value, using zero"
|
|
|
|
# Now do the bitwise comparisons.
|
|
# First example is speedsteps, which is the second bit
|
|
if (cv29Value & 2) == 2:
|
|
csvFile.print("28/128 Steps")
|
|
else:
|
|
csvFile.print("14 Steps")
|
|
|
|
# Second example is DC mode, which is the third bit
|
|
if (cv29Value & 4) == 4:
|
|
csvFile.print("On")
|
|
else:
|
|
csvFile.print("Off")
|
|
|
|
# Notify the writer of the end of this detail record
|
|
csvFile.println()
|
|
csvFile.flush()
|
|
print "Entry", entry.getId(), "written"
|
|
|
|
# Now do the actual work here
|
|
|
|
# Create output file.
|
|
# Unless modified here, this will create the output file in the same
|
|
# location as the roster itself.
|
|
# Default behaviour is for this to be in the user preferences directory
|
|
fc = JFileChooser()
|
|
fc.setSelectedFile(java.io.File(outFile))
|
|
if (java.awt.GraphicsEnvironment.isHeadless()) :
|
|
ret = JFileChooser.APPROVE_OPTION
|
|
else :
|
|
ret = fc.showSaveDialog(None)
|
|
|
|
if ret == JFileChooser.APPROVE_OPTION:
|
|
# We've got a valid filename
|
|
outFile = fc.getSelectedFile().toString()
|
|
print "Output file:", outFile
|
|
csvFile = org.apache.commons.csv.CSVPrinter(java.io.BufferedWriter(java.io.FileWriter(outFile)),org.apache.commons.csv.CSVFormat.DEFAULT)
|
|
|
|
# Output the header if required
|
|
if outputHeader==True:
|
|
writeHeader(csvFile)
|
|
|
|
# Output details
|
|
writeDetails(csvFile)
|
|
|
|
# Flush the write buffer and close the file
|
|
csvFile.flush()
|
|
csvFile.close()
|
|
print "Export complete"
|
|
if (not java.awt.GraphicsEnvironment.isHeadless()) :
|
|
JOptionPane.showMessageDialog(None,"Roster export completed","Roster export",JOptionPane.INFORMATION_MESSAGE)
|
|
else:
|
|
print "No export"
|
|
if (not java.awt.GraphicsEnvironment.isHeadless()) :
|
|
JOptionPane.showMessageDialog(None,"Roster not exported","Roster export",JOptionPane.INFORMATION_MESSAGE)
|