Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Formalize data types #38

Merged
merged 1 commit into from
May 26, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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