]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - processor-sdk/performance-audio-sr.git/blob - tools/pyalpha/pyalpha/pyalpha.py
Update submodule URLs
[processor-sdk/performance-audio-sr.git] / tools / pyalpha / pyalpha / pyalpha.py
1 """
2 /*
3 Copyright (c) 2004 - 2016, Texas Instruments Incorporated - http://www.ti.com/
4 All rights reserved.
6 * Redistribution and use in source and binary forms, with or without 
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
13 * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the
16 * distribution.
17 *
18 * Neither the name of Texas Instruments Incorporated nor the names of
19 * its contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 *
34 */
35 """
36 #### Library imports ####
37 import os
38 import re
39 import sys
40 import time
41 import errno
42 import subprocess
43 from serial import Serial
44 from random import randint
46 #### Package imports ####
47 from srecord import sRecord
49 ##########################
50 #### Module functions ####
51 def silentremove(filename):
52     """Delete a file if exists."""
53     try:
54         os.remove(filename)
55     except OSError as e:
56         if e.errno != errno.ENOENT:
57             raise # re-raise exception if a different error occured
58 #### Module Functions ####
59 ##########################
61 ###########################
62 #### Module Exceptions ####
63 class ConversionError(Exception):
64     def __init__(self, value):
65         self.value = value
66     def __str__(self):
67         return repr(self.value)        
68 #### Module Exceptions ####
69 ###########################
72 #################
73 #### PyAlpha ####
74 class PyAlpha:
75     """Interface for sending alpha commands"""
76     
77     def __init__(self, header, port='COM1', baud=19200, retain=False,
78                  inc='./alpha', bins='./bin', alfas='.', debug=False):
79         self.port  = port            
80         self.baud = baud
81         self.header = header
82         self.inc = inc
83         self.bins = bins
84         self.alfas = alfas
85         self.inverse = {}
86         self.retain = retain
87         self.debug = debug
88         self.build_inverse_mapping() # populates self.inverse
90     def send(self, alpha_list, fast=False):
91         """Sends alpha_list as S-Record over UART to the DUT"""
92         
93         if not alpha_list: return # die early
94         
95         # Test number a la calfa
96         testnum = randint(1000,9999)
97         fbase = self.alfas +  '/alfa' + str(testnum)
98         
99         # Generate C file
100         self.gen_c(alpha_list, fbase)
102         # Preprocess C file
103         self.preprocess(fbase)
105         # Convert to S-Record
106         ret = self.itox(fbase)
107         if ret:
108             self.__clean(fbase)
109             raise ConversionError('itox failed with code: ' + str(ret))
111         # Send S-Record to target device and read response
112         ret = self.write_read(fbase)
113         if not ret:
114             self.__clean(fbase)
115             return 'TIMEOUT'
117         # Don't do any postprocessing, just return after receiving S-record
118         if fast:
119             self.__clean(fbase)
120             return ret
121             
122         # Parse S-Record into alpha code
123         self.xtoi(fbase)
125         # Parse alpha code to alpha command, remove CRLF from the end
126         ret = self.inverse_compile(fbase).strip()
127         
128         # Clean up temporary files
129         self.__clean(fbase)
131         return ret
133                 
134     def write_read(self, fbase, timeout=5):
135         """Read S-Record file (.s) and write. Read response and save to S-Record response file (.x)"""
136         s_fname = fbase + '.s'
137         x_fname = fbase + '.x'
138         
139         with Serial(self.port, self.baud, timeout=1) as ser:
140             # WRITE
141             with open(s_fname, 'rb') as sfile:
142                 records = sfile.read()
143                 if self.debug: print 'Sending:', records
144                 ser.write('\r\n') # A single CRLF must be sent first for proper comm
145                 ser.write(records)
147             # READ
148             response = []
149             line = None
150             t = 0
151             while line != "S9030000FC\r\n" and t < timeout:
152                 line = ser.readline()
153                 if line:
154                     response.append(line)
155                 else:
156                     t += 1
158             # Strip away the random leading chars and emove empty lines
159             outarr = [line.lstrip('\x13\x11') for line in response if line]
160             if self.debug: print 'Received:', outarr
162         with open(x_fname, 'w') as xfile:
163             xfile.write(''.join(outarr))
165         return outarr
166     
167     def gen_c(self, alpha_list, fbase):
168         """Generate a C file (.c) to be pre-processed"""
169         c_fname = fbase + '.c'
170         
171         with open(c_fname, 'w') as cfile:
172             cfile.write('#include "' + self.header + '.h"\n')
173             cfile.write('alpha ' + ','.join(alpha_list) + '\n')
174     
175     def preprocess(self, fbase):
176         """Pre-process the C file (.c) to get hex representations of alpha commands in (.pp) file"""
177         pp_fname = fbase + '.pp'
178         
179         args = [
180             self.bins + '/acp6x.exe',
181             '-I', self.inc,
182             '-E',
183             fbase + '.c',
184         ]
186         with open(pp_fname, 'w') as ppfile:
187             pid = subprocess.Popen(args, stdout=ppfile, stderr=subprocess.PIPE)
188             pid.wait()
190     def itox(self, fbase):
191         """Calls itox.exe to convert .pp file to S-Record format (.s)"""
192         pp_fname = fbase + '.pp'
193         s_fname = fbase + '.s'
195         args = [
196             self.bins + '/itox.exe',
197             '-S', # S-record
198         ]
200         retcode = None
201         with open(s_fname, 'wb') as sfile, open(pp_fname, 'rb') as ppfile:
202             pid = subprocess.Popen(args, stdout=sfile, stdin=ppfile)
203             retcode = pid.wait()
205         return retcode
206     
207     def xtoi(self, fbase):
208         """Calls xtoi.exe to convert .x file to hex representation (.y)"""
209         x_fname = fbase + '.x'
210         y_fname = fbase + '.y'
211         
212         args = [
213             self.bins + '/xtoi.exe',
214             '-S'
215         ]
216         
217         with open(x_fname, 'rb') as xfile, open(y_fname, 'wb') as yfile:
218             pid = subprocess.Popen(args, stdout=yfile, stdin=xfile)
219             pid.wait()
220             
222     def inverse_compile(self, fbase):
223         """Converts hex representation (.y) to textual representation of alpha command (.z)"""
224         y_fname = fbase + '.y'
225         z_fname = fbase + '.z'
227         s = ''
228         with open(y_fname, 'rb') as yfile:
229             s = yfile.read()
231             for code,name in self.inverse.iteritems():
232                 s = re.sub(code, name, s)
234         with open(z_fname, 'wb') as zfile:
235             zfile.write(s)
237         return s
239     def __clean(self, fbase):
240         """Removes temporary files, unless otherwise specified (retain)"""
242         if not self.retain:
243             self.clean_up(fbase)
245     
246     def clean_up(self, fbase):
247         """Removes temporary files"""
248         
249         file_types = ['.c', '.pp', '.s', '.x', '.y', '.z']
251         # Apply file extensions to the fbase
252         fnames = [fbase + ft for ft in file_types]
253         map(silentremove, fnames)
255     def build_inverse_mapping(self):
256         """Parses through inverse-compilation file (.hdM) and creates a mapping
257         for creation of .z files"""
259         # .hdM file is in the include directory with specified name
260         fname = self.inc + '/' + self.header + '.hdM'
261         
262         # Each line in hdM is of the form:
263         #       # define alphaCommandName 0x####,0x####,...
264         define_str = r"^#define"
265         alpha_str  = r"(?P<alpha>\S+)"
266         hex_str    = r"(?P<hex>(0x[a-f0-9]{4},?)+)[\r\n]+$"
268         # Compile the regular expression
269         alpha_re = re.compile(define_str + " " +
270                               alpha_str + " " +
271                               hex_str)
273         # Parse file
274         with open(fname, 'rb') as f:
275             for line in f:
276                 mat = re.match(alpha_re, line)
277                 if not mat: continue
279                 name = mat.group('alpha')
280                 codes = mat.group('hex')
282                 self.inverse[codes] = name
284 #### PyAlpha ####
285 #################