From 555d662df4d743a80b85cd65f1b9d027de621889 Mon Sep 17 00:00:00 2001 From: Gabryel Reyes Date: Fri, 26 Apr 2024 12:29:22 +0200 Subject: [PATCH 1/5] Events callbacks for internal events such as Sync and De-sync Improvement Possibilities #9 --- library.json | 2 +- src/SerialMuxProtCommon.hpp | 8 ++ src/SerialMuxProtServer.hpp | 93 +++++++++++++++++-- .../test_SerialMuxProt/test_SerialMuxProt.cpp | 37 ++++++++ 4 files changed, 133 insertions(+), 7 deletions(-) diff --git a/library.json b/library.json index 1646700..1cdffc5 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "SerialMuxProt", - "version": "2.1.0", + "version": "2.2.0", "description": "Communication Protocol based on Streams. Uses Multiplexing to differentiate data channels.", "keywords": "SerialMuxProt", "repository": { diff --git a/src/SerialMuxProtCommon.hpp b/src/SerialMuxProtCommon.hpp index 6baf3f4..a16d237 100644 --- a/src/SerialMuxProtCommon.hpp +++ b/src/SerialMuxProtCommon.hpp @@ -96,6 +96,14 @@ SOFTWARE. */ typedef void (*ChannelCallback)(const uint8_t* payload, const uint8_t payloadSize, void* userData); +/** + * Event Notification Prototype Callback. + * Provides a notification to the application on the event it is registered to. + * + * @param[in] userData User data provided by the application. + */ +typedef void (*EventCallback)(void* userData); + /** * Channel Definition. */ diff --git a/src/SerialMuxProtServer.hpp b/src/SerialMuxProtServer.hpp index 8d5d41e..ec4079c 100644 --- a/src/SerialMuxProtServer.hpp +++ b/src/SerialMuxProtServer.hpp @@ -91,7 +91,9 @@ class SerialMuxProtServer m_numberOfTxChannels(0U), m_numberOfRxChannels(0U), m_numberOfPendingChannels(0U), - m_userData(userData) + m_userData(userData), + m_onSynced(nullptr), + m_onDeSynced(nullptr) { } @@ -261,6 +263,48 @@ class SerialMuxProtServer return m_numberOfRxChannels; } + /** + * Register a callback for the On-Synced event. + * The callback will be called when the client is synced to the server. + * + * @param[in] callback Callback to be registered. + * + * @returns true if the callback was registered, false otherwise. + */ + bool registerOnSyncedCallback(EventCallback callback) + { + bool registered = false; + + if (nullptr != callback) + { + m_onSynced = callback; + registered = true; + } + + return registered; + } + + /** + * Register a callback for the On-DeSynced event. + * The callback will be called when the client is desynced from the server. + * + * @param[in] callback Callback to be registered. + * + * @returns true if the callback was registered, false otherwise. + */ + bool registerOnDeSyncedCallback(EventCallback callback) + { + bool registered = false; + + if (nullptr != callback) + { + m_onDeSynced = callback; + registered = true; + } + + return registered; + } + private: /** * Control Channel Command: SYNC @@ -286,14 +330,14 @@ class SerialMuxProtServer if (rcvTimestamp == m_lastSyncCommand) { m_lastSyncResponse = m_lastSyncCommand; - m_isSynced = true; + setSyncedState(true); /* Manage Pending Subscriptions. */ managePendingSubscriptions(); } else { - m_isSynced = false; + setSyncedState(false); } } @@ -316,7 +360,7 @@ class SerialMuxProtServer if (false == send(CONTROL_CHANNEL_NUMBER, &output, sizeof(ControlChannelPayload))) { /* Fall out of sync if failed to send. */ - m_isSynced = false; + setSyncedState(false); } } @@ -514,7 +558,7 @@ class SerialMuxProtServer /* Timeout. */ if (m_lastSyncCommand != m_lastSyncResponse) { - m_isSynced = false; + setSyncedState(false); } /* Send SYNC Command. */ @@ -550,7 +594,7 @@ class SerialMuxProtServer if (false == send(CONTROL_CHANNEL_NUMBER, &output, sizeof(ControlChannelPayload))) { /* Out-of-Sync on failed send. */ - m_isSynced = false; + setSyncedState(false); break; } } @@ -649,6 +693,33 @@ class SerialMuxProtServer return (sum % UINT8_MAX); } + /** + * Change the current sync state. + * + * @param[in] isSynced New sync state. + */ + void setSyncedState(bool isSynced) + { + /* Set new synced state. */ + m_isSynced = isSynced; + + /* Notify the user is callback is registered. */ + if (true == m_isSynced) + { + if (nullptr != m_onSynced) + { + m_onSynced(m_userData); + } + } + else + { + if (nullptr != m_onDeSynced) + { + m_onDeSynced(m_userData); + } + } + } + private: /** * Array of tx Data Channels. @@ -724,6 +795,16 @@ class SerialMuxProtServer */ void* m_userData; + /** + * On-synced callback. + */ + EventCallback m_onSynced; + + /** + * On-desynced callback. + */ + EventCallback m_onDeSynced; + private: /* Not allowed. */ SerialMuxProtServer(); /**< Default Constructor */ diff --git a/test/test_SerialMuxProt/test_SerialMuxProt.cpp b/test/test_SerialMuxProt/test_SerialMuxProt.cpp index 62b26ba..2234a67 100644 --- a/test/test_SerialMuxProt/test_SerialMuxProt.cpp +++ b/test/test_SerialMuxProt/test_SerialMuxProt.cpp @@ -63,6 +63,7 @@ static void testCmdScrb(); static void testCmdScrbRsp(); static void testChannelCreation(); static void testDataSend(); +static void testEventCallbacks(); /****************************************************************************** * Local Variables @@ -128,6 +129,7 @@ static void loop() RUN_TEST(testCmdScrbRsp); RUN_TEST(testChannelCreation); RUN_TEST(testDataSend); + RUN_TEST(testEventCallbacks); UNITY_END(); @@ -553,3 +555,38 @@ static void testDataSend() testSerialMuxProtServer.sendData("TEST", testPayload, sizeof(testPayload)); TEST_ASSERT_EQUAL_UINT8_ARRAY(expectedOutputBufferVector[0U], gTestStream.m_outputBuffer, sizeof(testPayload)); } + +/** + * Test Event Callbacks on SerialMuxProt Server. + */ +static void testEventCallbacks() +{ + SerialMuxProtServer<1U> testSerialMuxProtServer(gTestStream); + uint8_t expectedOutputBufferVector[1U][MAX_FRAME_LEN] = {{0x01, 0x04, 0x1A, 0x12, 0x34, 0x56, 0x78}}; + uint8_t inputQueueVector[1U][MAX_FRAME_LEN] = {{0x00, 0x10, 0x11, 0x01, 0x00, 0x00, 0x00, 0x00}}; + + /* Register callbacks. */ + callbackCalled = false; + + TEST_ASSERT_TRUE(testSerialMuxProtServer.registerOnSyncedCallback([](void* userData) { callbackCalled = true; })); + TEST_ASSERT_TRUE(testSerialMuxProtServer.registerOnDeSyncedCallback([](void* userData) { callbackCalled = true; })); + + /* Flush Stream */ + gTestStream.flushInputBuffer(); + gTestStream.flushOutputBuffer(); + + /* Sync */ + gTestStream.pushToQueue(inputQueueVector[0U], controlChannelFrameLength); + testSerialMuxProtServer.process(1U); + testSerialMuxProtServer.process(2U); + TEST_ASSERT_TRUE(testSerialMuxProtServer.isSynced()); + TEST_ASSERT_TRUE(callbackCalled); + + /* De-sync.*/ + callbackCalled = false; + testSerialMuxProtServer.process(2000U); + testSerialMuxProtServer.process(7000U); + testSerialMuxProtServer.process(12000U); + TEST_ASSERT_FALSE(testSerialMuxProtServer.isSynced()); + TEST_ASSERT_TRUE(callbackCalled); +} \ No newline at end of file From 800993e40284b6f5939a75b17174bbfc75c7158d Mon Sep 17 00:00:00 2001 From: Gabryel Reyes Date: Fri, 26 Apr 2024 12:37:11 +0200 Subject: [PATCH 2/5] Updated publish workflow --- .github/workflows/release.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b5bae9f..ecba258 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -55,6 +55,4 @@ jobs: env: PLATFORMIO_AUTH_TOKEN: ${{ secrets.PLATFORMIO_AUTH_TOKEN }} run: | - TAG=$(git describe --exact-match --tags) - curl -LO $GITHUB_SERVER_URL/$GITHUB_REPOSITORY/releases/download/$TAG/SerialMuxProt-$TAG.zip - platformio package publish --type library SerialMuxProt-$TAG.zip --non-interactive + platformio package publish --non-interactive From 0bc383156bd5987edefe8a8b04af31d4315cbe3f Mon Sep 17 00:00:00 2001 From: Gabryel Reyes Date: Fri, 26 Apr 2024 12:48:52 +0200 Subject: [PATCH 3/5] Updated copyright year and documentation --- LICENSE | 2 +- README.md | 27 +++++++++++- doc/doxygen/Doxyfile | 2 +- examples/SerialMuxChannels.h | 2 +- examples/ServerA/main.cpp | 2 +- examples/ServerB/main.cpp | 2 +- python/SerialMuxProt.py | 2 +- python/__main__.py | 2 +- python/serial_client.py | 2 +- python/socket_client.py | 2 +- src/SerialMuxProtCommon.hpp | 44 +++++++++---------- src/SerialMuxProtServer.hpp | 2 +- test/common/Print.h | 2 +- test/common/Stream.h | 2 +- test/common/TestStream.h | 2 +- .../test_SerialMuxProt/test_SerialMuxProt.cpp | 11 +++-- 16 files changed, 65 insertions(+), 43 deletions(-) diff --git a/LICENSE b/LICENSE index 6ed45de..6c479e0 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2023 Gabryel Reyes +Copyright (c) 2023 - 2024 Gabryel Reyes Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index ae72f08..2555b97 100644 --- a/README.md +++ b/README.md @@ -202,13 +202,18 @@ struct Channel /** * Channel Notification Prototype Callback. * Provides the received data in the respective channel to the application. + * + * @param[in] payload Received data. + * @param[in] payloadSize Size of the received data. + * @param[in] userData User data provided by the application. */ -typedef void (*ChannelCallback)(const uint8_t* payload, const uint8_t payloadSize); +typedef void (*ChannelCallback)(const uint8_t* payload, const uint8_t payloadSize, void* userData); ``` - Callback passes only a pointer to the received Buffer. Data must be copied by application. - Memory is freed by the protocol after the callback is done. - DLC is passed as payloadSize to the application. +- The `userData` pointer specified in the constructor is passed to the application. ### State Machine @@ -223,6 +228,26 @@ typedef void (*ChannelCallback)(const uint8_t* payload, const uint8_t payloadSiz - Client is connected and responds to SYNC Commands. - SYNC Period set to 5 seconds. +### Event Callbacks + +It is possible to register `EventCallback` callbacks for the Synced and DeSynced events. These will be called once an event is triggered to notify the user. + +```cpp +/** + * Event Notification Prototype Callback. + * Provides a notification to the application on the event it is registered to. + * + * @param[in] userData User data provided by the application. + */ +typedef void (*EventCallback)(void* userData); + +/* Called on Sync. */ +bool registerOnSyncedCallback(EventCallback callback); + +/* Called on DeSync. */ +bool registerOnDeSyncedCallback(EventCallback callback); +``` + --- ## SerialMuxChannels diff --git a/doc/doxygen/Doxyfile b/doc/doxygen/Doxyfile index 31a103c..ccfbd79 100644 --- a/doc/doxygen/Doxyfile +++ b/doc/doxygen/Doxyfile @@ -48,7 +48,7 @@ PROJECT_NAME = SerialMuxProt # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 1.0.1 +PROJECT_NUMBER = 2.2.0 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/examples/SerialMuxChannels.h b/examples/SerialMuxChannels.h index e11a4dc..a811e75 100644 --- a/examples/SerialMuxChannels.h +++ b/examples/SerialMuxChannels.h @@ -1,6 +1,6 @@ /* MIT License * - * Copyright (c) 2023 Gabryel Reyes + * Copyright (c) 2023 - 2024 Gabryel Reyes * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/examples/ServerA/main.cpp b/examples/ServerA/main.cpp index 86ba9e6..b3b75ee 100644 --- a/examples/ServerA/main.cpp +++ b/examples/ServerA/main.cpp @@ -1,6 +1,6 @@ /* MIT License * - * Copyright (c) 2023 Gabryel Reyes + * Copyright (c) 2023 - 2024 Gabryel Reyes * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/examples/ServerB/main.cpp b/examples/ServerB/main.cpp index 0cd7381..583e994 100644 --- a/examples/ServerB/main.cpp +++ b/examples/ServerB/main.cpp @@ -1,6 +1,6 @@ /* MIT License * - * Copyright (c) 2023 Gabryel Reyes + * Copyright (c) 2023 - 2024 Gabryel Reyes * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/python/SerialMuxProt.py b/python/SerialMuxProt.py index 8eb8481..60ae406 100644 --- a/python/SerialMuxProt.py +++ b/python/SerialMuxProt.py @@ -2,7 +2,7 @@ # MIT License # -# Copyright (c) 2023 Gabryel Reyes +# Copyright (c) 2023 - 2024 Gabryel Reyes # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/python/__main__.py b/python/__main__.py index 0677e3c..8003bde 100644 --- a/python/__main__.py +++ b/python/__main__.py @@ -2,7 +2,7 @@ # MIT License # -# Copyright (c) 2023 Gabryel Reyes +# Copyright (c) 2023 - 2024 Gabryel Reyes # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/python/serial_client.py b/python/serial_client.py index b2f75a0..0224716 100644 --- a/python/serial_client.py +++ b/python/serial_client.py @@ -2,7 +2,7 @@ # MIT License # -# Copyright (c) 2023 Andreas Merkle +# Copyright (c) 2023 - 2024 Gabryel Reyes # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/python/socket_client.py b/python/socket_client.py index 64622cb..a5f1e90 100644 --- a/python/socket_client.py +++ b/python/socket_client.py @@ -2,7 +2,7 @@ # MIT License # -# Copyright (c) 2023 Andreas Merkle +# Copyright (c) 2023 - 2024 Gabryel Reyes # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal diff --git a/src/SerialMuxProtCommon.hpp b/src/SerialMuxProtCommon.hpp index a16d237..ca97036 100644 --- a/src/SerialMuxProtCommon.hpp +++ b/src/SerialMuxProtCommon.hpp @@ -1,26 +1,25 @@ /* MIT License - -Copyright (c) 2023 Gabryel Reyes - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -*/ + * + * Copyright (c) 2023 - 2024 Gabryel Reyes + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ /******************************************************************************* DESCRIPTION @@ -29,7 +28,6 @@ SOFTWARE. * @brief Common Constants and Structures of SerialMuxProt. * @author Gabryel Reyes * - * * @{ */ diff --git a/src/SerialMuxProtServer.hpp b/src/SerialMuxProtServer.hpp index ec4079c..0eff8e1 100644 --- a/src/SerialMuxProtServer.hpp +++ b/src/SerialMuxProtServer.hpp @@ -1,6 +1,6 @@ /* MIT License * - * Copyright (c) 2023 Gabryel Reyes + * Copyright (c) 2023 - 2024 Gabryel Reyes * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/test/common/Print.h b/test/common/Print.h index 33fd32f..2a64c81 100644 --- a/test/common/Print.h +++ b/test/common/Print.h @@ -1,6 +1,6 @@ /* MIT License * - * Copyright (c) 2023 Andreas Merkle + * Copyright (c) 2023 - 2024 Andreas Merkle * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/test/common/Stream.h b/test/common/Stream.h index df0d73a..75a6a13 100644 --- a/test/common/Stream.h +++ b/test/common/Stream.h @@ -1,6 +1,6 @@ /* MIT License * - * Copyright (c) 2023 Andreas Merkle + * Copyright (c) 2023 - 2024 Andreas Merkle * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/test/common/TestStream.h b/test/common/TestStream.h index 1f373f7..4fa33ba 100644 --- a/test/common/TestStream.h +++ b/test/common/TestStream.h @@ -1,6 +1,6 @@ /* MIT License * - * Copyright (c) 2023 Andreas Merkle + * Copyright (c) 2023 - 2024 Andreas Merkle * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal diff --git a/test/test_SerialMuxProt/test_SerialMuxProt.cpp b/test/test_SerialMuxProt/test_SerialMuxProt.cpp index 2234a67..6b35aaf 100644 --- a/test/test_SerialMuxProt/test_SerialMuxProt.cpp +++ b/test/test_SerialMuxProt/test_SerialMuxProt.cpp @@ -1,6 +1,6 @@ /* MIT License * - * Copyright (c) 2023 Andreas Merkle + * Copyright (c) 2023 - 2024 Gabryel Reyes * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -21,23 +21,22 @@ * SOFTWARE. */ +/******************************************************************************* + DESCRIPTION +*******************************************************************************/ /** * @author Gabryel Reyes * @brief This module contains the SerialMuxProt Server tests. */ -/****************************************************************************** - * Compile Switches - *****************************************************************************/ - /****************************************************************************** * Includes *****************************************************************************/ - #include #include #include #include + /****************************************************************************** * Compiler Switches *****************************************************************************/ From c7c5ee669465f1bae6b55c23e2eaf96c68c90deb Mon Sep 17 00:00:00 2001 From: Gabryel Reyes Date: Fri, 26 Apr 2024 13:01:38 +0200 Subject: [PATCH 4/5] Updated examples --- examples/ServerA/main.cpp | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/examples/ServerA/main.cpp b/examples/ServerA/main.cpp index b3b75ee..d136ce6 100644 --- a/examples/ServerA/main.cpp +++ b/examples/ServerA/main.cpp @@ -57,6 +57,8 @@ * Prototypes *****************************************************************************/ +static void gOnSyncedCallback(void* userData); + /****************************************************************************** * Local Variables *****************************************************************************/ @@ -90,6 +92,8 @@ uint32_t gLastLedSendTimestamp = 0U; */ void setup() { + bool syncedCallbackRegistered = false; + /* Initialize Serial */ Serial.begin(SERIAL_BAUDRATE); @@ -98,6 +102,19 @@ void setup() /* Create Channel for sending LED data. */ gSerialMuxProtChannelIdLedData = gSmpServer.createChannel(LED_CHANNEL_NAME, LED_CHANNEL_DLC); + + /* Register Synced Callback. */ + syncedCallbackRegistered = gSmpServer.registerOnSyncedCallback(gOnSyncedCallback); + + /* Check channel creation and callback register. */ + if ((0U == gSerialMuxProtChannelIdLedData) || (false == syncedCallbackRegistered)) + { + /* Something went wrong. */ + while (true) + { + /* Do nothing. */ + } + } } /** @@ -144,3 +161,14 @@ void loop() /****************************************************************************** * Local Functions *****************************************************************************/ + +/** + * Callback function for Synced event. + * + * @param userData User data passed to the callback. + */ +static void gOnSyncedCallback(void* userData) +{ + /* Print Synced message. */ + Serial.println("Synced"); +} From 96f6d94cee818561f0e0c7d7ff14a23a07ea9bf2 Mon Sep 17 00:00:00 2001 From: Gabryel Reyes Date: Fri, 26 Apr 2024 13:08:02 +0200 Subject: [PATCH 5/5] Removed const attribute on payload size for the callbacks. --- src/SerialMuxProtCommon.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SerialMuxProtCommon.hpp b/src/SerialMuxProtCommon.hpp index ca97036..b8f7997 100644 --- a/src/SerialMuxProtCommon.hpp +++ b/src/SerialMuxProtCommon.hpp @@ -92,7 +92,7 @@ * @param[in] payloadSize Size of the received data. * @param[in] userData User data provided by the application. */ -typedef void (*ChannelCallback)(const uint8_t* payload, const uint8_t payloadSize, void* userData); +typedef void (*ChannelCallback)(const uint8_t* payload, uint8_t payloadSize, void* userData); /** * Event Notification Prototype Callback.