xref: /btstack/tool/bluetooth_company_id.py (revision 77bd03813f180d723705f07c568f73ec226e388e)
15c544019SMatthias Ringwald#!/usr/bin/env python3
2779b256eSMatthias Ringwald#
3779b256eSMatthias Ringwald# Scrape GATT UUIDs from Bluetooth SIG page
4779b256eSMatthias Ringwald# https://www.bluetooth.com/specifications/assigned-numbers/company-identifiers
5779b256eSMatthias Ringwald#
6779b256eSMatthias Ringwald# Copyright 2017 BlueKitchen GmbH
7779b256eSMatthias Ringwald#
8779b256eSMatthias Ringwald
9779b256eSMatthias Ringwaldfrom lxml import html
10779b256eSMatthias Ringwaldimport datetime
11779b256eSMatthias Ringwaldimport requests
12779b256eSMatthias Ringwaldimport sys
13779b256eSMatthias Ringwaldimport codecs
14779b256eSMatthias Ringwaldimport os
15779b256eSMatthias Ringwaldimport re
16779b256eSMatthias Ringwald
17*77bd0381SMilanka Ringwaldimport csv
18*77bd0381SMilanka Ringwaldimport getopt
19*77bd0381SMilanka Ringwald
20ff7cea0bSMatthias Ringwald
21779b256eSMatthias Ringwaldprogram_info = '''
22779b256eSMatthias RingwaldBTstack Company ID Scraper for BTstack
23*77bd0381SMilanka RingwaldCopyright 2022, BlueKitchen GmbH
24779b256eSMatthias Ringwald'''
25779b256eSMatthias Ringwald
26779b256eSMatthias Ringwaldheader = '''
27779b256eSMatthias Ringwald/**
28b436f177SMatthias Ringwald * bluetooth_company_id.h generated from Bluetooth SIG website for BTstack by tool/bluetooth_company_id.py
29b436f177SMatthias Ringwald * {datetime}
30779b256eSMatthias Ringwald */
31779b256eSMatthias Ringwald
3280e33422SMatthias Ringwald#ifndef BLUETOOTH_COMPANY_ID_H
3380e33422SMatthias Ringwald#define BLUETOOTH_COMPANY_ID_H
34779b256eSMatthias Ringwald'''
35779b256eSMatthias Ringwald
36779b256eSMatthias Ringwaldpage_info = '''
37779b256eSMatthias Ringwald/**
38779b256eSMatthias Ringwald * Assigned numbers from {page}
39779b256eSMatthias Ringwald */
40779b256eSMatthias Ringwald'''
41779b256eSMatthias Ringwald
42779b256eSMatthias Ringwaldtrailer = '''
43779b256eSMatthias Ringwald#endif
44779b256eSMatthias Ringwald'''
45779b256eSMatthias Ringwald
46779b256eSMatthias Ringwaldtags = []
47779b256eSMatthias Ringwald
48ff7cea0bSMatthias Ringwalddef strip_non_ascii(string):
49ff7cea0bSMatthias Ringwald    stripped = (c for c in string if 0 < ord(c) < 127)
50ff7cea0bSMatthias Ringwald    return ''.join(stripped)
51ff7cea0bSMatthias Ringwald
52779b256eSMatthias Ringwalddef create_name(company):
53ff7cea0bSMatthias Ringwald    # limit to ascii
54ff7cea0bSMatthias Ringwald    company = strip_non_ascii(company)
55779b256eSMatthias Ringwald    # remove parts in braces
56779b256eSMatthias Ringwald    p = re.compile('\(.*\)')
57779b256eSMatthias Ringwald    tag = p.sub('',company).rstrip().upper()
58779b256eSMatthias Ringwald    tag = tag.replace('&AMP;',' AND ')
59779b256eSMatthias Ringwald    tag = tag.replace('&#39;','')
60779b256eSMatthias Ringwald    tag = tag.replace('&QUOT;',' ')
61779b256eSMatthias Ringwald    tag = tag.replace('+',' AND ')
62779b256eSMatthias Ringwald    tag = tag.replace(' - ', ' ')
63779b256eSMatthias Ringwald    tag = tag.replace('/', ' ')
64779b256eSMatthias Ringwald    tag = tag.replace(';',' ')
65779b256eSMatthias Ringwald    tag = tag.replace(',','')
66779b256eSMatthias Ringwald    tag = tag.replace('.', '')
67779b256eSMatthias Ringwald    tag = tag.replace('-','_')
68779b256eSMatthias Ringwald    tag = tag.replace('  ',' ')
69779b256eSMatthias Ringwald    tag = tag.replace(' ','_')
70ff7cea0bSMatthias Ringwald    tag = tag.replace('&','AND')
71ff7cea0bSMatthias Ringwald    tag = tag.replace("'","_")
72ff7cea0bSMatthias Ringwald    tag = tag.replace('"','_')
73ff7cea0bSMatthias Ringwald    tag = tag.replace('!','_')
74*77bd0381SMilanka Ringwald    tag = tag.replace('|','_')
75*77bd0381SMilanka Ringwald    tag = tag.replace('[','')
76*77bd0381SMilanka Ringwald    tag = tag.replace(']','')
77779b256eSMatthias Ringwald    return "BLUETOOTH_COMPANY_ID_" + tag
78779b256eSMatthias Ringwald
79*77bd0381SMilanka Ringwalddef parse_cvs(csv_file):
80*77bd0381SMilanka Ringwald    cvsreader = csv.reader(csv_file, delimiter=',', quotechar='\"')
81*77bd0381SMilanka Ringwald    # Skip header ['"Decimal","Hexadecimal","Company"']
82*77bd0381SMilanka Ringwald    next(cvsreader)
83ff7cea0bSMatthias Ringwald
84*77bd0381SMilanka Ringwald    companies = {}
85*77bd0381SMilanka Ringwald    for row in cvsreader:
86*77bd0381SMilanka Ringwald        id_dec = int(row[0])
87*77bd0381SMilanka Ringwald        companies[id_dec] = (row[1],row[2])
88*77bd0381SMilanka Ringwald    return companies
89*77bd0381SMilanka Ringwald
90*77bd0381SMilanka Ringwald
91*77bd0381SMilanka Ringwalddef write_cvs(fout, companies, url):
92*77bd0381SMilanka Ringwald    global tags
93d918542bSMatthias Ringwald    fout.write(page_info.format(page=url.replace('https://','')))
94779b256eSMatthias Ringwald
95*77bd0381SMilanka Ringwald    company_ids = sorted(list(companies.keys()))
96779b256eSMatthias Ringwald
97*77bd0381SMilanka Ringwald    for id_dec in company_ids:
98*77bd0381SMilanka Ringwald        id_hex = companies[id_dec][0]
99*77bd0381SMilanka Ringwald        company = create_name(companies[id_dec][1])
100779b256eSMatthias Ringwald
101779b256eSMatthias Ringwald        if company in tags:
102779b256eSMatthias Ringwald            company = company+"2"
103779b256eSMatthias Ringwald        else:
104779b256eSMatthias Ringwald            tags.append(company)
105*77bd0381SMilanka Ringwald
106779b256eSMatthias Ringwald        fout.write("#define %-80s %s\n" %  (company, id_hex))
107779b256eSMatthias Ringwald
108ff7cea0bSMatthias Ringwald    # map CSR onto QTIL
109ff7cea0bSMatthias Ringwald    fout.write("#define BLUETOOTH_COMPANY_ID_CAMBRIDGE_SILICON_RADIO BLUETOOTH_COMPANY_ID_QUALCOMM_TECHNOLOGIES_INTERNATIONAL_LTD\n")
110ff7cea0bSMatthias Ringwald
111*77bd0381SMilanka Ringwalddef main(argv):
112*77bd0381SMilanka Ringwald    url = "https://www.bluetooth.com/de/specifications/assigned-numbers/company-identifiers/#"
113779b256eSMatthias Ringwald    btstack_root = os.path.abspath(os.path.dirname(sys.argv[0]) + '/..')
114*77bd0381SMilanka Ringwald    tools_root = btstack_root + '/tool'
115*77bd0381SMilanka Ringwald    src_root   = btstack_root + '/src/'
116*77bd0381SMilanka Ringwald
117*77bd0381SMilanka Ringwald    header_filename = "bluetooth_company_id.h"
118*77bd0381SMilanka Ringwald    header_path = btstack_root + "/src/" + header_filename
119*77bd0381SMilanka Ringwald
120*77bd0381SMilanka Ringwald    cvs_filename = "CompanyIdentfiers - CSV.csv"
121*77bd0381SMilanka Ringwald    cvs_path = tools_root + "/" + cvs_filename
122779b256eSMatthias Ringwald
123779b256eSMatthias Ringwald    print(program_info)
124779b256eSMatthias Ringwald
125*77bd0381SMilanka Ringwald    try:
126*77bd0381SMilanka Ringwald        header_file = open(header_path, "w")
127*77bd0381SMilanka Ringwald    except FileNotFoundError:
128*77bd0381SMilanka Ringwald        print("\nFile \'%s\' cannot be created in \'%s\' directory." % (header_filename, src_root))
129*77bd0381SMilanka Ringwald        exit(1)
130779b256eSMatthias Ringwald
131*77bd0381SMilanka Ringwald    try:
132*77bd0381SMilanka Ringwald        with open(cvs_path, "r") as csv_file:
133*77bd0381SMilanka Ringwald            companies = parse_cvs(csv_file)
134*77bd0381SMilanka Ringwald
135*77bd0381SMilanka Ringwald            header_file.write(header.format(datetime=str(datetime.datetime.now())))
136*77bd0381SMilanka Ringwald            write_cvs(header_file, companies, url)
137*77bd0381SMilanka Ringwald            header_file.write(trailer)
138*77bd0381SMilanka Ringwald
139*77bd0381SMilanka Ringwald            print("Company IDs are stored in \'%s\'\n" % (header_path))
140*77bd0381SMilanka Ringwald    except FileNotFoundError:
141*77bd0381SMilanka Ringwald        print("\nCVS file \'%s\' not found in \'%s\'." % (cvs_filename, tools_root))
142*77bd0381SMilanka Ringwald        print("Please download the CVS file, then start the skript again.\n")
143*77bd0381SMilanka Ringwald        print("The CVS file can be downloaded from:")
144*77bd0381SMilanka Ringwald        print("     %s\n" % url)
145*77bd0381SMilanka Ringwald        exit(1)
146*77bd0381SMilanka Ringwald
147*77bd0381SMilanka Ringwaldif __name__ == "__main__":
148*77bd0381SMilanka Ringwald   main(sys.argv[1:])
149*77bd0381SMilanka Ringwald
150*77bd0381SMilanka Ringwald
151