@@ -697,6 +697,146 @@ void test_0x27_brute_force_prevention_2(void **state) {
697697 TEST_MEMORY_EQUAL(buf, DENIED, sizeof(DENIED));
698698}
699699
700+ int fn_test_0x2F(UDSServer_t *srv, UDSEvent_t ev, void *arg) {
701+ UDSIOCtrlArgs_t *args = arg;
702+
703+ TEST_INT_EQUAL(ev, UDS_EVT_IOControl);
704+ TEST_INT_EQUAL(args->dataId, 0x9B00);
705+ if (args->ioCtrlParam == 0x00) {
706+ TEST_INT_EQUAL(args->ctrlStateAndMaskLen, 0x00);
707+ const uint8_t response_data[] = {0x3A};
708+ return args->copy(srv, response_data, sizeof(response_data));
709+
710+ } else if (args->ioCtrlParam == 0x02) {
711+ // Provoke a negative response
712+ return UDS_NRC_SecurityAccessDenied;
713+
714+ } else if (args->ioCtrlParam == 0x03) {
715+ TEST_INT_EQUAL(args->ctrlStateAndMaskLen, 0x01);
716+ const uint8_t expected_data[] = {0x3C};
717+ TEST_MEMORY_EQUAL(args->ctrlStateAndMask, expected_data, args->ctrlStateAndMaskLen);
718+ const uint8_t response_data[] = {0x0C};
719+ return args->copy(srv, response_data, sizeof(response_data));
720+ }
721+
722+ return UDS_NRC_RequestOutOfRange;
723+ }
724+
725+ // ISO14229-1 2020 13.2.5.2 Example #1 - "Air Inlet Door Position" shortTermAdjustment
726+ // This test just simulates the 0x2F function request/responses of the example.
727+ void test_0x2F_example(void **state) {
728+ Env_t *e = *state;
729+ uint8_t buf[20] = {0};
730+
731+ e->server->fn = fn_test_0x2F;
732+ e->server->fn_data = NULL;
733+
734+ /* Request per ISO14229-1 2020 Table 406 */
735+ const uint8_t REQ1[] = {
736+ 0x2F, /* SID */
737+ 0x9B, /* DataIdentifier [High Byte] */
738+ 0x00, /* DataIdentifier [Low Byte] */
739+ 0x03, /* ControlOptionRecord [inputOutputControlParamter] */
740+ 0x3C, /* ControlOptionRecord [State#1] */
741+ };
742+
743+ UDSTpSend(e->client_tp, REQ1, sizeof(REQ1), NULL);
744+
745+ /* Response per ISO14229-1 2020 Table 407 */
746+ const uint8_t EXPECTED_RESP1[] = {
747+ 0x6F, /* Response SID */
748+ 0x9B, /* DataIdentifier [High Byte] */
749+ 0x00, /* DataIdentifier [Low Byte] */
750+ 0x03, /* ControlOptionRecord [inputOutputControlParamter] */
751+ 0x0C, /* ControlOptionRecord [State#1] */
752+ };
753+
754+ /* the client transport should receive a positive response within client_p2 ms */
755+ EXPECT_WITHIN_MS(e, UDSTpRecv(e->client_tp, buf, sizeof(buf), NULL) > 0,
756+ UDS_CLIENT_DEFAULT_P2_MS);
757+ TEST_MEMORY_EQUAL(buf, EXPECTED_RESP1, sizeof(EXPECTED_RESP1));
758+
759+ /* Request per ISO14229-1 2020 Table 410 */
760+ const uint8_t REQ2[] = {
761+ 0x2F, /* SID */
762+ 0x9B, /* DataIdentifier [High Byte] */
763+ 0x00, /* DataIdentifier [Low Byte] */
764+ 0x00, /* ControlOptionRecord [inputOutputControlParamter] */
765+ };
766+
767+ UDSTpSend(e->client_tp, REQ2, sizeof(REQ2), NULL);
768+
769+ /* Response per ISO14229-1 2020 Table 411 */
770+ const uint8_t EXPECTED_RESP2[] = {
771+ 0x6F, /* Response SID */
772+ 0x9B, /* DataIdentifier [High Byte] */
773+ 0x00, /* DataIdentifier [Low Byte] */
774+ 0x00, /* ControlOptionRecord [inputOutputControlParamter] */
775+ 0x3A, /* ControlOptionRecord [State#1] */
776+ };
777+
778+ /* the client transport should receive a positive response within client_p2 ms */
779+ EXPECT_WITHIN_MS(e, UDSTpRecv(e->client_tp, buf, sizeof(buf), NULL) > 0,
780+ UDS_CLIENT_DEFAULT_P2_MS);
781+ TEST_MEMORY_EQUAL(buf, EXPECTED_RESP2, sizeof(EXPECTED_RESP2));
782+ }
783+
784+ void test_0x2F_incorrect_request_length(void **state) {
785+ Env_t *e = *state;
786+ uint8_t buf[20] = {0};
787+
788+ e->server->fn = fn_test_0x2F;
789+ e->server->fn_data = NULL;
790+
791+ const uint8_t REQ[] = {
792+ 0x2F, /* SID */
793+ 0x9B, /* DataIdentifier [High Byte] */
794+ 0x00, /* DataIdentifier [Low Byte] */
795+ /* MISSING required ControlOptionRecord [inputOutputControlParamter] */
796+ };
797+
798+ UDSTpSend(e->client_tp, REQ, sizeof(REQ), NULL);
799+
800+ const uint8_t EXPECTED_RESP[] = {
801+ 0x7F, /* Response SID */
802+ 0x2F, /* Original Request SID */
803+ 0x13, /* NRC: IncorrectMessageLengthOrInvalidFormat */
804+ };
805+
806+ /* the client transport should receive a response within client_p2 ms */
807+ EXPECT_WITHIN_MS(e, UDSTpRecv(e->client_tp, buf, sizeof(buf), NULL) > 0,
808+ UDS_CLIENT_DEFAULT_P2_MS);
809+ TEST_MEMORY_EQUAL(buf, EXPECTED_RESP, sizeof(EXPECTED_RESP));
810+ }
811+
812+ void test_0x2F_negative_response(void **state) {
813+ Env_t *e = *state;
814+ uint8_t buf[20] = {0};
815+
816+ e->server->fn = fn_test_0x2F;
817+ e->server->fn_data = NULL;
818+
819+ const uint8_t REQ[] = {
820+ 0x2F, /* SID */
821+ 0x9B, /* DataIdentifier [High Byte] */
822+ 0x00, /* DataIdentifier [Low Byte] */
823+ 0x02, /* ControlOptionRecord [inputOutputControlParamter] */
824+ };
825+
826+ UDSTpSend(e->client_tp, REQ, sizeof(REQ), NULL);
827+
828+ const uint8_t EXPECTED_RESP[] = {
829+ 0x7F, /* Response SID */
830+ 0x2F, /* Original Request SID */
831+ 0x33, /* NRC: SecurityAccessDenied */
832+ };
833+
834+ /* the client transport should receive a response within client_p2 ms */
835+ EXPECT_WITHIN_MS(e, UDSTpRecv(e->client_tp, buf, sizeof(buf), NULL) > 0,
836+ UDS_CLIENT_DEFAULT_P2_MS);
837+ TEST_MEMORY_EQUAL(buf, EXPECTED_RESP, sizeof(EXPECTED_RESP));
838+ }
839+
700840int fn_test_0x31_RCRRP(UDSServer_t *srv, UDSEvent_t ev, void *arg) {
701841 return *(int *)(srv->fn_data);
702842}
@@ -980,6 +1120,9 @@ int main(int ac, char **av) {
9801120 cmocka_unit_test_setup_teardown(test_0x27_unlock, Setup, Teardown),
9811121 cmocka_unit_test_setup_teardown(test_0x27_brute_force_prevention_1, Setup, Teardown),
9821122 cmocka_unit_test_setup_teardown(test_0x27_brute_force_prevention_2, Setup, Teardown),
1123+ cmocka_unit_test_setup_teardown(test_0x2F_example, Setup, Teardown),
1124+ cmocka_unit_test_setup_teardown(test_0x2F_incorrect_request_length, Setup, Teardown),
1125+ cmocka_unit_test_setup_teardown(test_0x2F_negative_response, Setup, Teardown),
9831126 cmocka_unit_test_setup_teardown(test_0x31_RCRRP, Setup, Teardown),
9841127 cmocka_unit_test_setup_teardown(test_0x34_no_handler, Setup, Teardown),
9851128 cmocka_unit_test_setup_teardown(test_0x34, Setup, Teardown),
0 commit comments