Quelle bthledef.rs
Sprache: Rust
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0 > or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT >, at your option.
// All files in the project carrying such notice may not be copied, modified, or distributed
// except according to those terms.
use shared::basetsd::ULONG64;
use shared::guiddef::{GUID, IsEqualGUID};
use shared::minwindef::{UCHAR, ULONG, USHORT};
use um::winnt::{BOOLEAN, HANDLE, PVOID};
DEFINE_GUID!{GUID_BLUETOOTHLE_DEVICE_INTERFACE,
0 x781aee18,
0 x7733,
0 x4ce4,
0 xad,
0 xd0,
0 x91,
0 xf4,
0 x1c,
0 x67,
0 xb5,
0 x92}
DEFINE_GUID!{GUID_BLUETOOTH_GATT_SERVICE_DEVICE_INTERFACE,
0 x6e3bb679,
0 x4372,
0 x40c8,
0 x9e,
0 xaa,
0 x45,
0 x09,
0 xdf,
0 x26,
0 x0c,
0 xd8}
DEFINE_GUID!{BTH_LE_ATT_BLUETOOTH_BASE_GUID,
0 x00000000,
0 x0000,
0 x1000,
0 x80,
0 x00,
0 x00,
0 x80,
0 x5F,
0 x9B,
0 x34,
0 xFB}
pub const BTH_LE_SERVICE_GAP: USHORT =
0 x1800;
pub const BTH_LE_SERVICE_GATT: USHORT =
0 x1801;
pub const BTH_LE_GATT_ATTRIBUTE_TYPE_PRIMARY_SERVICE: USHORT =
0 x2800;
pub const BTH_LE_GATT_ATTRIBUTE_TYPE_SECONDARY_SERVICE: USHORT =
0 x2801;
pub const BTH_LE_GATT_ATTRIBUTE_TYPE_INCLUDE: USHORT =
0 x2802;
pub const BTH_LE_GATT_ATTRIBUTE_TYPE_CHARACTERISTIC: USHORT =
0 x2803;
pub const BTH_LE_GATT_CHARACTERISTIC_DESCRIPTOR_EXTENDED_PROPERTIES: USHORT =
0 x2900;
pub const BTH_LE_GATT_CHARACTERISTIC_DESCRIPTOR_USER_DESCRIPTION: USHORT =
0 x2901;
pub const BTH_LE_GATT_CHARACTERISTIC_DESCRIPTOR_CLIENT_CONFIGURATION: USHORT =
0 x2902
;
pub const BTH_LE_GATT_CHARACTERISTIC_DESCRIPTOR_SERVER_CONFIGURATION: USHORT = 0 x2903;
pub const BTH_LE_GATT_CHARACTERISTIC_DESCRIPTOR_FORMAT: USHORT = 0 x2904;
pub const BTH_LE_GATT_CHARACTERISTIC_DESCRIPTOR_AGGREGATE_FORMAT: USHORT = 0 x2905;
pub const BTH_LE_GATT_CHARACTERISTIC_TYPE_DEVICE_NAME: USHORT = 0 x2A00;
pub const BTH_LE_GATT_CHARACTERISTIC_TYPE_APPEARANCE: USHORT = 0 x2A01;
pub const BTH_LE_GATT_CHARACTERISTIC_TYPE_PERIPHERAL_PRIVACY_FLAG: USHORT = 0 x2A02;
pub const BTH_LE_GATT_CHARACTERISTIC_TYPE_RECONNECTION_ADDRESS: USHORT = 0 x2A03;
pub const BTH_LE_GATT_CHARACTERISTIC_TYPE_PERIPHERAL_PREFERED_CONNECTION_PARAMETER: USHORT
= 0 x2A04;
pub const BTH_LE_GATT_CHARACTERISTIC_TYPE_SERVICE_CHANGED: USHORT = 0 x2A05;
pub const BTH_LE_GAP_APPEARANCE_CATEGORY_OFFSET: u8 = 0 x6;
pub const BTH_LE_GAP_APPEARANCE_CATEGORY_MASK: USHORT = 0 x3ff;
#[ inline]
pub fn BTH_LE_GAP_APPEARANCE_GET_CATEGORY(a: USHORT) -> USHORT {
(a >> BTH_LE_GAP_APPEARANCE_CATEGORY_OFFSET) & BTH_LE_GAP_APPEARANCE_CATEGORY_MASK
}
#[ inline]
pub fn BTH_LE_GAP_APPEARANCE_SET_CATEGORY(a: &mut USHORT, c: USHORT) {
*a = (*a & !BTH_LE_GAP_APPEARANCE_CATEGORY_MASK)
| (c << BTH_LE_GAP_APPEARANCE_CATEGORY_OFFSET);
}
pub const BTH_LE_GAP_APPEARANCE_SUB_CATEGORY_MASK: USHORT = 0 x3f;
#[ inline]
pub fn BTH_LE_GAP_APPEARANCE_GET_SUB_CATEGORY(a: USHORT) -> UCHAR {
(a & BTH_LE_GAP_APPEARANCE_SUB_CATEGORY_MASK) as u8
}
#[ inline]
pub fn BTH_LE_GAP_APPEARANCE_SET_SUB_CATEGORY(a: &mut USHORT, s: UCHAR) {
*a = (*a & !BTH_LE_GAP_APPEARANCE_SUB_CATEGORY_MASK) | (s as u16);
}
pub const BTH_LE_GAP_APPEARANCE_CATEGORY_UNCATEGORIZED: USHORT = 0 x0000;
pub const BTH_LE_GAP_APPEARANCE_CATEGORY_PHONE: USHORT = 0 x0001;
pub const BTH_LE_GAP_APPEARANCE_CATEGORY_COMPUTER: USHORT = 0 x0002;
pub const BTH_LE_GAP_APPEARANCE_CATEGORY_WATCH: USHORT = 0 x0003;
pub const BTH_LE_GAP_APPEARANCE_CATEGORY_CLOCK: USHORT = 0 x0004;
pub const BTH_LE_GAP_APPEARANCE_CATEGORY_DISPLAY: USHORT = 0 x0005;
pub const BTH_LE_GAP_APPEARANCE_CATEGORY_REMOTE_CONTROL: USHORT = 0 x0006;
pub const BTH_LE_GAP_APPEARANCE_CATEGORY_EYE_GLASSES: USHORT = 0 x0007;
pub const BTH_LE_GAP_APPEARANCE_CATEGORY_TAG: USHORT = 0 x0008;
pub const BTH_LE_GAP_APPEARANCE_CATEGORY_KEYRING: USHORT = 0 x0009;
pub const BTH_LE_GAP_APPEARANCE_CATEGORY_MEDIA_PLAYER: USHORT = 0 x000a;
pub const BTH_LE_GAP_APPEARANCE_CATEGORY_BARCODE_SCANNER: USHORT = 0 x000b;
pub const BTH_LE_GAP_APPEARANCE_CATEGORY_THERMOMETER: USHORT = 0 x000c;
pub const BTH_LE_GAP_APPEARANCE_CATEGORY_HEART_RATE: USHORT = 0 x000d;
pub const BTH_LE_GAP_APPEARANCE_CATEGORY_BLOOD_PRESSURE: USHORT = 0 x000e;
pub const BTH_LE_GAP_APPEARANCE_CATEGORY_HID: USHORT = 0 x000f;
pub const BTH_LE_GAP_APPEARANCE_CATEGORY_GLUCOSE_METER: USHORT = 0 x0010;
pub const BTH_LE_GAP_APPEARANCE_CATEGORY_RUNNING_WALKING_SENSOR: USHORT = 0 x0011;
pub const BTH_LE_GAP_APPEARANCE_CATEGORY_CYCLING: USHORT = 0 x0012;
pub const BTH_LE_GAP_APPEARANCE_CATEGORY_PLUSE_OXIMETER: USHORT = 0 x0031;
pub const BTH_LE_GAP_APPEARANCE_CATEGORY_WEIGHT_SCALE: USHORT = 0 x0032;
pub const BTH_LE_GAP_APPEARANCE_CATEGORY_OUTDOOR_SPORTS_ACTIVITY: USHORT = 0 x0051;
pub const BTH_LE_GAP_APPEARANCE_SUBCATEGORY_GENERIC: UCHAR = 0 x00;
pub const BTH_LE_GAP_APPEARANCE_WATCH_SUBCATEGORY_SPORTS_WATCH: UCHAR = 0 x01;
pub const BTH_LE_GAP_APPEARANCE_THERMOMETER_SUBCATEGORY_EAR: UCHAR = 0 x01;
pub const BTH_LE_GAP_APPEARANCE_HEART_RATE_SUBCATEGORY_HEART_RATE_BELT: UCHAR = 0 x01;
pub const BTH_LE_GAP_APPEARANCE_BLOOD_PRESSURE_SUBCATEGORY_ARM: UCHAR = 0 x01;
pub const BTH_LE_GAP_APPEARANCE_BLOOD_PRESSURE_SUBCATEGORY_WRIST: UCHAR = 0 x02;
pub const BTH_LE_GAP_APPEARANCE_HID_SUBCATEGORY_KEYBOARD: UCHAR = 0 x01;
pub const BTH_LE_GAP_APPEARANCE_HID_SUBCATEGORY_MOUSE: UCHAR = 0 x02;
pub const BTH_LE_GAP_APPEARANCE_HID_SUBCATEGORY_JOYSTICK: UCHAR = 0 x03;
pub const BTH_LE_GAP_APPEARANCE_HID_SUBCATEGORY_GAMEPAD: UCHAR = 0 x04;
pub const BTH_LE_GAP_APPEARANCE_HID_SUBCATEGORY_DIGITIZER_TABLET: UCHAR = 0 x05;
pub const BTH_LE_GAP_APPEARANCE_HID_SUBCATEGORY_CARD_READER: UCHAR = 0 x06;
pub const BTH_LE_GAP_APPEARANCE_HID_SUBCATEGORY_DIGITAL_PEN: UCHAR = 0 x07;
pub const BTH_LE_GAP_APPEARANCE_HID_SUBCATEGORY_BARCODE_SCANNER: UCHAR = 0 x08;
pub const BTH_LE_GAP_APPEARANCE_RUNNING_WALKING_SENSOR_SUBCATEGORY_IN_SHOE: UCHAR = 0 x01;
pub const BTH_LE_GAP_APPEARANCE_RUNNING_WALKING_SENSOR_SUBCATEGORY_ON_SHOE: UCHAR = 0 x02;
pub const BTH_LE_GAP_APPEARANCE_RUNNING_WALKING_SENSOR_SUBCATEGORY_ON_HIP: UCHAR = 0 x03;
pub const BTH_LE_GAP_APPEARANCE_CYCLING_SUBCATEGORY_CYCLING_COMPUTER: UCHAR = 0 x01;
pub const BTH_LE_GAP_APPEARANCE_CYCLING_SUBCATEGORY_SPEED_SENSOR: UCHAR = 0 x02;
pub const BTH_LE_GAP_APPEARANCE_CYCLING_SUBCATEGORY_CADENCE_SENSOR: UCHAR = 0 x03;
pub const BTH_LE_GAP_APPEARANCE_CYCLING_SUBCATEGORY_POWER_SENSOR: UCHAR = 0 x04;
pub const BTH_LE_GAP_APPEARANCE_CYCLING_SUBCATEGORY_SPEED_AND_CADENCE_SENSOR: UCHAR = 0 x05;
pub const BTH_LE_GAP_APPEARANCE_PULSE_OXIMETER_SUBCATEGORY_FINGERTIP: UCHAR = 0 x01;
pub const BTH_LE_GAP_APPEARANCE_PULSE_OXIMETER_SUBCATEGORY_WRIST_WORN: UCHAR = 0 x02;
pub const BTH_LE_GAP_APPEARANCE_OUTDOOR_SPORTS_ACTIVITY_SUBCATEGORY_LOCATION_DISPLAY_DEVICE: UCHAR
= 0 x01;
pub const
BTH_LE_GAP_APPEARANCE_OUTDOOR_SPORTS_ACTIVITY_SUBCATEGORY_LOCATION_NAVIGATION_DISPLAY_DEVICE:
UCHAR = 0 x02;
pub const BTH_LE_GAP_APPEARANCE_OUTDOOR_SPORTS_ACTIVITY_SUBCATEGORY_LOCATION_POD: UCHAR = 0 x03;
pub const BTH_LE_GAP_APPEARANCE_OUTDOOR_SPORTS_ACTIVITY_SUBCATEGORY_LOCATION_NAVIGATION_POD: UCHAR
= 0 x04;
pub const BTH_LE_GATT_DEFAULT_MAX_INCLUDED_SERVICES_DEPTH: USHORT = 3 ;
pub const BTH_LE_ATT_TRANSACTION_TIMEOUT: USHORT = 30 ;
pub const BTH_LE_ATT_MAX_VALUE_SIZE: USHORT = 512 ;
pub const BTH_LE_ATT_CID: USHORT = 0 x0004;
pub const BTHLEENUM_ATT_MTU_MIN: USHORT = 23 ;
// #define BTHLEENUM_ATT_MTU_MAX (MAX_USHORT)
pub const BTHLEENUM_ATT_MTU_DEFAULT: USHORT = BTHLEENUM_ATT_MTU_MIN;
pub const BTHLEENUM_ATT_MTU_INITIAL_NEGOTIATION: USHORT = 525 ;
pub const BTH_LE_ERROR_INVALID_HANDLE: USHORT = 0 x01;
pub const BTH_LE_ERROR_READ_NOT_PERMITTED: USHORT = 0 x02;
pub const BTH_LE_ERROR_WRITE_NOT_PERMITTED: USHORT = 0 x03;
pub const BTH_LE_ERROR_INVALID_PDU: USHORT = 0 x04;
pub const BTH_LE_ERROR_INSUFFICIENT_AUTHENTICATION: USHORT = 0 x05;
pub const BTH_LE_ERROR_REQUEST_NOT_SUPPORTED: USHORT = 0 x06;
pub const BTH_LE_ERROR_INVALID_OFFSET: USHORT = 0 x07;
pub const BTH_LE_ERROR_INSUFFICIENT_AUTHORIZATION: USHORT = 0 x08;
pub const BTH_LE_ERROR_PREPARE_QUEUE_FULL: USHORT = 0 x09;
pub const BTH_LE_ERROR_ATTRIBUTE_NOT_FOUND: USHORT = 0 x0A;
pub const BTH_LE_ERROR_ATTRIBUTE_NOT_LONG: USHORT = 0 x0B;
pub const BTH_LE_ERROR_INSUFFICIENT_ENCRYPTION_KEY_SIZE: USHORT = 0 x0C;
pub const BTH_LE_ERROR_INVALID_ATTRIBUTE_VALUE_LENGTH: USHORT = 0 x0D;
pub const BTH_LE_ERROR_UNLIKELY: USHORT = 0 x0E;
pub const BTH_LE_ERROR_INSUFFICIENT_ENCRYPTION: USHORT = 0 x0F;
pub const BTH_LE_ERROR_UNSUPPORTED_GROUP_TYPE: USHORT = 0 x10;
pub const BTH_LE_ERROR_INSUFFICIENT_RESOURCES: USHORT = 0 x11;
pub const BTH_LE_ERROR_UNKNOWN: USHORT = 0 x1000;
pub const BLUETOOTH_GATT_FLAG_NONE: ULONG = 0 x00000000;
pub const BLUETOOTH_GATT_FLAG_CONNECTION_ENCRYPTED: ULONG = 0 x00000001;
pub const BLUETOOTH_GATT_FLAG_CONNECTION_AUTHENTICATED: ULONG = 0 x00000002;
pub const BLUETOOTH_GATT_FLAG_FORCE_READ_FROM_DEVICE: ULONG = 0 x00000004;
pub const BLUETOOTH_GATT_FLAG_FORCE_READ_FROM_CACHE: ULONG = 0 x00000008;
pub const BLUETOOTH_GATT_FLAG_SIGNED_WRITE: ULONG = 0 x00000010;
pub const BLUETOOTH_GATT_FLAG_WRITE_WITHOUT_RESPONSE: ULONG = 0 x00000020;
pub const BLUETOOTH_GATT_FLAG_RETURN_ALL: ULONG = 0 x00000040;
pub const BLUETOOTH_GATT_FLAG_VALID_MASK: ULONG = BLUETOOTH_GATT_FLAG_NONE
| BLUETOOTH_GATT_FLAG_CONNECTION_ENCRYPTED | BLUETOOTH_GATT_FLAG_CONNECTION_AUTHENTICATED
| BLUETOOTH_GATT_FLAG_FORCE_READ_FROM_DEVICE | BLUETOOTH_GATT_FLAG_FORCE_READ_FROM_CACHE
| BLUETOOTH_GATT_FLAG_SIGNED_WRITE | BLUETOOTH_GATT_FLAG_WRITE_WITHOUT_RESPONSE
| BLUETOOTH_GATT_FLAG_RETURN_ALL;
#[ inline]
pub fn IS_BLUETOOTH_GATT_FLAG_VALID(f: ULONG) -> bool {
(f & !BLUETOOTH_GATT_FLAG_VALID_MASK) == 0
}
pub type BLUETOOTH_GATT_EVENT_HANDLE = HANDLE;
UNION!{union BTH_LE_UUID_value {
[u32; 4 ],
ShortUuid ShortUuid_mut: USHORT,
LongUuid LongUuid_mut: GUID,
}}
STRUCT !{struct BTH_LE_UUID {
IsShortUuid: BOOLEAN,
Value: BTH_LE_UUID_value,
}}
pub type PBTH_LE_UUID = *mut BTH_LE_UUID;
STRUCT !{struct BTH_LE_GATT_SERVICE {
ServiceUuid: BTH_LE_UUID,
AttributeHandle: USHORT,
}}
pub type PBTH_LE_GATT_SERVICE = *mut BTH_LE_GATT_SERVICE;
ENUM !{enum BTH_LE_GATT_DESCRIPTOR_TYPE {
CharacteristicExtendedProperties,
CharacteristicUserDescription,
ClientCharacteristicConfiguration,
ServerCharacteristicConfiguration,
CharacteristicFormat,
CharacteristicAggregateFormat,
CustomDescriptor,
}}
pub type PBTH_LE_GATT_DESCRIPTOR_TYPE = *mut BTH_LE_GATT_DESCRIPTOR_TYPE;
STRUCT !{struct BTH_LE_GATT_CHARACTERISTIC {
ServiceHandle: USHORT,
CharacteristicUuid: BTH_LE_UUID,
AttributeHandle: USHORT,
CharacteristicValueHandle: USHORT,
IsBroadcastable: BOOLEAN,
IsReadable: BOOLEAN,
IsWritable: BOOLEAN,
IsWritableWithoutResponse: BOOLEAN,
IsSignedWritable: BOOLEAN,
IsNotifiable: BOOLEAN,
IsIndicatable: BOOLEAN,
HasExtendedProperties: BOOLEAN,
}}
pub type PBTH_LE_GATT_CHARACTERISTIC = *mut BTH_LE_GATT_CHARACTERISTIC;
STRUCT !{struct BTH_LE_GATT_CHARACTERISTIC_VALUE {
DataSize: ULONG,
Data: [UCHAR; 1 ],
}}
pub type PBTH_LE_GATT_CHARACTERISTIC_VALUE = *mut BTH_LE_GATT_CHARACTERISTIC_VALUE;
STRUCT !{struct BTH_LE_GATT_DESCRIPTOR {
ServiceHandle: USHORT,
CharacteristicHandle: USHORT,
DescriptorType: BTH_LE_GATT_DESCRIPTOR_TYPE,
DescriptorUuid: BTH_LE_UUID,
AttributeHandle: USHORT,
}}
pub type PBTH_LE_GATT_DESCRIPTOR = *mut BTH_LE_GATT_DESCRIPTOR;
STRUCT !{struct BTH_LE_GATT_DESCRIPTOR_VALUE_u_CharacteristicExtendedProperties {
IsReliableWriteEnabled: BOOLEAN,
IsAuxiliariesWritable: BOOLEAN,
}}
STRUCT !{struct BTH_LE_GATT_DESCRIPTOR_VALUE_u_ClientCharacteristicConfiguration {
IsSubscribeToNotification: BOOLEAN,
IsSubscribeToIndication: BOOLEAN,
}}
STRUCT !{struct BTH_LE_GATT_DESCRIPTOR_VALUE_u_ServerCharacteristicConfiguration {
IsBroadcast: BOOLEAN,
}}
STRUCT !{struct BTH_LE_GATT_DESCRIPTOR_VALUE_u_CharacteristicFormat {
Format: UCHAR,
Exponent: UCHAR,
Unit: BTH_LE_UUID,
NameSpace: UCHAR,
Description: BTH_LE_UUID,
}}
UNION!{union BTH_LE_GATT_DESCRIPTOR_VALUE_u {
[u32; 12 ],
CharacteristicExtendedProperties CharacteristicExtendedProperties_mut:
BTH_LE_GATT_DESCRIPTOR_VALUE_u_CharacteristicExtendedProperties,
ClientCharacteristicConfiguration ClientCharacteristicConfiguration_mut:
BTH_LE_GATT_DESCRIPTOR_VALUE_u_ClientCharacteristicConfiguration,
ServerCharacteristicConfiguration ServerCharacteristicConfiguration_mut:
BTH_LE_GATT_DESCRIPTOR_VALUE_u_ServerCharacteristicConfiguration,
CharacteristicFormat CharacteristicFormat_mut:
BTH_LE_GATT_DESCRIPTOR_VALUE_u_CharacteristicFormat,
}}
STRUCT !{struct BTH_LE_GATT_DESCRIPTOR_VALUE {
DescriptorType: BTH_LE_GATT_DESCRIPTOR_TYPE,
DescriptorUuid: BTH_LE_UUID,
u: BTH_LE_GATT_DESCRIPTOR_VALUE_u,
DataSize: ULONG,
Data: [UCHAR; 1 ],
}}
pub type PBTH_LE_GATT_DESCRIPTOR_VALUE = *mut BTH_LE_GATT_DESCRIPTOR_VALUE;
ENUM !{enum BTH_LE_GATT_EVENT_TYPE {
CharacteristicValueChangedEvent,
}}
FN !{stdcall PFNBLUETOOTH_GATT_EVENT_CALLBACK(
EventType: BTH_LE_GATT_EVENT_TYPE,
EventOutParameter: PVOID,
Context: PVOID,
) -> ()}
STRUCT !{struct BLUETOOTH_GATT_VALUE_CHANGED_EVENT_REGISTRATION {
NumCharacteristics: USHORT,
Characteristics: [BTH_LE_GATT_CHARACTERISTIC; 1 ],
}}
pub type PBLUETOOTH_GATT_VALUE_CHANGED_EVENT_REGISTRATION
= *mut BLUETOOTH_GATT_VALUE_CHANGED_EVENT_REGISTRATION;
STRUCT !{struct BLUETOOTH_GATT_VALUE_CHANGED_EVENT {
ChangedAttributeHandle: USHORT,
CharacteristicValueDataSize: usize,
CharacteristicValue: PBTH_LE_GATT_CHARACTERISTIC_VALUE,
}}
pub type PBLUETOOTH_GATT_VALUE_CHANGED_EVENT = *mut BLUETOOTH_GATT_VALUE_CHANGED_EVENT;
pub type BTH_LE_GATT_RELIABLE_WRITE_CONTEXT = ULONG64;
pub type PBTH_LE_GATT_RELIABLE_WRITE_CONTEXT = *mut ULONG64;
#[ inline]
pub fn IsBthLEUuidMatch(uuid1: &BTH_LE_UUID, uuid2: &BTH_LE_UUID) -> bool {
fn is_bluetooth_le_uuid(uuid: &GUID) -> bool {
uuid.Data2 == BTH_LE_ATT_BLUETOOTH_BASE_GUID.Data2
&& uuid.Data3 == BTH_LE_ATT_BLUETOOTH_BASE_GUID.Data3
&& uuid.Data4 == BTH_LE_ATT_BLUETOOTH_BASE_GUID.Data4
}
unsafe { match (uuid1.IsShortUuid != 0 , uuid2.IsShortUuid != 0 ) {
(true , true ) => uuid1.Value.ShortUuid() == uuid2.Value.ShortUuid(),
(false , false ) => IsEqualGUID(uuid1.Value.LongUuid(), uuid2.Value.LongUuid()),
(true , false ) => is_bluetooth_le_uuid(uuid2.Value.LongUuid())
&& ((*uuid1.Value.ShortUuid()) as u32) == uuid2.Value.LongUuid().Data1,
(false , true ) => is_bluetooth_le_uuid(uuid1.Value.LongUuid())
&& ((*uuid2.Value.ShortUuid()) as u32) == uuid1.Value.LongUuid().Data1,
}}
}
Messung V0.5 in Prozent C=95 H=100 G=97
¤ Dauer der Verarbeitung: 0.11 Sekunden
(vorverarbeitet am 2026-06-18)
¤
*© Formatika GbR, Deutschland
2026-07-09