1
2
3 __version__ = '$Revision: 5231 $'.split()[1]
4 __date__ = '$Date: 2006-12-20 08:54:50 -0500 (Wed, 20 Dec 2006) $'.split()[1]
5 __author__ = 'Kurt Schwehr'
6
7 __doc__='''
8 Create a basic field for an ais message
9
10 Here is one of the simplest possible examples of an integer that goes
11 from 0 to 255:
12
13 FIX: how do I do epydoc indented text?
14
15 ./aisfield.py -n MyName -t uint -d "My unsigned integer field"
16
17 <field name="MyName" numberofbits="8" type="uint">
18 <description>My unsigned integer field</description>
19 </field>
20
21
22
23 @author: U{'''+__author__+'''<http://xenon.stanford.edu/~schwehr/>}
24 @version: ''' + __version__ +'''
25 @copyright: 2006
26 @var __date__: Date of last svn commit
27 @undocumented: __version__ __author__ __doc__ myparser
28 @since: 2006-Sep-21
29 @status: under development
30 @organization: U{CCOM<http://ccom.unh.edu/>}
31 @license: GPL
32 '''
33
34 import sys
35
36
37
38
39
40 typeBitsGuess = { 'bool':1,
41 'uint':8, 'sint':8,
42 'udecimal':8, 'sdecimal':8,
43 'float':32, 'double':64,
44 'aisstr6':6, 'ascii7':7,
45 }
46 '''
47 Best initial guess for each type size. The floating point and
48 string values must be these sizes.
49 '''
50
51 typeChoices = ['bool','uint','sint','udecimal','sdecimal','float','double','aisstr6','ascii7']
52 '''
53 List of all the available types that may be used to fill an AIS message.
54 '''
55
56
57 numberTypes = ['uint','sint','udecimal','sdecimal','float','double']
58 '''
59 Subset of typeChoices that only has the numeric types
60 '''
61
62
63 -def tag(outfile,tagName,value,indent=''):
64 '''
65 Write out one complete tag
66 @param outfile: open file to write to
67 @param tagName: string containing the xml tag
68 @param value: what to put between the begin and end tag. Converts to a string
69 @param indent: how much to indent the tag
70 '''
71 outfile.write(indent+'<'+tagName+'>'+str(value)+'</'+tagName+'>\n')
72
73
75 '''
76 Convenience for thos that just want to tweak one or two things
77 @return: example dictionary that can then be added to.
78 '''
79
80 return {'maxRange': None, 'outputFile': None, 'lut': None,
81 'description': None, 'notes': None, 'required': None,
82 'minRange': None, 'numberOfBits': 1, 'units': None,
83 'scale': None, 'arrayLength': None, 'completeXml': False,
84 'decimalPlaces': None, 'unavailable': None,
85 'type': 'bool', 'name': None}
86
87
89 '''
90 Write out one field of xml. Here is a sample options dict
91
92 {'maxRange': None, 'outputFile': None, 'lut': None, 'description': None, 'notes': None, 'required': None, 'minRange': None, 'numberOfBits': 1, 'units': None, 'scale': None, 'arrayLength': None, 'completeXml': False, 'decimalPlaces': None, 'unavailable': None, 'type': 'bool', 'name': None}
93
94 @param options: dict of all the required fields
95
96 '''
97 o = options
98
99
100 if o.completeXml:
101 out.write('<?xml version="1.0" encoding="utf-8"?>\n')
102 out.write('<ais-binary-messages version="1.0">\n')
103 out.write('<!-- FIX: add date -->\n')
104 out.write('<!-- FIX: add user -->\n')
105 out.write('<!-- Produced by aisfield.py -->\n')
106 out.write('<!-- Options: '+str(options)+' -->\n')
107
108 indent='\t'
109 out.write(indent+'<field name="'+o.name+'" ')
110 if options.arrayLength: out.write('arraylength="'+str(o.arrayLength)+'" ')
111 out.write('numberofbits="'+str(o.numberOfBits)+'" type="'+o.type+'">\n')
112
113 if True:
114 indent+='\t'
115
116 out.write(indent+'<description>'+o.description+'</description>\n')
117 if o.notes:
118 for note in o.notes:
119 out.write(indent+'<note>'+note+'</note>\n')
120
121 if o.minRange: out.write(indent+'<range min="'+str(o.minRange)+'" max="'+str(o.maxRange)+'">\n')
122 if o.unavailable: tag(out,'unavailable',o.unavailable,indent)
123 if o.scale: tag(out,'scale',o.scale,indent)
124
125 if o.decimalPlaces: tag(out,'decimalplaces',o.decimalPlaces,indent)
126 if o.units: tag(out,'units',o.units,indent)
127
128 if o.required: tag(out,'required',o.required,indent)
129
130 if o.lut:
131 out.write(indent+'<lookuptable>\n')
132 indent += '\t'
133
134 for i in range(len(o.lut)):
135 out.write(indent+'<entry key="'+str(i)+'">'+str(o.lut[i])+'</entry>\n')
136 indent=indent[:-1]
137 out.write(indent+'</lookuptable>\n')
138
139 indent=indent[:-1]
140
141 out.write(indent+'</field>\n')
142
143 if o.completeXml:
144 out.write('</ais-binary-messages>\n')
145
146 return
147
148
150 '''
151 Check all of the options to make sure they work
152 @param options: dict with all option fields
153 @param notify: if true, emit error messages to stdout
154 @return: True if options all ok
155 '''
156 o = options
157 ok=True
158 if not o.name:
159 ok=False
160 if notify: print 'Must specify the "name" of the variable'
161
162
163 if o.arrayLength and o.arrayLength<2:
164 ok=False
165 if notify: print 'Array length must be 2 or more'
166
167 if (not o.numberOfBits) or (o.numberOfBits<1) or (o.numberOfBits>64):
168 ok=False
169 if notify: print 'Invalid number of bits:',o.numberOfBits
170
171 if not o.description:
172 ok=False
173 if notify: print 'Must give a description'
174
175 if o.unavailable and (o.type in numberTypes):
176 try:
177 float(o.unavailable)
178 except ValueError:
179 ok=False
180 if notify: print 'unavailable must be an number'
181
182
183 if o.scale:
184 try:
185 float(o.scale)
186 except ValueError:
187 ok=False
188 if notify: print 'Scale must be an number'
189
190 if o.lut and (o.type not in ['bool','uint']):
191 ok=False
192 if notify: print 'Lookup tables must be an unsigned integer'
193
194
195
196 return ok
197
198
199
200
201 if __name__=='__main__':
202 from optparse import OptionParser
203 myparser = OptionParser(usage="%prog [options]",
204 version="%prog "+__version__)
205
206
207 myparser.add_option('-o','--output',dest='outputFile',default=None,
208 help='Name of the xml file to write. Opens for appending [default: stdout]')
209
210 myparser.add_option('-c','--complete',dest='completeXml',default=False,action='store_true',
211 help='Write out a complete xml file for a message.'
212 +'Not really good for an ais message')
213
214
215 myparser.add_option('-n','--name',dest='name',default=None,type='string',
216 help='Name of the field [required]')
217
218 myparser.add_option('-a','--array-length',dest='arrayLength',type='int',default=None,
219 help='How many items to have or string length [default: not an array]')
220
221 myparser.add_option('-N','--number-of-bits',dest='numberOfBits',type='int',default=None,
222 help='Number of bits for each element in a field.'
223 +' ints and decimal can be in the range of 1..32. [default: best guess] ('+
224 (''.join([choice+':'+str(typeBitsGuess[choice])+' ' for choice in typeBitsGuess])[:-1])
225 +')')
226
227 myparser.add_option('-t','--type',dest='type', type='choice', default='bool',
228 choices=typeChoices,
229 help='What type of data will the option represent? "u" for unsigned, "s" for signed. ('+
230 (''.join([choice +' ' for choice in typeChoices]))[:-1]+')'
231 )
232
233 myparser.add_option('-d','--description',dest='description',default=None,type='string',
234 help='Description of the field [required]')
235 myparser.add_option('--note',dest='notes',action='append',type='string',default=None,
236 help='0 or more notes to attach to the field')
237
238 myparser.add_option('-r','--min-range',dest='minRange',default=None,type='float',
239 help='Minimum possible value for a field. [default: none]')
240 myparser.add_option('-R','--max-range',dest='maxRange',default=None,type='float',
241 help='Minimum possible value for a field. [default: none]')
242
243
244 myparser.add_option('-u','--unavailable',dest='unavailable',default=None,type='string',
245 help='Value to use for when none is known. [default: none]')
246
247
248
249 myparser.add_option('-s','--scale',dest='scale',default=None,type='string',
250 help='Value scale natural value to transmitted value. [default: none]')
251
252 myparser.add_option('-D','--decimal-places',dest='decimalPlaces',default=None,type='int',
253 help='Decimal places to keep after undoing scale. [default: none]')
254
255 myparser.add_option('-U','--units',dest='units',default=None,type='string',
256 help='What units are for the values. [default: none]')
257
258 myparser.add_option('--required',dest='required',default=None,type='float',
259 help='TRY NOT TO USE THIS ONE accept for dac, fid, and efid. '
260 +'Specify manditory value if the field can not change. [default: none]')
261
262 myparser.add_option('-l','--lookup-table',dest='lut',default=None,action='append',type='string',
263 help='Specify multiple entries in a lookup table. Starts with 0.')
264
265 (options,args) = myparser.parse_args()
266
267 if not options.numberOfBits:
268 options.numberOfBits = typeBitsGuess[options.type]
269
270
271
272 if not validate(options):
273 sys.exit('ERROR: Options not ok.')
274
275 if options.outputFile:
276 makeField(options,file(options.outputFile,'a'))
277 else:
278 makeField(options)
279