codegen.py 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-
  3. import json
  4. import sys
  5. import os
  6. import argparse
  7. import glob
  8. #import cStringIO
  9. from sys import version_info
  10. if version_info.major == 3:
  11. import importlib
  12. importlib.reload(sys)
  13. elif version_info.major == 2:
  14. reload(sys)
  15. sys.setdefaultencoding("utf-8")
  16. try: import simplejson as json
  17. except: import json
  18. # {"version":"1.0","properties":[{"id":"light_switch","name":"电灯开关","desc":"控制电灯开灭","required":true,"mode":"rw","define":{"type":"bool","mapping":{"0":"关","1":"开"}}},{"id":"color","name":"颜色","desc":"灯光颜色","mode":"rw","define":{"type":"enum","mapping":{"0":"Red","1":"Green","2":"Blue"}}},{"id":"brightness","name":"颜色","desc":"灯光颜色","mode":"rw","define":{"type":"int","unit":"%","unitDesc":"亮度百分比","min":"0","max":"100"}},{"id":"name","name":"灯位置名称","desc":"灯位置名称:书房、客厅等","mode":"rw","required":true,"define":{"type":"string","min":"0","max":"64"}}]}
  19. class TEMPLATE_CONSTANTS:
  20. VERSION = "version"
  21. TYPE = "type"
  22. NAME = "name"
  23. ID = "id"
  24. MIN = "min"
  25. MAX = "max"
  26. DEFINE = "define"
  27. PROPERTIES = "properties"
  28. EVENTS = "events"
  29. MAPPING = "mapping"
  30. UNIT = "unit"
  31. UNITDESC = "unitDesc"
  32. REQUIRED = "required"
  33. MODE = "mode"
  34. class iot_enum:
  35. def __init__(self, parent, name, index):
  36. self.parent = parent
  37. self.id = name
  38. self.index = index
  39. def get_c_macro_name(self):
  40. return "e_{}_{}".format(self.parent.upper(), self.id.upper())
  41. def get_define_str(self):
  42. return "#define {} {}".format(self.get_c_macro_name(), self.index)
  43. class iot_field:
  44. def __init__(self, prefix, id, name, index, field_obj):
  45. self.default_value = ""
  46. self.enums = []
  47. self.index = index
  48. self.id = id
  49. self.prefix = prefix
  50. self.name = name
  51. self.type_name = field_obj["define"]["type"]
  52. if self.type_name == "bool":
  53. self.type_define = "TYPE_DEF_TEMPLATE_BOOL"
  54. self.type_id = "TYPE_TEMPLATE_BOOL"
  55. self.default_value = "0"
  56. elif self.type_name == "enum":
  57. self.type_define = "TYPE_DEF_TEMPLATE_ENUM"
  58. self.type_id = "TYPE_TEMPLATE_ENUM"
  59. if TEMPLATE_CONSTANTS.DEFINE not in field_obj:
  60. raise ValueError("错误:{} 字段定义中未找到枚举定义{} 字段".format(name, TEMPLATE_CONSTANTS.DEFINE))
  61. enum_defs = field_obj["define"]["mapping"]
  62. for enum_id in enum_defs:
  63. enum_name = enum_defs[enum_id]
  64. current_enum = iot_enum(self.id, enum_name, enum_id)
  65. self.enums.append(current_enum)
  66. if self.default_value == "":
  67. self.default_value = enum_id
  68. if self.default_value == "":
  69. raise ValueError("错误:{} 字段默认值 {} 非法".format(name, field_obj["default"]))
  70. elif self.type_name == "float":
  71. self.type_define = "TYPE_DEF_TEMPLATE_FLOAT"
  72. self.type_id = "TYPE_TEMPLATE_FLOAT"
  73. self.min_value = field_obj["define"]["min"]
  74. self.max_value = field_obj["define"]["max"]
  75. self.default_value = field_obj["define"]["start"]
  76. if float(self.default_value) < float(self.min_value) or float(self.default_value) > float(self.max_value):
  77. raise ValueError("错误:{} 字段 default 指定的默认值超出 min~max 取值范围".format(name))
  78. elif self.type_name == "int":
  79. self.type_define = "TYPE_DEF_TEMPLATE_INT"
  80. self.type_id = "TYPE_TEMPLATE_INT"
  81. self.min_value = field_obj["define"]["min"]
  82. self.max_value = field_obj["define"]["max"]
  83. self.default_value = field_obj["define"]["start"]
  84. if int(self.default_value) < int(self.min_value) or int(self.default_value) > int(self.max_value):
  85. raise ValueError("错误:{} 字段 default 指定的默认值超出 min~max 取值范围".format(name))
  86. elif self.type_name == "string":
  87. self.type_define = "TYPE_DEF_TEMPLATE_STRING"
  88. self.type_id = "TYPE_TEMPLATE_STRING"
  89. self.min_value = field_obj["define"]["min"]
  90. self.max_value = field_obj["define"]["max"]
  91. self.default_value = "{'\\0'}"
  92. elif self.type_name == "timestamp":
  93. self.type_define = "TYPE_DEF_TEMPLATE_TIME"
  94. self.type_id = "TYPE_TEMPLATE_TIME"
  95. self.default_value = 0
  96. else:
  97. raise ValueError('{} 字段 数据类型 type={} 取值非法,有效值应为:bool,enum,int,float,string'.format(name, field_obj["type"]))
  98. def get_id_c_macro_name(self):
  99. return "TC_IOT_PROP_{}".format(self.id)
  100. def get_id_c_member_name(self):
  101. return "m_{}".format(self.id)
  102. def get_id_default_value(self):
  103. return "{}".format(self.default_value)
  104. def get_id_define_str(self):
  105. return "#define {} {}".format(self.get_id_c_macro_name(), self.index)
  106. def get_struct_field_declare(self):
  107. if self.type_id == "TYPE_TEMPLATE_STRING":
  108. return "TYPE_DEF_TEMPLATE_STRING m_{}[{}+1];".format(self.id, str(self.max_value))
  109. else:
  110. return "{} m_{};".format(self.type_define, self.id)
  111. def get_global_field_declare(self):
  112. if self.type_id == "TYPE_TEMPLATE_STRING":
  113. return "TYPE_DEF_TEMPLATE_STRING sg_{}{}[{}+1]={};".format(self.prefix, self.id, str(self.max_value),"{0}")
  114. else:
  115. return "{} sg_{}{} = {};".format(self.type_define, self.prefix, self.id, self.default_value)
  116. def get_meta_define_str(self, var_name):
  117. return '{{ "{}", &{}.{}, {} }},' \
  118. .format(self.id, var_name, self.get_id_c_member_name(), self.type_id)
  119. class iot_event:
  120. def __init__(self,id, name, index, event):
  121. self.index = index
  122. self.id = id
  123. self.name = name
  124. self.event_type = event["type"]
  125. self.desc = event["desc"]
  126. self.event_properties = []
  127. self.event_property_count = 0
  128. self.prefix = self.id + "_"
  129. for property in event["params"]:
  130. self.event_properties.append(iot_field(self.prefix, property["id"], property["name"], self.event_property_count, property))
  131. self.event_property_count += 1
  132. def get_sigle_event_info(self):
  133. event_info = ""
  134. event_info += "\n id:{} name:\"{}\" type:\"{}\"\n".format(self.id, self.name, self.event_type)
  135. event_info += " property_count:{} \n params:[".format(self.event_property_count)
  136. for field in self.event_properties:
  137. event_info += "\n para:{} type:{}".format(field.id, field.type_id)
  138. event_info += "\n ]"
  139. return event_info
  140. def gen_sigle_event_info(self):
  141. result = ""
  142. event_para_info = ""
  143. event_property_info = ""
  144. event_var_info = ""
  145. for field in self.event_properties:
  146. event_para_info += "static {}\n".format(field.get_global_field_declare())
  147. event_property_info += "\n {"
  148. if field.type_id == "TYPE_TEMPLATE_STRING":
  149. event_property_info += ".key = \"{}\", .data = sg_{}, .type = {}".format(field.id, self.prefix + field.id, field.type_id)
  150. else:
  151. event_property_info += ".key = \"{}\", .data = &sg_{}, .type = {}".format(field.id, self.prefix + field.id, field.type_id)
  152. event_property_info += "},"
  153. event_var_info += "static DeviceProperty g_propertyEvent_{}[] = ".format(self.id)
  154. result += event_para_info + event_var_info + "{\n"+event_property_info + "\n};\n"
  155. return result
  156. class iot_action:
  157. def __init__(self,id, name, index, action):
  158. self.index = index
  159. self.id = id
  160. self.name = name
  161. self.desc = action["desc"]
  162. self.action_input = []
  163. self.action_input_count = 0
  164. self.action_input_prefix = self.id + "_in_"
  165. self.action_output = []
  166. self.action_output_count = 0
  167. self.action_output_prefix = self.id + "_out_"
  168. for input in action["input"]:
  169. self.action_input.append(iot_field(self.action_input_prefix, input["id"], input["name"], self.action_input_count, input))
  170. self.action_input_count += 1
  171. for output in action["output"]:
  172. self.action_output.append(iot_field(self.action_output_prefix, output["id"], output["name"], self.action_output_count, output))
  173. self.action_output_count += 1
  174. def get_single_action_info(self):
  175. action_info = ""
  176. action_info += "\n id:{} name:\"{}\"\n".format(self.id, self.name)
  177. action_info += " action_input_count:{} \n inputs:[".format(self.action_input_count)
  178. for field in self.action_input:
  179. action_info += "\n para:{} type:{}".format(field.id, field.type_id)
  180. action_info += "\n ]"
  181. action_info += " action_output_count:{} \n output:[".format(self.action_output_count)
  182. for field in self.action_output:
  183. action_info += "\n para:{} type:{}".format(field.id, field.type_id)
  184. action_info += "\n ]"
  185. return action_info
  186. def gen_single_action_info(self):
  187. result = ""
  188. action_para_info = ""
  189. action_input_info = ""
  190. action_input_var_info = ""
  191. for field in self.action_input:
  192. action_para_info += "static {}\n".format(field.get_global_field_declare())
  193. action_input_info += "\n {"
  194. if field.type_id == "TYPE_TEMPLATE_STRING":
  195. action_input_info += ".key = \"{}\", .data = sg_{}, .type = {}".format(field.id, self.action_input_prefix + field.id, field.type_id)
  196. else:
  197. action_input_info += ".key = \"{}\", .data = &sg_{}, .type = {}".format(field.id, self.action_input_prefix + field.id, field.type_id)
  198. action_input_info += "},"
  199. action_input_var_info += "static DeviceProperty g_actionInput_{}[] = ".format(self.id)
  200. result += action_para_info + action_input_var_info + "{\n"+action_input_info + "\n};\n"
  201. action_para_info = ""
  202. action_input_info = ""
  203. action_input_var_info = ""
  204. for field in self.action_output:
  205. action_para_info += "static {}\n".format(field.get_global_field_declare())
  206. action_input_info += "\n {"
  207. if field.type_id == "TYPE_TEMPLATE_STRING":
  208. action_input_info += ".key = \"{}\", .data = sg_{}, .type = {}".format(field.id, self.action_output_prefix + field.id, field.type_id)
  209. else:
  210. action_input_info += ".key = \"{}\", .data = &sg_{}, .type = {}".format(field.id, self.action_output_prefix + field.id, field.type_id)
  211. action_input_info += "},"
  212. action_input_var_info += "static DeviceProperty g_actionOutput_{}[] = ".format(self.id)
  213. result += action_para_info + action_input_var_info + "{\n"+action_input_info + "\n};\n"
  214. return result
  215. class iot_struct:
  216. def __init__(self, model):
  217. self.version = model["version"]
  218. self.fields = []
  219. self.field_id = 0
  220. self.events = []
  221. self.event_id = 0
  222. self.actions = []
  223. self.action_id = 0
  224. if "properties" in model :
  225. for field_define in model["properties"]:
  226. if TEMPLATE_CONSTANTS.NAME not in field_define:
  227. raise ValueError("错误:字段定义中未找到 Name 字段")
  228. self.fields.append(iot_field("", field_define["id"], field_define["name"], self.field_id, field_define))
  229. self.field_id += 1
  230. if "events" in model :
  231. for event in model["events"]:
  232. if TEMPLATE_CONSTANTS.NAME not in event:
  233. raise ValueError("错误:字段定义中未找到 Name 字段")
  234. self.events.append(iot_event(event["id"], event["name"], self.event_id, event))
  235. self.event_id += 1
  236. if "actions" in model :
  237. for action in model["actions"]:
  238. if TEMPLATE_CONSTANTS.NAME not in action:
  239. raise ValueError("错误:字段定义中未找到 Name 字段")
  240. self.actions.append(iot_action(action["id"], action["name"], self.action_id, action))
  241. self.action_id += 1
  242. def dump_data_info(self):
  243. print("dump iot struct,counts:{}".format(self.field_id))
  244. for temp_field in self.fields:
  245. if temp_field.type_name == "enum":
  246. print("{} {} {} {} ".format(temp_field.id, temp_field.type_name, temp_field.default_value, temp_field.type_define))
  247. print("enums:{")
  248. for enum in temp_field.enums:
  249. print("{} ".format(enum.get_c_macro_name()))
  250. print("}")
  251. else:
  252. print("{} {} {} {}\n".format(temp_field.id, temp_field.type_name, temp_field.default_value,
  253. temp_field.type_define))
  254. def dump_event_info(self):
  255. count = 0
  256. event_str = ""
  257. event_str += ("#define EVENT_COUNTS ({})\n").format(self.event_id)
  258. for event_d in self.events:
  259. event_str += "{}\n".format(event_d.gen_sigle_event_info())
  260. count += 1
  261. return event_str
  262. def data_config_macro_define(self, struct_Template="sDataPoint",var_gTemplate="sg_DataTemplate"):
  263. define_str = ""
  264. define_str += "/*-----------------data config start -------------------*/ \n\n"
  265. define_str += "#define TOTAL_PROPERTY_COUNT {}\n\n".format(self.field_id)
  266. define_str += "static {} {}[TOTAL_PROPERTY_COUNT];\n\n".format(struct_Template, var_gTemplate)
  267. return define_str
  268. def declare_product_data_struct(self, struct_name="ProductDataDefine", var_gname="sg_ProductData"):
  269. result = ""
  270. result += "typedef struct _" + struct_name + " {\n"
  271. for field in self.fields:
  272. result += " {}\n".format(field.get_struct_field_declare())
  273. result += "} " + struct_name + ";\n\n"
  274. result += "static " + struct_name + " "+var_gname + ";\n\n"
  275. return result
  276. def property_data_initializer(self, struct_name="ProductDataDefine", var_gProduct="sg_ProductData", var_gTemplate="sg_DataTemplate"):
  277. count = 0
  278. init_str = ""
  279. init_str += "static void _init_data_template(void)\n{\n"
  280. #init_str += " memset((void *) & {}, 0, sizeof({}));\n".format(var_gProduct, struct_name)
  281. for field in self.fields:
  282. if field.type_define == "TYPE_DEF_TEMPLATE_STRING":
  283. init_str += " {}.{}[0] = {};\n".format(var_gProduct, field.get_id_c_member_name(), "'\\0'")
  284. init_str += " {}[{}].data_property.data = {}.{};\n".format(var_gTemplate, count, var_gProduct, field.get_id_c_member_name())
  285. init_str += " {}[{}].data_property.data_buff_len = sizeof({}.{})/sizeof({}.{}[{}]);\n".format(var_gTemplate, count, var_gProduct, field.get_id_c_member_name(),var_gProduct, field.get_id_c_member_name(), count)
  286. else:
  287. init_str += " {}.{} = {};\n".format(var_gProduct, field.get_id_c_member_name(),field.get_id_default_value())
  288. init_str += " {}[{}].data_property.data = &{}.{};\n".format(var_gTemplate, count, var_gProduct, field.get_id_c_member_name())
  289. init_str += " {}[{}].data_property.key = \"{}\";\n".format(var_gTemplate, count, field.id)
  290. init_str += " {}[{}].data_property.type = {};\n".format(var_gTemplate, count, field.type_id)
  291. init_str += " {}[{}].state = eCHANGED;\n\n".format(var_gTemplate, count)
  292. count += 1
  293. init_str += "};\n"
  294. return init_str
  295. def gen_data_config(self):
  296. data_config = ""
  297. data_config +="{}".format(self.data_config_macro_define())
  298. data_config +="{}".format(self.declare_product_data_struct())
  299. data_config += "{}".format(self.property_data_initializer())
  300. return data_config
  301. def gen_event_config(self):
  302. resault = ""
  303. event_config = ""
  304. events_var = ""
  305. event_str = ""
  306. event_config += ("\n#define EVENT_COUNTS ({})\n\n").format(self.event_id)
  307. events_var += "\nstatic sEvent g_events[]={\n"
  308. for event_d in self.events:
  309. event_config += "{}\n".format(event_d.gen_sigle_event_info())
  310. event_str += "\n {"
  311. event_str += "\n .event_name = \"{}\",".format(event_d.id)
  312. event_str += "\n .type = \"{}\",".format(event_d.event_type)
  313. event_str += "\n .timestamp = 0,"
  314. event_str += "\n .eventDataNum = sizeof(g_propertyEvent_{})/sizeof(g_propertyEvent_{}[0]),".format(event_d.id, event_d.id)
  315. event_str += "\n .pEventData = g_propertyEvent_{},".format(event_d.id)
  316. event_str +="\n },"
  317. resault += event_config + events_var + event_str + "\n};\n"
  318. return resault
  319. def gen_action_config(self):
  320. resault = ""
  321. action_config = ""
  322. actions_var = ""
  323. action_str = ""
  324. action_config += ("\n#define TOTAL_ACTION_COUNTS ({})\n\n").format(self.action_id)
  325. actions_var += "\nstatic DeviceAction g_actions[]={\n"
  326. for action_d in self.actions:
  327. action_config += "{}\n".format(action_d.gen_single_action_info())
  328. action_str += "\n {"
  329. action_str += "\n .pActionId = \"{}\",".format(action_d.id)
  330. action_str += "\n .timestamp = 0,"
  331. action_str += "\n .input_num = sizeof(g_actionInput_{})/sizeof(g_actionInput_{}[0]),".format(action_d.id, action_d.id)
  332. action_str += "\n .output_num = sizeof(g_actionOutput_{})/sizeof(g_actionOutput_{}[0]),".format(action_d.id, action_d.id)
  333. action_str += "\n .pInput = g_actionInput_{},".format(action_d.id)
  334. action_str += "\n .pOutput = g_actionOutput_{},".format(action_d.id)
  335. action_str +="\n },"
  336. resault += action_config + actions_var + action_str + "\n};\n"
  337. return resault
  338. def main():
  339. parser = argparse.ArgumentParser(description='Iothub datatemplate and events config code generator.', usage='use "./codegen.py -c xx/config.json" gen config code')
  340. parser.add_argument('-c','--config', dest='config',metavar='xxx.json', required=False,default='xxx.json',
  341. help='copy the generated file (data_config.c and events_config.c) to datatemplate_sample dir '
  342. 'or your own code dir with datatemplate. '
  343. '\nconfig file can be download from tencent iot-hub platfrom. https://console.cloud.tencent.com/iotcloud')
  344. parser.add_argument('-d','--dest', dest='dest', required=False,default='.',
  345. help='Dest directory for generated code files, no / at the end.')
  346. args = parser.parse_args()
  347. config_path = args.config
  348. if not os.path.exists(config_path):
  349. print(u"错误:配置文件不存在,请重新指定数据模板配置文件路径,请参考用法 ./codegen.py -c xx/data_template.json".format(config_path))
  350. return 1
  351. config_dir = os.path.dirname(config_path)
  352. if config_dir:
  353. config_dir += "/"
  354. f = open(config_path, "r")
  355. try:
  356. thingmodel = json.load(f)
  357. if 'properties' not in thingmodel:
  358. thingmodel.properties = []
  359. if 'events' not in thingmodel:
  360. thingmodel.events = []
  361. print(u"加载 {} 文件成功".format(config_path))
  362. except ValueError as e:
  363. print(u"错误:文件格式非法,请检查 {} 文件是否是 JSON 格式。".format(config_path))
  364. return 1
  365. if TEMPLATE_CONSTANTS.PROPERTIES not in thingmodel:
  366. print(u"错误:{} 文件中未发现 DataTemplate 属性字段,请检查文件格式是否合法。".format(config_path))
  367. return 1
  368. try:
  369. snippet = iot_struct(thingmodel)
  370. if snippet.field_id != 0 :
  371. output_data_config_file_name = args.dest + "/data_config.c"
  372. output_file = open(output_data_config_file_name, "w")
  373. output_file.write("{}".format(snippet.gen_data_config()))
  374. output_file.close()
  375. print(u"文件 {} 生成成功".format(output_data_config_file_name))
  376. if snippet.event_id != 0 :
  377. output_event_config_file_name = args.dest + "/events_config.c"
  378. output_file = open(output_event_config_file_name, "w")
  379. output_file.write("#ifdef EVENT_POST_ENABLED\n{}\n#endif\n".format(snippet.gen_event_config()))
  380. output_file.close()
  381. print(u"文件 {} 生成成功".format(output_event_config_file_name))
  382. if snippet.action_id != 0 :
  383. output_action_config_file_name = args.dest + "/action_config.c"
  384. output_file = open(output_action_config_file_name, "w")
  385. output_file.write("#ifdef ACTION_ENABLED\n{}\n#endif\n".format(snippet.gen_action_config()))
  386. output_file.close()
  387. print(u"文件 {} 生成成功".format(output_action_config_file_name))
  388. return 0
  389. except ValueError as e:
  390. print(e)
  391. return 1
  392. if __name__ == '__main__':
  393. sys.exit(main())