diff --git a/extras/test/src/test_command_decode.cpp b/extras/test/src/test_command_decode.cpp index 818d02136..b20f88605 100644 --- a/extras/test/src/test_command_decode.cpp +++ b/extras/test/src/test_command_decode.cpp @@ -50,6 +50,35 @@ SCENARIO("Test the decoding of command messages") { } /****************************************************************************/ + WHEN("Decode the ThingDetachCmd message") + { + CommandDown command; + /* + DA 00011000 # tag(69632) + 81 # array(1) + 78 24 # text(36) + 65343439346435352D383732612D346664322D393634362D393266383739343933393463 # "e4494d55-872a-4fd2-9646-92f87949394c" + */ + uint8_t const payload[] = {0xDA, 0x00, 0x01, 0x10, 0x00, 0x81, 0x78, 0x24, + 0x65, 0x34, 0x34, 0x39, 0x34, 0x64, 0x35, 0x35, + 0x2D, 0x38, 0x37, 0x32, 0x61, 0x2D, 0x34, 0x66, + 0x64, 0x32, 0x2D, 0x39, 0x36, 0x34, 0x36, 0x2D, + 0x39, 0x32, 0x66, 0x38, 0x37, 0x39, 0x34, 0x39, + 0x33, 0x39, 0x34, 0x63}; + + size_t payload_length = sizeof(payload) / sizeof(uint8_t); + CBORMessageDecoder decoder; + Decoder::Status err = decoder.decode((Message*)&command, payload, payload_length); + const char *thingIdToMatch = "e4494d55-872a-4fd2-9646-92f87949394c"; + + THEN("The decode is successful") { + REQUIRE(err == Decoder::Status::Complete); + REQUIRE(strcmp(command.thingDetachCmd.params.thing_id, thingIdToMatch) == 0); + REQUIRE(command.c.id == ThingDetachCmdId); + } + } + + /************************************************************************************/ WHEN("Decode the ThingUpdateCmdId message containing a number instead of a string") { @@ -71,9 +100,30 @@ SCENARIO("Test the decoding of command messages") { } } + /****************************************************************************/ + WHEN("Decode the ThingDetachCmd message containing a number instead of a string") + { + CommandDown command; + /* + DA 00011000 # tag(69632) + 81 # array(1) + 1A 65DCB821 # unsigned(1708963873) + */ + uint8_t const payload[] = {0xDA, 0x00, 0x01, 0x10, 0x00, 0x81, 0x1A, 0x65, + 0xDC, 0xB8, 0x21}; + + size_t payload_length = sizeof(payload) / sizeof(uint8_t); + CBORMessageDecoder decoder; + Decoder::Status err = decoder.decode((Message*)&command, payload, payload_length); + + THEN("The decode is successful") { + REQUIRE(err == Decoder::Status::Error); + } + } + /****************************************************************************/ - WHEN("Decode the SetTimezoneCommand message") + WHEN("Decode the TimezoneCommandDown message") { CommandDown command; diff --git a/extras/test/src/test_command_encode.cpp b/extras/test/src/test_command_encode.cpp index 7e31c1487..b18ecff7a 100644 --- a/extras/test/src/test_command_encode.cpp +++ b/extras/test/src/test_command_encode.cpp @@ -242,7 +242,7 @@ SCENARIO("Test the encoding of command messages") { /****************************************************************************/ - WHEN("Encode the SetTimezoneCommand message") + WHEN("Encode the TimezoneCommandDown message") { TimezoneCommandDown command; command.c.id = CommandId::TimezoneCommandDownId; @@ -304,6 +304,24 @@ SCENARIO("Test the encoding of command messages") { /****************************************************************************/ + WHEN("Encode the ThingDetachCmd message") + { + ThingDetachCmd command; + command.c.id = CommandId::ThingDetachCmdId; + + uint8_t buffer[512]; + size_t bytes_encoded = sizeof(buffer); + + CBORMessageEncoder encoder; + Encoder::Status err = encoder.encode((Message*)&command, buffer, bytes_encoded); + + THEN("The encoding is unsuccessful - ThingDetachCmd is not supported") { + REQUIRE(err == Encoder::Status::Error); + } + } + + /****************************************************************************/ + WHEN("Encode a message with unknown command Id") { OtaUpdateCmdDown command; diff --git a/src/ArduinoIoTCloudTCP.cpp b/src/ArduinoIoTCloudTCP.cpp index 687cdddf0..1c44f8611 100644 --- a/src/ArduinoIoTCloudTCP.cpp +++ b/src/ArduinoIoTCloudTCP.cpp @@ -410,6 +410,24 @@ void ArduinoIoTCloudTCP::handleMessage(int length) } break; + case CommandId::ThingDetachCmdId: + { + if (!_device.isAttached() || _thing_id != String(command.thingDetachCmd.params.thing_id)) { + DEBUG_VERBOSE("ArduinoIoTCloudTCP::%s [%d] thing detach rejected", __FUNCTION__, millis()); + } + + DEBUG_VERBOSE("ArduinoIoTCloudTCP::%s [%d] thing detach received", __FUNCTION__, millis()); + detachThing(); + } + break; + + case CommandId::TimezoneCommandDownId: + { + DEBUG_VERBOSE("ArduinoIoTCloudTCP::%s [%d] timezone update received", __FUNCTION__, millis()); + _thing.handleMessage((Message*)&command); + } + break; + case CommandId::LastValuesUpdateCmdId: { DEBUG_VERBOSE("ArduinoIoTCloudTCP::%s [%d] last values received", __FUNCTION__, millis()); diff --git a/src/ArduinoIoTCloudThing.cpp b/src/ArduinoIoTCloudThing.cpp index d2f49119b..d3df764a3 100644 --- a/src/ArduinoIoTCloudThing.cpp +++ b/src/ArduinoIoTCloudThing.cpp @@ -69,7 +69,7 @@ void ArduinoCloudThing::update() { } /* Handle external events */ - switch (_command) { + switch (_command.c.id) { case LastValuesUpdateCmdId: if (_state == State::RequestLastValues) { DEBUG_VERBOSE("CloudThing::%s Thing is synced", __FUNCTION__); @@ -77,6 +77,12 @@ void ArduinoCloudThing::update() { } break; + /* We have received a timezone update */ + case TimezoneCommandDownId: + TimeService.setTimeZoneData(_command.timezoneCommandDown.params.offset, + _command.timezoneCommandDown.params.until); + break; + /* We have received a reset command */ case ResetCmdId: nextState = State::Init; @@ -86,7 +92,7 @@ void ArduinoCloudThing::update() { break; } - _command = UnknownCmdId; + _command.c.id = UnknownCmdId; _state = nextState; } @@ -95,9 +101,9 @@ int ArduinoCloudThing::connected() { } void ArduinoCloudThing::handleMessage(Message* m) { - _command = UnknownCmdId; + _command.c.id = UnknownCmdId; if (m != nullptr) { - _command = m->id; + memcpy(&_command, m, sizeof(CommandDown)); } } diff --git a/src/ArduinoIoTCloudThing.h b/src/ArduinoIoTCloudThing.h index de52bc002..86cfb850f 100644 --- a/src/ArduinoIoTCloudThing.h +++ b/src/ArduinoIoTCloudThing.h @@ -51,7 +51,7 @@ class ArduinoCloudThing : public CloudProcess { }; State _state; - CommandId _command; + CommandDown _command; TimedAttempt _syncAttempt; PropertyContainer _propertyContainer; unsigned int _propertyContainerIndex; diff --git a/src/cbor/CBOR.cpp b/src/cbor/CBOR.cpp index ced5e3e7f..b043f5a14 100644 --- a/src/cbor/CBOR.cpp +++ b/src/cbor/CBOR.cpp @@ -36,6 +36,8 @@ CommandId toCommandId(CBORCommandTag tag) { return CommandId::OtaUpdateCmdDownId; case CBORCommandTag::CBORThingUpdateCmd: return CommandId::ThingUpdateCmdId; + case CBORCommandTag::CBORThingDetachCmd: + return CommandId::ThingDetachCmdId; case CBORCommandTag::CBORLastValuesUpdate: return CommandId::LastValuesUpdateCmdId; case CBORCommandTag::CBORTimezoneCommandDown: @@ -63,6 +65,8 @@ CBORCommandTag toCBORCommandTag(CommandId id) { return CBORCommandTag::CBOROtaUpdateCmdDown; case CommandId::ThingUpdateCmdId: return CBORCommandTag::CBORThingUpdateCmd; + case CommandId::ThingDetachCmdId: + return CBORCommandTag::CBORThingDetachCmd; case CommandId::LastValuesUpdateCmdId: return CBORCommandTag::CBORLastValuesUpdate; case CommandId::TimezoneCommandDownId: diff --git a/src/cbor/CBOR.h b/src/cbor/CBOR.h index 999570455..7e9a04d97 100644 --- a/src/cbor/CBOR.h +++ b/src/cbor/CBOR.h @@ -31,6 +31,7 @@ enum CBORCommandTag: uint64_t { // Commands DOWN CBOROtaUpdateCmdDown = 0x010100, CBORThingUpdateCmd = 0x010400, + CBORThingDetachCmd = 0x011000, CBORLastValuesUpdate = 0x010600, CBORTimezoneCommandDown = 0x010900, diff --git a/src/cbor/MessageDecoder.cpp b/src/cbor/MessageDecoder.cpp index c500ceae9..7c3e9a215 100644 --- a/src/cbor/MessageDecoder.cpp +++ b/src/cbor/MessageDecoder.cpp @@ -130,6 +130,17 @@ CBORMessageDecoder::ArrayParserState CBORMessageDecoder::decodeThingUpdateCmd(Cb return ArrayParserState::LeaveArray; } +CBORMessageDecoder::ArrayParserState CBORMessageDecoder::decodeThingDetachCmd(CborValue * param, Message * message) { + ThingDetachCmd * thingCommand = (ThingDetachCmd *) message; + + // Message is composed of a single parameter, a string (thing_id) + if (!copyCBORStringToArray(param, thingCommand->params.thing_id, sizeof(thingCommand->params.thing_id))) { + return ArrayParserState::Error; + } + + return ArrayParserState::LeaveArray; +} + CBORMessageDecoder::ArrayParserState CBORMessageDecoder::decodeTimezoneCommandDown(CborValue * param, Message * message) { TimezoneCommandDown * setTz = (TimezoneCommandDown *) message; @@ -213,6 +224,9 @@ CBORMessageDecoder::ArrayParserState CBORMessageDecoder::handle_Param(CborValue case CommandId::ThingUpdateCmdId: return CBORMessageDecoder::decodeThingUpdateCmd(param, message); + case CommandId::ThingDetachCmdId: + return CBORMessageDecoder::decodeThingDetachCmd(param, message); + case CommandId::TimezoneCommandDownId: return CBORMessageDecoder::decodeTimezoneCommandDown(param, message); diff --git a/src/cbor/MessageDecoder.h b/src/cbor/MessageDecoder.h index 712289c9d..1223e947b 100644 --- a/src/cbor/MessageDecoder.h +++ b/src/cbor/MessageDecoder.h @@ -65,6 +65,7 @@ class CBORMessageDecoder: public Decoder // Message specific decoders ArrayParserState decodeThingUpdateCmd(CborValue * param, Message * message); + ArrayParserState decodeThingDetachCmd(CborValue * param, Message * message); ArrayParserState decodeTimezoneCommandDown(CborValue * param, Message * message); ArrayParserState decodeLastValuesUpdateCmd(CborValue * param, Message * message); ArrayParserState decodeOtaUpdateCmdDown(CborValue * param, Message * message); diff --git a/src/message/Commands.h b/src/message/Commands.h index ce71f9c81..f0e9a15c9 100644 --- a/src/message/Commands.h +++ b/src/message/Commands.h @@ -37,6 +37,7 @@ enum CommandId: uint32_t { DeviceBeginCmdId, ThingBeginCmdId, ThingUpdateCmdId, + ThingDetachCmdId, DeviceRegisteredCmdId, DeviceAttachedCmdId, DeviceDetachedCmdId, @@ -89,6 +90,13 @@ struct ThingUpdateCmd { } params; }; +struct ThingDetachCmd { + Command c; + struct { + char thing_id[THING_ID_SIZE]; + } params; +}; + struct LastValuesBeginCmd { Command c; }; @@ -144,6 +152,7 @@ union CommandDown { struct Command c; struct OtaUpdateCmdDown otaUpdateCmdDown; struct ThingUpdateCmd thingUpdateCmd; + struct ThingDetachCmd thingDetachCmd; struct LastValuesUpdateCmd lastValuesUpdateCmd; struct TimezoneCommandDown timezoneCommandDown; };