From e2e818b437ae0ee70c18d31536253bde1175458c Mon Sep 17 00:00:00 2001 From: Andry Ogorodnik Date: Sun, 4 May 2025 22:05:22 +0300 Subject: [PATCH] HM-11/cc2541 bluetooth module --- components/src/radio/hm11/README.md | 6 + components/src/radio/hm11/hm11.adb | 3217 +++++++++++++++++ components/src/radio/hm11/hm11.ads | 1377 +++++++ .../STM32F429_Discovery/hm11_f429disco.gpr | 16 + examples/shared/hm11/.gdbinit | 24 + examples/shared/hm11/README.md | 8 + examples/shared/hm11/src/drivers.adb | 440 +++ examples/shared/hm11/src/drivers.ads | 134 + examples/shared/hm11/src/hm11_example.adb | 228 ++ 9 files changed, 5450 insertions(+) create mode 100644 components/src/radio/hm11/README.md create mode 100644 components/src/radio/hm11/hm11.adb create mode 100644 components/src/radio/hm11/hm11.ads create mode 100644 examples/STM32F429_Discovery/hm11_f429disco.gpr create mode 100644 examples/shared/hm11/.gdbinit create mode 100644 examples/shared/hm11/README.md create mode 100644 examples/shared/hm11/src/drivers.adb create mode 100644 examples/shared/hm11/src/drivers.ads create mode 100644 examples/shared/hm11/src/hm11_example.adb diff --git a/components/src/radio/hm11/README.md b/components/src/radio/hm11/README.md new file mode 100644 index 000000000..4e3d62a09 --- /dev/null +++ b/components/src/radio/hm11/README.md @@ -0,0 +1,6 @@ +This directory contains the driver for HM-11/cc2541 bluetooth module. +The cc2541 is 2.4-GHz Bluetooth low energy Compliant and Proprietary +RF System-on-Chip. + +The examples/STM32F429_Discovery/hm11_f429disco.gpr project contains +a simple example. diff --git a/components/src/radio/hm11/hm11.adb b/components/src/radio/hm11/hm11.adb new file mode 100644 index 000000000..32d0d5919 --- /dev/null +++ b/components/src/radio/hm11/hm11.adb @@ -0,0 +1,3217 @@ +------------------------------------------------------------------------------ +-- -- +-- Copyright (C) 2025, AdaCore -- +-- -- +-- Redistribution and use in source and binary forms, with or without -- +-- modification, are permitted provided that the following conditions are -- +-- met: -- +-- 1. Redistributions of source code must retain the above copyright -- +-- notice, this list of conditions and the following disclaimer. -- +-- 2. Redistributions in binary form must reproduce the above copyright -- +-- notice, this list of conditions and the following disclaimer in -- +-- the documentation and/or other materials provided with the -- +-- distribution. -- +-- 3. Neither the name of the copyright holder nor the names of its -- +-- contributors may be used to endorse or promote products derived -- +-- from this software without specific prior written permission. -- +-- -- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -- +-- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -- +-- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -- +-- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -- +-- HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -- +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -- +-- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -- +-- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -- +-- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -- +-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -- +-- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- +-- -- +------------------------------------------------------------------------------ + +package body HM11 is + + Ok_Get : constant String := "OK+Get:"; + Ok_Set : constant String := "OK+Set:"; + + function Image (Value : Natural) return String; + function Image (Value : Send_Data_Method) return String; + function Image (Value : Send_Data_Characteristic) return String; + function Image (Value : Boolean) return String; + -- Returns "1" if Value = True else "0" + function Image (Value : MAC_Address_Type) return String; + + function Value (V : HAL.UInt8) return Natural; + + ----------------------------- + -- Default_Receive_Handler -- + ----------------------------- + + procedure Default_Receive_Handler + (Port : HAL.UART.Any_UART_Port; + Received : System.Address; + Length : Natural; + Status : out UART_Status; + Timeout : Natural := 1000; + As_Stream : Boolean := False) + is + pragma Unreferenced (Timeout); + Data : UART_Data_8b (1 .. Length) with Import, Address => Received; + begin + pragma Assert (not As_Stream); + + Data := (others => 0); + Receive (Port.all, Data, Status); + end Default_Receive_Handler; + + -------------- + -- Transmit -- + -------------- + + procedure Transmit + (This : in out HM11_Driver; + Command : String; + Status : out UART_Status) + is + Local : constant String := Command; + Cmd_Data : UART_Data_8b (Local'Range) with Import, + Address => Local (Local'First)'Address; + begin + This.Port.Transmit (Cmd_Data, Status); + end Transmit; + + -------------- + -- Transmit -- + -------------- + + procedure Transmit + (This : in out HM11_Driver; + Command : String; + Data : UART_Data_8b; + Status : out UART_Status) + is + Local : constant String := Command; + Cmd_Data : UART_Data_8b (Local'Range) with Import, + Address => Local (Local'First)'Address; + begin + This.Port.Transmit (Cmd_Data & Data, Status); + end Transmit; + + -------------------- + -- Check_Responce -- + -------------------- + + procedure Check_Responce + (Received : System.Address; + Length : Natural; + Expect : String; + Status : in out UART_Status) + is + Data : UART_Data_8b (1 .. Length) with Import, Address => Received; + begin + if Status = Ok then + declare + Local : constant String := Expect; + Exp : UART_Data_8b (Local'Range) with Import, + Address => Local'Address; + begin + if Length < Exp'Length + or else Data (Data'First .. Data'First + Exp'Length - 1) /= Exp + then + Status := Err_Error; + end if; + end; + end if; + end Check_Responce; + + ------------------------ + -- Transmit_And_Check -- + ------------------------ + + procedure Transmit_And_Check + (This : in out HM11_Driver; + Command : String; + Expect : String; + Received : System.Address; + Length : Natural; + Status : out UART_Status) is + begin + Transmit (This, Command, Status); + + if Status = Ok then + This.Receive (This.Port, Received, Length, Status); + if Status /= Ok then + return; + end if; + + Check_Responce (Received, Length, Expect, Status); + end if; + end Transmit_And_Check; + + ------------------------ + -- Transmit_And_Check -- + ------------------------ + + procedure Transmit_And_Check + (This : in out HM11_Driver; + Command : String; + Expect : String; + Status : out UART_Status) is + begin + Transmit_And_Check + (This, Command, Expect, This.Responce'Address, Expect'Length, Status); + end Transmit_And_Check; + + -------------- + -- Get_Role -- + -------------- + + procedure Get_Role + (This : in out HM11_Driver; + Result : out Role; + Status : out UART_Status) is + begin + Transmit_And_Check + (This, "AT+ROLE?", Ok_Get, + This.Responce'Address, Ok_Get'Length + 1, Status); + + if Status = Ok then + Result := Role'Val (Value (This.Responce (Ok_Get'Length + 1))); + end if; + end Get_Role; + + -------------- + -- Set_Role -- + -------------- + + procedure Set_Role + (This : in out HM11_Driver; + Value : Role; + Status : out UART_Status) + is + C : constant String := Image (Role'Pos (Value)); + begin + Transmit_And_Check (This, "AT+ROLE" & C, Ok_Set & C, Status); + end Set_Role; + + --------------------------------------- + -- Get_Last_Connected_Device_Address -- + --------------------------------------- + + procedure Get_Last_Connected_Device_Address + (This : in out HM11_Driver; + MAC : out MAC_Address; + Status : out UART_Status) + is + Expect : constant String := "OK+RADD:"; + begin + Transmit_And_Check + (This, "AT+RADD?", Expect, + This.Responce'Address, Expect'Length + MAC_Address'Length, Status); + + if Status = Ok then + declare + Value : MAC_Address with Import, + Address => This.Responce (Expect'Length + 1)'Address; + begin + MAC := Value; + end; + end if; + end Get_Last_Connected_Device_Address; + + ------------------------------ + -- Get_Sensor_Work_Interval -- + ------------------------------ + + procedure Get_Sensor_Work_Interval + (This : in out HM11_Driver; + Interval : out Work_Interval; + Status : out UART_Status) + is + use type HAL.UInt8; + begin + Interval := "00"; + Transmit_And_Check + (This, "AT+RAT??", Ok_Get, + This.Responce'Address, Ok_Get'Length + 2, Status); + + if Status = Ok then + if This.Responce (Ok_Get'Length + 2) = 0 then + declare + L : Digit_Character with Import, + Address => This.Responce (Ok_Get'Length + 1)'Address; + begin + Interval (Interval'Last) := L; + end; + else + declare + L : Work_Interval with Import, + Address => This.Responce (Ok_Get'Length + 1)'Address; + begin + Interval := L; + end; + end if; + end if; + end Get_Sensor_Work_Interval; + + ------------------------------ + -- Set_Sensor_Work_Interval -- + ------------------------------ + + procedure Set_Sensor_Work_Interval + (This : in out HM11_Driver; + Interval : Work_Interval; + Status : out UART_Status) is + begin + if Interval (Interval'First) = '0' then + declare + C : constant Character := Character (Interval (Interval'Last)); + begin + Transmit_And_Check (This, "AT+RAT" & C, Ok_Set & C, Status); + end; + + else + declare + Local : constant Work_Interval := Interval; + S : String (Work_Interval'Range) with Import, + Address => Local (Local'First)'Address; + begin + Transmit_And_Check (This, "AT+RAT" & S, Ok_Set & S, Status); + end; + end if; + end Set_Sensor_Work_Interval; + + ------------------ + -- Set_Stop_Bit -- + ------------------ + + procedure Set_Stop_Bit + (This : in out HM11_Driver; + Value : Stop_Bit; + Status : out UART_Status) + is + S : constant String := Image (Stop_Bit'Pos (Value)); + begin + Transmit_And_Check (This, "AT+STOP" & S, Ok_Set & S, Status); + end Set_Stop_Bit; + + ------------------ + -- Get_Stop_Bit -- + ------------------ + + procedure Get_Stop_Bit + (This : in out HM11_Driver; + Result : out Stop_Bit; + Status : out UART_Status) is + begin + Transmit_And_Check + (This, "AT+STOP?", Ok_Get, + This.Responce'Address, Ok_Get'Length + 1, Status); + + if Status = Ok then + Result := Stop_Bit'Val (Value (This.Responce (Ok_Get'Length + 1))); + end if; + end Get_Stop_Bit; + + ----------- + -- Sleep -- + ----------- + + procedure Sleep + (This : in out HM11_Driver; + Status : out UART_Status) is + begin + Transmit_And_Check (This, "AT+SLEEP", "OK+SLEEP", Status); + end Sleep; + + ------------- + -- Wake_Up -- + ------------- + + procedure Wake_Up + (This : in out HM11_Driver; + Status : out UART_Status) + is + Cmd : constant String (1 .. 7) := (others => 'W'); + begin + Transmit_And_Check (This, Cmd, "OK+WAKE", Status); + end Wake_Up; + + ---------- + -- Test -- + ---------- + + procedure Test + (This : in out HM11_Driver; + Status : out UART_Status) is + begin + Transmit_And_Check (This, "AT", "OK", Status); + end Test; + + ---------------- + -- Disconnect -- + ---------------- + + procedure Disconnect + (This : in out HM11_Driver; + Status : out UART_Status) is + begin + Transmit_And_Check (This, "AT", When_Disconnected_Message, Status); + end Disconnect; + + ------------------------------ + -- Get_Advertising_Interval -- + ------------------------------ + + procedure Get_Advertising_Interval + (This : in out HM11_Driver; + Result : out Advertising_Interval; + Status : out UART_Status) is + begin + Transmit_And_Check + (This, "AT+ADVI?", Ok_Get, + This.Responce'Address, Ok_Get'Length + 1, Status); + + if Status = Ok then + case Character'Val (This.Responce (Ok_Get'Length + 1)) is + when '0' => Result := ms_100; + when '1' => Result := ms_211; + when '2' => Result := ms_252; + when '3' => Result := ms_318; + when '4' => Result := ms_417; + when '5' => Result := ms_546; + when '6' => Result := ms_760; + when '7' => Result := ms_852; + when '8' => Result := ms_1022; + when '9' => Result := ms_1285; + when 'A' => Result := ms_2000; + when 'B' => Result := ms_3000; + when 'C' => Result := ms_4000; + when 'D' => Result := ms_5000; + when 'E' => Result := ms_6000; + when 'F' => Result := ms_7000; + when others => + Status := Err_Error; + end case; + end if; + end Get_Advertising_Interval; + + ------------------------------ + -- Set_Advertising_Interval -- + ------------------------------ + + procedure Set_Advertising_Interval + (This : in out HM11_Driver; + Value : Advertising_Interval; + Status : out UART_Status) + is + C : constant Character := From_Advertising_Interval (Value); + begin + Transmit_And_Check (This, "AT+ADVI" & C, Ok_Set & C, Status); + end Set_Advertising_Interval; + + -------------------------- + -- Get_Advertising_Type -- + -------------------------- + + procedure Get_Advertising_Type + (This : in out HM11_Driver; + Result : out Advertising_Type; + Status : out UART_Status) is + begin + Transmit_And_Check + (This, "AT+ADTY?", Ok_Get, + This.Responce'Address, Ok_Get'Length + 1, Status); + + if Status = Ok then + Result := Advertising_Type'Val + (Value (This.Responce (Ok_Get'Length + 1))); + end if; + end Get_Advertising_Type; + + -------------------------- + -- Set_Advertising_Type -- + -------------------------- + + procedure Set_Advertising_Type + (This : in out HM11_Driver; + Value : Advertising_Type; + Status : out UART_Status) + is + C : constant String := Image (Advertising_Type'Pos (Value)); + begin + Transmit_And_Check (This, "AT+ADTY" & C, Ok_Set & C, Status); + end Set_Advertising_Type; + + --------------------------- + -- Get_White_List_Switch -- + --------------------------- + + procedure Get_White_List_Switch + (This : in out HM11_Driver; + Result : out Boolean; + Status : out UART_Status) is + begin + Transmit_And_Check + (This, "AT+ALLO?", Ok_Get, + This.Responce'Address, Ok_Get'Length + 1, Status); + + if Status = Ok then + Result := (if Character'Val (This.Responce (Ok_Get'Length + 1)) = '0' + then False + else True); + end if; + end Get_White_List_Switch; + + --------------------------- + -- Set_White_List_Switch -- + --------------------------- + + procedure Set_White_List_Switch + (This : in out HM11_Driver; + Value : Boolean; + Status : out UART_Status) + is + C : constant Character := (if Value then '1' else '0'); + begin + Transmit_And_Check (This, "AT+ALLO" & C, Ok_Set & C, Status); + end Set_White_List_Switch; + + -------------------------------- + -- Set_Battery_Monitor_Switch -- + -------------------------------- + + procedure Set_Battery_Monitor_Switch + (This : in out HM11_Driver; + Value : Boolean; + Status : out UART_Status) + is + C : constant Character := (if Value then '1' else '0'); + begin + Transmit_And_Check (This, "AT+BATC" & C, Ok_Set & C, Status); + end Set_Battery_Monitor_Switch; + + -------------------------------- + -- Get_Battery_Monitor_Switch -- + -------------------------------- + + procedure Get_Battery_Monitor_Switch + (This : in out HM11_Driver; + Result : out Boolean; + Status : out UART_Status) is + begin + Transmit_And_Check + (This, "AT+BATC?", Ok_Get, + This.Responce'Address, Ok_Get'Length + 1, Status); + + if Status = Ok then + Result := (if Character'Val (This.Responce (Ok_Get'Length + 1)) = '0' + then False + else True); + end if; + end Get_Battery_Monitor_Switch; + + ----------------------------- + -- Set_Battery_Information -- + ----------------------------- + + procedure Set_Battery_Information + (This : in out HM11_Driver; + Value : Persent; + Status : out UART_Status) + is + Expect : constant String := "OK+BATT"; + begin + Transmit_And_Check + (This, "AT+BATT" & Image (Natural (Value)), Expect, + This.Responce'Address, Expect'Length + 3, Status); + end Set_Battery_Information; + + ------------------------------- + -- Query_Battery_Information -- + ------------------------------- + + procedure Query_Battery_Information + (This : in out HM11_Driver; + Result : out Persent; + Status : out UART_Status) is + begin + Transmit_And_Check + (This, "AT+BATT?", Ok_Get, + This.Responce'Address, Ok_Get'Length + 3, Status); + + if Status = Ok then + declare + S : String (1 .. Find_Zero (This, 1) - 1) with Import, + Address => This.Responce (Ok_Get'Length + 1)'Address; + begin + Result := Persent'Value (S); + end; + end if; + end Query_Battery_Information; + + ------------------------ + -- Set_UART_Baud_Rate -- + ------------------------ + + procedure Set_UART_Baud_Rate + (This : in out HM11_Driver; + Value : UART_Baud_Rate; + Status : out UART_Status) + is + C : constant String := Image (UART_Baud_Rate'Pos (Value)); + begin + Transmit_And_Check (This, "AT+BAUD" & C, Ok_Set & C, Status); + end Set_UART_Baud_Rate; + + ------------------------ + -- Get_UART_Baud_Rate -- + ------------------------ + + procedure Get_UART_Baud_Rate + (This : in out HM11_Driver; + Result : out UART_Baud_Rate; + Status : out UART_Status) is + begin + Transmit_And_Check + (This, "AT+BAUD?", Ok_Get, + This.Responce'Address, Ok_Get'Length + 1, Status); + + if Status = Ok then + Result := UART_Baud_Rate'Val + (Value (This.Responce (Ok_Get'Length + 1))); + end if; + end Get_UART_Baud_Rate; + + ------------------------------------------------ + -- Set_Minimum_Link_Layer_Connection_Interval -- + ------------------------------------------------ + + procedure Set_Minimum_Link_Layer_Connection_Interval + (This : in out HM11_Driver; + Value : Link_Layer_Connection_Interval; + Status : out UART_Status) + is + C : constant String := Image + (Link_Layer_Connection_Interval'Pos (Value)); + begin + Transmit_And_Check (This, "AT+COMI" & C, Ok_Set & C, Status); + end Set_Minimum_Link_Layer_Connection_Interval; + + ------------------------------------------------ + -- Get_Minimum_Link_Layer_Connection_Interval -- + ------------------------------------------------ + + procedure Get_Minimum_Link_Layer_Connection_Interval + (This : in out HM11_Driver; + Result : out Link_Layer_Connection_Interval; + Status : out UART_Status) is + begin + Transmit_And_Check + (This, "AT+COMI?", Ok_Get, + This.Responce'Address, Ok_Get'Length + 1, Status); + + if Status = Ok then + Result := Link_Layer_Connection_Interval'Val + (Value (This.Responce (Ok_Get'Length + 1))); + end if; + end Get_Minimum_Link_Layer_Connection_Interval; + + ------------------------------------------------ + -- Set_Maximum_Link_Layer_Connection_Interval -- + ------------------------------------------------ + + procedure Set_Maximum_Link_Layer_Connection_Interval + (This : in out HM11_Driver; + Value : Link_Layer_Connection_Interval; + Status : out UART_Status) + is + C : constant String := Image + (Link_Layer_Connection_Interval'Pos (Value)); + begin + Transmit_And_Check (This, "AT+COMA" & C, Ok_Set & C, Status); + end Set_Maximum_Link_Layer_Connection_Interval; + + ------------------------------------------------ + -- Get_Maximum_Link_Layer_Connection_Interval -- + ------------------------------------------------ + + procedure Get_Maximum_Link_Layer_Connection_Interval + (This : in out HM11_Driver; + Result : out Link_Layer_Connection_Interval; + Status : out UART_Status) is + begin + Transmit_And_Check + (This, "AT+COMA?", Ok_Get, + This.Responce'Address, Ok_Get'Length + 1, Status); + + if Status = Ok then + Result := Link_Layer_Connection_Interval'Val + (Value (This.Responce (Ok_Get'Length + 1))); + end if; + end Get_Maximum_Link_Layer_Connection_Interval; + + --------------------------------------------- + -- Set_Link_Layer_Connection_Slave_Latency -- + --------------------------------------------- + + procedure Set_Link_Layer_Connection_Slave_Latency + (This : in out HM11_Driver; + Value : Layer_Connection_Latency; + Status : out UART_Status) + is + C : constant String := Image (Natural (Value)); + begin + Transmit_And_Check (This, "AT+COLA" & C, Ok_Set & C, Status); + end Set_Link_Layer_Connection_Slave_Latency; + + --------------------------------------------- + -- Get_Link_Layer_Connection_Slave_Latency -- + --------------------------------------------- + + procedure Get_Link_Layer_Connection_Slave_Latency + (This : in out HM11_Driver; + Result : out Layer_Connection_Latency; + Status : out UART_Status) is + begin + Transmit_And_Check + (This, "AT+COLA?", Ok_Get, + This.Responce'Address, Ok_Get'Length + 1, Status); + + if Status = Ok then + Result := Layer_Connection_Latency'Val + (Value (This.Responce (Ok_Get'Length + 1))); + end if; + end Get_Link_Layer_Connection_Slave_Latency; + + ---------------------------------------- + -- Set_Connection_Supervision_Timeout -- + ---------------------------------------- + + procedure Set_Connection_Supervision_Timeout + (This : in out HM11_Driver; + Value : Connection_Supervision_Timeout; + Status : out UART_Status) + is + C : constant String := Image + (Connection_Supervision_Timeout'Pos (Value)); + begin + Transmit_And_Check (This, "AT+COSU" & C, Ok_Set & C, Status); + end Set_Connection_Supervision_Timeout; + + ---------------------------------------- + -- Get_Connection_Supervision_Timeout -- + ---------------------------------------- + + procedure Get_Connection_Supervision_Timeout + (This : in out HM11_Driver; + Result : out Connection_Supervision_Timeout; + Status : out UART_Status) is + begin + Transmit_And_Check + (This, "AT+COSU?", Ok_Get, + This.Responce'Address, Ok_Get'Length + 1, Status); + + if Status = Ok then + Result := Connection_Supervision_Timeout'Val + (Value (This.Responce (Ok_Get'Length + 1))); + end if; + end Get_Connection_Supervision_Timeout; + + --------------------------- + -- Set_Update_Connection -- + --------------------------- + + procedure Set_Update_Connection + (This : in out HM11_Driver; + Value : Boolean; + Status : out UART_Status) + is + C : constant Character := (if Value then '1' else '0'); + begin + Transmit_And_Check (This, "AT+COUP" & C, Ok_Set & C, Status); + end Set_Update_Connection; + + --------------------------- + -- Get_Update_Connection -- + --------------------------- + + procedure Get_Update_Connection + (This : in out HM11_Driver; + Result : out Boolean; + Status : out UART_Status) is + begin + Transmit_And_Check + (This, "AT+COUP?", Ok_Get, + This.Responce'Address, Ok_Get'Length + 1, Status); + + if Status = Ok then + declare + S : Character with Import, + Address => This.Responce (Ok_Get'Length + 1)'Address; + begin + Result := (if S = '1' then True else False); + end; + end if; + end Get_Update_Connection; + + ---------------------------------- + -- Clear_Last_Connected_Address -- + ---------------------------------- + + procedure Clear_Last_Connected_Address + (This : in out HM11_Driver; + Status : out UART_Status) is + begin + Transmit_And_Check (This, "AT+CLEAR", "OK+CLEAR", Status); + end Clear_Last_Connected_Address; + + ------------------------- + -- Connect_Last_Device -- + ------------------------- + + procedure Connect_Last_Device + (This : in out HM11_Driver; + Result : out Connect_Result; + Status : out UART_Status) is + begin + Transmit_And_Check + (This, "AT+CONNL", When_Connected_Message, + This.Responce'Address, When_Connected_Message'Length + 1, Status); + + if Status = Ok then + declare + C : Character with Import, + Address => This.Responce + (When_Connected_Message'Length + 1)'Address; + begin + Result := To_Connect_Result (C); + end; + end if; + end Connect_Last_Device; + + --------------------- + -- Get_MAC_Address -- + --------------------- + + procedure Get_MAC_Address + (This : in out HM11_Driver; + Result : out MAC_Address; + Status : out UART_Status) + is + Expect : constant String := "OK+ADDR:"; + begin + Transmit_And_Check + (This, "AT+ADDR?", Expect, + This.Responce'Address, Expect'Length + MAC_Address'Length, Status); + + if Status = Ok then + declare + MAC : MAC_Address with Import, + Address => This.Responce (Expect'Length + 1)'Address; + begin + Result := MAC; + end; + end if; + end Get_MAC_Address; + + ---------------------------------- + -- Set_White_List_MAC_Addresses -- + ---------------------------------- + + procedure Set_White_List_MAC_Addresses + (This : in out HM11_Driver; + Index : MAC_White_List_Index; + Value : MAC_Address; + Status : out UART_Status) + is + Local : MAC_Address := Value; + M : String (Local'Range) with Import, + Address => Local (Local'First)'Address; + begin + Transmit_And_Check + (This, "AT+AD" & Image (Natural (Index)) & M, Ok_Set & M, Status); + end Set_White_List_MAC_Addresses; + + -------------------------------- + -- Get_White_List_MAC_Address -- + -------------------------------- + + procedure Get_White_List_MAC_Address + (This : in out HM11_Driver; + Index : MAC_White_List_Index; + Result : out MAC_Address; + Status : out UART_Status) + is + Num : constant String := Image (Natural (Index)); + Expect : constant String := "OK+AD" & Num & "?:"; + begin + Transmit_And_Check + (This, "AT+AD" & Num & "??", Expect, + This.Responce'Address, Expect'Length + MAC_Address'Length, Status); + + if Status = Ok then + declare + S : MAC_Address with Import, + Address => This.Responce (Ok_Get'Length + 1)'Address; + begin + Result := S; + end; + end if; + end Get_White_List_MAC_Address; + + ------------- + -- Connect -- + ------------- + + procedure Connect + (This : in out HM11_Driver; + MAC_Type : MAC_Address_Type; + Address : MAC_Address; + Result : out Connect_Result; + Status : out UART_Status) + is + + T : constant String := Image (MAC_Type); + Local : MAC_Address := Address; + A : String (Local'Range) with Import, + Address => Local (Local'First)'Address; + Expect : constant String := "OK+CO" & T & T; + + begin + Result := Other_Error; + Transmit_And_Check + (This, "AT+CO" & T & A, Expect, + This.Responce'Address, Expect'Length + 1, Status); + + if Status = Ok then + declare + C : Character with Import, + Address => This.Responce (Expect'Length + 1)'Address; + begin + Result := To_Connect_Result (C); + end; + end if; + end Connect; + + ------------- + -- Connect -- + ------------- + + procedure Connect + (This : in out HM11_Driver; + Index : Discovered_Index; + Result : out Connect_Result; + Status : out UART_Status) is + begin + Result := Other_Error; + Transmit_And_Check + (This => This, + Command => "AT+CONN" & Image (Natural (Index)), + Expect => When_Connected_Message, + Received => This.Responce'Address, + Length => When_Connected_Message'Length + 1, + Status => Status); + + if Status = Ok then + declare + S : Character with Import, + Address => This.Responce + (When_Connected_Message'Length + 1)'Address; + begin + Result := To_Connect_Result (S); + end; + end if; + end Connect; + + ---------- + -- Scan -- + ---------- + + procedure Scan + (This : in out HM11_Driver; + Callback : Discovered_Callback; + Timeout : Natural; + Status : out UART_Status) + is + OK_DISCS : constant String := "OK+DISCS"; + OK_DISC : constant String := "OK+DISC:"; + OK_NAME : constant String := "OK+NAME:"; + OK_RSSI : constant String := "OK+RSSI:"; + OK_DISCE : constant String := "OK+DISCE"; + Min_Prefix : constant := 8; + + procedure Call; + -- Call Callback with discovered info + + ---------- + -- Call -- + ---------- + + procedure Call is + begin + if This.Discovered_Info /= Null_Discovered_Info then + Callback + (Id => This.Discovered_Info.Id, + MAC => This.Discovered_Info.MAC, + Name => This.Discovered_Info.Name.Value + (1 .. This.Discovered_Info.Name.Last), + RSSI => This.Discovered_Info.RSSI.Value + (1 .. This.Discovered_Info.RSSI.Length)); + + This.Discovered_Info := Null_Discovered_Info; + This.Discovered_Info.Name.Last := 0; + This.Discovered_Info.RSSI.Last := 0; + end if; + end Call; + + Pos : Positive := 1; + Zero : Positive; + Stream_Closed : Boolean := False; + Length : Natural; + EON : Natural; + Kind : Scan_Stage_Kind := Selection; + + begin + This.Discovered_Info := Null_Discovered_Info; + + Transmit (This, "AT+DISC?", Status); + if Status /= Ok then + return; + end if; + + This.Receive + (This.Port, This.Responce'Address, This.Responce'Length, + Status, Timeout, As_Stream => True); + + Main : loop + This.Readed_Position (Stream_Closed, Zero); + exit Main when Stream_Closed; + Length := Calc_Lenght (This, Pos, Zero); + + loop + exit when Length = 0; + + -- End message, exit + exit Main when Start_With (This, OK_DISCE, Pos, Zero - 1); + + case Kind is + when Selection => + if Length < Min_Prefix then + -- Don't have enought characters + exit; + end if; + + if Start_With (This, OK_DISCS, Pos, Zero - 1) then + Move (This, Pos, OK_DISCS'Length, Zero, Length); + end if; + + if Start_With (This, OK_DISC, Pos, Zero - 1) then + Move (This, Pos, OK_DISC'Length, Zero, Length); + Kind := MAC; + end if; + + if Start_With (This, OK_NAME, Pos, Zero - 1) then + Move (This, Pos, OK_NAME'Length, Zero, Length); + Kind := Name; + end if; + + if Start_With (This, OK_RSSI, Pos, Zero - 1) then + Move (This, Pos, OK_RSSI'Length, Zero, Length); + Kind := RSSI; + end if; + + when MAC => + Call; -- Call the callback if we have previous data + + if Length < MAC_Address'Length then + exit; + + else + declare + Value : MAC_Address with Import, + Address => This.Responce (Pos)'Address; + begin + This.Discovered_Info.MAC := Value; + end; + Move (This, Pos, MAC_Address'Length, Zero, Length); + Kind := Selection; + end if; + + when Name => + EON := Find (This, ASCII.CR & ASCII.LF, Pos, Zero - 1); + if EON = 0 then + Append (This, This.Discovered_Info.Name, Pos, Zero - 1); + Pos := Zero; + + else + Append (This, This.Discovered_Info.Name, Pos, EON - 1); + Pos := EON + 1; + Kind := Selection; + end if; + + when RSSI => + EON := Find (This, ASCII.CR & ASCII.LF, Pos, Zero - 1); + if EON = 0 then + Append (This, This.Discovered_Info.RSSI, Pos, Zero - 1); + Pos := Zero; + + else + Append (This, This.Discovered_Info.RSSI, Pos, EON - 1); + Pos := EON + 1; + Kind := Selection; + end if; + end case; + end loop; + end loop Main; + + Call; + + if not Stream_Closed then + This.Receive + (This.Port, This.Responce'Address, This.Responce'Length, Status); + end if; + + exception + when others => + -- Stop stream + This.Receive + (This.Port, This.Responce'Address, This.Responce'Length, Status); + Status := Err_Error; + end Scan; + + ------------------ + -- Scan_iBeacon -- + ------------------ + + procedure Scan_iBeacon + (This : in out HM11_Driver; + Callback : Discovered_iBeacon_Callback; + Timeout : Natural; + Status : out UART_Status) + is + OK_DISCS : constant String := "OK+DISCS"; + OK_DISC : constant String := "OK+DISC"; + OK_DISCE : constant String := "OK+DISCE"; + + iBeacon_Data : UART_Data_8b (1 .. Discovered_iBeacon_Lenght); + iBeacon : String (iBeacon_Data'Range) with Import, + Address => iBeacon_Data'Address; + + Pos : Positive := 1; + Zero : Positive; + Stream_Closed : Boolean := False; + Length : Natural; + + begin + Transmit (This, "AT+DISI?", Status); + + if Status /= Ok then + return; + end if; + + This.Receive + (This.Port, This.Responce'Address, This.Responce'Length, + Status, Timeout, As_Stream => True); + + Main : loop + This.Readed_Position (Stream_Closed, Zero); + exit Main when Stream_Closed; + Length := Calc_Lenght (This, Pos, Zero); + + loop + exit when Length < OK_DISCS'Length; + + -- End message, exit + exit Main when Start_With (This, OK_DISCE, Pos, Zero - 1); + + if Start_With (This, OK_DISCS, Pos, Zero - 1) then + Move (This, Pos, OK_DISCS'Length, Zero, Length); + end if; + + if Start_With (This, OK_DISC, Pos, Zero - 1) + and then Length >= OK_DISC'Length + Discovered_iBeacon_Lenght + then + Copy (This, iBeacon_Data, Pos + OK_DISC'Length - 1); + + Move (This, Pos, OK_DISCS'Length + Discovered_iBeacon_Lenght, + Zero, Length); + + Callback (iBeacon); + end if; + end loop; + end loop Main; + + if not Stream_Closed then + This.Receive + (This.Port, This.Responce'Address, This.Responce'Length, Status); + end if; + + exception + when others => + -- Stop stream + This.Receive + (This.Port, This.Responce'Address, This.Responce'Length, Status); + Status := Err_Error; + end Scan_iBeacon; + + ----------------------------- + -- Set_iBeacon_Deploy_Mode -- + ----------------------------- + + procedure Set_iBeacon_Deploy_Mode + (This : in out HM11_Driver; + Value : iBeacon_Deploy_Mode; + Status : out UART_Status) + is + V : constant String := Image + (Natural (iBeacon_Deploy_Mode'Pos (Value)) + 1); + begin + Transmit_And_Check (This, "AT+DELO" & V, "OK+DELO" & V, Status); + end Set_iBeacon_Deploy_Mode; + + ----------------------------- + -- Remove_Bond_Information -- + ----------------------------- + + procedure Remove_Bond_Information + (This : in out HM11_Driver; + Status : out UART_Status) is + begin + Transmit_And_Check (This, "AT+ERASE", "OK+ERASE", Status); + end Remove_Bond_Information; + + ---------------------------- + -- Find_All_Services_UUID -- + ---------------------------- + + procedure Find_All_Services_UUID + (This : in out HM11_Driver; + Callback : Service_UUID_Callback; + Timeout : Natural; + Status : out UART_Status) + is + use type HAL.UInt8; + + Header : constant String (1 .. 56) := (others => '*'); + Started : Boolean := False; + + UUID_Data : UART_Data_8b (1 .. 14); + UUID : String (UUID_Data'Range) with Import, + Address => UUID_Data'Address; + + Pos : Positive := 1; + Zero : Positive; + Stream_Closed : Boolean := False; + Length : Natural; + begin + + Transmit (This, "AT+FINDSERVICES?", Status); + if Status /= Ok then + return; + end if; + + This.Receive + (This.Port, This.Responce'Address, This.Responce'Length, + Status, Timeout, As_Stream => True); + + Main : loop + This.Readed_Position (Stream_Closed, Zero); + exit Main when Stream_Closed; + Length := Calc_Lenght (This, Pos, Zero); + + loop + exit when Length < UUID_Data'Length; + + if This.Responce (Pos) = Character'Pos ('*') then + if Start_With (This, Header, Pos, Zero - 1) then + if Started then + -- End message, exit + exit Main; + else + + -- Start message + Started := True; + Move (This, Pos, Header'Length, Zero, Length); + end if; + end if; + + elsif Start_With (This, ASCII.CR & ASCII.LF, Pos, Zero - 1) then + Move (This, Pos, 2, Zero, Length); + + else + Copy (This, UUID_Data, Pos); + + Move (This, Pos, UUID_Data'Length, Zero, Length); + + Callback (UUID); + end if; + end loop; + end loop Main; + + if not Stream_Closed then + This.Receive + (This.Port, This.Responce'Address, This.Responce'Length, Status); + end if; + + exception + when others => + -- Stop stream + This.Receive + (This.Port, This.Responce'Address, This.Responce'Length, Status); + Status := Err_Error; + end Find_All_Services_UUID; + + ---------------------------------- + -- Find_All_Characteristic_UUID -- + ---------------------------------- + + procedure Find_All_Characteristic_UUID + (This : in out HM11_Driver; + Callback : Characteristic_UUID_Callback; + Timeout : Natural; + Status : out UART_Status) is + begin + Transmit (This, "AT+FINDALLCHARS?", Status); + if Status = Ok then + Read_Characteristic_UUID (This, Callback, Timeout, Status); + end if; + end Find_All_Characteristic_UUID; + + ------------------------------ + -- Find_Characteristic_UUID -- + ------------------------------ + + procedure Find_Characteristic_UUID + (This : in out HM11_Driver; + From : Handle_Type; + To : Handle_Type; + Callback : Characteristic_UUID_Callback; + Timeout : Natural; + Status : out UART_Status) + is + Local_From : Handle_Type := From; + F : String (Handle_Type'Range) with Import, + Address => Local_From (Local_From'First)'Address; + Local_To : Handle_Type := To; + T : String (Handle_Type'Range) with Import, + Address => Local_To (Local_To'First)'Address; + + begin + Transmit (This, "AT+CHAR" & F & T & "?", Status); + if Status = Ok then + Read_Characteristic_UUID (This, Callback, Timeout, Status); + end if; + end Find_Characteristic_UUID; + + ------------------------------ + -- Read_Characteristic_UUID -- + ------------------------------ + + procedure Read_Characteristic_UUID + (This : in out HM11_Driver; + Callback : Characteristic_UUID_Callback; + Timeout : Natural; + Status : out UART_Status) + is + use type HAL.UInt8; + + Header : constant String (1 .. 56) := (others => '*'); + Started : Boolean := False; + + UUID_Data : UART_Data_8b (1 .. 24); + UUID : String (UUID_Data'Range) with Import, + Address => UUID_Data'Address; + + Pos : Positive := 1; + Zero : Positive; + Stream_Closed : Boolean := False; + Length : Natural; + + begin + This.Receive + (This.Port, This.Responce'Address, This.Responce'Length, + Status, Timeout, As_Stream => True); + + Main : loop + This.Readed_Position (Stream_Closed, Zero); + exit Main when Stream_Closed; + Length := Calc_Lenght (This, Pos, Zero); + + loop + exit when Length < UUID_Data'Length; + + if This.Responce (Pos) = Character'Pos ('*') then + if Start_With (This, Header, Pos, Zero - 1) then + if Started then + -- End message, exit + exit Main; + else + -- Start message + Started := True; + Move (This, Pos, Header'Length, Zero, Length); + end if; + end if; + + elsif Start_With (This, ASCII.CR & ASCII.LF, Pos, Zero - 1) then + Move (This, Pos, 2, Zero, Length); + + else + Copy (This, UUID_Data, Pos); + + Move (This, Pos, UUID_Data'Length, Zero, Length); + + Callback (UUID); + end if; + end loop; + end loop Main; + + if not Stream_Closed then + This.Receive + (This.Port, This.Responce'Address, This.Responce'Length, Status); + end if; + + exception + when others => + -- Stop stream + This.Receive + (This.Port, This.Responce'Address, This.Responce'Length, Status); + Status := Err_Error; + end Read_Characteristic_UUID; + + + ---------------------------------- + -- Enable_Characteristic_Notify -- + ---------------------------------- + + procedure Enable_Characteristic_Notify + (This : in out HM11_Driver; + Handle : Handle_Type; + Status : out UART_Status; + Responce : out Notify_Responce) is + begin + Transmit (This, "AT+NOTIFY_ON" & To_String (Handle), Status); + Read_Characteristic_Notify_Responce (This, Status, Responce); + end Enable_Characteristic_Notify; + + ----------------------------------- + -- Disable_Characteristic_Notify -- + ----------------------------------- + + procedure Disable_Characteristic_Notify + (This : in out HM11_Driver; + Handle : Handle_Type; + Status : out UART_Status; + Responce : out Notify_Responce) is + begin + Transmit (This, "AT+NOTIFYOFF" & To_String (Handle), Status); + Read_Characteristic_Notify_Responce (This, Status, Responce); + end Disable_Characteristic_Notify; + + -------------------------------- + -- Read_Characteristic_Notify -- + -------------------------------- + + procedure Read_Characteristic_Notify + (This : in out HM11_Driver; + Handle : Handle_Type; + Status : out UART_Status; + Responce : out Notify_Responce) is + begin + Transmit (This, "AT+READDATA" & To_String (Handle), Status); + Read_Characteristic_Notify_Responce (This, Status, Responce); + end Read_Characteristic_Notify; + + ----------------------------------------- + -- Read_Characteristic_Notify_Responce -- + ----------------------------------------- + + procedure Read_Characteristic_Notify_Responce + (This : in out HM11_Driver; + Status : in out UART_Status; + Responce : out Notify_Responce) + is + Send_Ok : constant String := "OK+SEND-OK"; + Data_Er : constant String := "OK+DATA-ER"; + Data : UART_Data_8b (1 .. Send_Ok'Length); + + begin + if Status = Ok then + This.Port.Receive (Data, Status); + + if Status = Ok then + declare + S : String (Data'Range) with Import, + Address => Data (Data'First)'Address; + begin + if S = Send_Ok then + Responce := HM11.Send_Ok; + elsif S = Data_Er then + Responce := HM11.Data_Er; + else + Responce := HM11.Send_Er; + end if; + end; + end if; + end if; + end Read_Characteristic_Notify_Responce; + + ------------------------------------------ + -- Set_Method_And_Characteristic_Handle -- + ------------------------------------------ + + procedure Set_Method_And_Characteristic_Handle + (This : in out HM11_Driver; + Handle : Handle_Type; + Method : Send_Data_Method; + Status : out UART_Status) is + begin + Transmit_And_Check + (This, "AT+SET_WAY" & Image (Method) & To_String (Handle), + "OK+SEND-OK", Status); + end Set_Method_And_Characteristic_Handle; + + --------------------------------- + -- Send_Data_To_Characteristic -- + --------------------------------- + + procedure Send_Data_To_Characteristic + (This : in out HM11_Driver; + Handle : Handle_Type; + Method : Send_Data_Characteristic; + Data : UART_Data_8b; + Status : out UART_Status) is + begin + Transmit + (This, "AT+SEND_DATA" & Image (Method) & To_String (Handle), + Data, Status); + end Send_Data_To_Characteristic; + + --------------------------------------- + -- Set_Use_Characteristic_UUID_Count -- + --------------------------------------- + + procedure Set_Use_Characteristic_UUID_Count + (This : in out HM11_Driver; + Count : Characteristic_UUID_Count; + Status : out UART_Status) + is + I : constant String := + (if Count = Query + then "?" + else Image (Characteristic_UUID_Count'Pos (Count))); + begin + Transmit_And_Check (This, "AT+FFE2" & I, Ok_Set & I, Status); + end Set_Use_Characteristic_UUID_Count; + + -------------------------- + -- Set_Advertising_FLAG -- + -------------------------- + + procedure Set_Advertising_FLAG + (This : in out HM11_Driver; + Flag : Advertising_FLAG; + Status : out UART_Status) + is + Local_Flag : constant Advertising_FLAG := Flag; + S : constant String (Advertising_FLAG'Range) with Import, + Address => Local_Flag (Local_Flag'First)'Address; + begin + Transmit_And_Check (This, "AT+FLAG" & S, Ok_Set & S, Status); + end Set_Advertising_FLAG; + + ---------------------------------- + -- Set_UART_Flow_Control_Switch -- + ---------------------------------- + + procedure Set_UART_Flow_Control_Switch + (This : in out HM11_Driver; + Switch : Boolean; + Status : out UART_Status) + is + S : constant String := Image (Switch); + begin + Transmit_And_Check (This, "AT+FIOW" & S, Ok_Set & S, Status); + end Set_UART_Flow_Control_Switch; + + ---------------------------------- + -- Get_UART_Flow_Control_Switch -- + ---------------------------------- + + procedure Get_UART_Flow_Control_Switch + (This : in out HM11_Driver; + Switch : out Boolean; + Status : out UART_Status) is + begin + Transmit_And_Check + (This, "AT+FIOW?", Ok_Get, + This.Responce'Address, Ok_Get'Length + 1, Status); + + if Status = Ok then + declare + S : Character with Import, + Address => This.Responce (Ok_Get'Length + 1)'Address; + begin + Switch := S = '1'; + end; + end if; + end Get_UART_Flow_Control_Switch; + + ------------------------ + -- Set_Module_RX_Gain -- + ------------------------ + + procedure Set_Module_RX_Gain + (This : in out HM11_Driver; + Gain : RX_Gain; + Status : out UART_Status) + is + S : constant String := Image (RX_Gain'Pos (Gain)); + begin + Transmit_And_Check (This, "AT+GAIN" & S, Ok_Set & S, Status); + end Set_Module_RX_Gain; + + ------------------------ + -- Get_Module_RX_Gain -- + ------------------------ + + procedure Get_Module_RX_Gain + (This : in out HM11_Driver; + Gain : out RX_Gain; + Status : out UART_Status) is + begin + Transmit_And_Check + (This, "AT+GAIN?", Ok_Get, + This.Responce'Address, Ok_Get'Length + 1, Status); + + if Status = Ok then + Gain := RX_Gain'Val (Value (This.Responce (Ok_Get'Length + 1))); + end if; + end Get_Module_RX_Gain; + + ---------------------------------------------- + -- Set_Humi_Information_Byte_In_Advertising -- + ---------------------------------------------- + + procedure Set_Humi_Information_Byte_In_Advertising + (This : in out HM11_Driver; + Info : Humi_Information; + Status : out UART_Status) + is + Local_Info : constant Humi_Information := Info; + S : constant String (Humi_Information'Range) with Import, + Address => Local_Info (Local_Info'First)'Address; + begin + Transmit_And_Check (This, "AT+HUMI" & S, Ok_Set & S, Status); + end Set_Humi_Information_Byte_In_Advertising; + + ------------------- + -- Set_Work_Type -- + ------------------- + + procedure Set_Work_Type + (This : in out HM11_Driver; + Work : Work_Type; + Status : out UART_Status) + is + S : constant String := Image (Work_Type'Pos (Work)); + begin + Transmit_And_Check (This, "AT+IMME" & S, Ok_Set & S, Status); + end Set_Work_Type; + + ------------------- + -- Get_Work_Type -- + ------------------- + + procedure Get_Work_Type + (This : in out HM11_Driver; + Work : out Work_Type; + Status : out UART_Status) is + begin + Transmit_And_Check + (This, "AT+IMME?", Ok_Get, + This.Responce'Address, Ok_Get'Length + 1, Status); + + if Status = Ok then + Work := Work_Type'Val (Value (This.Responce (Ok_Get'Length + 1))); + end if; + end Get_Work_Type; + + ------------------------ + -- Set_iBeacon_Switch -- + ------------------------ + + procedure Set_iBeacon_Switch + (This : in out HM11_Driver; + Switch : Boolean; + Status : out UART_Status) + is + S : constant String := Image (Switch); + begin + Transmit_And_Check (This, "AT+IBEA" & S, Ok_Set & S, Status); + end Set_iBeacon_Switch; + + ------------------------ + -- Get_iBeacon_Switch -- + ------------------------ + + procedure Get_iBeacon_Switch + (This : in out HM11_Driver; + Switch : out Boolean; + Status : out UART_Status) is + begin + Transmit_And_Check + (This, "AT+IBEA?", Ok_Get, + This.Responce'Address, Ok_Get'Length + 1, Status); + + if Status = Ok then + declare + S : Character with Import, + Address => This.Responce (Ok_Get'Length + 1)'Address; + begin + Switch := S = '1'; + end; + end if; + end Get_iBeacon_Switch; + + ---------------------- + -- Set_iBeacon_UUID -- + ---------------------- + + procedure Set_iBeacon_UUID + (This : in out HM11_Driver; + UUID : iBeacon_UUID; + Status : out UART_Status) + is + Local_UUID : constant iBeacon_UUID := UUID; + + procedure Set (Pos : Natural); + procedure Set (Pos : Natural) + is + I : constant String := Image (Pos); + S : String (1 .. 8) with Import, + Address => Local_UUID (Pos * 8 + 1)'Address; + begin + Transmit_And_Check + (This, "AT+IBE" & I & "0x" & S, Ok_Set & I & "0x" & S, Status); + end Set; + + begin + for I in 0 .. 3 loop + Set (I); + exit when Status /= Ok; + end loop; + end Set_iBeacon_UUID; + + ---------------------- + -- Get_iBeacon_UUID -- + ---------------------- + + procedure Get_iBeacon_UUID + (This : in out HM11_Driver; + UUID : out iBeacon_UUID; + Status : out UART_Status) + is + Local_UUID : String (iBeacon_UUID'Range); + + procedure Get (Pos : Natural); + procedure Get (Pos : Natural) + is + I : constant String := Image (Pos); + begin + Transmit_And_Check + (This, "AT+IBE" & I & "?", Ok_Get, + This.Responce'Address, Ok_Get'Length + 10, Status); + + if Status = Ok then + declare + S : String (1 .. 8) with Import, + Address => This.Responce (Ok_Get'Length + 3)'Address; + begin + Local_UUID (Pos * 8 + 1 .. Pos * 8 + 8) := S; + end; + end if; + end Get; + + begin + for I in 0 .. 3 loop + Get (I); + exit when Status /= Ok; + end loop; + + declare + L : iBeacon_UUID with Import, + Address => Local_UUID (Local_UUID'First)'Address; + begin + UUID := L; + end; + end Get_iBeacon_UUID; + + -------------------------------- + -- Set_iBeacon_Marjor_Version -- + -------------------------------- + + procedure Set_iBeacon_Marjor_Version + (This : in out HM11_Driver; + Version : Version_Type; + Status : out UART_Status) + is + S : String (Version_Type'Range) with Import, + Address => Version (Version'First)'Address; + begin + Transmit_And_Check + (This, "AT+MARJ0x" & S, Ok_Set & "0x" & S, Status); + end Set_iBeacon_Marjor_Version; + + -------------------------------- + -- Get_iBeacon_Marjor_Version -- + -------------------------------- + + procedure Get_iBeacon_Marjor_Version + (This : in out HM11_Driver; + Version : out Version_Type; + Status : out UART_Status) is + begin + Transmit_And_Check + (This, "AT+MARJ?", Ok_Get, + This.Responce'Address, + Ok_Get'Length + Version_Type'Length + 2, Status); + + if Status = Ok then + declare + S : Version_Type with Import, + Address => This.Responce (Ok_Get'Length + 3)'Address; + begin + Version := S; + end; + end if; + end Get_iBeacon_Marjor_Version; + + ------------------------------- + -- Set_iBeacon_Minor_Version -- + ------------------------------- + + procedure Set_iBeacon_Minor_Version + (This : in out HM11_Driver; + Version : Version_Type; + Status : out UART_Status) + is + S : String (Version_Type'Range) with Import, + Address => Version (Version'First)'Address; + begin + Transmit_And_Check + (This, "AT+MINO0x" & S, Ok_Set & "0x" & S, Status); + end Set_iBeacon_Minor_Version; + + ------------------------------- + -- Get_iBeacon_Minor_Version -- + ------------------------------- + + procedure Get_iBeacon_Minor_Version + (This : in out HM11_Driver; + Version : out Version_Type; + Status : out UART_Status) is + begin + Transmit_And_Check + (This, "AT+MINO?", Ok_Get, + This.Responce'Address, + Ok_Get'Length + Version_Type'Length + 2, Status); + + if Status = Ok then + declare + S : Version_Type with Import, + Address => This.Responce (Ok_Get'Length + 3)'Address; + begin + Version := S; + end; + end if; + end Get_iBeacon_Minor_Version; + + -------------------------------- + -- Set_iBeacon_Measured_Power -- + -------------------------------- + + procedure Set_iBeacon_Measured_Power + (This : in out HM11_Driver; + Power : Measured_Power; + Status : out UART_Status) + is + S : String (Measured_Power'Range) with Import, + Address => Power (Power'First)'Address; + begin + Transmit_And_Check + (This, "AT+MEAS0x" & S, Ok_Set & "0x" & S, Status); + end Set_iBeacon_Measured_Power; + + -------------------------------- + -- Get_iBeacon_Measured_Power -- + -------------------------------- + + procedure Get_iBeacon_Measured_Power + (This : in out HM11_Driver; + Power : out Measured_Power; + Status : out UART_Status) is + begin + Transmit_And_Check + (This, "AT+MEAS?", Ok_Get, + This.Responce'Address, + Ok_Get'Length + Measured_Power'Length + 2, Status); + + if Status = Ok then + declare + S : Measured_Power with Import, + Address => This.Responce (Ok_Get'Length + 3)'Address; + begin + Power := S; + end; + end if; + end Get_iBeacon_Measured_Power; + + ------------------- + -- Set_Work_Mode -- + ------------------- + + procedure Set_Work_Mode + (This : in out HM11_Driver; + Mode : Work_Mode; + Status : out UART_Status) + is + S : constant String := Image (Work_Mode'Pos (Mode)); + begin + Transmit_And_Check (This, "AT+MODE" & S, Ok_Set & S, Status); + end Set_Work_Mode; + + ------------------- + -- Get_Work_Mode -- + ------------------- + + procedure Get_Work_Mode + (This : in out HM11_Driver; + Mode : out Work_Mode; + Status : out UART_Status) is + begin + Transmit_And_Check + (This, "AT+MODE?", Ok_Get, + This.Responce'Address, Ok_Get'Length + 1, Status); + + if Status = Ok then + Mode := Work_Mode'Val (Value (This.Responce (Ok_Get'Length + 1))); + end if; + end Get_Work_Mode; + + ---------------------------- + -- Set_Notify_Information -- + ---------------------------- + + procedure Set_Notify_Information + (This : in out HM11_Driver; + Notify : Boolean; + Status : out UART_Status) + is + S : constant String := Image (Notify); + begin + Transmit_And_Check (This, "AT+NOTI" & S, Ok_Set & S, Status); + end Set_Notify_Information; + + ---------------------------- + -- Get_Notify_Information -- + ---------------------------- + + procedure Get_Notify_Information + (This : in out HM11_Driver; + Notify : out Boolean; + Status : out UART_Status) is + begin + Transmit_And_Check + (This, "AT+NOTI?", Ok_Get, + This.Responce'Address, Ok_Get'Length + 1, Status); + + if Status = Ok then + declare + S : Character with Import, + Address => This.Responce (Ok_Get'Length + 1)'Address; + begin + Notify := S = '1'; + end; + end if; + end Get_Notify_Information; + + --------------------- + -- Set_Notify_Mode -- + --------------------- + + procedure Set_Notify_Mode + (This : in out HM11_Driver; + Mode : Notify_Mode; + Status : out UART_Status) + is + S : constant String := Image (Notify_Mode'Pos (Mode)); + begin + Transmit_And_Check (This, "AT+NOTP" & S, Ok_Set & S, Status); + end Set_Notify_Mode; + + --------------------- + -- Get_Notify_Mode -- + --------------------- + + procedure Get_Notify_Mode + (This : in out HM11_Driver; + Mode : out Notify_Mode; + Status : out UART_Status) is + begin + Transmit_And_Check + (This, "AT+NOTP?", Ok_Get, + This.Responce'Address, Ok_Get'Length + 1, Status); + + if Status = Ok then + Mode := Notify_Mode'Val (Value (This.Responce (Ok_Get'Length + 1))); + end if; + end Get_Notify_Mode; + + --------------------- + -- Set_Module_Name -- + --------------------- + + procedure Set_Module_Name + (This : in out HM11_Driver; + Name : String; + Status : out UART_Status) is + begin + Transmit_And_Check (This, "AT+NAME" & Name, Ok_Set & Name, Status); + end Set_Module_Name; + + --------------------- + -- Get_Module_Name -- + --------------------- + + function Get_Module_Name + (This : in out HM11_Driver) + return String + is + Status : UART_Status; + Expect : constant String := "OK+NAME:"; + Str : String (1 .. 12) with Import, + Address => This.Responce (Expect'Length + 1)'Address; + begin + Transmit_And_Check + (This, "AT+NAME?", Expect, + This.Responce'Address, Expect'Length + 12, Status); + + if Status = Ok then + return Str + (1 .. Natural'Min + (12, Find_Zero (This, Expect'Length + 1) - 1 - Expect'Length)); + else + return ""; + end if; + end Get_Module_Name; + + ---------------------- + -- Set_Output_Power -- + ---------------------- + + procedure Set_Output_Power + (This : in out HM11_Driver; + Power : Output_Power; + Status : out UART_Status) + is + S : constant String := Image (Output_Power'Pos (Power)); + begin + Transmit_And_Check (This, "AT+PCTL" & S, Ok_Set & S, Status); + end Set_Output_Power; + + ---------------------- + -- Get_Output_Power -- + ---------------------- + + procedure Get_Output_Power + (This : in out HM11_Driver; + Power : out Output_Power; + Status : out UART_Status) is + begin + Transmit_And_Check + (This, "AT+PCTL?", Ok_Get, + This.Responce'Address, Ok_Get'Length + 1, Status); + + if Status = Ok then + Power := Output_Power'Val (Value (This.Responce (Ok_Get'Length + 1))); + end if; + end Get_Output_Power; + + -------------------- + -- Set_Parity_Bit -- + -------------------- + + procedure Set_Parity_Bit + (This : in out HM11_Driver; + Parity : Parity_Bit; + Status : out UART_Status) + is + S : constant String := Image (Parity_Bit'Pos (Parity)); + begin + Transmit_And_Check (This, "AT+PARI" & S, Ok_Set & S, Status); + end Set_Parity_Bit; + + -------------------- + -- Get_Parity_Bit -- + -------------------- + + procedure Get_Parity_Bit + (This : in out HM11_Driver; + Parity : out Parity_Bit; + Status : out UART_Status) is + begin + Transmit_And_Check + (This, "AT+PARI?", Ok_Get, + This.Responce'Address, Ok_Get'Length + 1, Status); + + if Status = Ok then + Parity := Parity_Bit'Val (Value (This.Responce (Ok_Get'Length + 1))); + end if; + end Get_Parity_Bit; + + --------------------------- + -- Set_PIO_Output_Status -- + --------------------------- + + procedure Set_PIO_Output_Status + (This : in out HM11_Driver; + PIO : PIO_Number; + Output : PIO_Output; + Status : out UART_Status) + is + I : constant String := Image (PIO); + S : constant String := Image (PIO_Output'Pos (Output)); + Expect : constant String := "OK+PIO" & I & ":"; + begin + if PIO = 1 then + Transmit_And_Check (This, "AT+PIO1" & S, Ok_Set & S, Status); + else + Transmit_And_Check (This, "AT+PIO" & I & S, Expect & S, Status); + end if; + end Set_PIO_Output_Status; + + --------------------------- + -- Get_PIO_Output_Status -- + --------------------------- + + procedure Get_PIO_Output_Status + (This : in out HM11_Driver; + PIO : PIO_Number; + Output : out PIO_Output; + Status : out UART_Status) + is + I : constant String := Image (PIO); + Expect : constant String := "OK+PIO" & I & ":"; + begin + if PIO = 1 then + Transmit_And_Check + (This, "AT+PIO1?", Ok_Get, + This.Responce'Address, Ok_Get'Length + 1, Status); + + if Status = Ok then + Output := PIO_Output'Val + (Value (This.Responce (Ok_Get'Length + 1))); + end if; + + else + Transmit_And_Check + (This, "AT+PIO" & I & "?", Expect, + This.Responce'Address, Expect'Length + 1, Status); + + if Status = Ok then + Output := PIO_Output'Val + (Value (This.Responce (Expect'Length + 1))); + end if; + end if; + end Get_PIO_Output_Status; + + ---------------------------- + -- Get_PIOs_Output_Status -- + ---------------------------- + + procedure Get_PIOs_Output_Status + (This : in out HM11_Driver; + PIOs : out PIO_Numbers; + Status : out UART_Status) + is + Expect : constant String := "OK+PIO?"; + PIO : PIO_Numbers with Import, + Address => This.Responce (Expect'Length + 1)'Address; + begin + Transmit_And_Check + (This, "AT+PIO??", Expect, + This.Responce'Address, Expect'Length + 3, Status); + + if Status = Ok then + PIOs := PIO; + end if; + end Get_PIOs_Output_Status; + + ---------------------------- + -- Set_PIOs_Output_Status -- + ---------------------------- + + procedure Set_PIOs_Output_Status + (This : in out HM11_Driver; + PIOs : PIO_Numbers; + Status : out UART_Status) + is + Local : constant PIO_Numbers := PIOs; + S : constant String (PIO_Numbers'Range) with Import, + Address => Local (Local'First)'Address; + begin + Transmit_And_Check (This, "AT+MPIO" & S, Ok_Set & S, Status); + end Set_PIOs_Output_Status; + + ------------------ + -- Set_PIN_Code -- + ------------------ + + procedure Set_PIN_Code + (This : in out HM11_Driver; + Pin : PIN_Type; + Status : out UART_Status) + is + Local : constant PIN_Type := Pin; + S : constant String (PIN_Type'Range) with Import, + Address => Local (Local'First)'Address; + begin + Transmit_And_Check (This, "AT+PASS" & S, Ok_Set & S, Status); + end Set_PIN_Code; + + ------------------ + -- Get_PIN_Code -- + ------------------ + + procedure Get_PIN_Code + (This : in out HM11_Driver; + Pin : out PIN_Type; + Status : out UART_Status) is + begin + Transmit_And_Check + (This, "AT+PASS?", Ok_Get, + This.Responce'Address, Ok_Get'Length + PIN_Type'Length, Status); + + if Status = Ok then + declare + L : PIN_Type with Import, + Address => This.Responce (Ok_Get'Length + 1)'Address; + begin + Pin := L; + end; + end if; + end Get_PIN_Code; + + ---------------------- + -- Set_Module_Power -- + ---------------------- + + procedure Set_Module_Power + (This : in out HM11_Driver; + Power : Module_Power; + Status : out UART_Status) + is + S : constant String := Image (Module_Power'Pos (Power)); + begin + Transmit_And_Check (This, "AT+POWE" & S, Ok_Set & S, Status); + end Set_Module_Power; + + ---------------------- + -- Get_Module_Power -- + ---------------------- + + procedure Get_Module_Power + (This : in out HM11_Driver; + Power : out Module_Power; + Status : out UART_Status) is + begin + Transmit_And_Check + (This, "AT+POWE?", Ok_Get, + This.Responce'Address, Ok_Get'Length + 1, Status); + + if Status = Ok then + Power := Module_Power'Val (Value (This.Responce (Ok_Get'Length + 1))); + end if; + end Get_Module_Power; + + --------------------------- + -- Set_Module_Auto_Sleep -- + --------------------------- + + procedure Set_Module_Auto_Sleep + (This : in out HM11_Driver; + Sleep : Boolean; + Status : out UART_Status) + is + S : constant String := Image (not Sleep); + begin + Transmit_And_Check (This, "AT+PWRM" & S, Ok_Set & S, Status); + end Set_Module_Auto_Sleep; + + --------------------------- + -- Get_Module_Auto_Sleep -- + --------------------------- + + procedure Get_Module_Auto_Sleep + (This : in out HM11_Driver; + Sleep : out Boolean; + Status : out UART_Status) is + begin + Transmit_And_Check + (This, "AT+PWRM?", Ok_Get, + This.Responce'Address, Ok_Get'Length + 1, Status); + + if Status = Ok then + declare + S : Character with Import, + Address => This.Responce (Ok_Get'Length + 1)'Address; + begin + Sleep := S = '0'; + end; + end if; + end Get_Module_Auto_Sleep; + + ----------------------------------- + -- Set_Reliable_Advertising_Mode -- + ----------------------------------- + + procedure Set_Reliable_Advertising_Mode + (This : in out HM11_Driver; + Mode : Advertising_Mode; + Status : out UART_Status) + is + S : constant String := Image (Advertising_Mode'Pos (Mode)); + begin + Transmit_And_Check (This, "AT+RELI" & S, Ok_Set & S, Status); + end Set_Reliable_Advertising_Mode; + + ----------------------------------- + -- Get_Reliable_Advertising_Mode -- + ----------------------------------- + + procedure Get_Reliable_Advertising_Mode + (This : in out HM11_Driver; + Mode : out Advertising_Mode; + Status : out UART_Status) is + begin + Transmit_And_Check + (This, "AT+RELI?", Ok_Get, + This.Responce'Address, Ok_Get'Length + 1, Status); + + if Status = Ok then + Mode := Advertising_Mode'Val + (Value (This.Responce (Ok_Get'Length + 1))); + end if; + end Get_Reliable_Advertising_Mode; + + ----------- + -- Reset -- + ----------- + + procedure Reset + (This : in out HM11_Driver; + Status : out UART_Status) is + begin + Transmit_And_Check (This, "AT+RENEW", "OK+RENEW", Status); + end Reset; + + ------------- + -- Restart -- + ------------- + + procedure Restart + (This : in out HM11_Driver; + Status : out UART_Status) is + begin + Transmit_And_Check (This, "AT+RESET", "OK+RESET", Status); + end Restart; + + ------------------- + -- Start_Working -- + ------------------- + + procedure Start_Working + (This : in out HM11_Driver; + Status : out UART_Status) is + begin + Transmit_And_Check (This, "AT+START", "OK+START", Status); + end Start_Working; + + ---------------------------- + -- Set_Save_Connected_MAC -- + ---------------------------- + + procedure Set_Save_Connected_MAC + (This : in out HM11_Driver; + Save : Boolean; + Status : out UART_Status) + is + S : constant String := Image (not Save); + begin + Transmit_And_Check (This, "AT+SAVE" & S, Ok_Set & S, Status); + end Set_Save_Connected_MAC; + + ---------------------------- + -- Get_Save_Connected_MAC -- + ---------------------------- + + procedure Get_Save_Connected_MAC + (This : in out HM11_Driver; + Save : out Boolean; + Status : out UART_Status) is + begin + Transmit_And_Check + (This, "AT+SAVE?", Ok_Get, + This.Responce'Address, Ok_Get'Length + 1, Status); + + if Status = Ok then + declare + S : Character with Import, + Address => This.Responce (Ok_Get'Length + 1)'Address; + begin + Save := S = '0'; + end; + end if; + end Get_Save_Connected_MAC; + + ------------------------ + -- Set_Discovery_Time -- + ------------------------ + + procedure Set_Discovery_Time + (This : in out HM11_Driver; + Time : Discovery_Time; + Status : out UART_Status) + is + S : constant String := Image (Time); + begin + Transmit_And_Check (This, "AT+SCAN" & S, Ok_Set & S, Status); + end Set_Discovery_Time; + + ------------------------ + -- Get_Discovery_Time -- + ------------------------ + + procedure Get_Discovery_Time + (This : in out HM11_Driver; + Time : out Discovery_Time; + Status : out UART_Status) is + begin + Transmit_And_Check + (This, "AT+SCAN?", Ok_Get, + This.Responce'Address, Ok_Get'Length + 1, Status); + + if Status = Ok then + declare + S : String (1 .. 1) with Import, + Address => This.Responce (Ok_Get'Length + 1)'Address; + begin + Time := Discovery_Time'Value (S); + end; + end if; + end Get_Discovery_Time; + + --------------------- + -- Set_Sensor_Type -- + --------------------- + + procedure Set_Sensor_Type + (This : in out HM11_Driver; + Value : Sensor_Type; + Status : out UART_Status) + is + S : constant String := Image (Sensor_Type'Pos (Value)); + begin + Transmit_And_Check (This, "AT+SENS" & S, Ok_Set & S, Status); + end Set_Sensor_Type; + + --------------------- + -- Get_Sensor_Type -- + --------------------- + + procedure Get_Sensor_Type + (This : in out HM11_Driver; + Result : out Sensor_Type; + Status : out UART_Status) is + begin + Transmit_And_Check + (This, "AT+SENS?", Ok_Get, + This.Responce'Address, Ok_Get'Length + 1, Status); + + if Status = Ok then + Result := Sensor_Type'Val + (Value (This.Responce (Ok_Get'Length + 1))); + end if; + end Get_Sensor_Type; + + ------------------------------------------------ + -- Set_Show_Device_Information_When_Discovery -- + ------------------------------------------------ + + procedure Set_Show_Device_Information_When_Discovery + (This : in out HM11_Driver; + Show : Show_Device_Information; + Status : out UART_Status) + is + S : constant String := Image (Show_Device_Information'Pos (Show)); + begin + Transmit_And_Check (This, "AT+SHOW" & S, Ok_Set & S, Status); + end Set_Show_Device_Information_When_Discovery; + + ------------------------------------------------ + -- Get_Show_Device_Information_When_Discovery -- + ------------------------------------------------ + + procedure Get_Show_Device_Information_When_Discovery + (This : in out HM11_Driver; + Show : out Show_Device_Information; + Status : out UART_Status) is + begin + Transmit_And_Check + (This, "AT+SHOW?", Ok_Get, + This.Responce'Address, Ok_Get'Length + 1, Status); + + if Status = Ok then + Show := Show_Device_Information'Val + (Value (This.Responce (Ok_Get'Length + 1))); + end if; + end Get_Show_Device_Information_When_Discovery; + + ----------------------------------------- + -- Get_Sensor_Temperature_And_Humidity -- + ----------------------------------------- + + procedure Get_Sensor_Temperature_And_Humidity + (This : in out HM11_Driver; + Temperature : out Temperature_Type; + Humidity : out Humidity_Type; + Status : out UART_Status) is + begin + Transmit_And_Check + (This, "AT+TEHU?", Ok_Get, + This.Responce'Address, Ok_Get'Length + 6, Status); + + if Status = Ok then + declare + T : String (1 .. 3) with Import, + Address => This.Responce (Ok_Get'Length + 1)'Address; + H : String (1 .. 3) with Import, + Address => This.Responce (Ok_Get'Length + 4)'Address; + begin + Temperature := Temperature_Type'Value (T); + Humidity := Humidity_Type'Value (H); + end; + end if; + end Get_Sensor_Temperature_And_Humidity; + + ---------------------------- + -- Get_Module_Temperature -- + ---------------------------- + + procedure Get_Module_Temperature + (This : in out HM11_Driver; + Temperature : out Internal_Temperature_Type; + Status : out UART_Status) is + begin + Transmit_And_Check + (This, "AT+TEMP?", Ok_Get, + This.Responce'Address, + Ok_Get'Length + Internal_Temperature_Type'Length, Status); + + if Status = Ok then + declare + T : Internal_Temperature_Type with Import, + Address => This.Responce (Ok_Get'Length + 1)'Address; + begin + Temperature := T; + end; + end if; + end Get_Module_Temperature; + + ----------------------------------------------------- + -- Set_Temperature_Information_Byte_In_Advertising -- + ----------------------------------------------------- + + procedure Set_Temperature_Information_Byte_In_Advertising + (This : in out HM11_Driver; + Temperature : Advertising_Temperature_Type; + Status : out UART_Status) + is + Local : constant Advertising_Temperature_Type := Temperature; + S : constant String (Advertising_Temperature_Type'Range) with Import, + Address => Local (Local'First)'Address; + begin + Transmit_And_Check + (This, "AT+TEMP0x" & S, Ok_Set & "0x" & S, Status); + end Set_Temperature_Information_Byte_In_Advertising; + + --------------------------------------- + -- Set_Connect_Remote_Device_Timeout -- + --------------------------------------- + + procedure Set_Connect_Remote_Device_Timeout + (This : in out HM11_Driver; + Timeout : Connect_Timeout; + Status : out UART_Status) + is + Local : constant Connect_Timeout := Timeout; + S : constant String (Connect_Timeout'Range) with Import, + Address => Local (Local'First)'Address; + begin + Transmit_And_Check (This, "AT+TCON" & S, Ok_Set & S, Status); + end Set_Connect_Remote_Device_Timeout; + + --------------------------------------- + -- Get_Connect_Remote_Device_Timeout -- + --------------------------------------- + + procedure Get_Connect_Remote_Device_Timeout + (This : in out HM11_Driver; + Timeout : out Connect_Timeout; + Status : out UART_Status) is + begin + Transmit_And_Check + (This, "AT+TCON?", Ok_Get, + This.Responce'Address, + Ok_Get'Length + Connect_Timeout'Length, Status); + + if Status = Ok then + declare + L : Connect_Timeout with Import, + Address => This.Responce (Ok_Get'Length + 1)'Address; + begin + Timeout := L; + end; + end if; + end Get_Connect_Remote_Device_Timeout; + + ------------------- + -- Set_Bond_Mode -- + ------------------- + + procedure Set_Bond_Mode + (This : in out HM11_Driver; + Mode : Bond_Mode; + Status : out UART_Status) + is + S : constant String := Image (Bond_Mode'Pos (Mode)); + begin + Transmit_And_Check (This, "AT+TYPE" & S, Ok_Set & S, Status); + end Set_Bond_Mode; + + ------------------- + -- Get_Bond_Mode -- + ------------------- + + procedure Get_Bond_Mode + (This : in out HM11_Driver; + Mode : out Bond_Mode; + Status : out UART_Status) is + begin + Transmit_And_Check + (This, "AT+SHOW?", Ok_Get, + This.Responce'Address, Ok_Get'Length + 1, Status); + + if Status = Ok then + Mode := Bond_Mode'Val + (Value (This.Responce (Ok_Get'Length + 1))); + end if; + end Get_Bond_Mode; + + ---------------------- + -- Set_Service_UUID -- + ---------------------- + + procedure Set_Service_UUID + (This : in out HM11_Driver; + Value : UUID; + Status : out UART_Status) + is + Local : constant UUID := Value; + S : constant String (UUID'Range) with Import, + Address => Local (Local'First)'Address; + begin + Transmit_And_Check + (This, "AT+UUID0x" & S, Ok_Set & "0x" & S, Status); + end Set_Service_UUID; + + ---------------------- + -- Get_Service_UUID -- + ---------------------- + + procedure Get_Service_UUID + (This : in out HM11_Driver; + Result : out UUID; + Status : out UART_Status) is + begin + Transmit_And_Check + (This, "AT+UUID?", Ok_Get, + This.Responce'Address, Ok_Get'Length + UUID'Length + 2, Status); + + if Status = Ok then + declare + L : UUID with Import, + Address => This.Responce (Ok_Get'Length + 3)'Address; + begin + Result := L; + end; + end if; + end Get_Service_UUID; + + ------------------------- + -- Set_UART_Sleep_Type -- + ------------------------- + + procedure Set_UART_Sleep_Type + (This : in out HM11_Driver; + Value : UART_Sleep_Type; + Status : out UART_Status) + is + S : constant String := Image (UART_Sleep_Type'Pos (Value)); + begin + Transmit_And_Check (This, "AT+UART" & S, Ok_Set & S, Status); + end Set_UART_Sleep_Type; + + ------------------------- + -- Get_UART_Sleep_Type -- + ------------------------- + + procedure Get_UART_Sleep_Type + (This : in out HM11_Driver; + Result : out UART_Sleep_Type; + Status : out UART_Status) is + begin + Transmit_And_Check + (This, "AT+UART?", Ok_Get, + This.Responce'Address, Ok_Get'Length + 1, Status); + + if Status = Ok then + Result := UART_Sleep_Type'Val + (Value (This.Responce (Ok_Get'Length + 1))); + end if; + end Get_UART_Sleep_Type; + + ----------------------------------- + -- Set_Module_Advertisement_Data -- + ----------------------------------- + + procedure Set_Module_Advertisement_Data + (This : in out HM11_Driver; + Data : Advertisement_Data; + Status : out UART_Status) + is + Local : constant Advertisement_Data := Data; + S : constant String (Advertisement_Data'Range) with Import, + Address => Local (Local'First)'Address; + begin + Transmit_And_Check (This, "AT+PACK" & S, Ok_Set & S, Status); + end Set_Module_Advertisement_Data; + + ---------------------- + -- Software_Version -- + ---------------------- + + function Software_Version + (This : in out HM11_Driver) + return String + is + Zero : Natural; + Status : UART_Status; + + begin + Transmit (This, "AT+VERS?", Status); + if Status /= Ok then + return ""; + end if; + + This.Receive + (This.Port, This.Responce'Address, This.Responce'Length, Status); + + Zero := Find_Zero (This, This.Responce'First); + if Zero > 0 then + declare + V : String (This.Responce'First .. Zero - 1) with Import, + Address => This.Responce'Address; + begin + return V; + end; + + else + return ""; + end if; + + exception + when others => + return ""; + end Software_Version; + + ------------------------ + -- Set_Characteristic -- + ------------------------ + + procedure Set_Characteristic + (This : in out HM11_Driver; + Value : Characteristic_Type; + Status : out UART_Status) + is + Local : constant Characteristic_Type := Value; + S : constant String (Characteristic_Type'Range) with Import, + Address => Local (Local'First)'Address; + begin + Transmit_And_Check + (This, "AT+CHAR0x" & S, Ok_Set, + This.Responce'Address, Ok_Set'Length + 6, Status); + end Set_Characteristic; + + ------------------------ + -- Get_Characteristic -- + ------------------------ + + procedure Get_Characteristic + (This : in out HM11_Driver; + Result : out Characteristic_Type; + Status : out UART_Status) is + begin + Transmit_And_Check + (This, "AT+CHAR?", Ok_Get, + This.Responce'Address, Ok_Get'Length + 6, Status); + + if Status = Ok then + declare + L : Characteristic_Type with Import, + Address => This.Responce (Ok_Get'Length + 3)'Address; + begin + Result := L; + end; + end if; + end Get_Characteristic; + + ----------------------------- + -- Set_PIO_Collection_Rate -- + ----------------------------- + + procedure Set_PIO_Collection_Rate + (This : in out HM11_Driver; + Value : PIO_Collection_Rate; + Status : out UART_Status) + is + I : constant String := Image (Integer (Value)); + begin + Transmit_And_Check + (This, "AT+CYC" & (if I'Length = 1 then "0" else "") & I, Ok_Get, + This.Responce'Address, Ok_Get'Length + 2, Status); + end Set_PIO_Collection_Rate; + + ----------------------------- + -- Get_PIO_Collection_Rate -- + ----------------------------- + + procedure Get_PIO_Collection_Rate + (This : in out HM11_Driver; + Result : out PIO_Collection_Rate; + Status : out UART_Status) + is + use type HAL.UInt8; + begin + Transmit_And_Check + (This, "AT+CYC??", Ok_Get, + This.Responce'Address, Ok_Get'Length + 2, Status); + + if Status = Ok then + declare + I : String + (1 .. (if This.Responce (Ok_Get'Length + 2) = 0 then 1 else 2)) + with Import, + Address => This.Responce (Ok_Get'Length + 1)'Address; + begin + Result := PIO_Collection_Rate'Value (I); + end; + end if; + end Get_PIO_Collection_Rate; + + -------------------------- + -- Set_Power_Pin_Output -- + -------------------------- + + procedure Set_Power_Pin_Output + (This : in out HM11_Driver; + Value : PIO_Numbers; + Status : out UART_Status) + is + Local : constant PIO_Numbers := Value; + S : constant String (PIO_Numbers'Range) with Import, + Address => Local (Local'First)'Address; + begin + Transmit_And_Check + (This, "AT+BEFC" & S, Ok_Get, + This.Responce'Address, + Ok_Get'Length + PIO_Numbers'Length, Status); + end Set_Power_Pin_Output; + + -------------------------- + -- Get_Power_Pin_Output -- + -------------------------- + + procedure Get_Power_Pin_Output + (This : in out HM11_Driver; + Result : out PIO_Numbers; + Status : out UART_Status) is + begin + Transmit_And_Check + (This, "AT+BEFC?", Ok_Get, + This.Responce'Address, + Ok_Get'Length + PIO_Numbers'Length, Status); + + if Status = Ok then + declare + I : PIO_Numbers with Import, + Address => This.Responce (Ok_Get'Length + 1)'Address; + begin + Result := I; + end; + end if; + end Get_Power_Pin_Output; + + ---------------------------- + -- Set_Connect_Pin_Output -- + ---------------------------- + + procedure Set_Connect_Pin_Output + (This : in out HM11_Driver; + Value : PIO_Numbers; + Status : out UART_Status) + is + Local : constant PIO_Numbers := Value; + S : constant String (PIO_Numbers'Range) with Import, + Address => Local (Local'First)'Address; + begin + Transmit_And_Check + (This, "AT+AFTC" & S, Ok_Get, + This.Responce'Address, + Ok_Get'Length + PIO_Numbers'Length, Status); + end Set_Connect_Pin_Output; + + ---------------------------- + -- Get_Connect_Pin_Output -- + ---------------------------- + + procedure Get_Connect_Pin_Output + (This : in out HM11_Driver; + Result : out PIO_Numbers; + Status : out UART_Status) is + begin + Transmit_And_Check + (This, "AT+AFTC?", Ok_Get, + This.Responce'Address, + Ok_Get'Length + PIO_Numbers'Length, Status); + + if Status = Ok then + declare + I : PIO_Numbers with Import, + Address => This.Responce (Ok_Get'Length + 1)'Address; + begin + Result := I; + end; + end if; + end Get_Connect_Pin_Output; + + ---------------- + -- Start_With -- + ---------------- + + function Start_With + (This : HM11_Driver; + Value : String; + From : Positive; + To : Positive) + return Boolean + is + Last : Positive := From + Value'Length - 1; + Local : constant String := Value; + V : UART_Data_8b (Local'Range) with Import, Address => Local'Address; + begin + if From <= To then + return Last <= To and then This.Responce (From .. Last) = V; + + else + if Last <= This.Responce'Last then + return This.Responce (From .. Last) = V; + end if; + + Last := This.Responce'Last - From + 1; + return Start_With + (This, Value (Value'First .. Value'First + Last - 1), + From, This.Responce'Last) + and then Start_With (This, Value (Last .. Value'Last), 1, To); + end if; + end Start_With; + + ----------- + -- Image -- + ----------- + + function Image (Value : Natural) return String is + S : constant String := Value'Img; + begin + return S (S'First + 1 .. S'Last); + end Image; + + ----------- + -- Image -- + ----------- + + function Image (Value : Send_Data_Method) return String is + begin + case Value is + when Write => + return "WR"; + when Write_Without_Response => + return "WN"; + when Indicate => + return "IN"; + when Notify => + return "NO"; + end case; + end Image; + + ----------- + -- Image -- + ----------- + + function Image (Value : Send_Data_Characteristic) return String is + begin + case Value is + when Write => + return "WR"; + when Write_Without_Response => + return "WN"; + end case; + end Image; + + ----------- + -- Value -- + ----------- + + function Value (V : HAL.UInt8) return Natural is + begin + return Natural'Value (Character'Val (V) & ""); + end Value; + + ----------- + -- Value -- + ----------- + + function Image (Value : Boolean) return String is + begin + if Value then + return "1"; + else + return "0"; + end if; + end Image; + + ----------- + -- Image -- + ----------- + + function Image (Value : MAC_Address_Type) return String is + begin + case Value is + when Normal_Address => + return "N"; + when Static_MAC => + return "0"; + when Static_Random_MAC => + return "1"; + when Random_MAC => + return "2"; + end case; + end Image; + + ----------------------- + -- To_Connect_Result -- + ----------------------- + + function To_Connect_Result (C : Character) return Connect_Result is + begin + case C is + when 'L' => return Connecting; + when 'E' => return Connect_Error; + when 'F' => return Connect_Fail; + when 'N' => return No_Address; + when ' ' | ASCII.NUL | + '0' .. '5' => return Connected; + when others => return Other_Error; + end case; + end To_Connect_Result; + + --------------- + -- To_String -- + --------------- + + function To_String (Handle : Handle_Type) return String is + Local_Handle : Handle_Type := Handle; + H : String (Handle_Type'Range) with Import, + Address => Local_Handle (Local_Handle'First)'Address; + begin + return H; + end To_String; + + --------------- + -- Find_Zero -- + --------------- + + function Find_Zero + (This : HM11_Driver; + From : Positive) + return Natural + is + use type HAL.UInt8; + begin + for Index in From .. This.Responce'Last loop + if This.Responce (Index) = 0 then + return Index; + end if; + end loop; + + return This.Responce'Last + 1; + end Find_Zero; + + ---------- + -- Find -- + ---------- + + function Find + (This : HM11_Driver; + Value : String; + From : Positive; + To : Positive) + return Natural + is + Local : constant String := Value; + V : UART_Data_8b (Local'Range) with Import, Address => Local'Address; + Res : Natural; + + function Do_Find (F, T : Positive) return Natural; + function Do_Find (F, T : Positive) return Natural is + begin + for Index in F .. T loop + if This.Responce (Index .. Index + V'Length - 1) = V then + return Index; + end if; + end loop; + + return 0; + end Do_Find; + + begin + if From <= To then + return Do_Find (From, To - Value'Length + 1); + + else + Res := Do_Find (From, This.Responce'Last - Value'Length + 1); + if Res /= 0 then + return Res; + end if; + return Do_Find (This.Responce'First, To - Value'Length + 1); + end if; + end Find; + + ----------------- + -- Calc_Lenght -- + ----------------- + + function Calc_Lenght + (This : HM11_Driver; + From : Positive; + Zero : Positive) + return Natural is + begin + if From = Zero then + return 0; + end if; + + if From < Zero then + return Zero - From; + else + return (This.Responce'Last - From + 1) + + (This.Responce'First + Zero - 2); + end if; + end Calc_Lenght; + + ---------- + -- Move -- + ---------- + + procedure Move + (This : HM11_Driver; + Result : in out Positive; + Add : Positive; + Zero : Positive; + Length : out Natural) is + begin + Result := Result + Add; + if Result > This.Responce'Last then + Result := Result - This.Responce'Length; + end if; + Length := Calc_Lenght (This, Result, Zero); + end Move; + + ------------ + -- Append -- + ------------ + + procedure Append + (This : HM11_Driver; + Str : in out Variable_String; + From : Positive; + To : Positive) + is + procedure Do_Append (F, T : Positive); + procedure Do_Append (F, T : Positive) + is + S : String (F .. T) with Import, + Address => This.Responce (F)'Address; + begin + Str.Value (Str.Last + 1 .. Str.Last + S'Length) := S; + Str.Last := Str.Last + S'Length; + end Do_Append; + + begin + if From <= To then + Do_Append (From, To); + else + Do_Append (From, This.Responce'Last); + Do_Append (This.Responce'First, To); + end if; + end Append; + + ---------- + -- Copy -- + ---------- + + procedure Copy + (This : HM11_Driver; + To : out UART_Data_8b; + From : Positive) + is + L : Positive; + begin + if From + To'Length - 1 <= This.Responce'Last then + To := This.Responce (From .. From + To'Length - 1); + + else + L := This.Responce'Last - From + 1; + + To (To'First .. To'First + L - 1) := + This.Responce (From .. This.Responce'Last); + + To (To'First + L .. To'Last) := + This.Responce (This.Responce'First .. + This.Responce'First + To'Last - To'First - L); + end if; + + end Copy; + +end HM11; diff --git a/components/src/radio/hm11/hm11.ads b/components/src/radio/hm11/hm11.ads new file mode 100644 index 000000000..a578643de --- /dev/null +++ b/components/src/radio/hm11/hm11.ads @@ -0,0 +1,1377 @@ +------------------------------------------------------------------------------ +-- -- +-- Copyright (C) 2025, AdaCore -- +-- -- +-- Redistribution and use in source and binary forms, with or without -- +-- modification, are permitted provided that the following conditions are -- +-- met: -- +-- 1. Redistributions of source code must retain the above copyright -- +-- notice, this list of conditions and the following disclaimer. -- +-- 2. Redistributions in binary form must reproduce the above copyright -- +-- notice, this list of conditions and the following disclaimer in -- +-- the documentation and/or other materials provided with the -- +-- distribution. -- +-- 3. Neither the name of the copyright holder nor the names of its -- +-- contributors may be used to endorse or promote products derived -- +-- from this software without specific prior written permission. -- +-- -- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -- +-- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -- +-- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -- +-- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -- +-- HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -- +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -- +-- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -- +-- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -- +-- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -- +-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -- +-- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- +-- -- +------------------------------------------------------------------------------ + +-- Driver for HM-11/cc2541 chip + +with HAL.UART; use HAL.UART; +with System; + +package HM11 is + + pragma Extensions_Allowed (On); + + type Receive_Handler is not null access + procedure (Port : HAL.UART.Any_UART_Port; + Received : System.Address; + Length : Natural; + Status : out UART_Status; + Timeout : Natural := 1000; + As_Stream : Boolean := False); + -- Received points to memory where incoming data will be stored. + -- Length is the length of the memory buffer. + -- Timeout in milliseconds. + -- As_Stream starts reading without blocking the caller and read data + -- into Received in a cycle + + type Last_Read_Position_Handler is access + procedure (Closed : out Boolean; + Zero : out Positive); + -- The last read byte is Zero-1. Closed = True if stream is closed + -- due to error. + + procedure Default_Receive_Handler + (Port : HAL.UART.Any_UART_Port; + Received : System.Address; + Length : Natural; + Status : out UART_Status; + Timeout : Natural := 1000; + As_Stream : Boolean := False); + -- The default receive procedure is based on HAL.Receive that can be + -- used with synchronous USART only. Use a custom one based on the DMA + -- for asynchronous UART, like shown in + -- examples/STM32F429_Discovery/hm11_f429disco.gpr + + ----------- + -- Types -- + ----------- + + type Role is (Peripheral, Central); + + type Hex_Character is new Character range '0' .. 'F'; + type Digit_Character is new Character range '0' .. '9'; + + type Advertising_Interval is + (ms_100, ms_211, ms_252, ms_318, ms_417, ms_546, ms_760, ms_852, ms_1022, + ms_1285, ms_2000, ms_3000, ms_4000, ms_5000, ms_6000, ms_7000); + + type Advertising_Type is + (Advertising_ScanResponse_Connectable, + Last_Device_Connect, + Advertising_ScanResponse, + Advertising); + + type Advertising_FLAG is array (1 .. 2) of Hex_Character; + -- 0x00~0xFF + + type Advertising_Mode is (Normal_Advertising, Reliable_Advertising); + + type Advertising_Temperature_Type is array (1 .. 2) of Hex_Character; + + type MAC_Address_Type is + (Normal_Address, Static_MAC, Static_Random_MAC, Random_MAC); + + type MAC_Address is array (1 .. 12) of Hex_Character; + -- 0xB4: 0x99: 0x4C: 0xXX: 0xXX: 0xXX is BLE MAC Address + + type UUID is array (1 .. 4) of Hex_Character; + -- 4 Bytes Length, HEX format string, only accept 16-bit UUID now + + type Write_Method is (Write, Write_Without_Response); + + type MAC_White_List_Index is range 1 .. 3; + + type Persent is range 0 .. 100; + + type UART_Baud_Rate is + (BR_9600, BR_19200, BR_38400, BR_57600, BR_115200, + BR_4800, BR_2400, BR_1200, BR_230400); + + type Link_Layer_Connection_Interval is + (ms_7, ms_10, ms_15, ms_20, ms_25, ms_30, ms_35, ms_40, ms_45, ms_4000); + + type Layer_Connection_Latency is range 0 .. 4; + + type Connection_Supervision_Timeout is + (ms_100, ms_1000, ms_2000, ms_3000, ms_4000, ms_5000, ms_6000); + + type Connect_Result is + (Connecting, Connected, Connect_Error, Connect_Fail, + No_Address, Other_Error); + + type Discovered_Index is range 0 .. 5; + -- Index in the list of the discovered devices + + Max_Name_Length : constant := 248; + Max_RSII_Length : constant := 4; + Discovered_Lenght : constant := 8 + -- OK+DISCS Discovery hello + 8 + MAC_Address'Length + -- OK+DISC: + MAC address + 8 + Max_Name_Length + 2 + -- OK+NAME: + Name + CRLF + 8 + Max_RSII_Length + 2; -- OK+RSSI: + RSII + CRLF + + type Discovered_Callback is access procedure + (Id : Character; + MAC : MAC_Address; + Name : String; + RSSI : String); + -- Called when Scan method discovered a device. Name and RSSI may be empty + -- depends on Set_Show_Device_Information_When_Discovery setting. + + Discovered_iBeacon_Lenght : constant := 8 + -- OK+DISCS Discovery hello + 8 + -- Factory ID + 32 + -- iBeacon UUID + 10 + -- P2 + 12 + -- MAC + 4; -- RSSI + + type Discovered_iBeacon_Callback is access + procedure (Device : String); + -- Device has the following format: P0:P1:P2:P3:P4 + -- Factory ID: P0 length is 8 Bytes; + -- iBeacon UUID: P1 length is 32 Bytes; + -- P2 length is 10 Bytes, include: + -- Major Value (length 4 Bytes); + -- Minor Value (length 4 Bytes); + -- Measured Power (length 2 Bytes) + -- MAC: P3 length is 12 Bytes, + -- RSSI: P4 length is 4 Bytes, + -- Those values all is ASCII mode. + -- If the device not enable iBeacon function, P0, P1, P2 will + -- use '0' to fill in. + + type iBeacon_Deploy_Mode is (Broadcast_Scanning, Only_Broadcast); + + type Service_UUID_Callback is access procedure (Service : String); + -- Service format is [P1]:[P2]:[P3] where: + -- P1: 4 Bytes, Services start handle. + -- P2: 4 Bytes, Services end handle + -- P3: 4 Bytes, Services UUID + + type Characteristic_UUID_Callback is + access procedure (Characteristic : String); + -- Characteristic format is [P1]:[P2]:[P3] where: + -- P1: 4 Bytes, Characteristic handle. + -- P2: 14 Bytes, "RD|WR|WN|NO|IN", + -- P3: 4 Bytes, Characteristic UUID + -- Characteristic properties length 14 Bytes, full string is + -- "RD|WR|WN|NO|IN"; WR - Write; WN - Write_Without_Response; + -- IN - Indicate; NO - Notify; RD - Read; + -- Usually, a characteristic maybe only has one or two properties. + -- Unsupported property part replaced by "--" + + type Handle_Type is array (1 .. 4) of Hex_Character; + + type Notify_Responce is (Send_Ok, Send_Er, Data_Er); + -- Send_Ok: Send command successful. + -- Send_Er: Send command error + -- Data_Er: This characteristic doesn't have notify property. + + type Send_Data_Method is (Write, Write_Without_Response, Indicate, Notify); + + type Send_Data_Characteristic is (Write, Write_Without_Response); + + type Characteristic_UUID_Count is (Query, One, One_And_Next, One_And_Prev); + -- One: Only use one Characteristic, please look at + -- Set_Characteristic command + -- One_And_Next: Use two Characteristics + -- Second Char value = first Char value + 1 + -- First char value = Set_Characteristic value + -- One_And_Prev: Use two Characteristic + -- Second Char value = first Char value - 1 + -- First char value = Set_Characteristic value + + type RX_Gain is (No, Open); + + type Humi_Information is array (1 .. 2) of Hex_Character; + -- 0x00~0xFF + + type Work_Type is (Start_Immediately, Respond_AT_Command); + + type iBeacon_UUID is array (1 .. 32) of Hex_Character; + + type Version_Type is array (1 .. 4) of Hex_Character; + + type Measured_Power is array (1 .. 2) of Hex_Character; + + type Work_Mode is + (Transmission_Mode, PIO_Collection_Mode, Remote_Control_Mode); + + type Notify_Mode is (Without_Address, With_Address); + + type Output_Power is (Normal_Power, Max_Power); + + type Parity_Bit is (None, Odd, Even); + + subtype PIO_Number is Positive range 1 .. 3; + -- Note: HM-11 only have PIO0, PIO1, PIO2,PIO3. + -- PIO0 has system KEY function, PIO1 - System LED + + type PIO_Output is (Low, High); + + type PIO_Numbers is array (1 .. 3) of Hex_Character; + -- 000 ~ 3FF; Hex format string + + type PIN_Type is array (1 .. 6) of Digit_Character; + + type Module_Power is (Dbm_Minus_23, Dbm_Minus_6, Dbm_0, Dbm_6); + + type Work_Interval is array (1 .. 2) of Digit_Character; + + type Stop_Bit is (One_Stop_Bit, Two_Stop_Bit); + + subtype Discovery_Time is Positive range 1 .. 9; + + type Sensor_Type is (None, DHT11, DS18B20); + + type Show_Device_Information is + (Dont_Show, Show_Name, Show_RSSI, Show_RSSI_And_Name); + + subtype Temperature_Type is Natural range 0 .. 120; + subtype Humidity_Type is Natural range 0 .. 100; + + subtype Internal_Temperature_Type is String (1 .. 7); + + type Connect_Timeout is array (1 .. 6) of Digit_Character; + + type Bond_Mode is + (Not_Need_PIN, Auth_Not_Need_PIN, Auth_With_PIN, Auth_And_Bonded); + + type UART_Sleep_Type is (Can_Wake_Up_Through_UART, Shutdown_UART); + + type Advertisement_Data is array (1 .. 12) of Hex_Character; + + type Characteristic_Type is array (1 .. 4) of Hex_Character; + + type PIO_Collection_Rate is range 0 .. 99; + -- Unit: seconds + + When_Connected_Message : constant String := "OK+CONN"; + -- Message when device is connected. This message is sent via UART in + -- Peripheral Role when some other device connected to this one. + + When_Disconnected_Message : constant String := "OK+LOST"; + -- This message is sent via UART in + -- Peripheral Role when some other device connected to this one. + + Max_Message_Length : constant := Discovered_Lenght; + + ----------------- + -- HM11_Driver -- + ----------------- + + type HM11_Driver + (Port : HAL.UART.Any_UART_Port; + Receive : Receive_Handler; + Readed_Position : Last_Read_Position_Handler) + is limited private; + -- V7xx defaults: Name: HMSoft; Baud: 115200, N, 8, 1; Pin code: 000000; + -- Peripheral Role; Remote-Control mode. + + procedure Test + (This : in out HM11_Driver; + Status : out UART_Status); + -- Returns Status = Ok if device responsed + + function Software_Version + (This : in out HM11_Driver) + return String; + + procedure Set_Role + (This : in out HM11_Driver; + Value : Role; + Status : out UART_Status); + -- Default: Peripheral. + -- Warning: See Set_Work_Type to avoid losing the possibility of + -- sending AT commands. + + procedure Get_Role + (This : in out HM11_Driver; + Result : out Role; + Status : out UART_Status); + + procedure Get_MAC_Address + (This : in out HM11_Driver; + Result : out MAC_Address; + Status : out UART_Status); + + -- In iOS system you can't get module MAC address directly. So, we put MAC + -- address information into advert packet. + procedure Set_Advertising_Interval + (This : in out HM11_Driver; + Value : Advertising_Interval; + Status : out UART_Status); + -- Added since V517 version. + -- V522 version added max value F. + -- The maximum 1285ms recommendations from the IOS system. That mean + -- 1285ms is apple allowed maximum value. + + procedure Get_Advertising_Interval + (This : in out HM11_Driver; + Result : out Advertising_Interval; + Status : out UART_Status); + + procedure Set_Advertising_Type + (This : in out HM11_Driver; + Value : Advertising_Type; + Status : out UART_Status); + -- Added since V519 + + procedure Get_Advertising_Type + (This : in out HM11_Driver; + Result : out Advertising_Type; + Status : out UART_Status); + + procedure Set_White_List_Switch + (This : in out HM11_Driver; + Value : Boolean; + Status : out UART_Status); + -- This command added in V523. + -- White List allows three MAC address link to module. Please use + -- Set_White_List_MAC_Addresses command set white list MAC address. + + procedure Get_White_List_Switch + (This : in out HM11_Driver; + Result : out Boolean; + Status : out UART_Status); + + procedure Set_White_List_MAC_Addresses + (This : in out HM11_Driver; + Index : MAC_White_List_Index; + Value : MAC_Address; + Status : out UART_Status); + -- This command added in V523. + -- White List allows three MAC address link to module. + + procedure Get_White_List_MAC_Address + (This : in out HM11_Driver; + Index : MAC_White_List_Index; + Result : out MAC_Address; + Status : out UART_Status); + + procedure Set_Battery_Monitor_Switch + (This : in out HM11_Driver; + Value : Boolean; + Status : out UART_Status); + -- This command added in V520 + -- When is set, module will add battery information into scan + -- response data package. Default: False. + + procedure Get_Battery_Monitor_Switch + (This : in out HM11_Driver; + Result : out Boolean; + Status : out UART_Status); + + procedure Set_Battery_Information + (This : in out HM11_Driver; + Value : Persent; + Status : out UART_Status); + -- Should not be connected! + -- Required: Set_Battery_Monitor_Switch (False) + -- This is used to set battery information byte in advertising data when + -- you closed module power monitor, you can use battery information byte + -- in advertising package for other purposes. + + procedure Query_Battery_Information + (This : in out HM11_Driver; + Result : out Persent; + Status : out UART_Status); + -- There has three ways to get battery information: + -- a. Before establishing a connection. + -- b. After established a connection, In Mode 1 or 2, remote side + -- can send command. + -- Battery information has included in scan response data package, + -- one-hour updated once. When module has been discovered, you can get + -- battery information from scan response package. + -- Data format is: + -- 0x02, 0x16, 0x00, 0xB0, [FLAG], [temperature], [ humidity], [battery]. + + procedure Set_UART_Baud_Rate + (This : in out HM11_Driver; + Value : UART_Baud_Rate; + Status : out UART_Status); + -- Set baud rate. Default: 9600. Note: If setup to Value BR_1200, After + -- next power on, module will not support any AT Commands. + + procedure Get_UART_Baud_Rate + (This : in out HM11_Driver; + Result : out UART_Baud_Rate; + Status : out UART_Status); + + procedure Set_Minimum_Link_Layer_Connection_Interval + (This : in out HM11_Driver; + Value : Link_Layer_Connection_Interval; + Status : out UART_Status); + -- This command is added since V538 + -- Default: 20ms + + procedure Get_Minimum_Link_Layer_Connection_Interval + (This : in out HM11_Driver; + Result : out Link_Layer_Connection_Interval; + Status : out UART_Status); + + procedure Set_Maximum_Link_Layer_Connection_Interval + (This : in out HM11_Driver; + Value : Link_Layer_Connection_Interval; + Status : out UART_Status); + -- This command is added since V538 + -- Default: 40ms + + procedure Get_Maximum_Link_Layer_Connection_Interval + (This : in out HM11_Driver; + Result : out Link_Layer_Connection_Interval; + Status : out UART_Status); + + procedure Set_Link_Layer_Connection_Slave_Latency + (This : in out HM11_Driver; + Value : Layer_Connection_Latency; + Status : out UART_Status); + -- This command is added since V538 + -- Default: 0 + + procedure Get_Link_Layer_Connection_Slave_Latency + (This : in out HM11_Driver; + Result : out Layer_Connection_Latency; + Status : out UART_Status); + + procedure Set_Connection_Supervision_Timeout + (This : in out HM11_Driver; + Value : Connection_Supervision_Timeout; + Status : out UART_Status); + -- This command is added since V538 + -- Default: 6000ms + + procedure Get_Connection_Supervision_Timeout + (This : in out HM11_Driver; + Result : out Connection_Supervision_Timeout; + Status : out UART_Status); + + procedure Set_Update_Connection + (This : in out HM11_Driver; + Value : Boolean; + Status : out UART_Status); + -- This command is added since V538 + -- Only Peripheral role is used. + -- This command is only use when module is in slave role. In central role + -- you can use Set_Minimum_Link_Layer_Connection_Interval and + -- Set_Maximum_Link_Layer_Connection_Interval command change default + -- connect parameters. + -- Default: True + + procedure Get_Update_Connection + (This : in out HM11_Driver; + Result : out Boolean; + Status : out UART_Status); + -- Only Peripheral role is used. + + procedure Clear_Last_Connected_Address + (This : in out HM11_Driver; + Status : out UART_Status); + -- Notice: Only Central role is used. + + procedure Sleep + (This : in out HM11_Driver; + Status : out UART_Status); + -- Only support Peripheral role. + -- Enter sleep mode + + procedure Wake_Up + (This : in out HM11_Driver; + Status : out UART_Status); + -- Wake up from the sleep mode + + procedure Connect_Last_Device + (This : in out HM11_Driver; + Result : out Connect_Result; + Status : out UART_Status); + -- Required: Set_Work_Type (Respond_AT_Command) and Set_Role (Central) + -- and Set_Save_Connected_MAC (True). + -- If remote device is not in connectable Connect_Fail result will + -- received after about 10 seconds. + + procedure Connect + (This : in out HM11_Driver; + MAC_Type : MAC_Address_Type; + Address : MAC_Address; + Result : out Connect_Result; + Status : out UART_Status); + -- Required: Set_Work_Type (Respond_AT_Command) and Set_Role (Central) + + procedure Connect + (This : in out HM11_Driver; + Index : Discovered_Index; + Result : out Connect_Result; + Status : out UART_Status); + -- This command is use after execute Scan + -- This command will clear all discovered devices list. + + -- The first discovered device array index is 0, second device array + -- index is 1, Scan command could return more than 6 devices, buy only + -- first 6 devices could use array index, other devices must use AT+CO or + -- AT+LN command. + + procedure Scan + (This : in out HM11_Driver; + Callback : Discovered_Callback; + Timeout : Natural; + Status : out UART_Status); + -- Required: Set_Work_Type (Respond_AT_Command), Central role + + procedure Scan_iBeacon + (This : in out HM11_Driver; + Callback : Discovered_iBeacon_Callback; + Timeout : Natural; + Status : out UART_Status); + -- Added since V539 + -- Please set Set_Work_Type (Respond_AT_Command) and Central role first. + + procedure Set_iBeacon_Deploy_Mode + (This : in out HM11_Driver; + Value : iBeacon_Deploy_Mode; + Status : out UART_Status); + -- After received OK, module will reset after 500ms. + -- This command will let module into non-connectable status until + -- next power on. + + procedure Remove_Bond_Information + (This : in out HM11_Driver; + Status : out UART_Status); + -- Added in V524 version + + procedure Find_All_Services_UUID + (This : in out HM11_Driver; + Callback : Service_UUID_Callback; + Timeout : Natural; + Status : out UART_Status); + -- This command added since V700 + -- Required state: after connect; Required role: Central. + -- Only central role device can use that command. This command is used to + -- find all services UUID on the slave device. + + procedure Find_All_Characteristic_UUID + (This : in out HM11_Driver; + Callback : Characteristic_UUID_Callback; + Timeout : Natural; + Status : out UART_Status); + -- This command added since V700 + -- Required state: after connect; Required role: Central. + -- Only central role device can use that command. This command is used + -- to find all Characteristic UUID on the slave device. + + procedure Find_Characteristic_UUID + (This : in out HM11_Driver; + From : Handle_Type; + To : Handle_Type; + Callback : Characteristic_UUID_Callback; + Timeout : Natural; + Status : out UART_Status); + -- This command added since V700 + -- Required state: after connect; Required role: Central. + -- Only central role device can use that command. This command is used + -- to find all Characteristic UUID on the slave device. + -- From and To value could get from Find_All_Services_UUID Command. + + procedure Enable_Characteristic_Notify + (This : in out HM11_Driver; + Handle : Handle_Type; + Status : out UART_Status; + Responce : out Notify_Responce); + -- This command added since V700 + -- Required state: after connect; Required role: Central. + -- Only central role device can use that command. This command is used + -- to enable notify on a characteristic who owned notify property. + + procedure Disable_Characteristic_Notify + (This : in out HM11_Driver; + Handle : Handle_Type; + Status : out UART_Status; + Responce : out Notify_Responce); + -- This command added since V700 + -- Required state: after connect; Required role: Central. + -- Only central role device can use that command. This command is used + -- to disable notify on a characteristic who owned notify property. + + procedure Read_Characteristic_Notify + (This : in out HM11_Driver; + Handle : Handle_Type; + Status : out UART_Status; + Responce : out Notify_Responce); + -- This command added since V700 + -- Required state: after connect; Required role: Central. + -- Only central role device can use that command. This command is used to + -- read characteristic value who owned read property. + + procedure Set_Method_And_Characteristic_Handle + (This : in out HM11_Driver; + Handle : Handle_Type; + Method : Send_Data_Method; + Status : out UART_Status); + -- This command added since V701 + -- Required state: after connect; Required role: Central. + -- Note: after execute this command, now you can start to send and receive + -- data without any AT commands. + -- Note: This command is different between Send_Data_To_Characteristic, + -- this command only need be executed once more. + + procedure Send_Data_To_Characteristic + (This : in out HM11_Driver; + Handle : Handle_Type; + Method : Send_Data_Characteristic; + Data : UART_Data_8b; + Status : out UART_Status); + -- This command added since V700 + -- Required state: after connect; Required role: Central. + -- Only central role device can use that command. This command is used to + -- send data to a characteristic who owned Write or Write-Without-Response + -- property. + -- P1: two bytes length, always is "WR" or "WN" + -- P2: characteristic handle, get by Set_Characteristic or + -- Find_All_Characteristic_UUID command + -- P3: the data what you want to send. + -- Note: Since V701, We added Set_Method_And_Characteristic_Handle command, + -- you can forget this command. + + procedure Set_Use_Characteristic_UUID_Count + (This : in out HM11_Driver; + Count : Characteristic_UUID_Count; + Status : out UART_Status); + -- This command added since V550. + -- Only Peripheral role is used. + + procedure Set_Advertising_FLAG + (This : in out HM11_Driver; + Flag : Advertising_FLAG; + Status : out UART_Status); + -- This command added in V530. + -- This command is used to set flag information byte in advertising + -- package for other purposes. + + procedure Set_UART_Flow_Control_Switch + (This : in out HM11_Driver; + Switch : Boolean; + Status : out UART_Status); + -- Default: False + + procedure Get_UART_Flow_Control_Switch + (This : in out HM11_Driver; + Switch : out Boolean; + Status : out UART_Status); + + procedure Set_Module_RX_Gain + (This : in out HM11_Driver; + Gain : RX_Gain; + Status : out UART_Status); + -- This command is added since V535 + -- Default: No RX gain + + procedure Get_Module_RX_Gain + (This : in out HM11_Driver; + Gain : out RX_Gain; + Status : out UART_Status); + + procedure Set_Humi_Information_Byte_In_Advertising + (This : in out HM11_Driver; + Info : Humi_Information; + Status : out UART_Status); + -- Added in V544 + -- This command is used to set humi-information byte in advertising data. + + procedure Set_Work_Type + (This : in out HM11_Driver; + Work : Work_Type; + Status : out UART_Status); + -- In Peripheral role: + -- If Start_Immediately is setup, module will auto in advertising status. + -- If Respond_AT_Command is setup, module will do nothing, you can config + -- module now, until Start_Working command received, module will in + -- advertising status. + -- In Central role: + -- If Start_Immediately is setup, module will discovery and try made + -- connection automatic. + -- If Respond_AT_Command is setup, module will do nothing, you can use + -- Scan or Scan_iBeacon commands or other AT commands what you + -- want to execute. Or you can execute Start_Working let module in auto + -- work mode. + + procedure Get_Work_Type + (This : in out HM11_Driver; + Work : out Work_Type; + Status : out UART_Status); + -- Default: Start_Immediately + + procedure Set_iBeacon_Switch + (This : in out HM11_Driver; + Switch : Boolean; + Status : out UART_Status); + -- This command is added since V517 version. + -- Default: False + + procedure Get_iBeacon_Switch + (This : in out HM11_Driver; + Switch : out Boolean; + Status : out UART_Status); + + -- Default iBeacon UUID is: 74278BDA-B644-4520-8F0C-720EAF059935 + + procedure Set_iBeacon_UUID + (This : in out HM11_Driver; + UUID : iBeacon_UUID; + Status : out UART_Status); + -- This command is added since V520 version. + -- Default: False + + procedure Get_iBeacon_UUID + (This : in out HM11_Driver; + UUID : out iBeacon_UUID; + Status : out UART_Status); + + procedure Set_iBeacon_Marjor_Version + (This : in out HM11_Driver; + Version : Version_Type; + Status : out UART_Status); + -- This command is added since V517 version. + -- Default: 0xFFE0 + + procedure Get_iBeacon_Marjor_Version + (This : in out HM11_Driver; + Version : out Version_Type; + Status : out UART_Status); + + procedure Set_iBeacon_Minor_Version + (This : in out HM11_Driver; + Version : Version_Type; + Status : out UART_Status); + -- This command is added since V517 version. + -- Default: 0xFFE1 + + procedure Get_iBeacon_Minor_Version + (This : in out HM11_Driver; + Version : out Version_Type; + Status : out UART_Status); + + procedure Set_iBeacon_Measured_Power + (This : in out HM11_Driver; + Power : Measured_Power; + Status : out UART_Status); + -- This command is added since V519 version. + -- Default: 0xC5 + + procedure Get_iBeacon_Measured_Power + (This : in out HM11_Driver; + Power : out Measured_Power; + Status : out UART_Status); + + procedure Set_Work_Mode + (This : in out HM11_Driver; + Mode : Work_Mode; + Status : out UART_Status); + -- Default: Transmission_Mode + -- Mode Transmission_Mode: + -- Before establishing a connection, you can use the AT command + -- configuration module through UART. + -- After established a connection, you can send data to remote side + -- from each other. + -- Mode PIO_Collection_Mode: + -- Before establishing a connection, you can use the AT command + -- configuration module through UART. + -- After established a connection, you can send data to remote side. + -- Remote side can do fellows: + -- Send AT command configuration module. + -- Collect PIO04 to the PIO11 pins input state of HM-10. + -- Collect PIO03 pins input state of HM-11. + -- Remote control PIO2, PIO3 pins output state of HM-10. + -- Remote control PIO2 pin output state of HM-11. + -- Send data to module UART port (not include any AT command and per + -- package must less than 20 bytes). + -- Mode Remote_Control_Mode: + -- Before establishing a connection, you can use the AT command + -- configuration module through UART. + -- After established a connection, you can send data to remote side. + -- Remote side can do fellows: + -- Send AT command configuration module. + -- Remote control PIO2 to PIO11 pins output state of HM-10. + -- Remote control PIO2, PIO3 pins output state of HM-11. + -- Send data to module UART port (not include any AT command and per + -- package must less than 20 bytes). + + procedure Get_Work_Mode + (This : in out HM11_Driver; + Mode : out Work_Mode; + Status : out UART_Status); + + procedure Set_Notify_Information + (This : in out HM11_Driver; + Notify : Boolean; + Status : out UART_Status); + -- Default: True + -- If this value is set to True, when link ESTABLISHED or LOSTED module + -- will send OK+CONN or OK+LOST string through UART. + + procedure Get_Notify_Information + (This : in out HM11_Driver; + Notify : out Boolean; + Status : out UART_Status); + + procedure Set_Notify_Mode + (This : in out HM11_Driver; + Mode : Notify_Mode; + Status : out UART_Status); + -- Added since V534 + -- Default: Without_Address + -- This command must work with Set_Notify_Information (True), if this + -- switch is open, when the module connect or disconnect, the prompt + -- string will include the remote address. + -- OK+CONN:001122334455 String "001122334455" is the MAC address string + + procedure Get_Notify_Mode + (This : in out HM11_Driver; + Mode : out Notify_Mode; + Status : out UART_Status); + + procedure Set_Module_Name + (This : in out HM11_Driver; + Name : String; + Status : out UART_Status) + with Pre => (Name'Length in 1 .. 12); + -- Default: HMSoft + + function Get_Module_Name + (This : in out HM11_Driver) + return String; + + procedure Set_Output_Power + (This : in out HM11_Driver; + Power : Output_Power; + Status : out UART_Status); + -- Added in V527 + -- Default: Max_Power + + procedure Get_Output_Power + (This : in out HM11_Driver; + Power : out Output_Power; + Status : out UART_Status); + + procedure Set_Parity_Bit + (This : in out HM11_Driver; + Parity : Parity_Bit; + Status : out UART_Status); + -- Default: None + + procedure Get_Parity_Bit + (This : in out HM11_Driver; + Parity : out Parity_Bit; + Status : out UART_Status); + + procedure Set_PIO_Output_Status + (This : in out HM11_Driver; + PIO : PIO_Number; + Output : PIO_Output; + Status : out UART_Status); + -- Required Work_Mode: Transmission_Mode or Remote_Control_Mode. + + procedure Get_PIO_Output_Status + (This : in out HM11_Driver; + PIO : PIO_Number; + Output : out PIO_Output; + Status : out UART_Status); + + procedure Get_PIOs_Output_Status + (This : in out HM11_Driver; + PIOs : out PIO_Numbers; + Status : out UART_Status); + + procedure Set_PIOs_Output_Status + (This : in out HM11_Driver; + PIOs : PIO_Numbers; + Status : out UART_Status); + -- This command added since V551 + -- This command is used to control multiple PIO pins output HIGH or LOW. + -- PIOs is Hex format, max value 3FF changed to binary format is + -- 001111111111, Total length is 12 bit, left side to right bit mapped + -- to module PIO0 to PIOB, + -- Note: HM-11 only have PIO0, PIO1, PIO2, PIO3 + -- 1: is output HIGH; + -- 0: is output LOW. + + procedure Set_PIN_Code + (This : in out HM11_Driver; + Pin : PIN_Type; + Status : out UART_Status); + -- Default: 000000 + + procedure Get_PIN_Code + (This : in out HM11_Driver; + Pin : out PIN_Type; + Status : out UART_Status); + + procedure Set_Module_Power + (This : in out HM11_Driver; + Power : Module_Power; + Status : out UART_Status); + -- Default: Dbm_0 + + procedure Get_Module_Power + (This : in out HM11_Driver; + Power : out Module_Power; + Status : out UART_Status); + + procedure Set_Module_Auto_Sleep + (This : in out HM11_Driver; + Sleep : Boolean; + Status : out UART_Status); + -- Only Peripheral role is used. + -- Default: False + + procedure Get_Module_Auto_Sleep + (This : in out HM11_Driver; + Sleep : out Boolean; + Status : out UART_Status); + -- Only Peripheral role is used. + + procedure Set_Reliable_Advertising_Mode + (This : in out HM11_Driver; + Mode : Advertising_Mode; + Status : out UART_Status); + -- This command is added since V530 + -- Default: Normal_Advertising + -- This command is used to make sure module always send advertising + -- package when module is in long time standby mode. + + procedure Get_Reliable_Advertising_Mode + (This : in out HM11_Driver; + Mode : out Advertising_Mode; + Status : out UART_Status); + + procedure Reset + (This : in out HM11_Driver; + Status : out UART_Status); + -- Restore all setup value to factory setup + + procedure Restart + (This : in out HM11_Driver; + Status : out UART_Status); + + procedure Get_Last_Connected_Device_Address + (This : in out HM11_Driver; + MAC : out MAC_Address; + Status : out UART_Status); + + procedure Set_Sensor_Work_Interval + (This : in out HM11_Driver; + Interval : Work_Interval; + Status : out UART_Status); + -- Default: 0, Unit: minute + -- Note: This command is only used for HMSensor + + procedure Get_Sensor_Work_Interval + (This : in out HM11_Driver; + Interval : out Work_Interval; + Status : out UART_Status); + + procedure Set_Stop_Bit + (This : in out HM11_Driver; + Value : Stop_Bit; + Status : out UART_Status); + -- Default: One_Stop_Bit + + procedure Get_Stop_Bit + (This : in out HM11_Driver; + Result : out Stop_Bit; + Status : out UART_Status); + + procedure Start_Working + (This : in out HM11_Driver; + Status : out UART_Status); + -- This command is only used when Work_Type = Respond_AT_Command. + + procedure Set_Save_Connected_MAC + (This : in out HM11_Driver; + Save : Boolean; + Status : out UART_Status); + -- Only Central role is used. + -- Default: False + -- Note: In central role, when power on, module will check if there is + -- a device address in internal flash, if have, module will try to connect + -- it. If not, module will start a scan device procedure. + + procedure Get_Save_Connected_MAC + (This : in out HM11_Driver; + Save : out Boolean; + Status : out UART_Status); + -- Only Central role is used. + + procedure Set_Discovery_Time + (This : in out HM11_Driver; + Time : Discovery_Time; + Status : out UART_Status); + -- Add in V543 + -- Only Central role is used. + -- Default: 3 seconds + + procedure Get_Discovery_Time + (This : in out HM11_Driver; + Time : out Discovery_Time; + Status : out UART_Status); + -- Only Central role is used. + + procedure Set_Sensor_Type + (This : in out HM11_Driver; + Value : Sensor_Type; + Status : out UART_Status); + -- This command is only use for HMSensor + -- Sensor type on module PIO11 (PIO3 on HM-11) + -- Default: None + + procedure Get_Sensor_Type + (This : in out HM11_Driver; + Result : out Sensor_Type; + Status : out UART_Status); + + procedure Set_Show_Device_Information_When_Discovery + (This : in out HM11_Driver; + Show : Show_Device_Information; + Status : out UART_Status); + -- Default: Dont_Show + -- If Show_Name is set, Scan will add the device name information + -- into scan result package. + -- If Show_RSSI is set, Scan will add device RSSI information into + -- scan result package. + -- If Show_RSSI_And_Name is set, Scan will add device name and RSSI + -- information into scan result package. + + procedure Get_Show_Device_Information_When_Discovery + (This : in out HM11_Driver; + Show : out Show_Device_Information; + Status : out UART_Status); + + procedure Get_Sensor_Temperature_And_Humidity + (This : in out HM11_Driver; + Temperature : out Temperature_Type; + Humidity : out Humidity_Type; + Status : out UART_Status); + -- Note: This command is only use for HMSensor version and has a sensor + -- This value is added into scan response data package. + -- Data format is 0x02, 0x16, 0x00, 0xB0, [reserved], [temperature], + -- [humidity], [battery]. + -- Android: + -- Included in OnLeScan function result array, you can see it directly. + -- iOS: + -- Included in LeScan function result NSDictionary struct, service id + -- is 0xB000. + + procedure Get_Module_Temperature + (This : in out HM11_Driver; + Temperature : out Internal_Temperature_Type; + Status : out UART_Status); + -- HMSoft version could get internal temperature. + -- Added in V523 version, Modified at V544. + -- Note: HMSensor version, if not setup Set_Sensor_Type value, will get + -- IC temperature. + + procedure Set_Temperature_Information_Byte_In_Advertising + (This : in out HM11_Driver; + Temperature : Advertising_Temperature_Type; + Status : out UART_Status); + -- Added in V544 + -- This command is used to set temperature information byte in + -- advertising data. + + procedure Set_Connect_Remote_Device_Timeout + (This : in out HM11_Driver; + Timeout : Connect_Timeout; + Status : out UART_Status); + -- Only Central role is used. + -- Default: 000000 ms. + -- This command is only used in central role. + -- In central role, when module power on, if module have a saved device + -- MAC address, then module will not into scan procedure, module will try + -- to connect this device. This command caused module into a scan + -- procedure if setup value is not 000000. + + procedure Get_Connect_Remote_Device_Timeout + (This : in out HM11_Driver; + Timeout : out Connect_Timeout; + Status : out UART_Status); + -- Only Central role is used. + + procedure Set_Bond_Mode + (This : in out HM11_Driver; + Mode : Bond_Mode; + Status : out UART_Status); + -- Default: Auth_And_Bonded + -- Important: If your module version is less than V515, please don't use + -- this command. + -- Android system Auth_Not_Need_PIN is same to Auth_With_PIN. + -- Note: Value 3 is added in V524. + + procedure Get_Bond_Mode + (This : in out HM11_Driver; + Mode : out Bond_Mode; + Status : out UART_Status); + + procedure Set_Service_UUID + (This : in out HM11_Driver; + Value : UUID; + Status : out UART_Status); + + procedure Get_Service_UUID + (This : in out HM11_Driver; + Result : out UUID; + Status : out UART_Status); + + procedure Set_UART_Sleep_Type + (This : in out HM11_Driver; + Value : UART_Sleep_Type; + Status : out UART_Status); + -- Note: This command is only use for HMSensor version. + + procedure Get_UART_Sleep_Type + (This : in out HM11_Driver; + Result : out UART_Sleep_Type; + Status : out UART_Status); + + procedure Set_Module_Advertisement_Data + (This : in out HM11_Driver; + Data : Advertisement_Data; + Status : out UART_Status); + -- Added since V607/V702 + + procedure Disconnect + (This : in out HM11_Driver; + Status : out UART_Status); + -- Should be connected. + + procedure Set_Characteristic + (This : in out HM11_Driver; + Value : Characteristic_Type; + Status : out UART_Status); + -- Default: FFE1 + + procedure Get_Characteristic + (This : in out HM11_Driver; + Result : out Characteristic_Type; + Status : out UART_Status); + + procedure Set_PIO_Collection_Rate + (This : in out HM11_Driver; + Value : PIO_Collection_Rate; + Status : out UART_Status); + -- This command is added since V515 version + -- Default: 10 seconds + -- Required Work Mode = PIO_Collection_Mode, + -- when PIO state is change, module will send OK+Col:[xx] + -- to UART or remote side. This command is set send interval. + + procedure Get_PIO_Collection_Rate + (This : in out HM11_Driver; + Result : out PIO_Collection_Rate; + Status : out UART_Status); + + procedure Set_Power_Pin_Output + (This : in out HM11_Driver; + Value : PIO_Numbers; + Status : out UART_Status); + -- This command added in V527. + -- Default: 000 + -- Set pins state (high/low) after power supplied + -- Hex format 0x3FF change to binary format is 001111111111, total length + -- is 12 bit, left to right side is mapped to module PIO0~PIOB port, PIO0 + -- and PIo1 is used by system, So must be 0. Only Pio2~PIOB pins is + -- available. + + procedure Get_Power_Pin_Output + (This : in out HM11_Driver; + Result : out PIO_Numbers; + Status : out UART_Status); + + procedure Set_Connect_Pin_Output + (This : in out HM11_Driver; + Value : PIO_Numbers; + Status : out UART_Status); + -- This command added in V527. + -- Default: 000 + -- Set pins state (high/low) after power supplied + -- Hex format 0x3FF change to binary format is 001111111111, total length + -- is 12 bit, Left to right side is mapped to module PIO0~PIOB port, + -- PIO0 and PIo1 is used by system. So, must be 0, Only Pio2~PIOB pins + -- is available. + + procedure Get_Connect_Pin_Output + (This : in out HM11_Driver; + Result : out PIO_Numbers; + Status : out UART_Status); + + -- Query PIO04~PIO11 input(output) state "AT+COL??" + +private + + type Variable_String (Length : Positive) is record + Value : String (1 .. Length); + Last : Natural := 0; + end record; + + type Discovered_Info_Type is record + Id : Character; + MAC : MAC_Address; + Name : Variable_String (Max_Name_Length); + RSSI : Variable_String (Max_RSII_Length); + end record; + + Null_Discovered_Info : constant Discovered_Info_Type := + (' ', [others => '0'], others => <>); + + type Scan_Stage_Kind is (Selection, MAC, Name, RSSI); + -- Used when scanning to know what we parsing now. + + ----------------- + -- HM11_Driver -- + ----------------- + + type HM11_Driver + (Port : HAL.UART.Any_UART_Port; + Receive : Receive_Handler; + Readed_Position : Last_Read_Position_Handler) + is limited record + Responce : UART_Data_8b (1 .. Max_Message_Length * 5); + + Discovered_Info : Discovered_Info_Type := Null_Discovered_Info; + end record; + + procedure Transmit + (This : in out HM11_Driver; + Command : String; + Status : out UART_Status); + + procedure Transmit + (This : in out HM11_Driver; + Command : String; + Data : UART_Data_8b; + Status : out UART_Status); + + procedure Check_Responce + (Received : System.Address; + Length : Natural; + Expect : String; + Status : in out UART_Status); + -- Checks that Received (1 .. Expect'Length) = Expect + + procedure Transmit_And_Check + (This : in out HM11_Driver; + Command : String; + Expect : String; + Received : System.Address; + Length : Natural; + Status : out UART_Status); + -- Sends command and checks responce + + procedure Transmit_And_Check + (This : in out HM11_Driver; + Command : String; + Expect : String; + Status : out UART_Status); + -- The same as above but don't return the actual responce + + procedure Read_Characteristic_UUID + (This : in out HM11_Driver; + Callback : Characteristic_UUID_Callback; + Timeout : Natural; + Status : out UART_Status); + + procedure Read_Characteristic_Notify_Responce + (This : in out HM11_Driver; + Status : in out UART_Status; + Responce : out Notify_Responce); + + function Start_With + (This : HM11_Driver; + Value : String; + From : Positive; + To : Positive) + return Boolean; + + function Find_Zero + (This : HM11_Driver; + From : Positive) + return Natural; + + function Find + (This : HM11_Driver; + Value : String; + From : Positive; + To : Positive) + return Natural; + + function Calc_Lenght + (This : HM11_Driver; + From : Positive; + Zero : Positive) + return Natural; + + procedure Move + (This : HM11_Driver; + Result : in out Positive; + Add : Positive; + Zero : Positive; + Length : out Natural); + + procedure Append + (This : HM11_Driver; + Str : in out Variable_String; + From : Positive; + To : Positive); + + procedure Copy + (This : HM11_Driver; + To : out UART_Data_8b; + From : Positive); + + function To_Connect_Result (C : Character) return Connect_Result; + + function To_String (Handle : Handle_Type) return String; + + From_Advertising_Interval : constant array + (Advertising_Interval) of Character := + [ms_100 => '0', + ms_211 => '1', + ms_252 => '2', + ms_318 => '3', + ms_417 => '4', + ms_546 => '5', + ms_760 => '6', + ms_852 => '7', + ms_1022 => '8', + ms_1285 => '9', + ms_2000 => 'A', + ms_3000 => 'B', + ms_4000 => 'C', + ms_5000 => 'D', + ms_6000 => 'E', + ms_7000 => 'F']; + +end HM11; diff --git a/examples/STM32F429_Discovery/hm11_f429disco.gpr b/examples/STM32F429_Discovery/hm11_f429disco.gpr new file mode 100644 index 000000000..6456d0be3 --- /dev/null +++ b/examples/STM32F429_Discovery/hm11_f429disco.gpr @@ -0,0 +1,16 @@ +with "../../boards/stm32f429_discovery/stm32f429_discovery_full.gpr"; + +project HM11_F429Disco extends "../shared/common/common.gpr" is + + for Runtime ("Ada") use STM32F429_Discovery_Full'Runtime("Ada"); + for Target use "arm-eabi"; + for Main use ("hm11_example.adb"); + for Languages use ("Ada"); + for Source_Dirs use ("../shared/hm11/src"); + for Object_Dir use "../shared/hm11/obj/stm32f429disco"; + for Create_Missing_Dirs use "True"; + + package Compiler renames STM32F429_Discovery_Full.Compiler; + +end HM11_F429Disco; + diff --git a/examples/shared/hm11/.gdbinit b/examples/shared/hm11/.gdbinit new file mode 100644 index 000000000..618b9ce81 --- /dev/null +++ b/examples/shared/hm11/.gdbinit @@ -0,0 +1,24 @@ +# This command file will cause a Cortex-M3 or -M4 board to automatically +# reset immediately after a GDB "load" command executes. Note that GPS +# issues that command as part of the Debug->Init menu invocation. Manual +# "load" command invocations will also trigger the action. +# +# The reset is achieved by writing to the "Application Interrupt and Reset +# Control" register located at address 0xE000ED0C. +# +# Both the processor and the peripherals can be reset by writing a value +# of 0x05FA0004. That value will write to the SYSRESETREQ bit. If you want +# to avoid resetting the peripherals, change the value to 0x05FA0001. That +# value will write to the VECTRESET bit. Do *not* use a value that sets both +# bits. +# +# In both cases, any on-board debug hardware is not reset. +# +# See the book "The Definitive Guide to the ARM Cortex-M3 and Cortex-M4 +# Processors" by Joseph Yiu, 3rd edition, pp 262-263 for further details. + +define hookpost-load +echo Resetting the processor and peripherals...\n +set *0xE000ED0C := 0x05FA0004 +echo Reset complete\n +end \ No newline at end of file diff --git a/examples/shared/hm11/README.md b/examples/shared/hm11/README.md new file mode 100644 index 000000000..3e77e8bd5 --- /dev/null +++ b/examples/shared/hm11/README.md @@ -0,0 +1,8 @@ +This is a simple test/example for HM-11/cc2541 with +STM32F429Disco. HM-11/cc2541 should be connected +to the following board's pins: + +| Pheri STM | +|-------|-----| +| RX(4) | PC12| +| TX(2) | PD2 | diff --git a/examples/shared/hm11/src/drivers.adb b/examples/shared/hm11/src/drivers.adb new file mode 100644 index 000000000..fbedc5b3b --- /dev/null +++ b/examples/shared/hm11/src/drivers.adb @@ -0,0 +1,440 @@ +------------------------------------------------------------------------------ +-- -- +-- Copyright (C) 2025, AdaCore -- +-- -- +-- Redistribution and use in source and binary forms, with or without -- +-- modification, are permitted provided that the following conditions are -- +-- met: -- +-- 1. Redistributions of source code must retain the above copyright -- +-- notice, this list of conditions and the following disclaimer. -- +-- 2. Redistributions in binary form must reproduce the above copyright -- +-- notice, this list of conditions and the following disclaimer in -- +-- the documentation and/or other materials provided with the -- +-- distribution. -- +-- 3. Neither the name of the copyright holder nor the names of its -- +-- contributors may be used to endorse or promote products derived -- +-- from this software without specific prior written permission. -- +-- -- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -- +-- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -- +-- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -- +-- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -- +-- HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -- +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -- +-- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -- +-- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -- +-- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -- +-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -- +-- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- +-- -- +------------------------------------------------------------------------------ + +with Ada.Real_Time; use Ada.Real_Time; + +package body Drivers is + + Received_Address : System.Address with Volatile, Atomic; + Is_Stream : Boolean := False with Volatile, Atomic; + Maximum : Positive := 1 with Volatile, Atomic; + + Position : Positive := 1 with Volatile, Atomic; + Until_Time : Time; + + -------------- + -- Watchdog -- + -------------- + + protected body Watchdog is + + ----------------- + -- Await_Event -- + ----------------- + + entry Await_Event (Status : out UART_Status) when Event_Occurred is + begin + Status := Read_Status; + Event_Occurred := False; + end Await_Event; + + ------------- + -- Release -- + ------------- + + procedure Release (Status : UART_Status) is + begin + if not Event_Occurred then + Read_Status := Status; + Event_Occurred := True; + Stop; + end if; + end Release; + + ----------- + -- Start -- + ----------- + + procedure Start + (Received : System.Address; + Length : Natural; + Timeout : Ada.Real_Time.Time_Span) + is + Memory_Block : UART_Data_8b (1 .. Length) with Import, + Address => Received; + + begin + if Started then + return; + end if; + + Started := True; + Until_Time := Clock + Timeout; + + if not Is_Stream then + Memory_Block := (others => 0); + Clear_All_Status (Controller, Rx_Stream); + + Start_Transfer_with_Interrupts + (This => Controller, + Stream => Rx_Stream, + Source => Data_Register_Address (Drivers.UART), + Destination => Received, + Data_Count => HAL.UInt16 (Length), + Enabled_Interrupts => + (Half_Transfer_Complete_Interrupt => False, others => True)); + + Resume_DMA_Reception (Drivers.UART); + + else + Received_Address := Received; + Position := 1; + Maximum := Positive (Length); + if Is_Stream then + Memory_Block (1) := 0; + + else + Memory_Block := (others => 0); + end if; + + Clear_Status (UART, Read_Data_Register_Not_Empty); + Enable_Interrupts (UART, Source => Received_Data_Not_Empty); + end if; + + Clear_Status (UART, Parity_Error_Indicated); + Clear_Status (UART, Framing_Error_Indicated); + Clear_Status (UART, USART_Noise_Error_Indicated); + Clear_Status (UART, Overrun_Error_Indicated); + Clear_Status (UART, Line_Break_Detection_Indicated); + Clear_Status (UART, Clear_To_Send_Indicated); + Clear_Status (UART, Idle_Line_Detection_Indicated); + + Enable_Interrupts (UART, Source => Parity_Error); + Enable_Interrupts (UART, Source => Line_Break_Detection); + Enable_Interrupts (UART, Source => Clear_To_Send); + Enable_Interrupts (UART, Source => Error); + Enable_Interrupts (UART, Source => Idle_Line_Detection); + end Start; + + ---------- + -- Stop -- + ---------- + + procedure Stop + is + Dummy : DMA_Error_Code; + begin + if not Started then + return; + end if; + + Started := False; + + if not Is_Stream then + Clear_All_Status (Controller, Rx_Stream); + Pause_DMA_Reception (Drivers.UART); + + else + Disable_Interrupts (UART, Source => Received_Data_Not_Empty); + Clear_Status (UART, Read_Data_Register_Not_Empty); + end if; + + Disable_Interrupts (UART, Source => Parity_Error); + Disable_Interrupts (UART, Source => Line_Break_Detection); + Disable_Interrupts (UART, Source => Clear_To_Send); + Disable_Interrupts (UART, Source => Error); + Disable_Interrupts (UART, Source => Idle_Line_Detection); + + Clear_Status (UART, Parity_Error_Indicated); + Clear_Status (UART, Framing_Error_Indicated); + Clear_Status (UART, USART_Noise_Error_Indicated); + Clear_Status (UART, Overrun_Error_Indicated); + Clear_Status (UART, Line_Break_Detection_Indicated); + Clear_Status (UART, Clear_To_Send_Indicated); + Clear_Status (UART, Idle_Line_Detection_Indicated); + end Stop; + + ------------ + -- Readed -- + ------------ + + procedure Readed + (Closed : out Boolean; + Zero : out Positive) is + begin + Closed := not Started; + Zero := Position; + end Readed; + + end Watchdog; + + --------------------- + -- IRQ_DMA_Handler -- + --------------------- + + protected body IRQ_DMA_Handler is + + ---------------- + -- On_DMA_IRQ -- + ---------------- + + procedure On_DMA_IRQ is + + -- Check -- + procedure Check + (Status : DMA_Status_Flag; + Interrupt : DMA_Interrupt; + Result : UART_Status) is + begin + if STM32.DMA.Status (Controller, Rx_Stream, Status) then + if Interrupt_Enabled (Controller, Rx_Stream, Interrupt) then + Disable_Interrupt (Controller, Rx_Stream, Interrupt); + Clear_Status (Controller, Rx_Stream, Status); + Watchdog.Release (Result); + end if; + end if; + + exception + when others => + null; + end Check; + + begin + Check (Transfer_Error_Indicated, Transfer_Error_Interrupt, Err_Error); + Check (FIFO_Error_Indicated, FIFO_Error_Interrupt, Err_Error); + Check + (Direct_Mode_Error_Indicated, + Direct_Mode_Error_Interrupt, + Err_Error); + Check (Transfer_Complete_Indicated, Transfer_Complete_Interrupt, Ok); + + exception + when others => + null; + end On_DMA_IRQ; + + end IRQ_DMA_Handler; + + ---------------------- + -- IRQ_UART_Handler -- + ---------------------- + + protected body IRQ_UART_Handler is + + ----------------- + -- On_UART_IRQ -- + ----------------- + + procedure On_UART_IRQ + is + -- use type HAL.UInt8; + + -- Check -- + procedure Check + (Flag : USART_Status_Flag; + Interrupt : USART_Interrupt) is + begin + if Status (UART, Flag) and then + Interrupt_Enabled (UART, Interrupt) + then + Disable_Interrupts (UART, Source => Interrupt); + Clear_Status (UART, Flag); + Watchdog.Release (Err_Error); + end if; + + exception + when others => + null; + end Check; + + Memory_Block : UART_Data_8b (1 .. Maximum) with Import, + Address => Received_Address; + + begin + Check (Parity_Error_Indicated, Parity_Error); + Check (Framing_Error_Indicated, Error); + Check (USART_Noise_Error_Indicated, Error); + Check (Overrun_Error_Indicated, Error); + Check (Line_Break_Detection_Indicated, Line_Break_Detection); + Check (Clear_To_Send_Indicated, Clear_To_Send); + + if Status (UART, Idle_Line_Detection_Indicated) and then + Interrupt_Enabled (UART, Idle_Line_Detection) + then + if Clock > Until_Time then + Disable_Interrupts (UART, Source => Idle_Line_Detection); + Clear_Status (UART, Idle_Line_Detection_Indicated); + Watchdog.Release (Ok); + else + Clear_Status (UART, Idle_Line_Detection_Indicated); + end if; + end if; + + if Status (UART, Read_Data_Register_Not_Empty) and then + Interrupt_Enabled (UART, Received_Data_Not_Empty) + then + Memory_Block (Position) := HAL.UInt8 (Current_Input (UART)); + Clear_Status (UART, Read_Data_Register_Not_Empty); + + if Is_Stream then + if Position < Maximum then + Position := Position + 1; + else + Position := 1; + end if; + Memory_Block (Position) := 0; + + else + if Position = Maximum then + Watchdog.Release (Ok); + else + Position := Position + 1; + end if; + end if; + end if; + exception + when others => + null; + end On_UART_IRQ; + + end IRQ_UART_Handler; + + ------------------------- + -- DMA_Receive_Handler -- + ------------------------- + + procedure DMA_Receive_Handler + (Port : HAL.UART.Any_UART_Port; + Received : System.Address; + Length : Natural; + Status : out UART_Status; + Timeout : Natural := 1000; + As_Stream : Boolean := False) + is + pragma Unreferenced (Port); + + Memory_Block : UART_Data_8b (1 .. Length) with Import, + Address => Received; + + begin + if Is_Stream then + -- Called second time after `stream` started, close the `stream` + Watchdog.Stop; + Status := Ok; + return; + end if; + + Is_Stream := As_Stream; + + Watchdog.Start (Received, Length, Ada.Real_Time.Milliseconds (Timeout)); + + if Is_Stream then + Status := Ok; + + else + -- Do not wait if we want the data stream + Watchdog.Await_Event (Status); + end if; + + exception + when others => + Watchdog.Stop; + Status := Err_Error; + end DMA_Receive_Handler; + + ----------------------- + -- Last_Read_Handler -- + ----------------------- + + procedure Last_Read_Handler + (Closed : out Boolean; + Zero : out Positive) is + begin + Watchdog.Readed (Closed, Zero); + end Last_Read_Handler; + + --------------- + -- Init_UART -- + --------------- + + procedure Init_UART + is + use STM32.Device; + + begin + Enable_Clock (UART); + Enable_Clock (TX & RX); + + Configure_IO + (TX & RX, + (Mode => Mode_AF, + Resistors => Pull_Up, + AF => GPIO_AF_UART5_8, + AF_Output_Type => Push_Pull, + AF_Speed => Speed_50MHz)); + + Disable (UART); + + Set_Baud_Rate (UART, 9600); + Set_Mode (UART, Tx_Rx_Mode); + Set_Stop_Bits (UART, Stopbits_1); + Set_Word_Length (UART, Word_Length_8); + Set_Parity (UART, No_Parity); + Set_Flow_Control (UART, No_Flow_Control); + + Enable_Interrupts (UART, Error); + Enable_Interrupts (UART, Parity_Error); + Enable_Interrupts (UART, Received_Data_Not_Empty); + + Enable (UART); + end Init_UART; + + -------------------- + -- Initialize_DMA -- + -------------------- + + procedure Initialize_DMA is + use STM32.Device; + + Configuration : DMA_Stream_Configuration; + begin + Enable_Clock (Controller); + + Reset (Controller, Rx_Stream); + + Configuration.Channel := Rx_Channel; + Configuration.Direction := Peripheral_To_Memory; + Configuration.Increment_Peripheral_Address := False; + Configuration.Increment_Memory_Address := True; + Configuration.Peripheral_Data_Format := Bytes; + Configuration.Memory_Data_Format := Bytes; + Configuration.Operation_Mode := Normal_Mode; + Configuration.Priority := Priority_Very_High; + Configuration.FIFO_Enabled := False; + Configuration.Memory_Burst_Size := Memory_Burst_Single; + Configuration.Peripheral_Burst_Size := Peripheral_Burst_Single; + + Configure (Controller, Rx_Stream, Configuration); + Enable_DMA_Receive_Requests (Drivers.UART); + Pause_DMA_Reception (Drivers.UART); + end Initialize_DMA; + +end Drivers; diff --git a/examples/shared/hm11/src/drivers.ads b/examples/shared/hm11/src/drivers.ads new file mode 100644 index 000000000..5f0272bd0 --- /dev/null +++ b/examples/shared/hm11/src/drivers.ads @@ -0,0 +1,134 @@ +------------------------------------------------------------------------------ +-- -- +-- Copyright (C) 2025, AdaCore -- +-- -- +-- Redistribution and use in source and binary forms, with or without -- +-- modification, are permitted provided that the following conditions are -- +-- met: -- +-- 1. Redistributions of source code must retain the above copyright -- +-- notice, this list of conditions and the following disclaimer. -- +-- 2. Redistributions in binary form must reproduce the above copyright -- +-- notice, this list of conditions and the following disclaimer in -- +-- the documentation and/or other materials provided with the -- +-- distribution. -- +-- 3. Neither the name of the copyright holder nor the names of its -- +-- contributors may be used to endorse or promote products derived -- +-- from this software without specific prior written permission. -- +-- -- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -- +-- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -- +-- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -- +-- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -- +-- HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -- +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -- +-- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -- +-- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -- +-- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -- +-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -- +-- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- +-- -- +------------------------------------------------------------------------------ + +with Ada.Interrupts; +with Ada.Interrupts.Names; +with Ada.Real_Time; +with System; + +with STM32.DMA; use STM32.DMA; +with STM32.GPIO; use STM32.GPIO; +with STM32.USARTs; use STM32.USARTs; +with STM32.Device; +with HAL.UART; use HAL.UART; +with HM11; use HM11; + +package Drivers is + + TX : GPIO_Point renames STM32.Device.PC12; -- UART5_TX + -- Connect to HM-11 RX (4) + RX : GPIO_Point renames STM32.Device.PD2; -- UART5_RX + -- Connect to HM-11 TX (2) + + -- DMA -- + Controller : DMA_Controller renames STM32.Device.DMA_1; + Rx_Channel : constant DMA_Channel_Selector := Channel_4; + Rx_Stream : constant DMA_Stream_Selector := Stream_0; + DMA_Tx_IRQ : constant Ada.Interrupts.Interrupt_ID := + Ada.Interrupts.Names.DMA1_Stream0_Interrupt; + + -- UART -- + UART : STM32.USARTs.USART renames STM32.Device.UART_5; + UART_IRQ : constant Ada.Interrupts.Interrupt_ID := + Ada.Interrupts.Names.UART5_Interrupt; + + procedure DMA_Receive_Handler + (Port : HAL.UART.Any_UART_Port; + Received : System.Address; + Length : Natural; + Status : out UART_Status; + Timeout : Natural := 1000; + As_Stream : Boolean := False); + -- Reads UART5 RX with DMA + + procedure Last_Read_Handler + (Closed : out Boolean; + Zero : out Positive); + + -- HM-11 Driver + Driver : HM11_Driver + (UART'Access, DMA_Receive_Handler'Access, Last_Read_Handler'Access); + + procedure Init_UART; + -- Initialize GPIO/UART for HM-11/cc2541 + + procedure Initialize_DMA; + -- Initialize DMA for UART5 RX + +private + + -- Watchdog -- + protected Watchdog is + pragma Interrupt_Priority; + + procedure Start + (Received : System.Address; + Length : Natural; + Timeout : Ada.Real_Time.Time_Span); + + procedure Stop; + + entry Await_Event (Status : out UART_Status); + + procedure Release (Status : UART_Status); + + procedure Readed + (Closed : out Boolean; + Zero : out Positive); + + private + Started : Boolean := False; + Event_Occurred : Boolean := False; + + Read_Status : UART_Status := Ok; + end Watchdog; + + -- IRQ_UART_Handler -- + protected IRQ_UART_Handler is + pragma Interrupt_Priority; + + private + procedure On_UART_IRQ; + pragma Attach_Handler (On_UART_IRQ, UART_IRQ); + + end IRQ_UART_Handler; + + -- IRQ_DMA_Handler -- + protected IRQ_DMA_Handler is + pragma Interrupt_Priority; + + private + + procedure On_DMA_IRQ; + pragma Attach_Handler (On_DMA_IRQ, DMA_Tx_IRQ); + end IRQ_DMA_Handler; + +end Drivers; diff --git a/examples/shared/hm11/src/hm11_example.adb b/examples/shared/hm11/src/hm11_example.adb new file mode 100644 index 000000000..a7657c8c7 --- /dev/null +++ b/examples/shared/hm11/src/hm11_example.adb @@ -0,0 +1,228 @@ +------------------------------------------------------------------------------ +-- -- +-- Copyright (C) 2025, AdaCore -- +-- -- +-- Redistribution and use in source and binary forms, with or without -- +-- modification, are permitted provided that the following conditions are -- +-- met: -- +-- 1. Redistributions of source code must retain the above copyright -- +-- notice, this list of conditions and the following disclaimer. -- +-- 2. Redistributions in binary form must reproduce the above copyright -- +-- notice, this list of conditions and the following disclaimer in -- +-- the documentation and/or other materials provided with the -- +-- distribution. -- +-- 3. Neither the name of the copyright holder nor the names of its -- +-- contributors may be used to endorse or promote products derived -- +-- from this software without specific prior written permission. -- +-- -- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -- +-- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -- +-- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -- +-- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -- +-- HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -- +-- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -- +-- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -- +-- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -- +-- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -- +-- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -- +-- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -- +-- -- +------------------------------------------------------------------------------ + +-- Simple test/example for STM32F429disco with HM-11/cc2541 attached +-- It implements a simple "echo" server that can be connected from a phone + +with Ada.Exceptions; +with Last_Chance_Handler; pragma Unreferenced (Last_Chance_Handler); +-- The "last chance handler" is the user-defined routine that is called when +-- an exception is propagated. We need it in the executable, therefore it +-- must be somewhere in the closure of the context clauses. + +with Ada.Real_Time; use Ada.Real_Time; + +with HAL.UART; use HAL.UART; +with STM32.USARTs; +with HM11; use HM11; +with Drivers; use Drivers; + +-- Service +with STM32.Board; use STM32.Board; +with HAL.Bitmap; use HAL.Bitmap; +with BMP_Fonts; +with LCD_Std_Out; + +procedure HM11_Example is + + Status : UART_Status; + + Period : constant Time_Span := Milliseconds (200); + Next_Release : Time := Clock; + BG : constant Bitmap_Color := (Alpha => 255, others => 64); + + ----------- + -- Print -- + ----------- + + procedure Print (Msg : String) is + begin + LCD_Std_Out.Put_Line (Msg); + Display.Update_Layer (1, Copy_Back => True); + end Print; + + -------------- + -- On_Error -- + -------------- + + procedure On_Error (Msg : String) is + begin + Print (Msg); + + loop + STM32.Board.Toggle (Red_LED); + Next_Release := Next_Release + Period; + delay until Next_Release; + end loop; + end On_Error; + + ------------------ + -- Check_Status -- + ------------------ + + procedure Check_Status (Msg : String) is + begin + if Status = Ok then + Print (Msg & " OK"); + else + On_Error (Msg & " failed"); + end if; + end Check_Status; + +begin + delay 2.0; + + Drivers.Init_UART; + delay 1.0; + Drivers.Initialize_DMA; + delay 1.0; + + -- Init testing infrastructure + STM32.Board.Initialize_LEDs; + Display.Initialize; + Display.Initialize_Layer (1, ARGB_8888); + LCD_Std_Out.Set_Font (BMP_Fonts.Font12x12); + LCD_Std_Out.Current_Background_Color := BG; + Display.Hidden_Buffer (1).Set_Source (BG); + Display.Hidden_Buffer (1).Fill; + LCD_Std_Out.Clear_Screen; + + delay 1.0; + Print ("Initialized"); + + -- Tests -- + Test (Drivers.Driver, Status); + Check_Status ("Test"); + + delay 0.5; + declare + Result : MAC_Address; + S : String (Result'Range) with Import, Address => Result'Address; + begin + Get_MAC_Address (Drivers.Driver, Result, Status); + if Status /= Ok then + On_Error ("Get_MAC_Address failed"); + end if; + Print ("MAC_Address:" & S); + end; + + delay 0.5; + Set_Advertising_Type + (Drivers.Driver, Advertising_ScanResponse_Connectable, Status); + Check_Status ("Set_Advertising_Type"); + + delay 0.5; + Set_Bond_Mode (Drivers.Driver, Auth_With_PIN, Status); + Check_Status ("Set_Bond_Mode"); + + delay 0.5; + Set_Notify_Information (Drivers.Driver, True, Status); + Check_Status ("Set_Notify_Information"); + + delay 0.5; + Set_Module_Name (Drivers.Driver, "HMTest", Status); + Check_Status ("Set_Module_Name"); + + delay 0.5; + Set_PIN_Code (Drivers.Driver, "000000", Status); + Check_Status ("Set_PIN_Code"); + + delay 0.5; + Set_Work_Type (Drivers.Driver, Start_Immediately, Status); + Check_Status ("Set_Work_Type"); + + delay 0.5; + Set_Role (Drivers.Driver, Peripheral, Status); + Check_Status ("Set_Role"); + + delay 1.0; + Restart (Drivers.Driver, Status); + Check_Status ("Restart"); + + delay 2.0; + Print ("Waiting connection"); + + -- On this stage you can connect from your phone with + -- Serial bluetooth terminal (for example) + declare + Data : String (When_Connected_Message'Range); + begin + loop + DMA_Receive_Handler + (UART'Access, Data'Address, Data'Length, Status, 120 * 1000); + + if Data = When_Connected_Message then + Print ("Connected"); + exit; + end if; + + Check_Status ("Connect loop"); + end loop; + end; + + -- Waiting for data or disconnect + -- On this stage you can send (1 .. 5) message from phone terminal + -- and module will return this message back. + -- For example if you send `12345` you will see `12345` returned. + declare + Data : String (When_Disconnected_Message'Range); + Send : UART_Data_8b (Data'Range) with Import, Address => Data'Address; + begin + loop + DMA_Receive_Handler + (UART'Access, Data'Address, When_Disconnected_Message'Length, + Status, 120 * 1000); + + if Data = When_Disconnected_Message then + Print ("Disconnected"); + exit; + + else + STM32.USARTs.Transmit (UART, Send, Status); + end if; + + Check_Status ("Transmit loop"); + end loop; + end; + + -- All is OK + Print ("Done"); + + loop + STM32.Board.Toggle (Green_LED); + Next_Release := Next_Release + Period; + delay until Next_Release; + end loop; + +exception + when E : others => + On_Error (Ada.Exceptions.Exception_Information (E)); +end HM11_Example;