123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162 |
- # Copyright 2024 Google LLC
- #
- # Licensed under the Apache License, Version 2.0 (the "License");
- # you may not use this file except in compliance with the License.
- # You may obtain a copy of the License at
- #
- # http://www.apache.org/licenses/LICENSE-2.0
- #
- # Unless required by applicable law or agreed to in writing, software
- # distributed under the License is distributed on an "AS IS" BASIS,
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- # See the License for the specific language governing permissions and
- # limitations under the License.
- from waflib import Task
- import json
- import string
- import uuid
- # This file parses appinfo.json and generates a C file that get's built into
- # the pebble app binary.
- # See http://wiki.hq.getpebble.com/wiki/index.php/Software/Formats/AppinfoJson
- # for details on the format.
- def generate_appinfo(input_filename, output_filename):
- with open(input_filename, 'r') as json_file:
- try:
- app_info = json.load(json_file)
- except ValueError as e:
- raise Exception('Could not parse appinfo.json file: '+ str(e))
- generate_appinfo_c(app_info, output_filename)
- def generate_appinfo_c(app_info, output_filename, platform_name=None):
- # Handle top level options
- try:
- app_uuid = uuid.UUID(app_info['uuid'])
- except KeyError:
- raise Exception('Could not find $.uuid in appinfo.json')
- uuid_initializer_string = '{ %s }' % ", ".join(["0x%02X" % b for b in app_uuid.bytes])
- try:
- name = app_info['shortName']
- except KeyError:
- raise Exception('Could not find $.shortName in appinfo.json')
- try:
- company_name = app_info['companyName']
- except KeyError:
- raise Exception('Could not find $.companyName in appinfo.json')
- try:
- version_label = app_info['versionLabel']
- version_label_major = 0
- version_label_minor = 0
- version_label_list = version_label.split('.')
- if len(version_label_list) >= 1:
- version_label_major = version_label_list[0]
- if len(version_label_list) >= 2:
- version_label_minor = version_label_list[1]
- if len(version_label_list) > 2:
- raise Exception('appinfo.json versionLabel format for app revision must be "Major" or "Major.Minor"')
- # validate versionLabel range [0-255] and int-characters
- try:
- if int(version_label_major) < 0 or int(version_label_major) > 255:
- raise ValueError
- if int(version_label_minor) < 0 or int(version_label_minor) > 255:
- raise ValueError
- except ValueError:
- raise Exception('appinfo.json versionLabel contains invalid or out of range values [0-255]')
-
- except KeyError:
- raise Exception('Could not find $.versionLabel in appinfo.json')
- # Handle 'watchapp' options
- try:
- is_watchface = app_info['watchapp']['watchface']
- except KeyError:
- is_watchface = False
- try:
- only_shown_on_communication = app_info['watchapp']['onlyShownOnCommunication']
- except KeyError:
- only_shown_on_communication = False
- try:
- is_hidden = app_info['watchapp']['hiddenApp']
- except KeyError:
- is_hidden = False
- # Handle 'resources' options
- icon_resource_id = None
- try:
- for r in app_info['resources']['media']:
- if 'menuIcon' in r and r['menuIcon']:
- if icon_resource_id is not None:
- raise Exception('More than one resource is set to be your menuIcon!')
- icon_resource_id = 'RESOURCE_ID_' + r['name']
- except KeyError:
- pass
- if icon_resource_id is None:
- icon_resource_id = 'DEFAULT_MENU_ICON'
- try:
- is_rocky = app_info['projectType'] == 'rocky'
- except KeyError:
- is_rocky = False
- flags = []
- if is_watchface:
- flags.append('PROCESS_INFO_WATCH_FACE')
- if only_shown_on_communication:
- flags.append('PROCESS_INFO_VISIBILITY_SHOWN_ON_COMMUNICATION')
- if is_hidden:
- flags.append('PROCESS_INFO_VISIBILITY_HIDDEN')
- if is_rocky:
- flags.append('PROCESS_INFO_ROCKY_APP')
- if platform_name:
- flags.append('PROCESS_INFO_PLATFORM_{}'.format(platform_name.upper()))
- if len(flags):
- flags_string = ' | '.join(flags)
- else:
- flags_string = '0'
- with open(output_filename, 'w') as f:
- f.write('#include "pebble_process_info.h"\n')
- f.write('#include "src/resource_ids.auto.h"\n')
- f.write(PEBBLE_APP_INFO_TEMPLATE.substitute(
- version_major=version_label_major,
- version_minor=version_label_minor,
- name=name,
- company=company_name,
- icon_resource_id=icon_resource_id,
- flags=flags_string,
- uuid=uuid_initializer_string))
- PEBBLE_APP_INFO_TEMPLATE = string.Template("""
- const PebbleProcessInfo __pbl_app_info __attribute__ ((section (".pbl_header"))) = {
- .header = "PBLAPP",
- .struct_version = { PROCESS_INFO_CURRENT_STRUCT_VERSION_MAJOR, PROCESS_INFO_CURRENT_STRUCT_VERSION_MINOR },
- .sdk_version = { PROCESS_INFO_CURRENT_SDK_VERSION_MAJOR, PROCESS_INFO_CURRENT_SDK_VERSION_MINOR },
- .process_version = { ${version_major}, ${version_minor} },
- .load_size = 0xb6b6,
- .offset = 0xb6b6b6b6,
- .crc = 0xb6b6b6b6,
- .name = "${name}",
- .company = "${company}",
- .icon_resource_id = ${icon_resource_id},
- .sym_table_addr = 0xA7A7A7A7,
- .flags = ${flags},
- .num_reloc_entries = 0xdeadcafe,
- .uuid = ${uuid},
- .virtual_size = 0xb6b6
- };
- """)
|