Initial commit for stepper controller
[radiotelescope.git] / stepper_controller / arduino / stepper / menu.py
1 #!/usr/bin/python
2 #
3 # Build a linked list (indexed array) of characters to parse a
4 # number of commands and optional arguments and call a function
5 # for each command.
6 #
7 # Version: 0.1
8 # Date:    25 November 2009
9 # Author:  Harry McNally
10 #
11 #                      +-----------------------+
12 #                      |   d e c i s i o n s   |
13 #                      +-----------------------+
14 #                      | a n d   d e s i g n s |
15 #                      +-----------------------+
16 #
17 # Copyright (C) 2009 Decisions and Designs Pty Ltd. All rights reserved.
18 #
19 # This software may be distributed and modified under the terms of the GNU
20 # General Public License version 2 (GPL) as published by the Free Software
21 # Foundation and appearing in the file GPL2.TXT included in the packaging of
22 # this file. Please note that GPL Section 2[b] requires that all works based
23 # on this software must also be made publicly available under the terms of
24 # the GPL ("Copyleft").
25 #
26 # Contact information:
27 # Decisions and Designs Web site: http://www.decisions-and-designs.com.au
28 # e-mail:                         [email protected]
29 #
30
31 class Command:
32     """Data for a command string, arguments, and called function"""
33     def __init__(self, cmd, arg, fun):
34         self.cmd  = cmd
35         self.arg  = arg
36         self.fun  = fun
37
38 # All of the commands, varg list, and functions to call.
39 # The commands cannot overlap so "ab" and "abc" will clash (because
40 # of the option for following arguments). Coding the command parsing
41 # machine to overcome this would be slightly useful.
42 # Up to four characters can be included in the argument entry for
43 # up to four arguments (read left to right). Each character requests:
44 # u = uint32_t, i = int32_t, d = double
45 # Command("command", "varg_list", "function_name") 
46 menu = [                                                                 \
47          Command("az",    "dddu", "COMMAND_AZIMUTH_SIG"),                \
48          Command("ab",    "d",    "COMMAND_AZIMUTH_BASE_SIG"),           \
49          Command("as",    "d",    "COMMAND_AZIMUTH_SLEW_SIG"),           \
50          Command("aa",    "d",    "COMMAND_AZIMUTH_ACCELERATION_SIG"),   \
51          Command("at",    "u",    "COMMAND_AZIMUTH_STEPS_SIG"),          \
52          Command("acw",   "",     "COMMAND_AZIMUTH_CLOCKWISE_SIG"),      \
53          Command("acc",   "",     "COMMAND_AZIMUTH_CCW_SIG"),            \
54          Command("el",    "dddu", "COMMAND_ELEVATION_SIG"),              \
55          Command("eb",    "d",    "COMMAND_ELEVATION_BASE_SIG"),         \
56          Command("es",    "d",    "COMMAND_ELEVATION_SLEW_SIG"),         \
57          Command("ea",    "d",    "COMMAND_ELEVATION_ACCELERATION_SIG"), \
58          Command("et",    "u",    "COMMAND_ELEVATION_STEPS_SIG"),        \
59          Command("eu",    "",     "COMMAND_ELEVATION_UP_SIG"),           \
60          Command("ed",    "",     "COMMAND_ELEVATION_DOWN_SIG"),         \
61          Command("sta",   "",     "COMMAND_START_AZIMUTH_SIG"),          \
62          Command("ste",   "",     "COMMAND_START_ELEVATION_SIG"),        \
63          Command("stb",   "",     "COMMAND_START_AZ_EL_SIG"),            \
64        ]
65
66 def write_menu(file):
67     file.write('\n/*\n    Commands defined in the ui.py file\n')
68     file.write('    command signal arguments\n')
69     for item in menu:
70         file.write('    ' + repr(item.cmd) + ', ' +  repr(item.fun) + ', ' + \
71               repr(item.arg) + '\n')
72     file.write('*/\n\n')
73
74 function_list = []
75
76 class Function:
77     def __init__(self, arg, fun):
78         self.arg = arg
79         self.fun = fun
80
81 def write_function_list(file):
82     file.write('MenuSignal menuSignal[] = {\n') 
83     index = 0
84     csv = ' '
85     for function in function_list:
86         shift = 0
87         argb = 0
88         for ch in function.arg:
89             if (ch == 'u'):
90                 argb += 1 << shift
91             elif (ch == 'i'):
92                 argb += 2 << shift
93             elif (ch == 'd'):
94                 argb += 3 << shift
95             else :
96                 raise WriteFunctionBadVArgChar 
97             shift += 2
98         file.write('    ' + csv + '{ /* ' + repr(index) + ' */ ' + function.fun + ', ' + hex(argb) + ' }\n')
99         csv = ','
100         index += 1
101     file.write('};\n\n')    
102
103 class CommandEntry:
104     def __init__(self, ch):
105         self.branch = []
106         self.chr = ch
107
108 class FunctionEntry:
109     def __init__(self, ch, arg, fun):
110         self.chr = ch
111         self.index = len(function_list)
112         if self.index > 127:
113             raise FunctionListTooBig
114         function_list.append(Function(arg, fun))
115
116 class MenuTree:
117     """A (state) tree to traverse for each arriving character (event)""" 
118     def __init__(self):
119         self.root = self.branch = []
120
121     # Search the present list and, if the char is found,  index to the char's
122     # new list. Otherwise, add the char and index to the char's empty list.
123     def add_command_entry(self, ch):
124         for entry in self.branch:
125             # Entry already exists for this character
126             if entry.chr is ch:
127                 if isinstance(entry, FunctionEntry):
128                     raise FunctionEntrySubset
129                 self.branch = entry.branch
130                 return
131         # Make a new entry for this character
132         entry = CommandEntry(ch)
133         self.branch.append(entry)
134         self.branch = entry.branch
135
136     def add_function_entry(self, ch, arg, fun):
137         for entry in self.branch:
138             # Entry already exists for this character
139             if entry.chr is ch:
140                 if isinstance(entry, FunctionEntry):
141                     raise FunctionEntryDuplicate
142                 else:
143                     raise FunctioEntrySuperset
144         # Make a function entry for this character
145         entry = FunctionEntry(ch, arg, fun)
146         self.branch.append(entry)
147
148     def build_tree(self, commands):
149         for command in commands:
150             self.branch = self.root
151             for ch in command.cmd[:-1]:
152                 self.add_command_entry(ch)
153             self.add_function_entry(command.cmd[-1], command.arg, command.fun)
154
155     def index_branch(self, branch):
156         for entry in branch:
157             if isinstance(entry, CommandEntry):
158                 # Forward index this branch
159                 entry.index = self.next_index
160                 self.next_index += len(entry.branch) + 1
161                 if self.next_index > 127:
162                     raise CommandListTooBig
163                 # Recurse through the tree branches
164                 self.index_branch(entry.branch)
165
166     def index_tree(self):
167         self.branch = self.root
168         self.next_index = len(self.branch) + 1
169         self.index_branch(self.branch)
170
171     def write_branch(self, file, branch):
172         for entry in branch:
173             if isinstance(entry, CommandEntry):
174                 file.write('    { /* ' + repr(self.list_idx) + ' */ \'' + \
175                            entry.chr + '\', ' + repr(entry.index) + '       },\n')
176             else:         
177                 file.write('    { /* ' + repr(self.list_idx) + ' */ \'' + \
178                            entry.chr + '\', ' + repr(entry.index) + ' | EOC },\n')
179             self.list_idx += 1
180         file.write('    { /* ' + repr(self.list_idx) + ' */  0,  0       },\n')
181         self.list_idx += 1
182         # Recurse through branches
183         for entry in branch: 
184             if isinstance(entry, CommandEntry):
185                 self.write_branch(file, entry.branch)
186
187     def write_tree(self, file):
188         self.branch = self.root
189         self.list_idx = 0
190         file.write('Menu menu[] = {\n')
191         self.write_branch(file, self.branch)
192         file.write('};\n\n')
193        
194 if __name__ == "__main__":
195
196     import sys
197     import os
198
199     # Write default fail signal at index 0
200     function_list.append(Function('', 'COMMAND_FAIL_SIG'))
201     # Finish the tree
202     t = MenuTree()
203     t.build_tree(menu)
204     t.index_tree()
205     # Write the results into the file
206     output = open(sys.argv[1] + '.tmp', "w")
207     delete_lines = 0
208     for line in open(sys.argv[1]):
209         if not delete_lines:
210             output.write(line)
211         if 'Start tag for ui.py' in line:
212             delete_lines = 1    
213             write_menu(output)
214             t.write_tree(output)
215             write_function_list(output)
216         elif 'End tag for ui.py' in line:
217             delete_lines = 0
218             output.write(line)
219     output.close()\r
220     os.remove(sys.argv[1])
221     os.rename(sys.argv[1] + '.tmp', sys.argv[1])
222     

UCC git Repository :: git.ucc.asn.au