32 from collections
import OrderedDict
34 def print_help_and_exit():
35 print(
"Usage: lcd_code_generator.py [args]")
37 print(
" -c name controller name")
38 print(
" -b bits bits per pixel")
39 print(
" -B Do not add bits to screen class name")
40 print(
" -r WxH resolution")
41 print(
" -j json Use json data from file")
42 print(
" -t template path source templates, templates by default")
45 print(
" ./lcd_code_generator.py -c all")
59 "no_bits_in_name":
False,
60 "args_in_cmd_mode":
False,
79 while idx < len(sys.argv):
83 controller = sys.argv[idx]
86 bits = int(sys.argv[idx])
87 g_voc[
"bits"].append({
"bits": zip( resolution_db, [{}] * len(resolution_db) )})
91 templates = sys.argv[idx]
96 resolution = sys.argv[idx]
97 resolution_db.append( resolution )
98 for t
in g_voc[
"bits"]:
99 t.append( { resolution: {} } )
101 print(
"Unknown option: ", opt)
102 print_help_and_exit()
105 def get_val_by_path(path, default):
106 nodes = path.split(
'/')
108 for i
in range(0, len(nodes) - 1):
109 data = data.get(nodes[i],{})
111 ctl_path = templates +
"/lcd/" + g_voc[
"controller"] +
"/" + path
112 base_path = templates + path
113 if len( data ) == 0
and os.path.exists(ctl_path)
and os.path.isfile(ctl_path):
114 with open(ctl_path,
'r') as myfile: data = myfile.read().splitlines() 115 elif len( data ) == 0
and os.path.exists(base_path)
and os.path.isfile(base_path):
116 with open(base_path,
'r') as myfile: 117 data = myfile.read().splitlines() 119 data = data.get( nodes[-1], default )
122 def read_template(fname):
123 if not os.path.isfile(templates + fname):
125 with open(templates + fname,
'r') as myfile: 129 def fill_template(temp):
130 temp = temp.replace(
'~FUNCS_DECL~', get_val_by_path(
"FUNCS_DECL",
""))
131 temp = temp.replace(
'~FIELDS_DECL~', get_val_by_path(
"FIELDS_DECL",
""))
132 temp = temp.replace(
'~SERIAL_INTERFACE_ARGS~', get_val_by_path(
"serial_interface_args",
""))
133 temp = temp.replace(
'~CUSTOM_SERIAL_INTERFACE_ARGS~', get_val_by_path(
"custom_serial_interface_args",
""))
134 temp = temp.replace(
'~CUSTOM_INTERFACE_ARGS~', get_val_by_path(
"custom_interface_args",
""))
135 temp = temp.replace(
'~CONTROLLER~', get_val_by_path(
"CONTROLLER",
""))
136 temp = temp.replace(
'~controller~', get_val_by_path(
"controller",
""))
137 temp = temp.replace(
'~RESOLUTION~', get_val_by_path(
"resolution",
""))
138 temp = temp.replace(
'~EXBITS~', get_val_by_path(
"exbits",
""))
139 temp = temp.replace(
'~BITS~', get_val_by_path(
"_bits",
""))
140 temp = temp.replace(
'~WIDTH~', get_val_by_path(
"width",
""))
141 temp = temp.replace(
'~HEIGHT~',get_val_by_path(
"height",
""))
142 temp = temp.replace(
'~INIT~', get_val_by_path(
"init_data",
""))
143 temp = temp.replace(
'~OPTIONAL_CONFIG~', get_val_by_path(
"optional_config",
""))
144 temp = temp.replace(
'~CONFIG_FUNC~', get_val_by_path(
"options/config_func",
"_configureSpiDisplay"))
145 temp = temp.replace(
'~SET_BLOCK~', get_val_by_path(
"_set_block",
""))
146 temp = temp.replace(
'~END_BLOCK~', get_val_by_path(
"_end_block",
" this->stop();"))
147 temp = temp.replace(
'~FREQUENCY~', get_val_by_path(
"_frequency",
"4400000"))
148 temp = temp.replace(
'~I2C_ADDR~', get_val_by_path(
"interfaces/i2c/addr",
"0x3C"))
149 temp = temp.replace(
'~FUNCS_DEF~', get_val_by_path(
"FUNCS_DEF",
""))
150 temp = temp.replace(
'~RESET_DURATION~', str(get_val_by_path(
"options/reset_duration", 20)))
151 temp = temp.replace(
'~RESET_DELAY~', str(get_val_by_path(
"options/reset_delay", 100)))
154 def get_file_data(fname):
155 temp = read_template(fname)
156 temp = fill_template(temp)
159 def get_json_controller_list(fname):
160 with open(templates +
'lcd/' + fname +
"/" + fname +
".json")
as json_file:
161 data = json.load(json_file, object_pairs_hook=OrderedDict)
164 def load_data_from_json(fname, ctl):
165 with open(templates +
'lcd/' + fname)
as json_file:
166 data = json.load(json_file, object_pairs_hook=OrderedDict)
167 g_voc[
"bits"] = data[ctl][
"bits"];
168 g_voc[
"options"] = data[ctl][
"options"]
169 g_voc[
"interfaces"] = data[ctl][
"interfaces"]
170 g_voc[
"functions"] = data[ctl].get(
"functions", {})
172 def load_init_data_from_json(fname, ctl, bits, resolution):
173 with open(templates +
'lcd/' + fname)
as json_file:
174 data = json.load(json_file, object_pairs_hook=OrderedDict)
175 g_voc[
"init_data"] =
"\n".join( data[ctl][
"bits"][bits][resolution][
"init"] )
176 if "begin" in data[ctl][
"bits"][bits][resolution]:
177 g_voc[
"optional_config"] =
"\n".join( data[ctl][
"bits"][bits][resolution][
"begin"] )
179 g_voc[
"optional_config"] =
"" 181 templates = templates +
"/" 183 def generate_custom_decl(name, doc=[" /**", " * DOCUMENT"," */"], type=["void",""]):
184 lines = get_val_by_path(
"functions/" + name +
"/doc", doc)
185 decl = get_val_by_path(
"functions/" + name +
"/decl", type)
186 init = get_val_by_path(
"functions/" + name +
"/init",
None)
187 if init
is not None and len(init) > 0:
188 lines.append(
' '*4 + decl[0])
189 lines.append(
' '*4 + name +
"(" +
', '.join(decl[1:]) +
")")
190 lines.append(
' '*8 +
": " + init[0])
192 lines.append(
' '*8 +
", " + i)
193 lines.extend([
' '*4 +
"{",
' '*4 +
"}"])
195 lines.append(
" " + decl[0] +
" " + name +
"(" +
', '.join(decl[1:]) +
");")
196 return fill_template(
'\n'.join(lines))
198 def generate_custom_def(name, type=["void",""], code=[]):
199 init = get_val_by_path(
"functions/" + name +
"/init",
None)
202 delc = get_val_by_path(
"functions/" + name +
"/decl", type)
203 lines = [
"template <class I> " + delc[0] + \
204 " Interface~CONTROLLER~<I>::" + name +
"(" + \
205 ', '.join(delc[1:]) +
")",
"{" ]
206 code = get_val_by_path(
"functions/" + name +
"/code",code)
208 if name ==
"startBlock":
209 code = [generate_set_block_content()]
210 lines.append(
'\n'.join(code) )
211 lines.extend( [
"}",
""] )
212 return fill_template(
'\n'.join(lines))
214 def generate_set_block_content():
215 lines = [
" lcduint_t rx = w ? (x + w - 1) : (m_base.width() - 1);",
217 lines.append(
" this->send({0});".format(get_val_by_path(
"options/col_cmd",
"0x22")))
218 if not get_val_by_path(
"options/args_in_cmd_mode",
False):
219 lines.append(
" setDataMode(1); // According to datasheet all args must be passed in data mode")
220 if get_val_by_path(
"options/rowcol_bits",8) != 8:
221 lines.append(
" this->send(0);")
222 if get_val_by_path(
"options/column_div", 1) > 1:
223 lines.append(
" this->send(x / {0});".format(get_val_by_path(
"options/column_div", 1)) )
225 lines.append(
" this->send(x);" )
226 if get_val_by_path(
"options/rowcol_bits",8) != 8:
227 lines.append(
" this->send(0);")
228 if get_val_by_path(
"options/column_div", 1) > 1:
229 lines.append(
" this->send( (rx < m_base.width() ? rx : (m_base.width() - 1)) / {0} );".format(
230 get_val_by_path(
"options/column_div", 1)) )
232 lines.append(
" this->send( rx < m_base.width() ? rx : (m_base.width() - 1) );" )
234 if not get_val_by_path(
"options/args_in_cmd_mode",
False):
235 lines.append(
" setDataMode(0);")
236 lines.append(
" this->send({0});".format(get_val_by_path(
"options/row_cmd",
"0x72")))
237 if not get_val_by_path(
"options/args_in_cmd_mode",
False):
238 lines.append(
" setDataMode(1); // According to datasheet all args must be passed in data mode")
239 if get_val_by_path(
"options/rowcol_bits",8) != 8:
240 lines.append(
" this->send(0);")
241 lines.append(
" this->send(y);")
242 if get_val_by_path(
"options/rowcol_bits",8) != 8:
243 lines.append(
" this->send(0);")
244 lines.append(
" this->send(m_base.height() - 1);")
245 if not get_val_by_path(
"options/args_in_cmd_mode",
False):
246 lines.append(
" setDataMode(0);")
247 if get_val_by_path(
"options/exit_cmd_mode_command",
None)
is not None:
248 lines.append(
" this->send({0});".format( get_val_by_path(
"options/exit_cmd_mode_command",
None) ) )
249 lines.extend( [
" if ( m_dc >= 0 )",
257 " this->send(0x40);",
259 return "\n".join(lines)
261 def generate_controller_data(jsonfile, ctl):
262 controller = ctl.lower();
263 g_voc[
"CONTROLLER"] = controller.upper()
264 g_voc[
"controller"] = controller.lower()
266 if jsonfile
is not None:
267 load_data_from_json( jsonfile, ctl )
268 func_list = [
"Interface~CONTROLLER~",
"startBlock",
"nextBlock",
"endBlock",
"setDataMode",
"commandStart"]
269 for f
in get_val_by_path(
"functions/interface_list",[] ):
270 if f
not in func_list:
271 func_list.append( f )
272 g_voc[
"FUNCS_DECL"] =
"" 274 g_voc[
"FUNCS_DECL"] += generate_custom_decl(f) +
'\n\n' 275 g_voc[
"FUNCS_DEF"] =
"" 277 custom_def = generate_custom_def(f)
278 if custom_def
is not None:
279 g_voc[
"FUNCS_DEF"] += custom_def +
'\n' 280 g_voc[
"FIELDS_DECL"] =
'\n'.join(get_val_by_path(
"fields/Interface~CONTROLLER~",[]))
282 location =
"../src/v2/lcd/" + controller
283 shutil.rmtree(location,
True)
285 header = open(location +
"/lcd_" + controller +
".h",
"w" )
286 inl = open(location +
"/lcd_" + controller +
".inl",
"w" )
287 cpp = open(location +
"/lcd_" + controller +
".cpp",
"w" )
289 header.write( get_file_data(
'copyright.txt') )
290 inl.write( get_file_data(
'copyright.txt') )
291 cpp.write( get_file_data(
'copyright.txt') )
293 header.write( get_file_data(
'header.h') )
294 inl.write( get_file_data(
'header.inl') )
295 cpp.write( get_file_data(
'header.cpp') )
297 header.write( get_file_data(
'interface_spi.h') )
299 for _bits
in g_voc[
"bits"].keys():
300 g_voc[
"_bits"] = _bits;
301 if not get_val_by_path(
"options/no_bits_in_name",
False):
302 g_voc[
"exbits"] =
"x" + g_voc[
"_bits"]
305 header.write( get_file_data(
'display.h' ) )
306 inl.write( get_file_data(
'display.inl' ) )
307 for res
in g_voc[
"bits"][_bits].keys():
308 g_voc[
"resolution"] = res + g_voc[
"exbits"]
309 g_voc[
"init_data"] = get_file_data(
'init_data.inl')
310 if jsonfile
is not None:
311 load_init_data_from_json(jsonfile, ctl, _bits, res)
312 g_voc[
"width"] = res.split(
'x')[0]
313 g_voc[
"height"] = res.split(
'x')[1]
314 header.write( get_file_data(
'resolution.h') )
315 inl.write( get_file_data(
'resolution.inl') )
316 for intf
in g_voc[
"interfaces"].keys():
317 g_voc[
"serial_interface_args"] = get_val_by_path(
"bits/" + _bits +
"/" + res +
"/serial_interface_args",\
318 "*this, -1" if intf ==
"i2c" else "*this, config.dc")
319 g_voc[
"custom_serial_interface_args"] = get_val_by_path(
"bits/" + _bits +
"/" + res +
"/custom_serial_interface_args",\
320 "*this, -1" if intf ==
"i2c" else "*this, dcPin")
321 g_voc[
"custom_interface_args"] = get_val_by_path(
"bits/" + _bits +
"/" + res +
"/custom_interface_args",\
322 "*this, dcPin, frequency = frequency ? frequency : ~FREQUENCY~")
323 g_voc[
"_frequency"] = str(get_val_by_path(
"interfaces/" + intf +
"/frequency", 4400000 ))
324 header.write( get_file_data(
'display_' + intf +
'.h') )
325 cpp.write( get_file_data(
'display_' + intf +
'.cpp') )
327 header.write( get_file_data(
'footer.h') )
333 display_list = [f
for f
in os.listdir(templates +
"lcd")
if len(f) > 3]
334 for display
in display_list:
335 _ctl_list = get_json_controller_list(display)
336 for _ctl
in _ctl_list:
337 generate_controller_data( _ctl +
"/" + _ctl +
".json", _ctl)