13
13
# See the License for the specific language governing permissions and
14
14
# limitations under the License.
15
15
16
+ import dataclasses
16
17
import enum
17
18
import logging
18
19
import os
26
27
from stringcase import capitalcase
27
28
28
29
29
- def FieldToGlobalName (field : Field , context : TypeLookupContext ) -> Union [str , None ]:
30
- """Global names are used for generic callbacks shared across
31
- all clusters (e.g. for bool/float/uint32 and similar)
32
- """
33
- if field .is_list :
34
- return None # lists are always specific per cluster
30
+ @dataclasses .dataclass
31
+ class GenerateTarget :
32
+ template : str
33
+ output_name : str
35
34
36
- if FieldQuality .NULLABLE & field .qualities :
37
- return None
38
35
39
- if FieldQuality .OPTIONAL & field .qualities :
40
- return None
36
+ @dataclasses .dataclass
37
+ class GlobalType :
38
+ name : str # java name
39
+ cpp_type : str # underlying type
40
+
41
+
42
+ # types that java should see globally
43
+ _GLOBAL_TYPES = [
44
+ GlobalType ("Boolean" , "bool" ),
45
+ GlobalType ("CharString" , "const chip::CharSpan" ),
46
+ GlobalType ("Double" , "double" ),
47
+ GlobalType ("Float" , "float" ),
48
+ GlobalType ("Int8s" , "int8_t" ),
49
+ GlobalType ("Int8u" , "uint8_t" ),
50
+ GlobalType ("Int16s" , "int16_t" ),
51
+ GlobalType ("Int16u" , "uint16_t" ),
52
+ GlobalType ("Int32s" , "int32_t" ),
53
+ GlobalType ("Int32u" , "uint32_t" ),
54
+ GlobalType ("Int64s" , "int64_t" ),
55
+ GlobalType ("Int64u" , "uint64_t" ),
56
+ GlobalType ("OctetString" , "const chip::ByteSpan" ),
57
+ ]
41
58
59
+
60
+ def _UnderlyingType (field : Field , context : TypeLookupContext ) -> Union [str , None ]:
42
61
actual = ParseDataType (field .data_type , context )
43
62
if type (actual ) == IdlEnumType :
44
63
actual = actual .base_type
@@ -68,6 +87,99 @@ def FieldToGlobalName(field: Field, context: TypeLookupContext) -> Union[str, No
68
87
return None
69
88
70
89
90
+ def FieldToGlobalName (field : Field , context : TypeLookupContext ) -> Union [str , None ]:
91
+ """Global names are used for generic callbacks shared across
92
+ all clusters (e.g. for bool/float/uint32 and similar)
93
+ """
94
+ if field .is_list :
95
+ return None # lists are always specific per cluster
96
+
97
+ if FieldQuality .NULLABLE & field .qualities :
98
+ return None
99
+
100
+ if FieldQuality .OPTIONAL & field .qualities :
101
+ return None
102
+
103
+ return _UnderlyingType (field , context )
104
+
105
+
106
+ # Based on atomicType in ZAP:
107
+ # src-electron/generator/matter/app/zap-templates/common/override.js
108
+ _KNOWN_DECODABLE_TYPES = {
109
+ 'action_id' : 'chip::ActionId' ,
110
+ 'attrib_id' : 'chip::AttributeId' ,
111
+ 'cluster_id' : 'chip::ClusterId' ,
112
+ 'command_id' : 'chip::CommandId' ,
113
+ 'data_ver' : 'chip::DataVersion' ,
114
+ 'devtype_id' : 'chip::DeviceTypeId' ,
115
+ 'endpoint_no' : 'chip::EndpointId' ,
116
+ 'eui64' : 'chip::NodeId' ,
117
+ 'event_id' : 'chip::EventId' ,
118
+ 'event_no' : 'chip::EventNumber' ,
119
+ 'fabric_id' : 'chip::FabricId' ,
120
+ 'fabric_idx' : 'chip::FabricIndex' ,
121
+ 'fabric_idx' : 'chip::FabricIndex' ,
122
+ 'field_id' : 'chip::FieldId' ,
123
+ 'group_id' : 'chip::GroupId' ,
124
+ 'node_id' : 'chip::NodeId' ,
125
+ 'percent' : 'chip::Percent' ,
126
+ 'percent100ths' : 'chip::Percent100ths' ,
127
+ 'transaction_id' : 'chip::TransactionId' ,
128
+ 'vendor_id' : 'chip::VendorId' ,
129
+
130
+ # non-named enums
131
+ 'enum8' : 'uint8_t' ,
132
+ 'enum16' : 'uint16_t' ,
133
+ 'enum32' : 'uint32_t' ,
134
+ 'enum64' : 'uint64_t' ,
135
+ }
136
+
137
+
138
+ def _CppType (field : Field , context : TypeLookupContext ) -> Union [str , None ]:
139
+ if field .data_type .name .lower () in _KNOWN_DECODABLE_TYPES :
140
+ return _KNOWN_DECODABLE_TYPES [field .data_type .name .lower ()]
141
+
142
+ actual = ParseDataType (field .data_type , context )
143
+ if isinstance (actual , BasicString ):
144
+ if actual .is_binary :
145
+ return 'chip::ByteSpan'
146
+ else :
147
+ return 'chip::CharSpan'
148
+ elif isinstance (actual , BasicInteger ):
149
+ if actual .is_signed :
150
+ return "int{}_t" .format (actual .power_of_two_bits )
151
+ else :
152
+ return "uint{}_t" .format (actual .power_of_two_bits )
153
+ elif isinstance (actual , FundamentalType ):
154
+ if actual == FundamentalType .BOOL :
155
+ return 'bool'
156
+ elif actual == FundamentalType .FLOAT :
157
+ return 'float'
158
+ elif actual == FundamentalType .DOUBLE :
159
+ return 'double'
160
+ else :
161
+ logging .warn ('Unknown fundamental type: %r' % actual )
162
+ elif isinstance (actual , IdlType ):
163
+ return f"chip::app::Clusters::{ context .cluster .name } ::Structs::{ field .data_type .name } ::DecodableType"
164
+ elif isinstance (actual , IdlBitmapType ):
165
+ return f"chip::BitMask<chip::app::Clusters::{ context .cluster .name } ::{ field .data_type .name } >"
166
+
167
+ # Handles IdlEnumType
168
+ return f"chip::app::Clusters::{ context .cluster .name } ::{ field .data_type .name } "
169
+
170
+
171
+ def DecodableJniType (field : Field , context : TypeLookupContext ) -> str :
172
+ actual = _CppType (field , context )
173
+
174
+ if field .is_list :
175
+ return f"const chip::app::DataModel::DecodableList<{ actual } > &"
176
+
177
+ if field .is_nullable :
178
+ return f"const chip::app::DataModel::Nullable<{ actual } > &"
179
+
180
+ return actual
181
+
182
+
71
183
def GlobalNameToJavaName (name : str ) -> str :
72
184
if name in {'Int8u' , 'Int8s' , 'Int16u' , 'Int16s' }:
73
185
return 'Integer'
@@ -143,6 +255,51 @@ def attributesWithSupportedCallback(attrs, context: TypeLookupContext):
143
255
yield attr
144
256
145
257
258
+ def _IsUsingGlobalCallback (field : Field , context : TypeLookupContext ):
259
+ """Test to determine if the data type of a field can use one of
260
+ the global callbacks (i.e. it is a basic double/integer/bool etc.)
261
+ """
262
+ if field .is_list :
263
+ return False
264
+
265
+ if field .is_nullable :
266
+ return False
267
+
268
+ return field .data_type .name in {
269
+ "boolean" ,
270
+ "single" ,
271
+ "double" ,
272
+ "int8s" ,
273
+ "int8u" ,
274
+ "int16s" ,
275
+ "int16u" ,
276
+ "int24s" ,
277
+ "int24u" ,
278
+ "int32s" ,
279
+ "int32u" ,
280
+ "int40s" ,
281
+ "int40u" ,
282
+ "int48s" ,
283
+ "int48u" ,
284
+ "int56s" ,
285
+ "int56u" ,
286
+ "int64s" ,
287
+ "int64u" ,
288
+ "enum8" ,
289
+ "enum16" ,
290
+ "enum32" ,
291
+ "enum64" ,
292
+ "bitmap8" ,
293
+ "bitmap16" ,
294
+ "bitmap32" ,
295
+ "bitmap64" ,
296
+ "char_string" ,
297
+ "long_char_string" ,
298
+ "octet_string" ,
299
+ "long_octet_string" ,
300
+ }
301
+
302
+
146
303
def NamedFilter (choices : List , name : str ):
147
304
for choice in choices :
148
305
if choice .name == name :
@@ -419,8 +576,10 @@ def __init__(self, storage: GeneratorStorage, idl: Idl, **kargs):
419
576
self .jinja_env .filters ['asEncodable' ] = EncodableValueFrom
420
577
self .jinja_env .filters ['createLookupContext' ] = CreateLookupContext
421
578
self .jinja_env .filters ['canGenerateSubscribe' ] = CanGenerateSubscribe
579
+ self .jinja_env .filters ['decodableJniType' ] = DecodableJniType
422
580
423
581
self .jinja_env .tests ['is_response_struct' ] = IsResponseStruct
582
+ self .jinja_env .tests ['is_using_global_callback' ] = _IsUsingGlobalCallback
424
583
425
584
426
585
class JavaJNIGenerator (__JavaCodeGenerator ):
@@ -434,6 +593,31 @@ def internal_render_all(self):
434
593
Renders .CPP files required for JNI support.
435
594
"""
436
595
596
+ large_targets = [
597
+ GenerateTarget (template = "CHIPCallbackTypes.jinja" ,
598
+ output_name = "jni/CHIPCallbackTypes.h" ),
599
+ GenerateTarget (template = "CHIPReadCallbacks_h.jinja" ,
600
+ output_name = "jni/CHIPReadCallbacks.h" )
601
+ ]
602
+
603
+ for target in large_targets :
604
+ self .internal_render_one_output (
605
+ template_path = target .template ,
606
+ output_file_name = target .output_name ,
607
+ vars = {
608
+ 'idl' : self .idl ,
609
+ 'clientClusters' : [c for c in self .idl .clusters if c .side == ClusterSide .CLIENT ],
610
+ 'globalTypes' : _GLOBAL_TYPES ,
611
+ }
612
+ )
613
+
614
+ cluster_targets = [
615
+ GenerateTarget (template = "ChipClustersRead.jinja" ,
616
+ output_name = "jni/{cluster_name}Client-ReadImpl.cpp" ),
617
+ GenerateTarget (template = "ChipClustersCpp.jinja" ,
618
+ output_name = "jni/{cluster_name}Client-InvokeSubscribeImpl.cpp" ),
619
+ ]
620
+
437
621
self .internal_render_one_output (
438
622
template_path = "CHIPCallbackTypes.jinja" ,
439
623
output_file_name = "jni/CHIPCallbackTypes.h" ,
@@ -449,23 +633,17 @@ def internal_render_all(self):
449
633
if cluster .side != ClusterSide .CLIENT :
450
634
continue
451
635
452
- self .internal_render_one_output (
453
- template_path = "ChipClustersRead.jinja" ,
454
- output_file_name = "jni/%sClient-ReadImpl.cpp" % cluster .name ,
455
- vars = {
456
- 'cluster' : cluster ,
457
- 'typeLookup' : TypeLookupContext (self .idl , cluster ),
458
- }
459
- )
460
-
461
- self .internal_render_one_output (
462
- template_path = "ChipClustersCpp.jinja" ,
463
- output_file_name = "jni/%sClient-InvokeSubscribeImpl.cpp" % cluster .name ,
464
- vars = {
465
- 'cluster' : cluster ,
466
- 'typeLookup' : TypeLookupContext (self .idl , cluster ),
467
- }
468
- )
636
+ for target in cluster_targets :
637
+ self .internal_render_one_output (
638
+ template_path = target .template ,
639
+ output_file_name = target .output_name .format (
640
+ cluster_name = cluster .name ),
641
+ vars = {
642
+ 'cluster' : cluster ,
643
+ 'typeLookup' : TypeLookupContext (self .idl , cluster ),
644
+ 'globalTypes' : _GLOBAL_TYPES ,
645
+ }
646
+ )
469
647
470
648
471
649
class JavaClassGenerator (__JavaCodeGenerator ):
0 commit comments