Skip to content

Commit

Permalink
Formalize data types
Browse files Browse the repository at this point in the history
- ManufacturerData: handle different return values
- Apple
  - fail on non-binary inputs
  - return binary input on error case
- ServiceData: serialization functions
  • Loading branch information
danielspofford committed May 26, 2019
1 parent 3a4f861 commit 87b1f1d
Show file tree
Hide file tree
Showing 12 changed files with 169 additions and 38 deletions.
17 changes: 17 additions & 0 deletions lib/harald/data_type.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
defmodule Harald.DataType do
@moduledoc """
Reference: Core Specification Supplement, Part A
"""

alias Harald.DataType.{ManufacturerData, ServiceData}

@doc """
Returns a list of data type implementation modules.
"""
def modules do
[
ManufacturerData,
ServiceData
]
end
end
10 changes: 4 additions & 6 deletions lib/harald/data_type/manufacturer_data.ex
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
defmodule Harald.ManufacturerData do
defmodule Harald.DataType.ManufacturerData do
@moduledoc """
> The Manufacturer Specific data type is used for manufacturer specific data.
Expand All @@ -8,7 +8,7 @@ defmodule Harald.ManufacturerData do
`Harald.ManufacturerDataBehaviour` and `Harald.Serializable` behaviours.
"""

alias Harald.ManufacturerData.Apple
alias Harald.DataType.ManufacturerData.Apple
require Harald.AssignedNumbers.CompanyIdentifiers, as: CompanyIdentifiers

@modules [Apple]
Expand Down Expand Up @@ -59,12 +59,10 @@ defmodule Harald.ManufacturerData do
) do
case unquote(module).deserialize(sub_bin) do
{:ok, data} -> {:ok, {unquote(module).company, data}}
:error -> {:error, bin}
{:error, _} -> {:error, bin}
end
end
end)

def deserialize(_) do
{:error, :unhandled_company_id}
end
def deserialize(bin), do: {:error, bin}
end
9 changes: 3 additions & 6 deletions lib/harald/data_type/manufacturer_data/apple.ex
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
defmodule Harald.ManufacturerData.Apple do
defmodule Harald.DataType.ManufacturerData.Apple do
@moduledoc """
Serialization module for Apple.
Expand Down Expand Up @@ -83,10 +83,7 @@ defmodule Harald.ManufacturerData.Apple do
{:ok, {"iBeacon", %{major: 1, minor: 2, tx_power: 3, uuid: 4}}}
iex> deserialize(<<2, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 1, 0, 2>>)
:error
iex> deserialize(false)
:error
{:error, <<2, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 1, 0, 2>>}
"""
@impl Serializable
def deserialize(<<@ibeacon_identifier, @ibeacon_length, binary::binary-size(21)>>) do
Expand All @@ -107,5 +104,5 @@ defmodule Harald.ManufacturerData.Apple do
{:ok, {"iBeacon", data}}
end

def deserialize(_), do: :error
def deserialize(bin) when is_binary(bin), do: {:error, bin}
end
64 changes: 64 additions & 0 deletions lib/harald/data_type/service_data.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
defmodule Harald.DataType.ServiceData do
@moduledoc """
> The Service Data data type consists of a service UUID with the data associated with that
> service.
Reference: Core Specification Supplement, Part A, section 1.11.1
"""

alias Harald.Serializable
require Harald.AssignedNumbers.GenericAccessProfile, as: GenericAccessProfile

@behaviour Serializable

@description_32 "Service Data - 32-bit UUID"

@doc """
Returns the three GAP descriptions encompassed by service data.
"""
def gap_descriptions, do: [@description_32]

@doc """
iex> serialize({"Service Data - 32-bit UUID", %{data: <<5, 6>>, uuid: 67305985}})
{:ok, <<32, 1, 2, 3, 4, 5, 6>>}
"""
@impl Serializable
def serialize({@description_32, %{data: data, uuid: uuid}}) do
binary = <<
GenericAccessProfile.id(unquote(@description_32)),
uuid::little-size(32),
data::binary
>>

{:ok, binary}
end

def serialize(_), do: :error

@doc """
Deserializes a service data binary.
iex> deserialize(<<32, 1, 2, 3, 4, 5, 6>>)
{:ok, {"Service Data - 32-bit UUID", %{data: <<5, 6>>, uuid: 67305985}}}
"""
@impl Serializable
def deserialize(<<GenericAccessProfile.id(unquote(@description_32)), bin::binary>>) do
{status, data} =
case bin do
<<uuid::little-size(32), data::binary>> ->
service_data_32 = %{
uuid: uuid,
data: data
}

{:ok, service_data_32}

_ ->
{:error, bin}
end

{status, {@description_32, data}}
end

def deserialize(bin), do: {:error, bin}
end
2 changes: 1 addition & 1 deletion lib/harald/hci/event/le_meta/advertising_report/device.ex
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ defmodule Harald.HCI.Event.LEMeta.AdvertisingReport.Device do
"""

alias Harald.HCI.{ArrayedData, Event.LEMeta.AdvertisingReport.Device}
alias Harald.{ManufacturerData, Serializable, Transport.UART.Framing}
alias Harald.{DataType.ManufacturerData, Serializable, Transport.UART.Framing}
require Harald.AssignedNumbers.GenericAccessProfile, as: GenericAccessProfile

@enforce_keys [:event_type, :address_type, :address, :data, :rss]
Expand Down
24 changes: 24 additions & 0 deletions test/harald/data_type/manufacturer_data/apple_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
defmodule Harald.DataType.ManufacturerData.AppleTest do
use ExUnit.Case, async: true
use ExUnitProperties
alias Harald.Generators.DataType.ManufacturerData.Apple, as: AppleGen
alias Harald.DataType.ManufacturerData.Apple

doctest Apple, import: true

property "symmetric (de)serialization" do
check all bin <- AppleGen.binary() do
case Apple.deserialize(bin) do
{:ok, data} -> assert {:ok, bin} == Apple.serialize(data)
{:error, _} -> :ok
end
end

check all bin <- StreamData.binary() do
case Apple.deserialize(bin) do
{:ok, data} -> assert {:ok, bin} == Apple.serialize(data)
{:error, _} -> :ok
end
end
end
end
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
defmodule Harald.ManufacturerDataTest do
defmodule Harald.DataType.ManufacturerDataTest do
use ExUnit.Case, async: true
use ExUnitProperties
alias Harald.Generators.ManufacturerData, as: ManufacturerDataGen
alias Harald.ManufacturerData
alias Harald.Generators.DataType.ManufacturerData, as: ManufacturerDataGen
alias Harald.DataType.ManufacturerData

doctest ManufacturerData, import: true

Expand Down
24 changes: 24 additions & 0 deletions test/harald/data_type/service_data_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
defmodule Harald.DataType.ServiceDataTest do
use ExUnit.Case, async: true
use ExUnitProperties
alias Harald.Generators.DataType.ServiceData, as: ServiceDataGen
alias Harald.DataType.ServiceData

doctest ServiceData, import: true

property "symmetric (de)serialization" do
check all bin <- ServiceDataGen.binary() do
case ServiceData.deserialize(bin) do
{:ok, data} -> assert {:ok, bin} == ServiceData.serialize(data)
{:error, _} -> :ok
end
end

check all bin <- StreamData.binary() do
case ServiceData.deserialize(bin) do
{:ok, data} -> assert {:ok, bin} == ServiceData.serialize(data)
{:error, _} -> :ok
end
end
end
end
18 changes: 0 additions & 18 deletions test/harald/manufacturer_data/apple_test.exs

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
defmodule Harald.Generators.ManufacturerData do
defmodule Harald.Generators.DataType.ManufacturerData do
@moduledoc """
StreamData generators for manufacturer data.
"""

use ExUnitProperties
alias Harald.{Generators, ManufacturerData}
alias Harald.{DataType.ManufacturerData, Generators}
require Harald.AssignedNumbers.GenericAccessProfile, as: GenericAccessProfile

@spec binary :: no_return()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
defmodule Harald.Generators.ManufacturerData.Apple do
defmodule Harald.Generators.DataType.ManufacturerData.Apple do
@moduledoc """
StreamData generators for Apple manufacturer data.
Expand All @@ -8,7 +8,7 @@ defmodule Harald.Generators.ManufacturerData.Apple do
"""

use ExUnitProperties
alias Harald.ManufacturerData.Apple
alias Harald.DataType.ManufacturerData.Apple

@spec binary :: no_return()
def binary do
Expand Down
25 changes: 25 additions & 0 deletions test/support/generators/data_type/service_data.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
defmodule Harald.Generators.DataType.ServiceData do
@moduledoc """
StreamData generators for service data.
"""

import ExUnitProperties, only: :macros
alias Harald.DataType.ServiceData
require Harald.AssignedNumbers.GenericAccessProfile, as: GenericAccessProfile

@description_32 "Service Data - 32-bit UUID"

def binary do
gen all gap_description <- StreamData.member_of(ServiceData.gap_descriptions()),
bin <- binary(gap_description) do
bin
end
end

def binary(@description_32) do
gen all uuid <- StreamData.binary(length: 4),
data <- StreamData.binary(length: 1) do
<<GenericAccessProfile.id(unquote(@description_32)), uuid::binary-size(4), data::binary>>
end
end
end

0 comments on commit 87b1f1d

Please sign in to comment.