接入基本设备
This commit is contained in:
parent
2f84f70a5f
commit
7729332f41
BIN
Assets/Resources/Images/Bluetooth_0.png
Normal file
BIN
Assets/Resources/Images/Bluetooth_0.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.9 KiB |
104
Assets/Resources/Images/Bluetooth_0.png.meta
Normal file
104
Assets/Resources/Images/Bluetooth_0.png.meta
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 05133d14d67abd743954cf1d04471e99
|
||||||
|
TextureImporter:
|
||||||
|
internalIDToNameTable: []
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 11
|
||||||
|
mipmaps:
|
||||||
|
mipMapMode: 0
|
||||||
|
enableMipMap: 0
|
||||||
|
sRGBTexture: 1
|
||||||
|
linearTexture: 0
|
||||||
|
fadeOut: 0
|
||||||
|
borderMipMap: 0
|
||||||
|
mipMapsPreserveCoverage: 0
|
||||||
|
alphaTestReferenceValue: 0.5
|
||||||
|
mipMapFadeDistanceStart: 1
|
||||||
|
mipMapFadeDistanceEnd: 3
|
||||||
|
bumpmap:
|
||||||
|
convertToNormalMap: 0
|
||||||
|
externalNormalMap: 0
|
||||||
|
heightScale: 0.25
|
||||||
|
normalMapFilter: 0
|
||||||
|
isReadable: 0
|
||||||
|
streamingMipmaps: 0
|
||||||
|
streamingMipmapsPriority: 0
|
||||||
|
grayScaleToAlpha: 0
|
||||||
|
generateCubemap: 6
|
||||||
|
cubemapConvolution: 0
|
||||||
|
seamlessCubemap: 0
|
||||||
|
textureFormat: 1
|
||||||
|
maxTextureSize: 2048
|
||||||
|
textureSettings:
|
||||||
|
serializedVersion: 2
|
||||||
|
filterMode: -1
|
||||||
|
aniso: -1
|
||||||
|
mipBias: -100
|
||||||
|
wrapU: 1
|
||||||
|
wrapV: 1
|
||||||
|
wrapW: -1
|
||||||
|
nPOTScale: 0
|
||||||
|
lightmap: 0
|
||||||
|
compressionQuality: 50
|
||||||
|
spriteMode: 1
|
||||||
|
spriteExtrude: 1
|
||||||
|
spriteMeshType: 1
|
||||||
|
alignment: 0
|
||||||
|
spritePivot: {x: 0.5, y: 0.5}
|
||||||
|
spritePixelsToUnits: 100
|
||||||
|
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
spriteGenerateFallbackPhysicsShape: 1
|
||||||
|
alphaUsage: 1
|
||||||
|
alphaIsTransparency: 1
|
||||||
|
spriteTessellationDetail: -1
|
||||||
|
textureType: 8
|
||||||
|
textureShape: 1
|
||||||
|
singleChannelComponent: 0
|
||||||
|
maxTextureSizeSet: 0
|
||||||
|
compressionQualitySet: 0
|
||||||
|
textureFormatSet: 0
|
||||||
|
applyGammaDecoding: 0
|
||||||
|
platformSettings:
|
||||||
|
- serializedVersion: 3
|
||||||
|
buildTarget: DefaultTexturePlatform
|
||||||
|
maxTextureSize: 2048
|
||||||
|
resizeAlgorithm: 0
|
||||||
|
textureFormat: -1
|
||||||
|
textureCompression: 1
|
||||||
|
compressionQuality: 50
|
||||||
|
crunchedCompression: 0
|
||||||
|
allowsAlphaSplitting: 0
|
||||||
|
overridden: 0
|
||||||
|
androidETC2FallbackOverride: 0
|
||||||
|
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||||
|
- serializedVersion: 3
|
||||||
|
buildTarget: Standalone
|
||||||
|
maxTextureSize: 2048
|
||||||
|
resizeAlgorithm: 0
|
||||||
|
textureFormat: -1
|
||||||
|
textureCompression: 1
|
||||||
|
compressionQuality: 50
|
||||||
|
crunchedCompression: 0
|
||||||
|
allowsAlphaSplitting: 0
|
||||||
|
overridden: 0
|
||||||
|
androidETC2FallbackOverride: 0
|
||||||
|
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||||
|
spriteSheet:
|
||||||
|
serializedVersion: 2
|
||||||
|
sprites: []
|
||||||
|
outline: []
|
||||||
|
physicsShape: []
|
||||||
|
bones: []
|
||||||
|
spriteID: 5e97eb03825dee720800000000000000
|
||||||
|
internalID: 0
|
||||||
|
vertices: []
|
||||||
|
indices:
|
||||||
|
edges: []
|
||||||
|
weights: []
|
||||||
|
secondaryTextures: []
|
||||||
|
spritePackingTag:
|
||||||
|
pSDRemoveMatte: 0
|
||||||
|
pSDShowRemoveMatteOption: 0
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
BIN
Assets/Resources/Images/Bluetooth_2.png
Normal file
BIN
Assets/Resources/Images/Bluetooth_2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.6 KiB |
104
Assets/Resources/Images/Bluetooth_2.png.meta
Normal file
104
Assets/Resources/Images/Bluetooth_2.png.meta
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 4990d472dee7f3b428ae030c3a2b936f
|
||||||
|
TextureImporter:
|
||||||
|
internalIDToNameTable: []
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 11
|
||||||
|
mipmaps:
|
||||||
|
mipMapMode: 0
|
||||||
|
enableMipMap: 0
|
||||||
|
sRGBTexture: 1
|
||||||
|
linearTexture: 0
|
||||||
|
fadeOut: 0
|
||||||
|
borderMipMap: 0
|
||||||
|
mipMapsPreserveCoverage: 0
|
||||||
|
alphaTestReferenceValue: 0.5
|
||||||
|
mipMapFadeDistanceStart: 1
|
||||||
|
mipMapFadeDistanceEnd: 3
|
||||||
|
bumpmap:
|
||||||
|
convertToNormalMap: 0
|
||||||
|
externalNormalMap: 0
|
||||||
|
heightScale: 0.25
|
||||||
|
normalMapFilter: 0
|
||||||
|
isReadable: 0
|
||||||
|
streamingMipmaps: 0
|
||||||
|
streamingMipmapsPriority: 0
|
||||||
|
grayScaleToAlpha: 0
|
||||||
|
generateCubemap: 6
|
||||||
|
cubemapConvolution: 0
|
||||||
|
seamlessCubemap: 0
|
||||||
|
textureFormat: 1
|
||||||
|
maxTextureSize: 2048
|
||||||
|
textureSettings:
|
||||||
|
serializedVersion: 2
|
||||||
|
filterMode: -1
|
||||||
|
aniso: -1
|
||||||
|
mipBias: -100
|
||||||
|
wrapU: 1
|
||||||
|
wrapV: 1
|
||||||
|
wrapW: -1
|
||||||
|
nPOTScale: 0
|
||||||
|
lightmap: 0
|
||||||
|
compressionQuality: 50
|
||||||
|
spriteMode: 1
|
||||||
|
spriteExtrude: 1
|
||||||
|
spriteMeshType: 1
|
||||||
|
alignment: 0
|
||||||
|
spritePivot: {x: 0.5, y: 0.5}
|
||||||
|
spritePixelsToUnits: 100
|
||||||
|
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
|
||||||
|
spriteGenerateFallbackPhysicsShape: 1
|
||||||
|
alphaUsage: 1
|
||||||
|
alphaIsTransparency: 1
|
||||||
|
spriteTessellationDetail: -1
|
||||||
|
textureType: 8
|
||||||
|
textureShape: 1
|
||||||
|
singleChannelComponent: 0
|
||||||
|
maxTextureSizeSet: 0
|
||||||
|
compressionQualitySet: 0
|
||||||
|
textureFormatSet: 0
|
||||||
|
applyGammaDecoding: 0
|
||||||
|
platformSettings:
|
||||||
|
- serializedVersion: 3
|
||||||
|
buildTarget: DefaultTexturePlatform
|
||||||
|
maxTextureSize: 2048
|
||||||
|
resizeAlgorithm: 0
|
||||||
|
textureFormat: -1
|
||||||
|
textureCompression: 1
|
||||||
|
compressionQuality: 50
|
||||||
|
crunchedCompression: 0
|
||||||
|
allowsAlphaSplitting: 0
|
||||||
|
overridden: 0
|
||||||
|
androidETC2FallbackOverride: 0
|
||||||
|
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||||
|
- serializedVersion: 3
|
||||||
|
buildTarget: Standalone
|
||||||
|
maxTextureSize: 2048
|
||||||
|
resizeAlgorithm: 0
|
||||||
|
textureFormat: -1
|
||||||
|
textureCompression: 1
|
||||||
|
compressionQuality: 50
|
||||||
|
crunchedCompression: 0
|
||||||
|
allowsAlphaSplitting: 0
|
||||||
|
overridden: 0
|
||||||
|
androidETC2FallbackOverride: 0
|
||||||
|
forceMaximumCompressionQuality_BC6H_BC7: 0
|
||||||
|
spriteSheet:
|
||||||
|
serializedVersion: 2
|
||||||
|
sprites: []
|
||||||
|
outline: []
|
||||||
|
physicsShape: []
|
||||||
|
bones: []
|
||||||
|
spriteID: 5e97eb03825dee720800000000000000
|
||||||
|
internalID: 0
|
||||||
|
vertices: []
|
||||||
|
indices:
|
||||||
|
edges: []
|
||||||
|
weights: []
|
||||||
|
secondaryTextures: []
|
||||||
|
spritePackingTag:
|
||||||
|
pSDRemoveMatte: 0
|
||||||
|
pSDShowRemoveMatteOption: 0
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@ -34,7 +34,7 @@ RectTransform:
|
|||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
m_AnchorMin: {x: 0, y: 1}
|
m_AnchorMin: {x: 0, y: 1}
|
||||||
m_AnchorMax: {x: 0, y: 1}
|
m_AnchorMax: {x: 0, y: 1}
|
||||||
m_AnchoredPosition: {x: 124, y: -40}
|
m_AnchoredPosition: {x: 60, y: -40}
|
||||||
m_SizeDelta: {x: 62, y: 64}
|
m_SizeDelta: {x: 62, y: 64}
|
||||||
m_Pivot: {x: 0, y: 1}
|
m_Pivot: {x: 0, y: 1}
|
||||||
--- !u!1 &2745425216517653314
|
--- !u!1 &2745425216517653314
|
||||||
@ -111,6 +111,43 @@ MonoBehaviour:
|
|||||||
m_FillOrigin: 0
|
m_FillOrigin: 0
|
||||||
m_UseSpriteMesh: 0
|
m_UseSpriteMesh: 0
|
||||||
m_PixelsPerUnitMultiplier: 1
|
m_PixelsPerUnitMultiplier: 1
|
||||||
|
--- !u!1 &2777627832895409916
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 2165555432541117810}
|
||||||
|
m_Layer: 5
|
||||||
|
m_Name: AntIcon
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!224 &2165555432541117810
|
||||||
|
RectTransform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 2777627832895409916}
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_Children:
|
||||||
|
- {fileID: 540031521672414432}
|
||||||
|
- {fileID: 4177612200037049886}
|
||||||
|
m_Father: {fileID: 6430829710355291381}
|
||||||
|
m_RootOrder: 0
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||||
|
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||||
|
m_AnchoredPosition: {x: 24.4, y: 1}
|
||||||
|
m_SizeDelta: {x: 44, y: 44}
|
||||||
|
m_Pivot: {x: 0.5, y: 0.5}
|
||||||
--- !u!1 &3159732546393567601
|
--- !u!1 &3159732546393567601
|
||||||
GameObject:
|
GameObject:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
@ -140,15 +177,15 @@ RectTransform:
|
|||||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
m_Children:
|
m_Children:
|
||||||
- {fileID: 540031521672414432}
|
- {fileID: 2165555432541117810}
|
||||||
- {fileID: 4177612200037049886}
|
- {fileID: 7669984967702354254}
|
||||||
m_Father: {fileID: 2716191576886074694}
|
m_Father: {fileID: 2716191576886074694}
|
||||||
m_RootOrder: 0
|
m_RootOrder: 0
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
m_AnchorMin: {x: 0, y: 1}
|
m_AnchorMin: {x: 0, y: 1}
|
||||||
m_AnchorMax: {x: 0, y: 1}
|
m_AnchorMax: {x: 0, y: 1}
|
||||||
m_AnchoredPosition: {x: 0, y: 0}
|
m_AnchoredPosition: {x: 0, y: 0}
|
||||||
m_SizeDelta: {x: 64, y: 64}
|
m_SizeDelta: {x: 118, y: 64}
|
||||||
m_Pivot: {x: 0, y: 1}
|
m_Pivot: {x: 0, y: 1}
|
||||||
--- !u!222 &6268486626046139400
|
--- !u!222 &6268486626046139400
|
||||||
CanvasRenderer:
|
CanvasRenderer:
|
||||||
@ -705,6 +742,80 @@ CanvasGroup:
|
|||||||
m_Interactable: 1
|
m_Interactable: 1
|
||||||
m_BlocksRaycasts: 1
|
m_BlocksRaycasts: 1
|
||||||
m_IgnoreParentGroups: 0
|
m_IgnoreParentGroups: 0
|
||||||
|
--- !u!1 &5162363420470615978
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 652708983550405284}
|
||||||
|
- component: {fileID: 2795585007386087676}
|
||||||
|
- component: {fileID: 6254887144258792832}
|
||||||
|
m_Layer: 5
|
||||||
|
m_Name: Image
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!224 &652708983550405284
|
||||||
|
RectTransform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 5162363420470615978}
|
||||||
|
m_LocalRotation: {x: 0.08715578, y: -0, z: -0, w: 0.9961947}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 7669984967702354254}
|
||||||
|
m_RootOrder: 1
|
||||||
|
m_LocalEulerAnglesHint: {x: 10, y: 0, z: 0}
|
||||||
|
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||||
|
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||||
|
m_AnchoredPosition: {x: 0, y: 0}
|
||||||
|
m_SizeDelta: {x: 44, y: 44}
|
||||||
|
m_Pivot: {x: 0.5, y: 0.5}
|
||||||
|
--- !u!222 &2795585007386087676
|
||||||
|
CanvasRenderer:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 5162363420470615978}
|
||||||
|
m_CullTransparentMesh: 0
|
||||||
|
--- !u!114 &6254887144258792832
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 5162363420470615978}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
m_Material: {fileID: 0}
|
||||||
|
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||||
|
m_RaycastTarget: 1
|
||||||
|
m_Maskable: 1
|
||||||
|
m_OnCullStateChanged:
|
||||||
|
m_PersistentCalls:
|
||||||
|
m_Calls: []
|
||||||
|
m_Sprite: {fileID: 21300000, guid: 407dc13d102a8d842bbaa773773df936, type: 3}
|
||||||
|
m_Type: 0
|
||||||
|
m_PreserveAspect: 0
|
||||||
|
m_FillCenter: 1
|
||||||
|
m_FillMethod: 4
|
||||||
|
m_FillAmount: 1
|
||||||
|
m_FillClockwise: 1
|
||||||
|
m_FillOrigin: 0
|
||||||
|
m_UseSpriteMesh: 0
|
||||||
|
m_PixelsPerUnitMultiplier: 1
|
||||||
--- !u!1 &5440549946619805752
|
--- !u!1 &5440549946619805752
|
||||||
GameObject:
|
GameObject:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
@ -741,7 +852,7 @@ RectTransform:
|
|||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
m_AnchorMin: {x: 0.5, y: 1}
|
m_AnchorMin: {x: 0.5, y: 1}
|
||||||
m_AnchorMax: {x: 0.5, y: 1}
|
m_AnchorMax: {x: 0.5, y: 1}
|
||||||
m_AnchoredPosition: {x: 0, y: -90}
|
m_AnchoredPosition: {x: 35.2, y: -90}
|
||||||
m_SizeDelta: {x: 134, y: 34}
|
m_SizeDelta: {x: 134, y: 34}
|
||||||
m_Pivot: {x: 0.5, y: 0.5}
|
m_Pivot: {x: 0.5, y: 0.5}
|
||||||
--- !u!222 &3527654833021650121
|
--- !u!222 &3527654833021650121
|
||||||
@ -974,11 +1085,11 @@ RectTransform:
|
|||||||
m_PrefabInstance: {fileID: 0}
|
m_PrefabInstance: {fileID: 0}
|
||||||
m_PrefabAsset: {fileID: 0}
|
m_PrefabAsset: {fileID: 0}
|
||||||
m_GameObject: {fileID: 6502171739230510504}
|
m_GameObject: {fileID: 6502171739230510504}
|
||||||
m_LocalRotation: {x: 0.08715578, y: 0, z: 0, w: 0.9961947}
|
m_LocalRotation: {x: 0.08715578, y: -0, z: -0, w: 0.9961947}
|
||||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
m_Children: []
|
m_Children: []
|
||||||
m_Father: {fileID: 6430829710355291381}
|
m_Father: {fileID: 2165555432541117810}
|
||||||
m_RootOrder: 1
|
m_RootOrder: 1
|
||||||
m_LocalEulerAnglesHint: {x: 10, y: 0, z: 0}
|
m_LocalEulerAnglesHint: {x: 10, y: 0, z: 0}
|
||||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||||
@ -1048,11 +1159,11 @@ RectTransform:
|
|||||||
m_PrefabInstance: {fileID: 0}
|
m_PrefabInstance: {fileID: 0}
|
||||||
m_PrefabAsset: {fileID: 0}
|
m_PrefabAsset: {fileID: 0}
|
||||||
m_GameObject: {fileID: 7066476020851680862}
|
m_GameObject: {fileID: 7066476020851680862}
|
||||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
m_Children: []
|
m_Children: []
|
||||||
m_Father: {fileID: 6430829710355291381}
|
m_Father: {fileID: 2165555432541117810}
|
||||||
m_RootOrder: 0
|
m_RootOrder: 0
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||||
@ -1175,6 +1286,117 @@ MonoBehaviour:
|
|||||||
m_VerticalOverflow: 0
|
m_VerticalOverflow: 0
|
||||||
m_LineSpacing: 1
|
m_LineSpacing: 1
|
||||||
m_Text: Searching...
|
m_Text: Searching...
|
||||||
|
--- !u!1 &8591994605769169618
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 6521823677394231837}
|
||||||
|
- component: {fileID: 743327725710735410}
|
||||||
|
- component: {fileID: 1839312524778472856}
|
||||||
|
m_Layer: 5
|
||||||
|
m_Name: Ble
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!224 &6521823677394231837
|
||||||
|
RectTransform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 8591994605769169618}
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 7669984967702354254}
|
||||||
|
m_RootOrder: 0
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
m_AnchorMin: {x: 0, y: 1}
|
||||||
|
m_AnchorMax: {x: 0, y: 1}
|
||||||
|
m_AnchoredPosition: {x: 0, y: 0}
|
||||||
|
m_SizeDelta: {x: 44, y: 44}
|
||||||
|
m_Pivot: {x: 0, y: 1}
|
||||||
|
--- !u!222 &743327725710735410
|
||||||
|
CanvasRenderer:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 8591994605769169618}
|
||||||
|
m_CullTransparentMesh: 0
|
||||||
|
--- !u!114 &1839312524778472856
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 8591994605769169618}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier:
|
||||||
|
m_Material: {fileID: 0}
|
||||||
|
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||||
|
m_RaycastTarget: 1
|
||||||
|
m_Maskable: 1
|
||||||
|
m_OnCullStateChanged:
|
||||||
|
m_PersistentCalls:
|
||||||
|
m_Calls: []
|
||||||
|
m_Sprite: {fileID: 21300000, guid: 05133d14d67abd743954cf1d04471e99, type: 3}
|
||||||
|
m_Type: 0
|
||||||
|
m_PreserveAspect: 0
|
||||||
|
m_FillCenter: 1
|
||||||
|
m_FillMethod: 4
|
||||||
|
m_FillAmount: 1
|
||||||
|
m_FillClockwise: 1
|
||||||
|
m_FillOrigin: 0
|
||||||
|
m_UseSpriteMesh: 0
|
||||||
|
m_PixelsPerUnitMultiplier: 1
|
||||||
|
--- !u!1 &8808031170711301744
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 7669984967702354254}
|
||||||
|
m_Layer: 5
|
||||||
|
m_Name: BleIcon
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!224 &7669984967702354254
|
||||||
|
RectTransform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 8808031170711301744}
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_Children:
|
||||||
|
- {fileID: 6521823677394231837}
|
||||||
|
- {fileID: 652708983550405284}
|
||||||
|
m_Father: {fileID: 6430829710355291381}
|
||||||
|
m_RootOrder: 1
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
|
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||||
|
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||||
|
m_AnchoredPosition: {x: -28.5, y: 1.4}
|
||||||
|
m_SizeDelta: {x: 44, y: 44}
|
||||||
|
m_Pivot: {x: 0.5, y: 0.5}
|
||||||
--- !u!1001 &564608893206712879
|
--- !u!1001 &564608893206712879
|
||||||
PrefabInstance:
|
PrefabInstance:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
|
|||||||
@ -141,6 +141,7 @@ namespace Assets.Scripts.Apis
|
|||||||
|
|
||||||
public async Task<JsonResult<object>> GetEarthData(double lat, double lon)
|
public async Task<JsonResult<object>> GetEarthData(double lat, double lon)
|
||||||
{
|
{
|
||||||
|
//CultureInfo.InvariantCulture
|
||||||
var result = await GetAsync<JsonResult<object>>($"Map/GetEarthData?lat={ lat }&lon={ lon }");
|
var result = await GetAsync<JsonResult<object>>($"Map/GetEarthData?lat={ lat }&lon={ lon }");
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@ -26,6 +26,20 @@ namespace Assets.Scripts.Devices
|
|||||||
get; protected set;
|
get; protected set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public NetworkType Network { get; internal set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 信号强度
|
||||||
|
/// 信号从0dbm~97dbm,个人建议是0~30是强,30~70是中,70~97是弱。
|
||||||
|
/// </summary>
|
||||||
|
public int SignalStrength { get; internal set; }
|
||||||
|
|
||||||
|
protected AbstractDevice(NetworkType networkType)
|
||||||
|
{
|
||||||
|
this.Network = networkType;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public abstract void Connect();
|
public abstract void Connect();
|
||||||
|
|
||||||
public abstract void Disconnect(bool save = true);
|
public abstract void Disconnect(bool save = true);
|
||||||
|
|||||||
@ -26,7 +26,7 @@ namespace Assets.Scripts.Devices.Ant
|
|||||||
public readonly byte uid;
|
public readonly byte uid;
|
||||||
|
|
||||||
|
|
||||||
public DataSourceBase(racerSportType sportType, bool isHuman)
|
public DataSourceBase(racerSportType sportType, bool isHuman):base(NetworkType.ANT)
|
||||||
{
|
{
|
||||||
this.sportType = sportType;
|
this.sportType = sportType;
|
||||||
this.isHuman = isHuman;
|
this.isHuman = isHuman;
|
||||||
|
|||||||
@ -9,7 +9,7 @@ using UnityEngine;
|
|||||||
|
|
||||||
namespace Assets.Scripts.Devices.Ant
|
namespace Assets.Scripts.Devices.Ant
|
||||||
{
|
{
|
||||||
public class FitDevice : AbstractAntDevice, ISpeedDevice, IPowerDevice, ICadenceDevice, IRequiresRiderWeight
|
public class FitDevice : AbstractAntDevice, ISpeedDevice, IPowerDevice, ICadenceDevice, IRequiresRiderWeight, ITrainerDevice
|
||||||
{
|
{
|
||||||
public const int MAX_NO_EVENT_STOP_COUNT = 12;
|
public const int MAX_NO_EVENT_STOP_COUNT = 12;
|
||||||
|
|
||||||
|
|||||||
19
Assets/Scripts/Devices/Ant/Interfaces/ITrainerDevice.cs
Normal file
19
Assets/Scripts/Devices/Ant/Interfaces/ITrainerDevice.cs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Assets.Scripts.Devices.Ant.Interfaces
|
||||||
|
{
|
||||||
|
public interface ITrainerDevice
|
||||||
|
{
|
||||||
|
void SetErgMode(int targetPower);
|
||||||
|
|
||||||
|
void SetResistanceMode(double value);
|
||||||
|
|
||||||
|
void SetWindResistance(double? height = null);
|
||||||
|
|
||||||
|
void SetTrackResistance(double grade);
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Assets/Scripts/Devices/Ant/Interfaces/ITrainerDevice.cs.meta
Normal file
11
Assets/Scripts/Devices/Ant/Interfaces/ITrainerDevice.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 362cacfc69d803d478112e7c293cfa17
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@ -39,4 +39,10 @@ namespace Assets.Scripts.Devices.Ant
|
|||||||
Trainer,
|
Trainer,
|
||||||
VirtualPower,
|
VirtualPower,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum NetworkType
|
||||||
|
{
|
||||||
|
BLE,
|
||||||
|
ANT
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,8 @@
|
|||||||
using Assets.Scripts.Ble.HeartRate;
|
using Assets.Scripts.Ble.HeartRate;
|
||||||
using Assets.Scripts.Ble.Service;
|
using Assets.Scripts.Ble.Service;
|
||||||
using Assets.Scripts.Devices.Ant;
|
using Assets.Scripts.Devices.Ant;
|
||||||
|
using Assets.Scripts.Devices.Ble.Characteristic;
|
||||||
|
using Assets.Scripts.Devices.Ble.Interfaces;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -22,7 +24,9 @@ namespace Assets.Scripts.Devices.Ble
|
|||||||
|
|
||||||
public override string Name { get => peripheralInfo.Name; protected set => base.Name = value; }
|
public override string Name { get => peripheralInfo.Name; protected set => base.Name = value; }
|
||||||
|
|
||||||
public BleDevice(BlePeripheralInfo peripheralInfo, BleWinHwInterface bleWinHwInterface, SensorType sensor) //: base(peripheralInfo)
|
public List<ICharacteristic> Characteristics { get; protected set; } = new List<ICharacteristic>();
|
||||||
|
|
||||||
|
public BleDevice(BlePeripheralInfo peripheralInfo, BleWinHwInterface bleWinHwInterface, SensorType sensor) : base(NetworkType.BLE)
|
||||||
{
|
{
|
||||||
this.hwInterface = bleWinHwInterface;
|
this.hwInterface = bleWinHwInterface;
|
||||||
this.hwInterface.BluetoothStateChangedEvent += BluetoothStateChangedEvent;
|
this.hwInterface.BluetoothStateChangedEvent += BluetoothStateChangedEvent;
|
||||||
@ -33,6 +37,10 @@ namespace Assets.Scripts.Devices.Ble
|
|||||||
//base.Name = this.peripheralInfo.Name;
|
//base.Name = this.peripheralInfo.Name;
|
||||||
|
|
||||||
//Debug.Log(base.Name + "," + sensor.ToString());
|
//Debug.Log(base.Name + "," + sensor.ToString());
|
||||||
|
|
||||||
|
Characteristics.Add(new BatteryLevel());
|
||||||
|
Characteristics.Add(new ManufacturerNameCharacteristic());
|
||||||
|
Characteristics.Add(new ModelNumberCharacteristic());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ConnectToPeripheralIfPossible()
|
public void ConnectToPeripheralIfPossible()
|
||||||
@ -230,7 +238,7 @@ namespace Assets.Scripts.Devices.Ble
|
|||||||
public override void Disconnect(bool save = true)
|
public override void Disconnect(bool save = true)
|
||||||
{
|
{
|
||||||
//throw new NotImplementedException();
|
//throw new NotImplementedException();
|
||||||
|
this.hwInterface.DisconnectPeripheral(this.peripheralInfo, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -43,11 +43,19 @@ namespace Assets.Scripts.Devices.Ble
|
|||||||
{
|
{
|
||||||
if (!discoveredDevices.ContainsKey(device.Peripheral.Address))
|
if (!discoveredDevices.ContainsKey(device.Peripheral.Address))
|
||||||
{
|
{
|
||||||
Debug.Log("发现设备" + device.Peripheral.Address + device.Peripheral.Name + ", type:" + device.SensorType);
|
Debug.Log($"发现设备{ device.Peripheral.Address }, \t\tName:{ device.Peripheral.Name }, type:{ device.SensorType }");
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(device.Peripheral.Name))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
if(device.SensorType == Ant.SensorType.Trainer)
|
if(device.SensorType == Ant.SensorType.Trainer)
|
||||||
{
|
{
|
||||||
//var device1 = new Ftms(device.Peripheral, hwInterface);
|
//var device1 = new Ftms(device.Peripheral, hwInterface);
|
||||||
//discoveredDevices.Add(device.Peripheral.Address, device1);
|
//discoveredDevices.Add(device.Peripheral.Address, device1);
|
||||||
|
|
||||||
|
var device1 = new Tacx(device.Peripheral, hwInterface);
|
||||||
|
discoveredDevices.Add(device.Peripheral.Address, device1);
|
||||||
}
|
}
|
||||||
else if(device.SensorType == Ant.SensorType.HeartRate)
|
else if(device.SensorType == Ant.SensorType.HeartRate)
|
||||||
{
|
{
|
||||||
@ -59,8 +67,18 @@ namespace Assets.Scripts.Devices.Ble
|
|||||||
var device1 = new CyclingPower(device.Peripheral, hwInterface);
|
var device1 = new CyclingPower(device.Peripheral, hwInterface);
|
||||||
discoveredDevices.Add(device.Peripheral.Address, device1);
|
discoveredDevices.Add(device.Peripheral.Address, device1);
|
||||||
}
|
}
|
||||||
|
else if(device.SensorType == Ant.SensorType.SpeedCadence)
|
||||||
|
{
|
||||||
|
var device1 = new SpeedCadence(device.Peripheral, hwInterface);
|
||||||
|
discoveredDevices.Add(device.Peripheral.Address, device1);
|
||||||
|
}
|
||||||
//discoveredDevices.Add(device.Peripheral.Address, new BleDevice(device.Peripheral, hwInterface, device.SensorType));
|
//discoveredDevices.Add(device.Peripheral.Address, new BleDevice(device.Peripheral, hwInterface, device.SensorType));
|
||||||
}
|
}
|
||||||
|
if (discoveredDevices.ContainsKey(device.Peripheral.Address))
|
||||||
|
{
|
||||||
|
discoveredDevices[device.Peripheral.Address].SignalStrength = device.Rssi;
|
||||||
|
//Debug.Log($"设备{ device.Peripheral.Name }信号量:{ device.Rssi }");
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
49
Assets/Scripts/Devices/Ble/Characteristic/BatteryLevel.cs
Normal file
49
Assets/Scripts/Devices/Ble/Characteristic/BatteryLevel.cs
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
using Assets.Scripts.Ble;
|
||||||
|
using Assets.Scripts.Devices.Ble.Interfaces;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Assets.Scripts.Devices.Ble.Characteristic
|
||||||
|
{
|
||||||
|
public class BatteryLevel : ICharacteristic
|
||||||
|
{
|
||||||
|
public Guid Uuid => ServiceUuids.Characteristics.BatteryLevel;
|
||||||
|
|
||||||
|
public Guid ServiceUuid => ServiceUuids.Get(ServiceUuids.Battery).IdGuid;
|
||||||
|
|
||||||
|
private ICharacteristic _characteristicUnavailable = null;
|
||||||
|
public ICharacteristic CharacteristicUnavailable
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return this._characteristicUnavailable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual bool IsOptional
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int BatteryLevelValue { get; private set; }
|
||||||
|
|
||||||
|
public void HandleAttributeReceived(byte[] data)
|
||||||
|
{
|
||||||
|
BatteryLevelValue = (int)data[0];
|
||||||
|
|
||||||
|
Debug.Log($"电量:{ BatteryLevelValue }");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetUnavailable()
|
||||||
|
{
|
||||||
|
this._characteristicUnavailable = this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: b654b3a52c37e6f47b9823953c8fd5d1
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@ -0,0 +1,57 @@
|
|||||||
|
using Assets.Scripts.Ble;
|
||||||
|
using Assets.Scripts.Devices.Ble.Interfaces;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Assets.Scripts.Devices.Ble.Characteristic
|
||||||
|
{
|
||||||
|
public class CyclingPowerMeasurement: ICharacteristic
|
||||||
|
{
|
||||||
|
public Guid Uuid
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return ServiceUuids.Characteristics.CyclingPowerMeasurement;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Guid ServiceUuid
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return ServiceUuids.Get(ServiceUuids.CyclingPower).IdGuid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual bool IsOptional
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private double wheelCircumference;
|
||||||
|
|
||||||
|
public int Power { get; private set; }
|
||||||
|
|
||||||
|
public CyclingPowerMeasurement(double wheelCircumference)
|
||||||
|
{
|
||||||
|
this.wheelCircumference = wheelCircumference;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void HandleAttributeReceived(byte[] data)
|
||||||
|
{
|
||||||
|
|
||||||
|
this.Power = BitConverter.ToInt16(data, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetUnavailable()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 9b0646295dbaa0a4e951de9bd391e475
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@ -0,0 +1,271 @@
|
|||||||
|
using Assets.Scripts.Ble;
|
||||||
|
using Assets.Scripts.Devices.Ble.Interfaces;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using UnityEngine;
|
||||||
|
using Assets.Scripts.Devices.Ble.Extension;
|
||||||
|
|
||||||
|
namespace Assets.Scripts.Devices.Ble.Characteristic
|
||||||
|
{
|
||||||
|
public class CyclingSpeedCadenceMeasurement : ICharacteristic
|
||||||
|
{
|
||||||
|
private CyclingSpeedCadenceMeasurement.IUpdate _currentUpdate;
|
||||||
|
private CyclingSpeedCadenceMeasurement.IUpdate _previousUpdate = new CyclingSpeedCadenceMeasurement.NullUpdate();
|
||||||
|
private const byte MaxNoEvents = (byte)4;
|
||||||
|
private byte _noCadenceEventCount;
|
||||||
|
private byte _noSpeedEventCount;
|
||||||
|
|
||||||
|
|
||||||
|
public Guid Uuid => ServiceUuids.Characteristics.CscMeasurement;
|
||||||
|
|
||||||
|
public Guid ServiceUuid => ServiceUuids.Get(ServiceUuids.CyclingSpeedCadence).IdGuid;
|
||||||
|
|
||||||
|
public bool IsOptional => false;
|
||||||
|
|
||||||
|
public double Speed { get; private set; }
|
||||||
|
public int Cadence { get; private set; }
|
||||||
|
|
||||||
|
public double WheelCircumference { private get; set; }
|
||||||
|
|
||||||
|
public CyclingSpeedCadenceMeasurement(double wheelCircumference)
|
||||||
|
{
|
||||||
|
this.WheelCircumference = wheelCircumference;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void HandleAttributeReceived(byte[] data)
|
||||||
|
{
|
||||||
|
//throw new NotImplementedException();
|
||||||
|
//Debug.Log(string.Join(",", data));
|
||||||
|
|
||||||
|
this._currentUpdate = new CyclingSpeedCadenceMeasurement.Update(data);
|
||||||
|
this.HandleCadenceUpdate();
|
||||||
|
this.HandleSpeedUpdate();
|
||||||
|
this._previousUpdate = this._currentUpdate;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleCadenceUpdate()
|
||||||
|
{
|
||||||
|
if (this._currentUpdate.HasCadence && (int)this._currentUpdate.CadenceEventCount != (int)this._previousUpdate.CadenceEventCount)
|
||||||
|
{
|
||||||
|
this._noCadenceEventCount = (byte)0;
|
||||||
|
if (this.CadenceTimeDifference() <= 0)
|
||||||
|
return;
|
||||||
|
this.Cadence = this.CalculateCadence();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this._noCadenceEventCount = (byte)((uint)this._noCadenceEventCount + 1U);
|
||||||
|
if ((int)this._noCadenceEventCount < 4)
|
||||||
|
return;
|
||||||
|
this.Cadence = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleSpeedUpdate()
|
||||||
|
{
|
||||||
|
if (this._currentUpdate.HasSpeed && (int)this._currentUpdate.SpeedEventCount != (int)this._previousUpdate.SpeedEventCount)
|
||||||
|
{
|
||||||
|
this._noSpeedEventCount = (byte)0;
|
||||||
|
double num = this.CalculateSpeed();
|
||||||
|
if (num >= 150.0)
|
||||||
|
return;
|
||||||
|
this.Speed = num;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this._noSpeedEventCount = (byte)((uint)this._noSpeedEventCount + 1U);
|
||||||
|
if ((int)this._noSpeedEventCount < 4)
|
||||||
|
return;
|
||||||
|
this.Speed = 0.0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int CalculateCadence()
|
||||||
|
{
|
||||||
|
int num = this.CadenceEventDifference() * 61440 / this.CadenceTimeDifference();
|
||||||
|
if (num > (int)byte.MaxValue)
|
||||||
|
return (int)byte.MaxValue;
|
||||||
|
if (num < 0)
|
||||||
|
return 0;
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int CadenceTimeDifference()
|
||||||
|
{
|
||||||
|
if ((int)this._currentUpdate.CadenceTime1024 > (int)this._previousUpdate.CadenceTime1024)
|
||||||
|
return (int)this._currentUpdate.CadenceTime1024 - (int)this._previousUpdate.CadenceTime1024;
|
||||||
|
return (int)ushort.MaxValue - (int)this._previousUpdate.CadenceTime1024 + (int)this._currentUpdate.CadenceTime1024 + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int CadenceEventDifference()
|
||||||
|
{
|
||||||
|
if ((int)this._currentUpdate.CadenceEventCount > (int)this._previousUpdate.CadenceEventCount)
|
||||||
|
return (int)this._currentUpdate.CadenceEventCount - (int)this._previousUpdate.CadenceEventCount;
|
||||||
|
return (int)ushort.MaxValue - (int)this._previousUpdate.CadenceEventCount + (int)this._currentUpdate.CadenceEventCount + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private double CalculateSpeed()
|
||||||
|
{
|
||||||
|
double num = (double)(ulong)(this.WheelCircumference / 10.0 * 36864.0 * (double)this.SpeedEventDifference() / (double)this.SpeedTimeDifference()) / 1000.0;
|
||||||
|
if (num >= 0.0)
|
||||||
|
return num;
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int SpeedTimeDifference()
|
||||||
|
{
|
||||||
|
if ((int)this._currentUpdate.SpeedTime1024 > (int)this._previousUpdate.SpeedTime1024)
|
||||||
|
return (int)this._currentUpdate.SpeedTime1024 - (int)this._previousUpdate.SpeedTime1024;
|
||||||
|
return (int)ushort.MaxValue - (int)this._previousUpdate.SpeedTime1024 + (int)this._currentUpdate.SpeedTime1024 + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private uint SpeedEventDifference()
|
||||||
|
{
|
||||||
|
if (this._currentUpdate.SpeedEventCount > this._previousUpdate.SpeedEventCount)
|
||||||
|
return this._currentUpdate.SpeedEventCount - this._previousUpdate.SpeedEventCount;
|
||||||
|
return (uint)(-1 - (int)this._previousUpdate.SpeedEventCount + (int)this._currentUpdate.SpeedEventCount + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetUnavailable()
|
||||||
|
{
|
||||||
|
//throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
private interface IUpdate
|
||||||
|
{
|
||||||
|
bool HasCadence { get; }
|
||||||
|
|
||||||
|
bool HasSpeed { get; }
|
||||||
|
|
||||||
|
uint SpeedEventCount { get; }
|
||||||
|
|
||||||
|
ushort SpeedTime1024 { get; }
|
||||||
|
|
||||||
|
ushort CadenceEventCount { get; }
|
||||||
|
|
||||||
|
ushort CadenceTime1024 { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private class Update : CyclingSpeedCadenceMeasurement.IUpdate
|
||||||
|
{
|
||||||
|
private static readonly byte WheelRevolutionsFlagBit = (byte)0;
|
||||||
|
private static readonly byte CrankRevolutionsFlagBit = (byte)1;
|
||||||
|
private readonly byte[] _data;
|
||||||
|
|
||||||
|
private byte Flags
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return this._data[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool HasCadence
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return PrimitiveExtensions.IsBitSet(this.Flags, (int)CyclingSpeedCadenceMeasurement.Update.CrankRevolutionsFlagBit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool HasSpeed
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return PrimitiveExtensions.IsBitSet(this.Flags, (int)CyclingSpeedCadenceMeasurement.Update.WheelRevolutionsFlagBit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint SpeedEventCount
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return BitConvertHelper.ToUInt32(this._data, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ushort SpeedTime1024
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return BitConvertHelper.ToUInt16(this._data, 5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ushort CadenceEventCount
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return BitConvertHelper.ToUInt16(this._data, this.HasSpeed ? 7 : 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ushort CadenceTime1024
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return BitConvertHelper.ToUInt16(this._data, this.HasSpeed ? 9 : 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Update(byte[] data)
|
||||||
|
{
|
||||||
|
this._data = data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class NullUpdate : CyclingSpeedCadenceMeasurement.IUpdate
|
||||||
|
{
|
||||||
|
public bool HasCadence
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool HasSpeed
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint SpeedEventCount
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return 0U;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ushort SpeedTime1024
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return (ushort)0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ushort CadenceEventCount
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return (ushort)0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ushort CadenceTime1024
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return (ushort)0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 0ea4d73295288ad4a9f561a37246110a
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@ -0,0 +1,45 @@
|
|||||||
|
using Assets.Scripts.Ble;
|
||||||
|
using Assets.Scripts.Devices.Ble.Interfaces;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Assets.Scripts.Devices.Ble.Characteristic
|
||||||
|
{
|
||||||
|
public class FtmsFitnessMachineFeature : ICharacteristic
|
||||||
|
{
|
||||||
|
public Guid Uuid => ServiceUuids.Characteristics.FitnessMachineFeature;
|
||||||
|
|
||||||
|
public Guid ServiceUuid => ServiceUuids.Get(ServiceUuids.Ftms).IdGuid;
|
||||||
|
|
||||||
|
public bool IsOptional => false;
|
||||||
|
|
||||||
|
public bool IsInclinationSupported
|
||||||
|
{
|
||||||
|
get; private set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsInclinationTargetSettingSupported
|
||||||
|
{
|
||||||
|
get; private set;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void HandleAttributeReceived(byte[] data)
|
||||||
|
{
|
||||||
|
//throw new NotImplementedException();
|
||||||
|
if (data.Length != 8)
|
||||||
|
return;
|
||||||
|
this.IsInclinationSupported = ByteExtensions.IsFlagSet(data[0], (byte)8);
|
||||||
|
//this.ResistanceLevelSupported = ByteExtensions.IsFlagSet(data[0], sbyte.MinValue);
|
||||||
|
|
||||||
|
this.IsInclinationTargetSettingSupported = ByteExtensions.IsFlagSet(data[4], 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetUnavailable()
|
||||||
|
{
|
||||||
|
//throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: c6095c96152da4c47870708061e1d5ac
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
220
Assets/Scripts/Devices/Ble/Characteristic/FtmsIndoorBikeData.cs
Normal file
220
Assets/Scripts/Devices/Ble/Characteristic/FtmsIndoorBikeData.cs
Normal file
@ -0,0 +1,220 @@
|
|||||||
|
using Assets.Scripts.Ble;
|
||||||
|
using Assets.Scripts.Devices.Ble.Interfaces;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Assets.Scripts.Devices.Ble.Characteristic
|
||||||
|
{
|
||||||
|
public class FtmsIndoorBikeData : ICharacteristic
|
||||||
|
{
|
||||||
|
private readonly ushort? _instantSpeedSubject = new ushort?();
|
||||||
|
private readonly ushort? _averageSpeedSubject = new ushort?();
|
||||||
|
private readonly ushort? _instantCadenceSubject = new ushort?();
|
||||||
|
private readonly ushort? _averageCadenceSubject = (new ushort?());
|
||||||
|
private readonly uint? _totalDistanceSubject = (new uint?());
|
||||||
|
private readonly short? _resistanceLevelSubject = (new short?());
|
||||||
|
private readonly short? _instantPowerSubject = (new short?());
|
||||||
|
private readonly short? _averagePowerSubject = (new short?());
|
||||||
|
private readonly ushort? _totalEnergySubject = (new ushort?());
|
||||||
|
private readonly ushort? _energyPerHourSubject = (new ushort?());
|
||||||
|
private readonly byte? _energyPerMinuteSubject = (new byte?());
|
||||||
|
private readonly byte? _heartRateSubject = (new byte?());
|
||||||
|
private readonly byte? _metabolicEquivalentSubject = (new byte?());
|
||||||
|
private readonly ushort? _elapsedTimeSubject = (new ushort?());
|
||||||
|
private readonly ushort? _remainingTimeSubject = (new ushort?());
|
||||||
|
|
||||||
|
public short? InstantPower
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return this._instantPowerSubject;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public ushort? InstantCadence
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return this._instantCadenceSubject;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public ushort? InstantSpeed
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return this._instantSpeedSubject;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Guid Uuid => ServiceUuids.Characteristics.IndoorBikeData;
|
||||||
|
|
||||||
|
public Guid ServiceUuid => ServiceUuids.Get(ServiceUuids.Ftms).IdGuid;
|
||||||
|
|
||||||
|
public bool IsOptional => false;
|
||||||
|
|
||||||
|
public void HandleAttributeReceived(byte[] data)
|
||||||
|
{
|
||||||
|
if(data.Length < 2)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<FtmsIndoorBikeData.IndoorBikeDataField> list = new List<FtmsIndoorBikeData.IndoorBikeDataField>();
|
||||||
|
if (!ByteExtensions.IsFlagSetAtPosition(data[0], (byte)0))
|
||||||
|
list.Add(FtmsIndoorBikeData.IndoorBikeDataField.InstantaneousSpeed);
|
||||||
|
if (ByteExtensions.IsFlagSetAtPosition(data[0], (byte)1))
|
||||||
|
list.Add(FtmsIndoorBikeData.IndoorBikeDataField.AverageSpeed);
|
||||||
|
if (ByteExtensions.IsFlagSetAtPosition(data[0], (byte)2))
|
||||||
|
list.Add(FtmsIndoorBikeData.IndoorBikeDataField.InstantaneousCadence);
|
||||||
|
if (ByteExtensions.IsFlagSetAtPosition(data[0], (byte)3))
|
||||||
|
list.Add(FtmsIndoorBikeData.IndoorBikeDataField.AverageCadence);
|
||||||
|
if (ByteExtensions.IsFlagSetAtPosition(data[0], (byte)4))
|
||||||
|
list.Add(FtmsIndoorBikeData.IndoorBikeDataField.TotalDistance);
|
||||||
|
if (ByteExtensions.IsFlagSetAtPosition(data[0], (byte)5))
|
||||||
|
list.Add(FtmsIndoorBikeData.IndoorBikeDataField.ResistanceLevel);
|
||||||
|
if (ByteExtensions.IsFlagSetAtPosition(data[0], (byte)6))
|
||||||
|
list.Add(FtmsIndoorBikeData.IndoorBikeDataField.InstantaneousPower);
|
||||||
|
if (ByteExtensions.IsFlagSetAtPosition(data[0], (byte)7))
|
||||||
|
list.Add(FtmsIndoorBikeData.IndoorBikeDataField.AveragePower);
|
||||||
|
if (ByteExtensions.IsFlagSetAtPosition(data[1], (byte)0))
|
||||||
|
list.Add(FtmsIndoorBikeData.IndoorBikeDataField.ExpendedEnergy);
|
||||||
|
if (ByteExtensions.IsFlagSetAtPosition(data[1], (byte)1))
|
||||||
|
list.Add(FtmsIndoorBikeData.IndoorBikeDataField.HeartRate);
|
||||||
|
if (ByteExtensions.IsFlagSetAtPosition(data[1], (byte)2))
|
||||||
|
list.Add(FtmsIndoorBikeData.IndoorBikeDataField.MetabolicEquivalent);
|
||||||
|
if (ByteExtensions.IsFlagSetAtPosition(data[1], (byte)3))
|
||||||
|
list.Add(FtmsIndoorBikeData.IndoorBikeDataField.ElapsedTime);
|
||||||
|
if (ByteExtensions.IsFlagSetAtPosition(data[1], (byte)4))
|
||||||
|
list.Add(FtmsIndoorBikeData.IndoorBikeDataField.RemainingTime);
|
||||||
|
int offset = 2;
|
||||||
|
foreach (FtmsIndoorBikeData.IndoorBikeDataField field in list)
|
||||||
|
offset += this.ParseField(data, offset, field);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetUnavailable()
|
||||||
|
{
|
||||||
|
//throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
private int ParseField(byte[] attribute, int offset, FtmsIndoorBikeData.IndoorBikeDataField field)
|
||||||
|
{
|
||||||
|
int fieldSize = FtmsIndoorBikeData.GetFieldSize(field);
|
||||||
|
if (attribute.Length < fieldSize + offset)
|
||||||
|
throw new ArgumentException("attribute");
|
||||||
|
switch (field)
|
||||||
|
{
|
||||||
|
case FtmsIndoorBikeData.IndoorBikeDataField.InstantaneousSpeed:
|
||||||
|
ICharacteristicExtensions.HandleUshortAttributeValue((ICharacteristic)this, attribute, offset, this._instantSpeedSubject);
|
||||||
|
break;
|
||||||
|
case FtmsIndoorBikeData.IndoorBikeDataField.AverageSpeed:
|
||||||
|
ICharacteristicExtensions.HandleUshortAttributeValue((ICharacteristic)this, attribute, offset, this._averageSpeedSubject);
|
||||||
|
break;
|
||||||
|
case FtmsIndoorBikeData.IndoorBikeDataField.InstantaneousCadence:
|
||||||
|
ICharacteristicExtensions.HandleUshortAttributeValue((ICharacteristic)this, attribute, offset, this._instantCadenceSubject);
|
||||||
|
break;
|
||||||
|
case FtmsIndoorBikeData.IndoorBikeDataField.AverageCadence:
|
||||||
|
ICharacteristicExtensions.HandleUshortAttributeValue((ICharacteristic)this, attribute, offset, this._averageCadenceSubject);
|
||||||
|
break;
|
||||||
|
case FtmsIndoorBikeData.IndoorBikeDataField.TotalDistance:
|
||||||
|
ICharacteristicExtensions.HandleUint24AttributeValue((ICharacteristic)this, attribute, offset, this._totalDistanceSubject);
|
||||||
|
break;
|
||||||
|
case FtmsIndoorBikeData.IndoorBikeDataField.ResistanceLevel:
|
||||||
|
ICharacteristicExtensions.HandleShortAttributeValue((ICharacteristic)this, attribute, offset, this._resistanceLevelSubject);
|
||||||
|
break;
|
||||||
|
case FtmsIndoorBikeData.IndoorBikeDataField.InstantaneousPower:
|
||||||
|
ICharacteristicExtensions.HandleShortAttributeValue((ICharacteristic)this, attribute, offset, this._instantPowerSubject);
|
||||||
|
break;
|
||||||
|
case FtmsIndoorBikeData.IndoorBikeDataField.AveragePower:
|
||||||
|
ICharacteristicExtensions.HandleShortAttributeValue((ICharacteristic)this, attribute, offset, this._averagePowerSubject);
|
||||||
|
break;
|
||||||
|
case FtmsIndoorBikeData.IndoorBikeDataField.ExpendedEnergy:
|
||||||
|
ICharacteristicExtensions.HandleUshortAttributeValue((ICharacteristic)this, attribute, offset, this._totalEnergySubject);
|
||||||
|
ICharacteristicExtensions.HandleUshortAttributeValue((ICharacteristic)this, attribute, offset + 2, this._energyPerHourSubject);
|
||||||
|
ICharacteristicExtensions.HandleByteAttributeValue((ICharacteristic)this, attribute, offset + 4, this._energyPerMinuteSubject);
|
||||||
|
break;
|
||||||
|
case FtmsIndoorBikeData.IndoorBikeDataField.HeartRate:
|
||||||
|
ICharacteristicExtensions.HandleByteAttributeValue((ICharacteristic)this, attribute, offset, this._heartRateSubject);
|
||||||
|
break;
|
||||||
|
case FtmsIndoorBikeData.IndoorBikeDataField.MetabolicEquivalent:
|
||||||
|
ICharacteristicExtensions.HandleByteAttributeValue((ICharacteristic)this, attribute, offset, this._metabolicEquivalentSubject);
|
||||||
|
break;
|
||||||
|
case FtmsIndoorBikeData.IndoorBikeDataField.ElapsedTime:
|
||||||
|
ICharacteristicExtensions.HandleUshortAttributeValue((ICharacteristic)this, attribute, offset, this._elapsedTimeSubject);
|
||||||
|
break;
|
||||||
|
case FtmsIndoorBikeData.IndoorBikeDataField.RemainingTime:
|
||||||
|
ICharacteristicExtensions.HandleUshortAttributeValue((ICharacteristic)this, attribute, offset, this._remainingTimeSubject);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return fieldSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int GetFieldSize(FtmsIndoorBikeData.IndoorBikeDataField field)
|
||||||
|
{
|
||||||
|
int num = 0;
|
||||||
|
switch (field)
|
||||||
|
{
|
||||||
|
case FtmsIndoorBikeData.IndoorBikeDataField.InstantaneousSpeed:
|
||||||
|
num = 2;
|
||||||
|
break;
|
||||||
|
case FtmsIndoorBikeData.IndoorBikeDataField.AverageSpeed:
|
||||||
|
num = 2;
|
||||||
|
break;
|
||||||
|
case FtmsIndoorBikeData.IndoorBikeDataField.InstantaneousCadence:
|
||||||
|
num = 2;
|
||||||
|
break;
|
||||||
|
case FtmsIndoorBikeData.IndoorBikeDataField.AverageCadence:
|
||||||
|
num = 2;
|
||||||
|
break;
|
||||||
|
case FtmsIndoorBikeData.IndoorBikeDataField.TotalDistance:
|
||||||
|
num = 3;
|
||||||
|
break;
|
||||||
|
case FtmsIndoorBikeData.IndoorBikeDataField.ResistanceLevel:
|
||||||
|
num = 2;
|
||||||
|
break;
|
||||||
|
case FtmsIndoorBikeData.IndoorBikeDataField.InstantaneousPower:
|
||||||
|
num = 2;
|
||||||
|
break;
|
||||||
|
case FtmsIndoorBikeData.IndoorBikeDataField.AveragePower:
|
||||||
|
num = 2;
|
||||||
|
break;
|
||||||
|
case FtmsIndoorBikeData.IndoorBikeDataField.ExpendedEnergy:
|
||||||
|
num = 5;
|
||||||
|
break;
|
||||||
|
case FtmsIndoorBikeData.IndoorBikeDataField.HeartRate:
|
||||||
|
num = 1;
|
||||||
|
break;
|
||||||
|
case FtmsIndoorBikeData.IndoorBikeDataField.MetabolicEquivalent:
|
||||||
|
num = 1;
|
||||||
|
break;
|
||||||
|
case FtmsIndoorBikeData.IndoorBikeDataField.ElapsedTime:
|
||||||
|
num = 2;
|
||||||
|
break;
|
||||||
|
case FtmsIndoorBikeData.IndoorBikeDataField.RemainingTime:
|
||||||
|
num = 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return num;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private enum IndoorBikeDataField
|
||||||
|
{
|
||||||
|
InstantaneousSpeed,
|
||||||
|
AverageSpeed,
|
||||||
|
InstantaneousCadence,
|
||||||
|
AverageCadence,
|
||||||
|
TotalDistance,
|
||||||
|
ResistanceLevel,
|
||||||
|
InstantaneousPower,
|
||||||
|
AveragePower,
|
||||||
|
ExpendedEnergy,
|
||||||
|
HeartRate,
|
||||||
|
MetabolicEquivalent,
|
||||||
|
ElapsedTime,
|
||||||
|
RemainingTime,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: e3577d5802131984c9463ba280183935
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@ -1,4 +1,5 @@
|
|||||||
using Assets.Scripts.Ble;
|
using Assets.Scripts.Ble;
|
||||||
|
using Assets.Scripts.Devices.Ble.Interfaces;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -8,7 +9,7 @@ using UnityEngine;
|
|||||||
|
|
||||||
namespace Assets.Scripts.Devices.Ble.Characteristic
|
namespace Assets.Scripts.Devices.Ble.Characteristic
|
||||||
{
|
{
|
||||||
public class HeartRateMeasurement
|
public class HeartRateMeasurement : ICharacteristic
|
||||||
{
|
{
|
||||||
public Guid Uuid
|
public Guid Uuid
|
||||||
{
|
{
|
||||||
@ -26,6 +27,13 @@ namespace Assets.Scripts.Devices.Ble.Characteristic
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsOptional
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
private HrmFormat Format { get; set; }
|
private HrmFormat Format { get; set; }
|
||||||
|
|
||||||
// Token: 0x170005EB RID: 1515
|
// Token: 0x170005EB RID: 1515
|
||||||
@ -39,7 +47,7 @@ namespace Assets.Scripts.Devices.Ble.Characteristic
|
|||||||
if (this.Format == HrmFormat.Short)
|
if (this.Format == HrmFormat.Short)
|
||||||
{
|
{
|
||||||
this.BeatsPerMinute = BitConvertHelper.ToUInt8(data, 1);
|
this.BeatsPerMinute = BitConvertHelper.ToUInt8(data, 1);
|
||||||
Debug.Log("心率:" + this.BeatsPerMinute);
|
//Debug.Log("心率:" + this.BeatsPerMinute);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (data.Length < 3)
|
if (data.Length < 3)
|
||||||
@ -49,6 +57,10 @@ namespace Assets.Scripts.Devices.Ble.Characteristic
|
|||||||
this.BeatsPerMinute = BitConvertHelper.ToUInt16(data, 1);
|
this.BeatsPerMinute = BitConvertHelper.ToUInt16(data, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SetUnavailable()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
[Flags]
|
[Flags]
|
||||||
private enum HrmFlags
|
private enum HrmFlags
|
||||||
{
|
{
|
||||||
|
|||||||
@ -0,0 +1,46 @@
|
|||||||
|
using Assets.Scripts.Devices.Ble.Interfaces;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Assets.Scripts.Devices.Ble.Characteristic
|
||||||
|
{
|
||||||
|
public static class ICharacteristicExtensions
|
||||||
|
{
|
||||||
|
public static void HandleByteAttributeValue(this ICharacteristic characteristic, byte[] attribute, int offset, byte? subject)
|
||||||
|
{
|
||||||
|
if (attribute.Length < 1 + offset)
|
||||||
|
throw new ArgumentException("attribute");
|
||||||
|
byte num = attribute[offset];
|
||||||
|
subject =new byte?(num);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void HandleShortAttributeValue(this ICharacteristic characteristic, byte[] attribute, int offset, short? subject)
|
||||||
|
{
|
||||||
|
if (attribute.Length < 2 + offset)
|
||||||
|
throw new ArgumentException("attribute");
|
||||||
|
short num = BitConverter.ToInt16(attribute, offset);
|
||||||
|
subject= new short?(num);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void HandleUshortAttributeValue(this ICharacteristic characteristic, byte[] attribute, int offset, ushort? subject)
|
||||||
|
{
|
||||||
|
if (attribute.Length < 2 + offset)
|
||||||
|
throw new ArgumentException("attribute");
|
||||||
|
ushort num = BitConverter.ToUInt16(attribute, offset);
|
||||||
|
subject =new ushort?(num);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void HandleUint24AttributeValue(this ICharacteristic characteristic, byte[] attribute, int offset, uint? subject)
|
||||||
|
{
|
||||||
|
if (attribute.Length < 4 + offset - 1)
|
||||||
|
throw new ArgumentException("attribute");
|
||||||
|
byte[] numArray = new byte[4];
|
||||||
|
Buffer.BlockCopy((Array)attribute, offset, (Array)numArray, 0, 3);
|
||||||
|
uint num = BitConverter.ToUInt32(numArray, 0);
|
||||||
|
subject = (new uint?(num));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 238bc68320174c9429b5958b5207b2c5
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@ -0,0 +1,31 @@
|
|||||||
|
using Assets.Scripts.Ble;
|
||||||
|
using Assets.Scripts.Devices.Ble.Interfaces;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Assets.Scripts.Devices.Ble.Characteristic
|
||||||
|
{
|
||||||
|
public class ManufacturerNameCharacteristic : ICharacteristic
|
||||||
|
{
|
||||||
|
public Guid Uuid => ServiceUuids.Characteristics.ManufactureNameString;
|
||||||
|
|
||||||
|
public Guid ServiceUuid => ServiceUuids.Get(ServiceUuids.DeviceInformation).IdGuid;
|
||||||
|
|
||||||
|
public bool IsOptional => true;
|
||||||
|
|
||||||
|
public void HandleAttributeReceived(byte[] data)
|
||||||
|
{
|
||||||
|
//throw new NotImplementedException();
|
||||||
|
Debug.Log(Encoding.UTF8.GetString(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetUnavailable()
|
||||||
|
{
|
||||||
|
//throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 4f0a2af64ce8fe84cbdf0e5a14bbc8ae
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@ -0,0 +1,31 @@
|
|||||||
|
using Assets.Scripts.Ble;
|
||||||
|
using Assets.Scripts.Devices.Ble.Interfaces;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Assets.Scripts.Devices.Ble.Characteristic
|
||||||
|
{
|
||||||
|
public class ModelNumberCharacteristic : ICharacteristic
|
||||||
|
{
|
||||||
|
public Guid Uuid => ServiceUuids.Characteristics.ModelNumber;
|
||||||
|
|
||||||
|
public Guid ServiceUuid => ServiceUuids.Get(ServiceUuids.DeviceInformation).IdGuid;
|
||||||
|
|
||||||
|
public bool IsOptional => true;
|
||||||
|
|
||||||
|
public void HandleAttributeReceived(byte[] data)
|
||||||
|
{
|
||||||
|
//throw new NotImplementedException();
|
||||||
|
Debug.Log($"model number:\t{ Encoding.UTF8.GetString(data) }");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetUnavailable()
|
||||||
|
{
|
||||||
|
//throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: ef489f56607ba2540b8954b67e1a4d3e
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
205
Assets/Scripts/Devices/Ble/Characteristic/TacxFecNotify.cs
Normal file
205
Assets/Scripts/Devices/Ble/Characteristic/TacxFecNotify.cs
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
using Assets.Scripts.Ble;
|
||||||
|
using Assets.Scripts.Devices.Ble.Interfaces;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Assets.Scripts.Devices.Ble.Characteristic
|
||||||
|
{
|
||||||
|
public class TacxFecNotify : ICharacteristic
|
||||||
|
{
|
||||||
|
public Guid Uuid => ServiceUuids.Characteristics.TacxFecRead;
|
||||||
|
|
||||||
|
public Guid ServiceUuid => ServiceUuids.Get(ServiceUuids.TacxBle).IdGuid;
|
||||||
|
|
||||||
|
public virtual bool IsOptional
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public double Speed { get; set; }
|
||||||
|
|
||||||
|
private int _Power;
|
||||||
|
public int Power
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _Power;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_Power = DeviceValueFilter.Power(value);
|
||||||
|
//Debug.Log(_Power);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int _Cadence;
|
||||||
|
public int Cadence
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _Cadence;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_Cadence = DeviceValueFilter.Cadence(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void HandleAttributeReceived(byte[] data)
|
||||||
|
{
|
||||||
|
//throw new NotImplementedException();
|
||||||
|
var responseId = data[2];
|
||||||
|
|
||||||
|
if (responseId != (byte)ANT_Managed_Library.ANT_ReferenceLibrary.ANTMessageID.BROADCAST_DATA_0x4E)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var data1 = data.Skip(3).ToArray();
|
||||||
|
var pageNumber = data1[1];
|
||||||
|
switch (pageNumber)
|
||||||
|
{
|
||||||
|
case 16:
|
||||||
|
{
|
||||||
|
HandleGeneralDataPage(data1.Skip(1).ToArray());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 19:
|
||||||
|
{
|
||||||
|
//lastInstCadence = data1[5];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 21: //bike data
|
||||||
|
case 22: //Row data, same format as bike for cad and power
|
||||||
|
case 20: //Elliptical, same format as bike for cad and power
|
||||||
|
case 24: //Nordic Skier, same format as bike for cad and power
|
||||||
|
{
|
||||||
|
//lastInstCadence = data1[5];
|
||||||
|
//lastInstPower = (ushort)(data1[6] + (data1[7] << 8));
|
||||||
|
//System.Console.Out.WriteLine("Cadence:" + response.messageContents[5] + ",Power:" + (response.messageContents[6] + (response.messageContents[7] << 8)));
|
||||||
|
//System.Console.Out.WriteLine("SPM:"+response.messageContents[5]+"Power:"+(response.messageContents[6] + (response.messageContents[7] << 8)));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 25:
|
||||||
|
|
||||||
|
HandleTrainerDataPage(data1.Skip(1).ToArray());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleGeneralDataPage(byte[] dataPayload)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
byte equipmentType = dataPayload[1];
|
||||||
|
byte elapsedTime = dataPayload[2];
|
||||||
|
byte distanceTraveled = dataPayload[3];
|
||||||
|
|
||||||
|
//byte heartRate = dataPayload[6];
|
||||||
|
//FecPageHandler.HeartRateDataSource heartRateDataSource = (FecPageHandler.HeartRateDataSource)(dataPayload[7] & 3);
|
||||||
|
//bool traveledEnabled = (dataPayload[7] & 4) == 1;
|
||||||
|
//bool distanceTraveledEnabled = (dataPayload[7] & 8) == 1;
|
||||||
|
//FecPageHandler.FeState feState = (FecPageHandler.FeState)(dataPayload[7] & 128);
|
||||||
|
//bool lapToggle = (dataPayload[7] & 128) == 1;
|
||||||
|
//this._fecGeneralData = new FecGeneralData(equipmentType, elapsedTime, distanceTraveled, (short)num, feState, lapToggle, heartRate, heartRateDataSource, traveledEnabled, distanceTraveledEnabled);
|
||||||
|
bool traveledEnabled = ((int)dataPayload[7] & 4) == 1;
|
||||||
|
bool distanceTraveledEnabled = ((int)dataPayload[7] & 8) == 1;
|
||||||
|
|
||||||
|
int num1 = (int)dataPayload[4] | (int)dataPayload[5] << 8; // Instantaneous speed, m/s
|
||||||
|
Speed = (double)num1 / 1000.0 * 60.0 * 60.0 / 1000.0; //转换成公里/小时
|
||||||
|
//Console.WriteLine(num1 +"-----"+Speed);
|
||||||
|
//fecDevice.UpdateSpeed(new double?(value));
|
||||||
|
//PubCommData.Speed = num2;
|
||||||
|
|
||||||
|
//byte? b2 = (heartRate == 255) ? null : new byte?(heartRate);
|
||||||
|
//int? xl = b2.HasValue ? new int?((int)b2.GetValueOrDefault()) : 0;
|
||||||
|
//Console.WriteLine("最新速度" + Speed);
|
||||||
|
//Console.WriteLine("最新心率" + xl);
|
||||||
|
|
||||||
|
//string str = "";
|
||||||
|
//for (int i = 0; i < response.messageContents.Length; i++)
|
||||||
|
//{
|
||||||
|
// str += "," + response.messageContents[i];
|
||||||
|
//}
|
||||||
|
//PubCommData.sp = "速度:" + str;
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void HandleTrainerDataPage(byte[] dataPayload)
|
||||||
|
{
|
||||||
|
//if (response.messageContents.Length < 11) break;
|
||||||
|
//double value = 0;
|
||||||
|
//for (int i = 0; i < response.messageContents.Length; i++)
|
||||||
|
//{
|
||||||
|
// if (i < 8)
|
||||||
|
// {
|
||||||
|
// value += response.messageContents[i];
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
//double value1 = response.messageContents[10] * 256 + response.messageContents[9];
|
||||||
|
|
||||||
|
|
||||||
|
//double power = response.messageContents[7] * 256 + response.messageContents[6];
|
||||||
|
//Console.WriteLine("power:" + power);
|
||||||
|
//PubCommData.power = power;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (dataPayload[5] > 0)
|
||||||
|
{
|
||||||
|
//Console.WriteLine(dataPayload[5] + "," + dataPayload[6]);//瞬时功率
|
||||||
|
}
|
||||||
|
byte num1 = dataPayload[1];
|
||||||
|
byte num2 = dataPayload[2];
|
||||||
|
int accumulatedPower = (int)dataPayload[3] | (int)dataPayload[4] << 8;
|
||||||
|
int instantaneousPower = (int)dataPayload[5] | ((int)dataPayload[6] & 15) << 8; //Watts
|
||||||
|
bool bikePowerCalibrationRequired = ((int)dataPayload[6] >> 4 & 1) == 1;
|
||||||
|
bool resistanceCalibrationRequired = ((int)dataPayload[6] >> 5 & 1) == 1;
|
||||||
|
bool userConfigurationRequired = ((int)dataPayload[6] >> 6 & 1) == 1;
|
||||||
|
bool speedIsTooLow = ((int)dataPayload[7] & 1) == 1;
|
||||||
|
bool speedIsTooHigh = ((int)dataPayload[7] & 2) == 1;
|
||||||
|
|
||||||
|
//PubCommData.power = instantaneousPower;
|
||||||
|
Power = instantaneousPower;
|
||||||
|
|
||||||
|
//bool bikePowerCalibrationRequired = (response.messageContents[6] >> 4 & 1) == 1;
|
||||||
|
//bool resistanceCalibrationRequired = (response.messageContents[6] >> 5 & 1) == 1;
|
||||||
|
//bool flag = (response.messageContents[6] >> 6 & 1) == 1;
|
||||||
|
//bool speedIsTooLow = (response.messageContents[7] & 1) == 1;
|
||||||
|
//bool speedIsTooHigh = (response.messageContents[7] & 2) == 1;
|
||||||
|
//FecPageHandler.FeState feState = (FecPageHandler.FeState)(dataPayload[7] & 112);
|
||||||
|
//bool lapToggle = (dataPayload[7] & 128) == 1;
|
||||||
|
//this._fecTrainerData = new FecTrainerData((int)eventCount, (int)b, accumulatedPower, num, bikePowerCalibrationRequired, resistanceCalibrationRequired, flag, speedIsTooLow, speedIsTooHigh, feState, lapToggle);
|
||||||
|
//device.UpdatePower(new int?(num));
|
||||||
|
byte? nullable = (int)num2 == (int)byte.MaxValue ? new byte?() : new byte?(num2);
|
||||||
|
int? cadence = nullable.HasValue ? new int?((int)nullable.GetValueOrDefault()) : new int?();
|
||||||
|
this.Cadence = cadence.GetValueOrDefault();
|
||||||
|
|
||||||
|
//Console.WriteLine($"power:{ instantaneousPower },Cadence:{ cadence }, data:{ string.Join(",", dataPayload) }");
|
||||||
|
|
||||||
|
if (!userConfigurationRequired)
|
||||||
|
return;
|
||||||
|
//UpdateUserConfiguration();
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public virtual void SetUnavailable()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 640f21041d0bf6347b1e48669c9a8691
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
39
Assets/Scripts/Devices/Ble/Characteristic/TacxFecWrite.cs
Normal file
39
Assets/Scripts/Devices/Ble/Characteristic/TacxFecWrite.cs
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
using Assets.Scripts.Ble;
|
||||||
|
using Assets.Scripts.Devices.Ble.Interfaces;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Assets.Scripts.Devices.Ble.Characteristic
|
||||||
|
{
|
||||||
|
public class TacxFecWrite : ICharacteristic
|
||||||
|
{
|
||||||
|
public virtual bool IsOptional
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Guid Uuid => ServiceUuids.Characteristics.TacxFecRead;
|
||||||
|
|
||||||
|
public Guid ServiceUuid => ServiceUuids.Get(ServiceUuids.TacxBle).IdGuid;
|
||||||
|
|
||||||
|
public void HandleAttributeReceived(byte[] data)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteMessageToControlPoint()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void SetUnavailable()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 6c9564a0124aa5946b25bdd1a97ade2c
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@ -1,5 +1,6 @@
|
|||||||
using Assets.Scripts.Ble;
|
using Assets.Scripts.Ble;
|
||||||
using Assets.Scripts.Devices.Ant.Interfaces;
|
using Assets.Scripts.Devices.Ant.Interfaces;
|
||||||
|
using Assets.Scripts.Devices.Ble.Characteristic;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -12,12 +13,16 @@ namespace Assets.Scripts.Devices.Ble.Devices
|
|||||||
public class CyclingPower : BleDevice, IPowerDevice
|
public class CyclingPower : BleDevice, IPowerDevice
|
||||||
{
|
{
|
||||||
private List<BleServiceInfo> Services;
|
private List<BleServiceInfo> Services;
|
||||||
|
private CyclingPowerMeasurement cyclingPowerMeasurement;
|
||||||
public CyclingPower(BlePeripheralInfo peripheralInfo, BleWinHwInterface bleWinHwInterface) : base(peripheralInfo, bleWinHwInterface, Ant.SensorType.Power)
|
public CyclingPower(BlePeripheralInfo peripheralInfo, BleWinHwInterface bleWinHwInterface) : base(peripheralInfo, bleWinHwInterface, Ant.SensorType.Power)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
cyclingPowerMeasurement = new CyclingPowerMeasurement(1920);
|
||||||
|
base.Characteristics.Add(cyclingPowerMeasurement);
|
||||||
bleWinHwInterface.CharacteristicReadEvent += CharacteristicReadMainCallback;
|
bleWinHwInterface.CharacteristicReadEvent += CharacteristicReadMainCallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int Power { get => 999; set => throw new NotImplementedException(); }
|
public int Power { get => cyclingPowerMeasurement.Power; set => throw new NotImplementedException(); }
|
||||||
|
|
||||||
protected override void CreateServices(List<BleServiceInfo> discoveredServices)
|
protected override void CreateServices(List<BleServiceInfo> discoveredServices)
|
||||||
{
|
{
|
||||||
@ -35,7 +40,7 @@ namespace Assets.Scripts.Devices.Ble.Devices
|
|||||||
|
|
||||||
this.hwInterface.SubscribeCharacteristic(character, (hw, cha, res) =>
|
this.hwInterface.SubscribeCharacteristic(character, (hw, cha, res) =>
|
||||||
{
|
{
|
||||||
Debug.Log("1111111111111111111111");
|
//Debug.Log("1111111111111111111111");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -46,7 +51,22 @@ namespace Assets.Scripts.Devices.Ble.Devices
|
|||||||
|
|
||||||
private void CharacteristicReadMainCallback(BleWinHwInterface hwInterface, BleCharacteristicInfo characteristic, BleResponse<byte[]> response)
|
private void CharacteristicReadMainCallback(BleWinHwInterface hwInterface, BleCharacteristicInfo characteristic, BleResponse<byte[]> response)
|
||||||
{
|
{
|
||||||
Debug.Log("main call" + string.Join(",", response.Data));
|
//Debug.Log("power main call" + string.Join(",", response.Data));
|
||||||
|
|
||||||
|
//Debug.Log(characteristic.MatchGuid(cyclingPowerMeasurement.Uuid));
|
||||||
|
//Debug.Log(characteristic.Service.MatchGuid(cyclingPowerMeasurement.ServiceUuid));
|
||||||
|
//if (characteristic.MatchGuid(cyclingPowerMeasurement.Uuid))
|
||||||
|
//{
|
||||||
|
// cyclingPowerMeasurement.HandleAttributeReceived(response.Data);
|
||||||
|
|
||||||
|
//}
|
||||||
|
foreach (var item in base.Characteristics)
|
||||||
|
{
|
||||||
|
if (characteristic.MatchGuid(item.Uuid))
|
||||||
|
{
|
||||||
|
item.HandleAttributeReceived(response.Data);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
using Assets.Scripts.Ble;
|
using Assets.Scripts.Ble;
|
||||||
using Assets.Scripts.Devices.Ant.Interfaces;
|
using Assets.Scripts.Devices.Ant.Interfaces;
|
||||||
|
using Assets.Scripts.Devices.Ble.Characteristic;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -8,19 +9,119 @@ using System.Threading.Tasks;
|
|||||||
|
|
||||||
namespace Assets.Scripts.Devices.Ble.Devices
|
namespace Assets.Scripts.Devices.Ble.Devices
|
||||||
{
|
{
|
||||||
public class Ftms : BleDevice, IPowerDevice
|
public class Ftms : BleDevice, ISpeedDevice, IPowerDevice, ICadenceDevice, ITrainerDevice
|
||||||
{
|
{
|
||||||
|
|
||||||
|
public int Power { get => _ftmsIndoorBikeData.InstantPower.GetValueOrDefault(0); set => throw new NotImplementedException(); }
|
||||||
|
public double Speed { get => _ftmsIndoorBikeData.InstantSpeed.GetValueOrDefault(0); set => throw new NotImplementedException(); }
|
||||||
|
public int Cadence { get => _ftmsIndoorBikeData.InstantCadence.GetValueOrDefault(0); set => throw new NotImplementedException(); }
|
||||||
|
|
||||||
|
private FtmsIndoorBikeData _ftmsIndoorBikeData;
|
||||||
|
|
||||||
|
private List<BleServiceInfo> Services;
|
||||||
|
private BleCharacteristicInfo controlPointCharacteristic;
|
||||||
|
|
||||||
public Ftms(BlePeripheralInfo peripheralInfo, BleWinHwInterface bleWinHwInterface) :base(peripheralInfo, bleWinHwInterface, Ant.SensorType.Trainer)
|
public Ftms(BlePeripheralInfo peripheralInfo, BleWinHwInterface bleWinHwInterface) :base(peripheralInfo, bleWinHwInterface, Ant.SensorType.Trainer)
|
||||||
{
|
{
|
||||||
|
this._ftmsIndoorBikeData = new FtmsIndoorBikeData();
|
||||||
|
base.Characteristics.Add(this._ftmsIndoorBikeData);
|
||||||
|
|
||||||
|
base.Characteristics.Add(new FtmsFitnessMachineFeature());
|
||||||
|
|
||||||
|
bleWinHwInterface.CharacteristicReadEvent += CharacteristicReadMainCallback;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int Power { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
|
|
||||||
|
|
||||||
protected override void CreateServices(List<BleServiceInfo> discoveredServices)
|
protected override void CreateServices(List<BleServiceInfo> discoveredServices)
|
||||||
|
{
|
||||||
|
this.Services = discoveredServices;
|
||||||
|
|
||||||
|
foreach (var service in this.Services)
|
||||||
|
{
|
||||||
|
hwInterface.DiscoverCharacteristic(service, (hwInterface, service1, response) =>
|
||||||
|
{
|
||||||
|
foreach (var character in response.Data)
|
||||||
|
{
|
||||||
|
if (character.MatchGuid(ServiceUuids.Characteristics.IndoorBikeData))
|
||||||
|
{
|
||||||
|
//Debug.Log("功率功能");
|
||||||
|
|
||||||
|
this.hwInterface.SubscribeCharacteristic(character, (hw, cha, res) =>
|
||||||
|
{
|
||||||
|
//Debug.Log("1111111111111111111111");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else if (character.MatchGuid(ServiceUuids.Characteristics.FitnessMachineControlPoint))
|
||||||
|
{
|
||||||
|
this.controlPointCharacteristic = character;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CharacteristicReadMainCallback(BleWinHwInterface hwInterface, BleCharacteristicInfo characteristic, BleResponse<byte[]> response)
|
||||||
|
{
|
||||||
|
foreach (var item in base.Characteristics)
|
||||||
|
{
|
||||||
|
if (characteristic.MatchGuid(item.Uuid))
|
||||||
|
{
|
||||||
|
//Debug.Log(string.Join(",", response.Data));
|
||||||
|
item.HandleAttributeReceived(response.Data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetErgMode(int targetPower)
|
||||||
|
{
|
||||||
|
//throw new NotImplementedException();
|
||||||
|
byte[] bytes = BitConverter.GetBytes(targetPower);
|
||||||
|
this.hwInterface.WriteCharacteristic(this.controlPointCharacteristic, new byte[3] {
|
||||||
|
(byte)5,
|
||||||
|
bytes[0],
|
||||||
|
bytes[1]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetResistanceMode(double value)
|
||||||
|
{
|
||||||
|
//throw new NotImplementedException();
|
||||||
|
var data = new byte[]
|
||||||
|
{
|
||||||
|
(byte)4,
|
||||||
|
(byte)0.1
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetWindResistance(double? height = null)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
throw new NotImplementedException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 轨道阻力
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="grade"></param>
|
||||||
|
public void SetTrackResistance(double grade)
|
||||||
|
{
|
||||||
|
if (this.State != Ant.DeviceState.Connected)
|
||||||
|
return;
|
||||||
|
if (controlPointCharacteristic == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
short windSpeed = 0;
|
||||||
|
short value2 = (short)(grade);
|
||||||
|
byte rollingResistanceCoefficient = (byte)(0.004 * 10000);
|
||||||
|
byte windResistanceCoefficient = 0;
|
||||||
|
var data = new List<byte>();// { 17, (byte)windSpeed, (byte)value2, rollingResistanceCoefficient, windResistanceCoefficient };
|
||||||
|
data.Add(17);
|
||||||
|
data.AddRange(BitConverter.GetBytes(windSpeed));
|
||||||
|
data.AddRange(BitConverter.GetBytes(value2));
|
||||||
|
data.AddRange(BitConverter.GetBytes(rollingResistanceCoefficient));
|
||||||
|
data.AddRange(BitConverter.GetBytes(windResistanceCoefficient));
|
||||||
|
|
||||||
|
|
||||||
|
this.hwInterface.WriteCharacteristic(this.controlPointCharacteristic, data.ToArray());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,14 +18,13 @@ namespace Assets.Scripts.Devices.Ble.Devices
|
|||||||
private HeartRateMeasurement heartRateMeasurement;
|
private HeartRateMeasurement heartRateMeasurement;
|
||||||
public HeartRate(BlePeripheralInfo peripheralInfo, BleWinHwInterface bleWinHwInterface) : base(peripheralInfo, bleWinHwInterface, Ant.SensorType.HeartRate)
|
public HeartRate(BlePeripheralInfo peripheralInfo, BleWinHwInterface bleWinHwInterface) : base(peripheralInfo, bleWinHwInterface, Ant.SensorType.HeartRate)
|
||||||
{
|
{
|
||||||
Debug.Log("创建心率设备");
|
|
||||||
heartRateMeasurement = new HeartRateMeasurement();
|
heartRateMeasurement = new HeartRateMeasurement();
|
||||||
|
|
||||||
|
base.Characteristics.Add(heartRateMeasurement);
|
||||||
|
|
||||||
bleWinHwInterface.CharacteristicReadEvent += CharacteristicReadMainCallback;
|
bleWinHwInterface.CharacteristicReadEvent += CharacteristicReadMainCallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
protected override void CreateServices(List<BleServiceInfo> discoveredServices)
|
protected override void CreateServices(List<BleServiceInfo> discoveredServices)
|
||||||
{
|
{
|
||||||
//throw new NotImplementedException();
|
//throw new NotImplementedException();
|
||||||
@ -33,18 +32,33 @@ namespace Assets.Scripts.Devices.Ble.Devices
|
|||||||
|
|
||||||
foreach (var service in this.Services)
|
foreach (var service in this.Services)
|
||||||
{
|
{
|
||||||
|
//Debug.Log($"11111 "+ service.Id.ToString());
|
||||||
hwInterface.DiscoverCharacteristic(service, (hwInterface, service1, response) =>
|
hwInterface.DiscoverCharacteristic(service, (hwInterface, service1, response) =>
|
||||||
{
|
{
|
||||||
foreach (var character in response.Data)
|
foreach (var character in response.Data)
|
||||||
{
|
{
|
||||||
if (character.MatchGuid(heartRateMeasurement.Uuid))
|
if (character.MatchGuid(heartRateMeasurement.Uuid))
|
||||||
{
|
{
|
||||||
Debug.Log("心率功能");
|
|
||||||
|
|
||||||
this.hwInterface.SubscribeCharacteristic(character, (hw, cha, res) =>
|
this.hwInterface.SubscribeCharacteristic(character, (hw, cha, res) =>
|
||||||
{
|
{
|
||||||
Debug.Log("1111111111111111111111");
|
//Debug.Log($"心率计subscribe char:{ }");
|
||||||
});
|
});
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach (var item in Characteristics.Where(c=>c.IsOptional))
|
||||||
|
{
|
||||||
|
//Debug.Log(item.GetType() + "服务可用"+ item.Uuid.ToString() +", service:" + item.ServiceUuid);
|
||||||
|
var ccc = response.Data.FirstOrDefault(r => r.MatchGuid(item.Uuid));
|
||||||
|
if (ccc == null)
|
||||||
|
{
|
||||||
|
item.SetUnavailable();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.Log(item.GetType() + "服务可用");
|
||||||
|
|
||||||
|
GetBatteryLevel(ccc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -52,10 +66,26 @@ namespace Assets.Scripts.Devices.Ble.Devices
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void GetBatteryLevel(BleCharacteristicInfo bbbb)
|
||||||
|
{
|
||||||
|
this.hwInterface.ReadCharacteristic(bbbb, (hwInterface1, characteristic1, response1) => {
|
||||||
|
Debug.Log("read收到消息:" + string.Join(",", response1));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private void CharacteristicReadMainCallback(BleWinHwInterface hwInterface, BleCharacteristicInfo characteristic, BleResponse<byte[]> response)
|
private void CharacteristicReadMainCallback(BleWinHwInterface hwInterface, BleCharacteristicInfo characteristic, BleResponse<byte[]> response)
|
||||||
{
|
{
|
||||||
Debug.Log("main call" + string.Join(",", response.Data));
|
//Debug.Log("heart rate main call" + string.Join(",", response.Data));
|
||||||
heartRateMeasurement.HandleAttributeReceived(response.Data);
|
|
||||||
|
foreach (var item in base.Characteristics)
|
||||||
|
{
|
||||||
|
if (characteristic.MatchGuid(item.Uuid))
|
||||||
|
{
|
||||||
|
item.HandleAttributeReceived(response.Data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//heartRateMeasurement.HandleAttributeReceived(response.Data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
103
Assets/Scripts/Devices/Ble/Devices/SpeedCadence.cs
Normal file
103
Assets/Scripts/Devices/Ble/Devices/SpeedCadence.cs
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
using Assets.Scripts.Ble;
|
||||||
|
using Assets.Scripts.Devices.Ant.Interfaces;
|
||||||
|
using Assets.Scripts.Devices.Ble.Characteristic;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Assets.Scripts.Devices.Ble.Devices
|
||||||
|
{
|
||||||
|
public class SpeedCadence : BleDevice, ISpeedDevice, ICadenceDevice
|
||||||
|
{
|
||||||
|
private CyclingSpeedCadenceMeasurement _cyclingSpeedCadenceMeasurement;
|
||||||
|
public int Cadence { get => _cyclingSpeedCadenceMeasurement.Cadence; set => throw new NotImplementedException(); }
|
||||||
|
public double Speed { get => _cyclingSpeedCadenceMeasurement.Speed; set => throw new NotImplementedException(); }
|
||||||
|
|
||||||
|
private double _wheelCircumference;
|
||||||
|
private List<BleServiceInfo> Services;
|
||||||
|
public SpeedCadence(BlePeripheralInfo peripheralInfo, BleWinHwInterface bleWinHwInterface) : base(peripheralInfo, bleWinHwInterface, Ant.SensorType.SpeedCadence)
|
||||||
|
{
|
||||||
|
Debug.Log("创建速度踏频设备");
|
||||||
|
_cyclingSpeedCadenceMeasurement = new CyclingSpeedCadenceMeasurement(this._wheelCircumference);
|
||||||
|
base.Characteristics.Add(_cyclingSpeedCadenceMeasurement);
|
||||||
|
|
||||||
|
bleWinHwInterface.CharacteristicReadEvent += CharacteristicReadMainCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetWheelCircumference(double value)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void CreateServices(List<BleServiceInfo> discoveredServices)
|
||||||
|
{
|
||||||
|
this.Services = discoveredServices;
|
||||||
|
|
||||||
|
foreach (var service in this.Services)
|
||||||
|
{
|
||||||
|
//Debug.Log($"11111 "+ service.Id.ToString());
|
||||||
|
hwInterface.DiscoverCharacteristic(service, (hwInterface, service1, response) =>
|
||||||
|
{
|
||||||
|
Debug.Log($"设备{ this.Name }的char: { string.Join("\r\n", response.Data.Select(d=>d.Id)) }");
|
||||||
|
foreach (var character in response.Data)
|
||||||
|
{
|
||||||
|
if (character.MatchGuid(_cyclingSpeedCadenceMeasurement.Uuid))
|
||||||
|
{
|
||||||
|
this.hwInterface.SubscribeCharacteristic(character, (hw, cha, res) =>
|
||||||
|
{
|
||||||
|
//Debug.Log("1111111111111111111111");
|
||||||
|
});
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach (var item in Characteristics.Where(c => c.IsOptional))
|
||||||
|
{
|
||||||
|
//Debug.Log(item.GetType() + "服务可用"+ item.Uuid.ToString() +", service:" + item.ServiceUuid);
|
||||||
|
var ccc = response.Data.FirstOrDefault(r => r.MatchGuid(item.Uuid));
|
||||||
|
if (ccc == null)
|
||||||
|
{
|
||||||
|
item.SetUnavailable();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.Log(item.GetType() + "服务可用");
|
||||||
|
|
||||||
|
GetBatteryLevel(ccc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void GetBatteryLevel(BleCharacteristicInfo bbbb)
|
||||||
|
{
|
||||||
|
this.hwInterface.ReadCharacteristic(bbbb, (hwInterface1, characteristic1, response1) => {
|
||||||
|
Debug.Log("read收到消息:" + string.Join(",", response1));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void CharacteristicReadMainCallback(BleWinHwInterface hwInterface, BleCharacteristicInfo characteristic, BleResponse<byte[]> response)
|
||||||
|
{
|
||||||
|
//Debug.Log("power main call" + string.Join(",", response.Data));
|
||||||
|
|
||||||
|
//Debug.Log(characteristic.MatchGuid(cyclingPowerMeasurement.Uuid));
|
||||||
|
//Debug.Log(characteristic.Service.MatchGuid(cyclingPowerMeasurement.ServiceUuid));
|
||||||
|
//if (characteristic.MatchGuid(cyclingPowerMeasurement.Uuid))
|
||||||
|
//{
|
||||||
|
// cyclingPowerMeasurement.HandleAttributeReceived(response.Data);
|
||||||
|
|
||||||
|
//}
|
||||||
|
foreach (var item in base.Characteristics)
|
||||||
|
{
|
||||||
|
if (characteristic.MatchGuid(item.Uuid))
|
||||||
|
{
|
||||||
|
item.HandleAttributeReceived(response.Data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Assets/Scripts/Devices/Ble/Devices/SpeedCadence.cs.meta
Normal file
11
Assets/Scripts/Devices/Ble/Devices/SpeedCadence.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 3fc83bb07e841d04bb491332cdfeb669
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
262
Assets/Scripts/Devices/Ble/Devices/Tacx.cs
Normal file
262
Assets/Scripts/Devices/Ble/Devices/Tacx.cs
Normal file
@ -0,0 +1,262 @@
|
|||||||
|
using Assets.Scripts.Ble;
|
||||||
|
using Assets.Scripts.Devices.Ant;
|
||||||
|
using Assets.Scripts.Devices.Ant.Interfaces;
|
||||||
|
using Assets.Scripts.Devices.Ble.Characteristic;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Assets.Scripts.Devices.Ble.Devices
|
||||||
|
{
|
||||||
|
public class Tacx : BleDevice, IPowerDevice, ICadenceDevice, ISpeedDevice, ITrainerDevice
|
||||||
|
{
|
||||||
|
public int Power { get => tacxFecNotify.Power; set => throw new NotImplementedException(); }
|
||||||
|
public int Cadence { get => tacxFecNotify.Cadence; set => throw new NotImplementedException(); }
|
||||||
|
public double Speed { get => tacxFecNotify.Speed; set => throw new NotImplementedException(); }
|
||||||
|
|
||||||
|
private List<BleServiceInfo> Services;
|
||||||
|
|
||||||
|
private TacxFecNotify tacxFecNotify;
|
||||||
|
private BleCharacteristicInfo tacxFecWriteCharacteristic;
|
||||||
|
|
||||||
|
private TacxFecWrite tacxFecWrite;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 当前坡度,当切换到其他模式的时候,需要把坡度设置为0
|
||||||
|
/// </summary>
|
||||||
|
private double _grade = 0;
|
||||||
|
|
||||||
|
public Tacx(BlePeripheralInfo peripheralInfo, BleWinHwInterface bleWinHwInterface) : base(peripheralInfo, bleWinHwInterface, Ant.SensorType.Trainer)
|
||||||
|
{
|
||||||
|
tacxFecNotify = new TacxFecNotify();
|
||||||
|
base.Characteristics.Add(tacxFecNotify);
|
||||||
|
|
||||||
|
tacxFecWrite = new TacxFecWrite();
|
||||||
|
base.Characteristics.Add(tacxFecWrite);
|
||||||
|
|
||||||
|
bleWinHwInterface.CharacteristicReadEvent += CharacteristicReadMainCallback;
|
||||||
|
|
||||||
|
//bleWinHwInterface.WriteCharacteristic()
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void CreateServices(List<BleServiceInfo> discoveredServices)
|
||||||
|
{
|
||||||
|
this.Services = discoveredServices;
|
||||||
|
|
||||||
|
foreach (var service in this.Services)
|
||||||
|
{
|
||||||
|
hwInterface.DiscoverCharacteristic(service, (hwInterface, service1, response) =>
|
||||||
|
{
|
||||||
|
foreach (var character in response.Data)
|
||||||
|
{
|
||||||
|
if (character.MatchGuid(ServiceUuids.Characteristics.TacxFecRead))
|
||||||
|
{
|
||||||
|
//Debug.Log("功率功能");
|
||||||
|
|
||||||
|
this.hwInterface.SubscribeCharacteristic(character, (hw, cha, res) =>
|
||||||
|
{
|
||||||
|
//Debug.Log("1111111111111111111111");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else if (character.MatchGuid(ServiceUuids.Characteristics.TacxFecWrite))
|
||||||
|
{
|
||||||
|
this.tacxFecWriteCharacteristic = character;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CharacteristicReadMainCallback(BleWinHwInterface hwInterface, BleCharacteristicInfo characteristic, BleResponse<byte[]> response)
|
||||||
|
{
|
||||||
|
foreach (var item in base.Characteristics)
|
||||||
|
{
|
||||||
|
if (characteristic.MatchGuid(item.Uuid))
|
||||||
|
{
|
||||||
|
//Debug.Log(string.Join(",", response.Data));
|
||||||
|
item.HandleAttributeReceived(response.Data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetErgMode(int targetPower)
|
||||||
|
{
|
||||||
|
Debug.Log("目标功率1");
|
||||||
|
if (this.State != Ant.DeviceState.Connected)
|
||||||
|
return;
|
||||||
|
if (tacxFecWriteCharacteristic == null)
|
||||||
|
return;
|
||||||
|
Debug.Log($"目标功率:{ targetPower }");
|
||||||
|
List<byte> data = new List<byte> { 164, 9, 79, 5, 49,
|
||||||
|
byte.MaxValue,
|
||||||
|
byte.MaxValue,
|
||||||
|
byte.MaxValue,
|
||||||
|
byte.MaxValue,
|
||||||
|
byte.MaxValue,
|
||||||
|
(byte)(targetPower & byte.MaxValue),
|
||||||
|
(byte)(targetPower >> 8 & byte.MaxValue)
|
||||||
|
};
|
||||||
|
byte checksum = (byte)0;
|
||||||
|
data.ForEach(b => checksum ^= b);
|
||||||
|
data.Add(checksum);
|
||||||
|
|
||||||
|
this.hwInterface.WriteCharacteristic(this.tacxFecWriteCharacteristic, data.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 阻力模式
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value"></param>
|
||||||
|
public void SetResistanceMode(double value)
|
||||||
|
{
|
||||||
|
if (this.State != Ant.DeviceState.Connected)
|
||||||
|
return;
|
||||||
|
if (tacxFecWriteCharacteristic == null)
|
||||||
|
return;
|
||||||
|
if(_grade > 0)
|
||||||
|
{
|
||||||
|
this.SetTrackResistance(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
double resistance = value / 100 * 200;
|
||||||
|
|
||||||
|
List<byte> data = new List<byte> { 164, 9, 79, 5, 48,
|
||||||
|
byte.MaxValue,
|
||||||
|
byte.MaxValue,
|
||||||
|
byte.MaxValue,
|
||||||
|
byte.MaxValue,
|
||||||
|
byte.MaxValue,
|
||||||
|
byte.MaxValue,
|
||||||
|
(byte)resistance
|
||||||
|
};
|
||||||
|
byte checksum = (byte)0;
|
||||||
|
data.ForEach(b => checksum ^= b);
|
||||||
|
data.Add(checksum);
|
||||||
|
|
||||||
|
this.hwInterface.WriteCharacteristic(this.tacxFecWriteCharacteristic, data.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 风阻
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="height">海拔高度,单位米</param>
|
||||||
|
public void SetWindResistance(double? height = null)
|
||||||
|
{
|
||||||
|
if (this.State != Ant.DeviceState.Connected)
|
||||||
|
return;
|
||||||
|
if (tacxFecWriteCharacteristic == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_grade > 0)
|
||||||
|
{
|
||||||
|
this.SetTrackResistance(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte windResistance = 0;
|
||||||
|
|
||||||
|
if (height.HasValue)
|
||||||
|
{
|
||||||
|
//Wind Resistance Coefficient [kg/m] = Frontal Surface Area [m2] x Drag Coefficient x Air Density[kg / m3]
|
||||||
|
var wr = 0.40 * 1.0 * AirDensity.GetAirDensity(height.Value);
|
||||||
|
if (wr > 1.86)
|
||||||
|
{
|
||||||
|
wr = 1.86;
|
||||||
|
}
|
||||||
|
windResistance = (byte)(Convert.ToInt32(Math.Round(wr, 2) / 0.01));
|
||||||
|
|
||||||
|
Console.WriteLine($"风阻系数:{ windResistance }");
|
||||||
|
}
|
||||||
|
|
||||||
|
byte id = 79;
|
||||||
|
byte size = 9;
|
||||||
|
byte channel = 5;
|
||||||
|
List<byte> data = new List<byte> { 164, size, id, channel, 50,
|
||||||
|
byte.MaxValue,
|
||||||
|
byte.MaxValue,
|
||||||
|
byte.MaxValue,
|
||||||
|
byte.MaxValue,
|
||||||
|
windResistance,
|
||||||
|
byte.MaxValue,
|
||||||
|
byte.MaxValue,
|
||||||
|
};
|
||||||
|
byte checksum = (byte)0;
|
||||||
|
data.ForEach(b => checksum ^= b);
|
||||||
|
data.Add(checksum);
|
||||||
|
|
||||||
|
this.hwInterface.WriteCharacteristic(this.tacxFecWriteCharacteristic, data.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 轨道阻力
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="grade">坡度百分比的值,单位是%</param>
|
||||||
|
public void SetTrackResistance(double grade)
|
||||||
|
{
|
||||||
|
if (this.State != Ant.DeviceState.Connected)
|
||||||
|
return;
|
||||||
|
if (tacxFecWriteCharacteristic == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_grade = grade;
|
||||||
|
if (_grade > 15)
|
||||||
|
{
|
||||||
|
_grade = 15;
|
||||||
|
}
|
||||||
|
else if (_grade < -5)
|
||||||
|
{
|
||||||
|
_grade = -5;
|
||||||
|
}
|
||||||
|
|
||||||
|
var gradeValue = Convert.ToInt32((grade + 200) * 100);
|
||||||
|
var gradeBytes = BitConverter.GetBytes(gradeValue);
|
||||||
|
|
||||||
|
byte id = 79;
|
||||||
|
byte size = 9;
|
||||||
|
byte channel = 5;
|
||||||
|
List<byte> data = new List<byte> { 164, size, id, channel, 51,
|
||||||
|
byte.MaxValue,
|
||||||
|
byte.MaxValue,
|
||||||
|
byte.MaxValue,
|
||||||
|
byte.MaxValue,
|
||||||
|
gradeBytes[0],
|
||||||
|
gradeBytes[1],
|
||||||
|
byte.MaxValue,
|
||||||
|
};
|
||||||
|
byte checksum = (byte)0;
|
||||||
|
data.ForEach(b => checksum ^= b);
|
||||||
|
data.Add(checksum);
|
||||||
|
|
||||||
|
this.hwInterface.WriteCharacteristic(this.tacxFecWriteCharacteristic, data.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateUserConfiguration(double weight)
|
||||||
|
{
|
||||||
|
var _weight = (int)(weight * 100);
|
||||||
|
if (this.State != Ant.DeviceState.Connected)
|
||||||
|
return;
|
||||||
|
if (tacxFecWriteCharacteristic == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
byte id = 79;
|
||||||
|
byte size = 4;
|
||||||
|
byte channel = 5;
|
||||||
|
List<byte> data = new List<byte> { 164, size, id, channel, 55,
|
||||||
|
(byte) (_weight & (int) byte.MaxValue),
|
||||||
|
(byte) (_weight >> 8 & (int) byte.MaxValue),
|
||||||
|
byte.MaxValue,
|
||||||
|
(byte) 143,
|
||||||
|
(byte) 12,
|
||||||
|
(byte) 70,
|
||||||
|
(byte) 0
|
||||||
|
};
|
||||||
|
byte checksum = (byte)0;
|
||||||
|
data.ForEach(b => checksum ^= b);
|
||||||
|
data.Add(checksum);
|
||||||
|
|
||||||
|
this.hwInterface.WriteCharacteristic(this.tacxFecWriteCharacteristic, data.ToArray());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Assets/Scripts/Devices/Ble/Devices/Tacx.cs.meta
Normal file
11
Assets/Scripts/Devices/Ble/Devices/Tacx.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: d133d5406fc475841a781b88d91dc139
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
21
Assets/Scripts/Devices/Ble/Extension/PrimitiveExtensions.cs
Normal file
21
Assets/Scripts/Devices/Ble/Extension/PrimitiveExtensions.cs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Assets.Scripts.Devices.Ble.Extension
|
||||||
|
{
|
||||||
|
public static class PrimitiveExtensions
|
||||||
|
{
|
||||||
|
public static bool IsBitSet(this byte value, int position)
|
||||||
|
{
|
||||||
|
return ((uint)value & (uint)(1 << position)) > 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsBitSet(this ushort value, int position)
|
||||||
|
{
|
||||||
|
return ((uint)value & (uint)(1 << position)) > 0U;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: d49278e3c0c3a8a43bc1145abf67a5c0
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
8
Assets/Scripts/Devices/Ble/Interfaces.meta
Normal file
8
Assets/Scripts/Devices/Ble/Interfaces.meta
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: c3f0cb374472e52419b47f6e6d582341
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
20
Assets/Scripts/Devices/Ble/Interfaces/ICharacteristic.cs
Normal file
20
Assets/Scripts/Devices/Ble/Interfaces/ICharacteristic.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Assets.Scripts.Devices.Ble.Interfaces
|
||||||
|
{
|
||||||
|
public interface ICharacteristic
|
||||||
|
{
|
||||||
|
Guid Uuid { get; }
|
||||||
|
Guid ServiceUuid { get; }
|
||||||
|
|
||||||
|
bool IsOptional { get; }
|
||||||
|
|
||||||
|
void HandleAttributeReceived(byte[] data);
|
||||||
|
|
||||||
|
void SetUnavailable();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: e333c9c3812a8654c87353be9e87e84e
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@ -16,7 +16,7 @@ namespace Assets.Scripts.Ble.Scan
|
|||||||
public BlePeripheralInfo Peripheral { get; }
|
public BlePeripheralInfo Peripheral { get; }
|
||||||
public int Rssi { get; }
|
public int Rssi { get; }
|
||||||
|
|
||||||
public SensorType SensorType { get; }
|
public SensorType SensorType { get; internal set; }
|
||||||
public BleAdvertisementInfo(BlePeripheralInfo peripheral, int rssi, bool connectible, List<Guid> services, byte[] manufactureData, SensorType sensor)
|
public BleAdvertisementInfo(BlePeripheralInfo peripheral, int rssi, bool connectible, List<Guid> services, byte[] manufactureData, SensorType sensor)
|
||||||
{
|
{
|
||||||
this.Peripheral = peripheral;
|
this.Peripheral = peripheral;
|
||||||
@ -26,6 +26,8 @@ namespace Assets.Scripts.Ble.Scan
|
|||||||
//this.ManufactureData = manufactureData;
|
//this.ManufactureData = manufactureData;
|
||||||
|
|
||||||
this.SensorType = sensor;
|
this.SensorType = sensor;
|
||||||
|
|
||||||
|
Index = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly List<Guid> services;
|
private readonly List<Guid> services;
|
||||||
@ -36,5 +38,14 @@ namespace Assets.Scripts.Ble.Scan
|
|||||||
return this.services;
|
return this.services;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void TryAddService(Guid service)
|
||||||
|
{
|
||||||
|
if (this.services.Contains(service))
|
||||||
|
return;
|
||||||
|
this.services.Add(service);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Index { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,7 +7,7 @@ using System.Threading.Tasks;
|
|||||||
namespace Assets.Scripts.Ble
|
namespace Assets.Scripts.Ble
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// rouvy里的 WinBlePeripheralInfo类
|
/// r里的 WinBlePeripheralInfo类
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class BleDeviceProxy
|
public class BleDeviceProxy
|
||||||
{
|
{
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
using Assets.Scripts.Ble.Win;
|
using Assets.Scripts.Ble.Win;
|
||||||
using Assets.Scripts.Devices.Ant;
|
using Assets.Scripts.Devices.Ant;
|
||||||
using Assets.Scripts.Devices.Ble;
|
using Assets.Scripts.Devices.Ble;
|
||||||
|
using Assets.Scripts.Devices.Ble.Win;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -96,53 +97,90 @@ namespace Assets.Scripts.Ble
|
|||||||
|
|
||||||
private void WatcherScanInfoReceived(WclBleMainThread sender, long address, string name, int rssi, CPPBridge.WclBleAdvertisementType packetType, Guid? service)
|
private void WatcherScanInfoReceived(WclBleMainThread sender, long address, string name, int rssi, CPPBridge.WclBleAdvertisementType packetType, Guid? service)
|
||||||
{
|
{
|
||||||
//Debug.Log($"address:{ address }, name:{ name }, service:{ (service == null ? "" : service.Value.ToString()) }");
|
//if(address != 224160707349234)
|
||||||
|
//{
|
||||||
|
//return;
|
||||||
|
//}
|
||||||
|
if (service.HasValue)
|
||||||
|
{
|
||||||
|
//Debug.Log($"address:{ address }, name:{ name }, service:{ (service == null ? "" : service.Value.ToString()) }");
|
||||||
|
}
|
||||||
if (!string.IsNullOrWhiteSpace(name))
|
if (!string.IsNullOrWhiteSpace(name))
|
||||||
{
|
{
|
||||||
if (pCache.ContainsKey(address.ToString()))
|
if (pCache.ContainsKey(address.ToString()))
|
||||||
{
|
{
|
||||||
((pCache[address.ToString()].Peripheral) as WinBlePeripheralInfo).SetName(name);
|
(pCache[address.ToString()].Peripheral as WinBlePeripheralInfo).SetName(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//Debug.Log("service:" + service.ToString()+",name:" + name);
|
//Debug.Log("service:" + service.ToString()+",name:" + name);
|
||||||
if (service.HasValue && ServiceUuids.Services.Select(s => s.IdGuid).Any(x => x.Equals(service.Value)))
|
if (!service.HasValue || ServiceUuids.Services.Select(s => s.IdGuid).All(x => !x.Equals(service.Value)))
|
||||||
{
|
{
|
||||||
SensorType sensor = SensorType.None;
|
return;
|
||||||
List<Guid> services = null;
|
}
|
||||||
if (service != null)
|
SensorType sensor = SensorType.None;
|
||||||
|
List<Guid> services = null;
|
||||||
|
if (service != null)
|
||||||
|
{
|
||||||
|
|
||||||
|
services = new List<Guid> { service.Value };
|
||||||
|
foreach(var item in ServiceUuids.Services)
|
||||||
{
|
{
|
||||||
|
if(item.IdGuid != service.Value)
|
||||||
services = new List<Guid> { service.Value };
|
|
||||||
foreach(var item in ServiceUuids.Services)
|
|
||||||
{
|
{
|
||||||
if(item.IdGuid != service.Value)
|
continue;
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if(item.IdByteArray == ServiceUuids.Ftms)
|
|
||||||
{
|
|
||||||
sensor = SensorType.Trainer;
|
|
||||||
}
|
|
||||||
else if(item.IdByteArray == ServiceUuids.HeartRate)
|
|
||||||
{
|
|
||||||
sensor = SensorType.HeartRate;
|
|
||||||
}
|
|
||||||
else if(item.IdByteArray == ServiceUuids.CyclingPower)
|
|
||||||
{
|
|
||||||
sensor = SensorType.Power;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
if(item.IdByteArray == ServiceUuids.Ftms)
|
||||||
|
{
|
||||||
|
sensor = SensorType.Trainer;
|
||||||
|
}
|
||||||
|
else if(item.IdByteArray == ServiceUuids.HeartRate)
|
||||||
|
{
|
||||||
|
sensor = SensorType.HeartRate;
|
||||||
|
}
|
||||||
|
else if(item.IdByteArray == ServiceUuids.CyclingPower)
|
||||||
|
{
|
||||||
|
sensor = SensorType.Power;
|
||||||
|
//sensor = SensorType.Trainer;
|
||||||
|
}
|
||||||
|
else if(item.IdByteArray == ServiceUuids.CyclingSpeedCadence)
|
||||||
|
{
|
||||||
|
sensor = SensorType.SpeedCadence;
|
||||||
|
}
|
||||||
|
else if(item.IdByteArray == ServiceUuids.TacxBle)
|
||||||
|
{
|
||||||
|
sensor = SensorType.Trainer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if (!pCache.ContainsKey(address.ToString())) {
|
if (!pCache.ContainsKey(address.ToString()))
|
||||||
var device = new BleAdvertisementInfo(new WinBlePeripheralInfo(address.ToString(), name), rssi, true, services, null, sensor);
|
{
|
||||||
pCache.Add(address.ToString(), device);
|
var device = new BleAdvertisementInfo(new WinBlePeripheralInfo(address.ToString(), name), rssi, true, services, null, sensor);
|
||||||
|
pCache.Add(address.ToString(), device);
|
||||||
|
|
||||||
WclBleGattThread gattClient = this.SetUpGattClient(device.Peripheral);
|
WclBleGattThread gattClient = this.SetUpGattClient(device.Peripheral);
|
||||||
//this.ConnectInternal(gattClient);
|
//this.ConnectInternal(gattClient);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//Debug.Log(sensor);
|
||||||
|
//pCache[address.ToString()].SensorType = sensor;
|
||||||
|
foreach (var item in services)
|
||||||
|
{
|
||||||
|
pCache[address.ToString()].TryAddService(item);
|
||||||
|
}
|
||||||
|
pCache[address.ToString()].Index++;
|
||||||
|
if(pCache[address.ToString()].SensorType == SensorType.Power && pCache[address.ToString()].Services.Any(s=> s.Equals(ServiceUuids.Get(ServiceUuids.TacxBle).IdGuid)))
|
||||||
|
{
|
||||||
|
pCache[address.ToString()].SensorType = SensorType.Trainer;
|
||||||
|
//Debug.Log("纠正为trainer, "+ pCache[address.ToString()].Index);
|
||||||
}
|
}
|
||||||
|
|
||||||
_discoveredCallback?.Invoke(pCache[address.ToString()]);
|
|
||||||
|
if (pCache[address.ToString()].Index > 4 || pCache[address.ToString()].SensorType != SensorType.Power)
|
||||||
|
{
|
||||||
|
_discoveredCallback?.Invoke(pCache[address.ToString()]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,8 +217,11 @@ namespace Assets.Scripts.Ble
|
|||||||
|
|
||||||
private void ConnectInternal(WclBleGattThread gattClient)
|
private void ConnectInternal(WclBleGattThread gattClient)
|
||||||
{
|
{
|
||||||
int num = gattClient.Connect();
|
//Task.Run(() =>
|
||||||
Debug.Log("连接设备返回" + num);
|
//{
|
||||||
|
int num = gattClient.Connect();
|
||||||
|
Debug.Log("连接设备返回" + num);
|
||||||
|
//});
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void DisconnectPeripheral(BlePeripheralInfo peripheral, Action callback)
|
internal void DisconnectPeripheral(BlePeripheralInfo peripheral, Action callback)
|
||||||
@ -323,7 +364,10 @@ namespace Assets.Scripts.Ble
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.characteristicsDiscoveredCallbacks.Add(service, callback);
|
if (!this.characteristicsDiscoveredCallbacks.ContainsKey(service))
|
||||||
|
{
|
||||||
|
this.characteristicsDiscoveredCallbacks.Add(service, callback);
|
||||||
|
}
|
||||||
int num = gattThread.DiscoverCharacteristics(service);
|
int num = gattThread.DiscoverCharacteristics(service);
|
||||||
if (WclBleErrors.IsSuccessCode(num))
|
if (WclBleErrors.IsSuccessCode(num))
|
||||||
{
|
{
|
||||||
@ -355,11 +399,29 @@ namespace Assets.Scripts.Ble
|
|||||||
this.GattCharacteristicSubscribed(gattThread, characteristic, response);
|
this.GattCharacteristicSubscribed(gattThread, characteristic, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void WriteCharacteristic(BleCharacteristicInfo characteristic, byte[] data)
|
||||||
|
{
|
||||||
|
var gattThread = this.wclBleMainThread.GetGattThread(characteristic.Peripheral);
|
||||||
|
if(gattThread == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int num = gattThread.WriteCharacteristic(characteristic, data);
|
||||||
|
if (WclBleErrors.IsSuccessCode(num))
|
||||||
|
{
|
||||||
|
Debug.Log("设置命令成功");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
this.wclBleMainThread.Dispose();
|
this.wclBleMainThread.Dispose();
|
||||||
this.wclBleMainThread = null;
|
this.wclBleMainThread = null;
|
||||||
hwInterface = null;
|
hwInterface = null;
|
||||||
|
pCache.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ReadCharacteristic(BleCharacteristicInfo characteristic, CharacteristicReadCallback callback)
|
public void ReadCharacteristic(BleCharacteristicInfo characteristic, CharacteristicReadCallback callback)
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
using Assets.Scripts.Devices.Ble;
|
using Assets.Scripts.Devices.Ble;
|
||||||
|
using Assets.Scripts.Devices.Ble.Win;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
using Assets.Scripts.Devices.Ble;
|
using Assets.Scripts.Devices.Ble;
|
||||||
|
using Assets.Scripts.Devices.Ble.Win;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|||||||
43
Assets/Scripts/Devices/Ble/Win/WclAlertableWait.cs
Normal file
43
Assets/Scripts/Devices/Ble/Win/WclAlertableWait.cs
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Assets.Scripts.Devices.Ble.Win
|
||||||
|
{
|
||||||
|
internal class WclAlertableWait
|
||||||
|
{
|
||||||
|
[DllImport("WclBlePluginCPP.dll", CallingConvention = CallingConvention.StdCall, EntryPoint = "WCLWait")]
|
||||||
|
[return: MarshalAs(UnmanagedType.U4)]
|
||||||
|
public static extern uint Wait([MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.SysInt, SizeParamIndex = 1)][In] IntPtr[] Handle, [MarshalAs(UnmanagedType.U4)][In] uint Cnt, [MarshalAs(UnmanagedType.U4)][In] uint Timeout);
|
||||||
|
|
||||||
|
// Token: 0x0600207E RID: 8318
|
||||||
|
[DllImport("WclBlePluginCPP.dll", CallingConvention = CallingConvention.StdCall, EntryPoint = "WCLFlushApc")]
|
||||||
|
[return: MarshalAs(UnmanagedType.U4)]
|
||||||
|
public static extern uint FlushApc();
|
||||||
|
|
||||||
|
// Token: 0x0600207F RID: 8319
|
||||||
|
[DllImport("WclBlePluginCPP.dll", CallingConvention = CallingConvention.StdCall, EntryPoint = "WCLSetApcSync")]
|
||||||
|
public static extern void SetApcSync();
|
||||||
|
|
||||||
|
// Token: 0x04001189 RID: 4489
|
||||||
|
public const uint WAIT_OBJECT_0 = 0U;
|
||||||
|
|
||||||
|
// Token: 0x0400118A RID: 4490
|
||||||
|
public const uint WAIT_IO_COMPLETION = 192U;
|
||||||
|
|
||||||
|
// Token: 0x0400118B RID: 4491
|
||||||
|
public const uint WAIT_TIMEOUT = 258U;
|
||||||
|
|
||||||
|
// Token: 0x0400118C RID: 4492
|
||||||
|
public const uint WAIT_FAILED = 4294967295U;
|
||||||
|
|
||||||
|
// Token: 0x0400118D RID: 4493
|
||||||
|
public const uint INFINITE = 4294967295U;
|
||||||
|
|
||||||
|
// Token: 0x0400118E RID: 4494
|
||||||
|
public const string GuidTemplate = "0000XXXX-0000-1000-8000-00805F9B34FB";
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Assets/Scripts/Devices/Ble/Win/WclAlertableWait.cs.meta
Normal file
11
Assets/Scripts/Devices/Ble/Win/WclAlertableWait.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 4ec3942a1d98efc4eb36cd00001109b1
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@ -1,15 +1,16 @@
|
|||||||
using Assets.Scripts.Ble.Win;
|
using Assets.Scripts.Ble;
|
||||||
|
using Assets.Scripts.Ble.Win;
|
||||||
using Assets.Scripts.Ble.Win.CPPBridge;
|
using Assets.Scripts.Ble.Win.CPPBridge;
|
||||||
using Assets.Scripts.Devices.Ble;
|
|
||||||
using Assets.Scripts.Devices.Ble.Win;
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace Assets.Scripts.Ble
|
namespace Assets.Scripts.Devices.Ble.Win
|
||||||
{
|
{
|
||||||
internal class WclBleGattThread
|
internal class WclBleGattThread
|
||||||
{
|
{
|
||||||
@ -163,7 +164,12 @@ namespace Assets.Scripts.Ble
|
|||||||
private readonly long address;
|
private readonly long address;
|
||||||
|
|
||||||
public BlePeripheralInfo Peripheral { get; }
|
public BlePeripheralInfo Peripheral { get; }
|
||||||
|
private Thread thread;
|
||||||
|
private ConcurrentQueue<Action> actions = new ConcurrentQueue<Action>();
|
||||||
|
private bool start = false;
|
||||||
|
private ManualResetEvent sEvent;
|
||||||
|
private AutoResetEvent aEvent;
|
||||||
|
private ManualResetEvent tEvent;
|
||||||
internal WclBleGattThread(BlePeripheralInfo bleDevice, IntPtr radio)
|
internal WclBleGattThread(BlePeripheralInfo bleDevice, IntPtr radio)
|
||||||
{
|
{
|
||||||
this.Peripheral = bleDevice;
|
this.Peripheral = bleDevice;
|
||||||
@ -175,10 +181,84 @@ namespace Assets.Scripts.Ble
|
|||||||
|
|
||||||
public bool Start()
|
public bool Start()
|
||||||
{
|
{
|
||||||
this.SetUpWorkerThread();
|
if (this.start)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
this.start = true;
|
||||||
|
|
||||||
|
this.sEvent = new ManualResetEvent(false);
|
||||||
|
this.tEvent = new ManualResetEvent(false);
|
||||||
|
this.aEvent = new AutoResetEvent(false);
|
||||||
|
|
||||||
|
//thread = new Thread(new ThreadStart(ThreadProc));
|
||||||
|
// this.sEvent.Set();
|
||||||
|
|
||||||
|
// IntPtr[] handle = new IntPtr[]
|
||||||
|
// {
|
||||||
|
// this.tEvent.SafeWaitHandle.DangerousGetHandle(),
|
||||||
|
// this.aEvent.SafeWaitHandle.DangerousGetHandle()
|
||||||
|
// };
|
||||||
|
// while (WclAlertableWait.Wait(handle, 2U, WclAlertableWait.INFINITE) != WclAlertableWait.WAIT_OBJECT_0)
|
||||||
|
// {
|
||||||
|
// Action action;
|
||||||
|
// if (this.actions.TryDequeue(out action))
|
||||||
|
// {
|
||||||
|
// if (action != null)
|
||||||
|
// {
|
||||||
|
// Debug.Log("连接设备");
|
||||||
|
// action();
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// }));
|
||||||
|
//thread.Start();
|
||||||
|
|
||||||
|
//this.sEvent.WaitOne();
|
||||||
|
ThreadProc();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void Stop()
|
||||||
|
{
|
||||||
|
Debug.Log("停止");
|
||||||
|
start = false;
|
||||||
|
thread?.Abort();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ThreadProc()
|
||||||
|
{
|
||||||
|
this.SetUpWorkerThread();
|
||||||
|
//this.sEvent.Set();
|
||||||
|
//this.DoWorkerLoop();
|
||||||
|
|
||||||
|
//this.CleanUpWorkerThread();
|
||||||
|
//this.InternalCleanUp();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CleanUpWorkerThread()
|
||||||
|
{
|
||||||
|
this.gatt.Disconnect();
|
||||||
|
this.gatt.Dispose();
|
||||||
|
this.gatt = null;
|
||||||
|
}
|
||||||
|
private void InternalCleanUp()
|
||||||
|
{
|
||||||
|
this.sEvent.Close();
|
||||||
|
this.sEvent.Dispose();
|
||||||
|
this.sEvent = null;
|
||||||
|
|
||||||
|
this.aEvent.Close();
|
||||||
|
this.aEvent.Dispose();
|
||||||
|
this.aEvent = null;
|
||||||
|
|
||||||
|
this.tEvent.Close();
|
||||||
|
this.tEvent.Dispose();
|
||||||
|
this.tEvent = null;
|
||||||
|
}
|
||||||
|
|
||||||
private void SetUpWorkerThread()
|
private void SetUpWorkerThread()
|
||||||
{
|
{
|
||||||
this.gatt = new WclBleGattClient(this.address, this.rPtr)
|
this.gatt = new WclBleGattClient(this.address, this.rPtr)
|
||||||
@ -189,6 +269,28 @@ namespace Assets.Scripts.Ble
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void DoWorkerLoop()
|
||||||
|
{
|
||||||
|
IntPtr[] handle = new IntPtr[]
|
||||||
|
{
|
||||||
|
this.tEvent.SafeWaitHandle.DangerousGetHandle(),
|
||||||
|
this.aEvent.SafeWaitHandle.DangerousGetHandle()
|
||||||
|
};
|
||||||
|
while (WclAlertableWait.Wait(handle, 2U, 4294967295U) != 0U)
|
||||||
|
{
|
||||||
|
//this.InvokeQueuedActions();
|
||||||
|
Action action;
|
||||||
|
if (this.actions.TryDequeue(out action))
|
||||||
|
{
|
||||||
|
if (action != null)
|
||||||
|
{
|
||||||
|
Debug.Log("连接设备");
|
||||||
|
action();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void OnCharacteristicChanged(WclBleGattClient connection, ushort handle, byte[] value)
|
private void OnCharacteristicChanged(WclBleGattClient connection, ushort handle, byte[] value)
|
||||||
{
|
{
|
||||||
if (!this.subscribedCharHandles.ContainsKey(handle)) {
|
if (!this.subscribedCharHandles.ContainsKey(handle)) {
|
||||||
@ -260,6 +362,10 @@ namespace Assets.Scripts.Ble
|
|||||||
public int Connect()
|
public int Connect()
|
||||||
{
|
{
|
||||||
this.gatt.Connect();
|
this.gatt.Connect();
|
||||||
|
//this.actions.Enqueue(() =>
|
||||||
|
//{
|
||||||
|
// this.gatt.Connect();
|
||||||
|
//});
|
||||||
return WclBleErrors.WCL_E_SUCCESS;
|
return WclBleErrors.WCL_E_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -381,6 +487,21 @@ namespace Assets.Scripts.Ble
|
|||||||
this.gattCharacteristicsSubscribed(this, characteristic, response);
|
this.gattCharacteristicsSubscribed(this, characteristic, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int WriteCharacteristic(BleCharacteristicInfo characteristicInfo, byte[] data)
|
||||||
|
{
|
||||||
|
if (!this.charMapping.ContainsKey(characteristicInfo))
|
||||||
|
{
|
||||||
|
return WclBleErrors.WCL_E_CONNECTION_NOT_ACTIVE;
|
||||||
|
}
|
||||||
|
GattCharacteristic gCh = this.charMapping[characteristicInfo];
|
||||||
|
|
||||||
|
int result = this.gatt.WriteCharacteristic(gCh, data);
|
||||||
|
|
||||||
|
|
||||||
|
return WclBleErrors.WCL_E_SUCCESS;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private class WinBleCharacteristicInfo : BleCharacteristicInfo
|
private class WinBleCharacteristicInfo : BleCharacteristicInfo
|
||||||
{
|
{
|
||||||
// Token: 0x06003F85 RID: 16261 RVA: 0x000EA274 File Offset: 0x000E8474
|
// Token: 0x06003F85 RID: 16261 RVA: 0x000EA274 File Offset: 0x000E8474
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
using Assets.Scripts.Ble.CPPBridge;
|
using Assets.Scripts.Ble;
|
||||||
|
using Assets.Scripts.Ble.CPPBridge;
|
||||||
using Assets.Scripts.Devices.Ble;
|
using Assets.Scripts.Devices.Ble;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@ -8,7 +9,7 @@ using System.Threading;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace Assets.Scripts.Ble
|
namespace Assets.Scripts.Devices.Ble.Win
|
||||||
{
|
{
|
||||||
internal class WclBleMainThread
|
internal class WclBleMainThread
|
||||||
{
|
{
|
||||||
@ -99,6 +100,12 @@ namespace Assets.Scripts.Ble
|
|||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
|
Debug.Log("停止thread");
|
||||||
|
foreach (var item in this.gattClients.Values)
|
||||||
|
{
|
||||||
|
item.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
wclBleManager.Dispose();
|
wclBleManager.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
215
Assets/Scripts/Devices/Ble/Win/WclBleThread.cs
Normal file
215
Assets/Scripts/Devices/Ble/Win/WclBleThread.cs
Normal file
@ -0,0 +1,215 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace Assets.Scripts.Devices.Ble.Win
|
||||||
|
{
|
||||||
|
internal abstract class WclBleThread
|
||||||
|
{
|
||||||
|
// Token: 0x170005E2 RID: 1506
|
||||||
|
// (get) Token: 0x06002114 RID: 8468 RVA: 0x000890FE File Offset: 0x000872FE
|
||||||
|
public bool IsRunning
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return this.started || this.IsTerminating;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Token: 0x170005E3 RID: 1507
|
||||||
|
// (get) Token: 0x06002115 RID: 8469 RVA: 0x00089112 File Offset: 0x00087312
|
||||||
|
public bool IsTerminating
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return this.terminating;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Token: 0x170005E4 RID: 1508
|
||||||
|
// (get) Token: 0x06002116 RID: 8470 RVA: 0x0008911C File Offset: 0x0008731C
|
||||||
|
public bool CanLoadWork
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return this.IsRunning && !this.IsTerminating;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Token: 0x06002117 RID: 8471
|
||||||
|
protected abstract void SetUpWorkerThread();
|
||||||
|
|
||||||
|
// Token: 0x06002118 RID: 8472
|
||||||
|
protected abstract void CleanUpWorkerThread();
|
||||||
|
|
||||||
|
// Token: 0x06002119 RID: 8473 RVA: 0x00089131 File Offset: 0x00087331
|
||||||
|
protected void TreadProcInitialized()
|
||||||
|
{
|
||||||
|
this.sEvent.Set();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Token: 0x0600211A RID: 8474 RVA: 0x0008913F File Offset: 0x0008733F
|
||||||
|
protected void ProcessPendingAPCMessages()
|
||||||
|
{
|
||||||
|
while (WclAlertableWait.FlushApc() != 0U)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Token: 0x0600211B RID: 8475 RVA: 0x00089148 File Offset: 0x00087348
|
||||||
|
protected void InternalCleanUp()
|
||||||
|
{
|
||||||
|
this.sEvent.Close();
|
||||||
|
this.sEvent.Dispose();
|
||||||
|
this.sEvent = null;
|
||||||
|
this.aEvent.Close();
|
||||||
|
this.aEvent.Dispose();
|
||||||
|
this.aEvent = null;
|
||||||
|
this.tEvent.Close();
|
||||||
|
this.tEvent.Dispose();
|
||||||
|
this.tEvent = null;
|
||||||
|
this.terminating = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Token: 0x0600211C RID: 8476 RVA: 0x000891B5 File Offset: 0x000873B5
|
||||||
|
private void ThreadProc()
|
||||||
|
{
|
||||||
|
this.SetUpWorkerThread();
|
||||||
|
this.sEvent.Set();
|
||||||
|
this.DoWorkerLoop();
|
||||||
|
this.CleanUpWorkerThread();
|
||||||
|
this.InternalCleanUp();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Token: 0x0600211D RID: 8477 RVA: 0x000891DC File Offset: 0x000873DC
|
||||||
|
private void DoWorkerLoop()
|
||||||
|
{
|
||||||
|
IntPtr[] handle = new IntPtr[]
|
||||||
|
{
|
||||||
|
this.tEvent.SafeWaitHandle.DangerousGetHandle(),
|
||||||
|
this.aEvent.SafeWaitHandle.DangerousGetHandle()
|
||||||
|
};
|
||||||
|
while (WclAlertableWait.Wait(handle, 2U, 4294967295U) != 0U && !this.terminating)
|
||||||
|
{
|
||||||
|
this.InvokeQueuedActions();
|
||||||
|
if (this.terminating)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Token: 0x0600211E RID: 8478 RVA: 0x0008923C File Offset: 0x0008743C
|
||||||
|
public virtual bool Start()
|
||||||
|
{
|
||||||
|
if (this.IsRunning)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
this.sEvent = new ManualResetEvent(false);
|
||||||
|
this.tEvent = new ManualResetEvent(false);
|
||||||
|
this.aEvent = new AutoResetEvent(false);
|
||||||
|
this.wThread = new Thread(new ThreadStart(this.ThreadProc));
|
||||||
|
this.wThread.Start();
|
||||||
|
this.sEvent.WaitOne();
|
||||||
|
this.started = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Token: 0x0600211F RID: 8479 RVA: 0x000892B0 File Offset: 0x000874B0
|
||||||
|
public virtual bool Stop()
|
||||||
|
{
|
||||||
|
if (!this.started || this.IsTerminating)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
this.terminating = true;
|
||||||
|
this.tEvent.Set();
|
||||||
|
this.wThread = null;
|
||||||
|
this.ClearActionQueue();
|
||||||
|
this.started = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Token: 0x06002120 RID: 8480 RVA: 0x000892FD File Offset: 0x000874FD
|
||||||
|
protected bool EnqueueAction(Action action)
|
||||||
|
{
|
||||||
|
if (this.CanLoadWork)
|
||||||
|
{
|
||||||
|
this.aQueue.Enqueue(action);
|
||||||
|
this.aEvent.Set();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Token: 0x06002121 RID: 8481 RVA: 0x00089324 File Offset: 0x00087524
|
||||||
|
protected void ClearActionQueue()
|
||||||
|
{
|
||||||
|
Action action;
|
||||||
|
while (this.aQueue.TryDequeue(out action))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Token: 0x06002122 RID: 8482 RVA: 0x00089340 File Offset: 0x00087540
|
||||||
|
protected void InvokeQueuedActions()
|
||||||
|
{
|
||||||
|
while (this.DequeueAdnInvokeAction())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Token: 0x06002123 RID: 8483 RVA: 0x0008934C File Offset: 0x0008754C
|
||||||
|
protected bool DequeueAdnInvokeAction()
|
||||||
|
{
|
||||||
|
Action action = this.TryDequActione();
|
||||||
|
if (action == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
action();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Token: 0x06002124 RID: 8484 RVA: 0x0008936C File Offset: 0x0008756C
|
||||||
|
private Action TryDequActione()
|
||||||
|
{
|
||||||
|
if (!this.CanLoadWork)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Action result;
|
||||||
|
if (!this.aQueue.TryDequeue(out result))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Token: 0x04001341 RID: 4929
|
||||||
|
protected ManualResetEvent tEvent;
|
||||||
|
|
||||||
|
// Token: 0x04001342 RID: 4930
|
||||||
|
protected AutoResetEvent aEvent;
|
||||||
|
|
||||||
|
// Token: 0x04001343 RID: 4931
|
||||||
|
private readonly ConcurrentQueue<Action> aQueue = new ConcurrentQueue<Action>();
|
||||||
|
|
||||||
|
// Token: 0x04001344 RID: 4932
|
||||||
|
protected ManualResetEvent sEvent;
|
||||||
|
|
||||||
|
// Token: 0x04001345 RID: 4933
|
||||||
|
protected Thread wThread;
|
||||||
|
|
||||||
|
// Token: 0x04001346 RID: 4934
|
||||||
|
protected volatile bool terminating;
|
||||||
|
|
||||||
|
// Token: 0x04001347 RID: 4935
|
||||||
|
private volatile bool started;
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Assets/Scripts/Devices/Ble/Win/WclBleThread.cs.meta
Normal file
11
Assets/Scripts/Devices/Ble/Win/WclBleThread.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 25f702c985f2a1b41990cc8fcdcb0450
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@ -5,6 +5,7 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
namespace Assets.Scripts.Devices
|
namespace Assets.Scripts.Devices
|
||||||
{
|
{
|
||||||
@ -45,6 +46,7 @@ namespace Assets.Scripts.Devices
|
|||||||
var adapter = adapters.FirstOrDefault(a => a.Interface == connectionInterface);
|
var adapter = adapters.FirstOrDefault(a => a.Interface == connectionInterface);
|
||||||
if(adapter != null)
|
if(adapter != null)
|
||||||
{
|
{
|
||||||
|
Debug.Log("bbbbbb " + (adapter.GetState().ToString()));
|
||||||
return adapter.GetState();
|
return adapter.GetState();
|
||||||
}
|
}
|
||||||
return DeviceAdapterState.Unavailable;
|
return DeviceAdapterState.Unavailable;
|
||||||
|
|||||||
@ -10,6 +10,7 @@ public class DeviceItem : Selectable, IEventSystemHandler, IPointerClickHandler
|
|||||||
{
|
{
|
||||||
private bool isOn;
|
private bool isOn;
|
||||||
private Text mText;
|
private Text mText;
|
||||||
|
private Text mType;
|
||||||
public AbstractDevice DeviceInfo
|
public AbstractDevice DeviceInfo
|
||||||
{
|
{
|
||||||
get;set;
|
get;set;
|
||||||
@ -18,6 +19,7 @@ public class DeviceItem : Selectable, IEventSystemHandler, IPointerClickHandler
|
|||||||
protected override void Awake()
|
protected override void Awake()
|
||||||
{
|
{
|
||||||
mText = this.transform.Find("Name").GetComponent<Text>();
|
mText = this.transform.Find("Name").GetComponent<Text>();
|
||||||
|
mType = this.transform.Find("Type").GetComponent<Text>();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start is called before the first frame update
|
// Start is called before the first frame update
|
||||||
@ -25,11 +27,17 @@ public class DeviceItem : Selectable, IEventSystemHandler, IPointerClickHandler
|
|||||||
{
|
{
|
||||||
//this.currentSelectionState = SelectionState.Selected
|
//this.currentSelectionState = SelectionState.Selected
|
||||||
|
|
||||||
mText.text = DeviceInfo.Name + "-" + DeviceInfo.DeviceNumber;
|
mText.text = DeviceInfo.Name;// + "-" + DeviceInfo.DeviceNumber;
|
||||||
|
if(DeviceInfo.Network == NetworkType.ANT)
|
||||||
|
{
|
||||||
|
mText.text += "-" + DeviceInfo.DeviceNumber;
|
||||||
|
}
|
||||||
//if(DeviceInfo.State == DeviceState.Connected)
|
//if(DeviceInfo.State == DeviceState.Connected)
|
||||||
{
|
{
|
||||||
// this.SetSelectedStyle();
|
// this.SetSelectedStyle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mType.text = DeviceInfo.Network.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -19,7 +19,7 @@ public class MainNav : MonoBehaviour
|
|||||||
var device = this.transform.Find("Device");
|
var device = this.transform.Find("Device");
|
||||||
UIManager.AddEvent(device.gameObject, EventTriggerType.PointerClick, x =>
|
UIManager.AddEvent(device.gameObject, EventTriggerType.PointerClick, x =>
|
||||||
{
|
{
|
||||||
Debug.Log("click device");
|
//Debug.Log("click device");
|
||||||
UIManager.ShowDevicePanel();
|
UIManager.ShowDevicePanel();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -8,6 +8,7 @@ using UnityEngine;
|
|||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
using UnityEngine.EventSystems;
|
using UnityEngine.EventSystems;
|
||||||
using DG.Tweening;
|
using DG.Tweening;
|
||||||
|
using Assets.Scripts.Devices.Ble.Devices;
|
||||||
|
|
||||||
public class DeviceController : PFUIPanel
|
public class DeviceController : PFUIPanel
|
||||||
{
|
{
|
||||||
@ -21,6 +22,11 @@ public class DeviceController : PFUIPanel
|
|||||||
RectTransform circulo;
|
RectTransform circulo;
|
||||||
private GameObject statusText;
|
private GameObject statusText;
|
||||||
|
|
||||||
|
private Image bleStatus;
|
||||||
|
private Sprite ble0;
|
||||||
|
private Sprite ble1;
|
||||||
|
RectTransform bleCirculo;
|
||||||
|
|
||||||
private bool _available = false;
|
private bool _available = false;
|
||||||
private bool Available
|
private bool Available
|
||||||
{
|
{
|
||||||
@ -54,11 +60,38 @@ public class DeviceController : PFUIPanel
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool _bleAvailable = false;
|
||||||
|
private bool BleAvailable
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _bleAvailable;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value == _bleAvailable)
|
||||||
|
return;
|
||||||
|
_bleAvailable = value;
|
||||||
|
if (_bleAvailable)
|
||||||
|
{
|
||||||
|
bleStatus.sprite = ble1;
|
||||||
|
DOTween.Kill(bleCirculo, false);
|
||||||
|
bleCirculo.GetComponent<Image>().sprite = circuloCompleto;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bleStatus.sprite = ble0;
|
||||||
|
bleCirculo.GetComponent<Image>().sprite = circuloCarga;
|
||||||
|
bleCirculo.DOLocalRotate(new Vector3(0, 0, 360), 1f, RotateMode.FastBeyond360).SetEase(Ease.Linear).SetLoops(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected override void Awake()
|
protected override void Awake()
|
||||||
{
|
{
|
||||||
base.Awake();
|
base.Awake();
|
||||||
|
|
||||||
Debug.Log("device awake");
|
//Debug.Log("device awake");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start is called before the first frame update
|
// Start is called before the first frame update
|
||||||
@ -84,13 +117,12 @@ public class DeviceController : PFUIPanel
|
|||||||
//});
|
//});
|
||||||
|
|
||||||
var bg = this.transform.Find("Status").Find("Bg");
|
var bg = this.transform.Find("Status").Find("Bg");
|
||||||
antStatus = bg.Find("Ant+").GetComponent<Image>();
|
|
||||||
|
|
||||||
statusText = this.transform.Find("Status").Find("GameObject").gameObject;
|
statusText = this.transform.Find("Status").Find("GameObject").gameObject;
|
||||||
statusText.SetActive(false);
|
statusText.SetActive(false);
|
||||||
|
|
||||||
|
antStatus = bg.Find("AntIcon/Ant+").GetComponent<Image>();
|
||||||
circulo = bg.Find("Image").GetComponent<RectTransform>();
|
circulo = bg.Find("AntIcon/Image").GetComponent<RectTransform>();
|
||||||
//circulo.DORotate(new Vector3(0, 0, 360), 1.5f, RotateMode.Fast).SetLoops(-1);
|
//circulo.DORotate(new Vector3(0, 0, 360), 1.5f, RotateMode.Fast).SetLoops(-1);
|
||||||
circulo.DOLocalRotate(new Vector3(0, 0, 360), 1f, RotateMode.FastBeyond360).SetEase(Ease.Linear).SetLoops(-1);
|
circulo.DOLocalRotate(new Vector3(0, 0, 360), 1f, RotateMode.FastBeyond360).SetEase(Ease.Linear).SetLoops(-1);
|
||||||
|
|
||||||
@ -99,7 +131,42 @@ public class DeviceController : PFUIPanel
|
|||||||
circuloCarga = Resources.Load<Sprite>("Images/icon-circulo-carga");
|
circuloCarga = Resources.Load<Sprite>("Images/icon-circulo-carga");
|
||||||
circuloCompleto = Resources.Load<Sprite>("Images/icon-circulo-completo");
|
circuloCompleto = Resources.Load<Sprite>("Images/icon-circulo-completo");
|
||||||
|
|
||||||
|
|
||||||
|
bleStatus = bg.Find("BleIcon/Ble").GetComponent<Image>();
|
||||||
|
bleCirculo = bg.Find("BleIcon/Image").GetComponent<RectTransform>();
|
||||||
|
bleCirculo.DOLocalRotate(new Vector3(0, 0, 360), 1f, RotateMode.FastBeyond360).SetEase(Ease.Linear).SetLoops(-1);
|
||||||
|
ble0 = Resources.Load<Sprite>("Images/Bluetooth_0");
|
||||||
|
ble1 = Resources.Load<Sprite>("Images/Bluetooth_2");
|
||||||
|
|
||||||
base.SetRounded(bg, 64);
|
base.SetRounded(bg, 64);
|
||||||
|
|
||||||
|
|
||||||
|
//var text = this.transform.Find("InputField").GetComponent<InputField>();
|
||||||
|
|
||||||
|
//var btn = this.transform.Find("Button").GetComponent<Button>();
|
||||||
|
//btn.onClick.AddListener(() =>
|
||||||
|
//{
|
||||||
|
// //Debug.Log(text.text);
|
||||||
|
// var device = App.MainDeviceAdapter.GetDevices().FirstOrDefault(d => d.State == DeviceState.Connected && d.Sensor == SensorType.HeartRate);
|
||||||
|
// if(device == null)
|
||||||
|
// {
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// //(device as HeartRate).GetBatteryLevel();
|
||||||
|
|
||||||
|
|
||||||
|
// //(device as Tacx).SetResistanceMode(int.Parse(text.text));
|
||||||
|
|
||||||
|
// //if (device is Tacx)
|
||||||
|
// //{
|
||||||
|
// // (device as Tacx).SetTrackResistance(double.Parse(text.text));
|
||||||
|
// //}
|
||||||
|
// //else if(device is FitDevice)
|
||||||
|
// //{
|
||||||
|
// // (device as FitDevice).SetErgMode(100* 4);
|
||||||
|
// //}
|
||||||
|
|
||||||
|
//});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -109,9 +176,11 @@ public class DeviceController : PFUIPanel
|
|||||||
timer -= Time.deltaTime;
|
timer -= Time.deltaTime;
|
||||||
if (timer <= 0)
|
if (timer <= 0)
|
||||||
{
|
{
|
||||||
//Available = AntConnector.Instance().IsAvailable;
|
|
||||||
Available = App.MainDeviceAdapter.GetState(Assets.Scripts.Devices.ConnectionInterface.ANT) == Assets.Scripts.Devices.DeviceAdapterState.On;
|
Available = App.MainDeviceAdapter.GetState(Assets.Scripts.Devices.ConnectionInterface.ANT) == Assets.Scripts.Devices.DeviceAdapterState.On;
|
||||||
|
|
||||||
|
BleAvailable = App.MainDeviceAdapter.GetState(Assets.Scripts.Devices.ConnectionInterface.BLE) == Assets.Scripts.Devices.DeviceAdapterState.On;
|
||||||
|
//Debug.Log("ble available:" + App.MainDeviceAdapter.GetState(Assets.Scripts.Devices.ConnectionInterface.BLE).ToString());
|
||||||
|
|
||||||
timer = 1.0f;
|
timer = 1.0f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user