PROFINET IO Controller Stack 1.0.0
Modern C++ implementation of a PROFINET IO Controller stack
Loading...
Searching...
No Matches
test_exceptions.cpp
Go to the documentation of this file.
1
3
4#include <gtest/gtest.h>
5
6#include <string>
7#include <type_traits>
8#include <array>
10
11namespace profinet
12{
13
14// ============================================================================
15// Exception Hierarchy Tests
16// ============================================================================
17
19TEST(ExceptionHierarchyTests, DcpErrorInheritsProfinetError)
20{
21 EXPECT_TRUE((std::is_base_of_v<ProfinetError, DCPError>));
22}
23
25TEST(ExceptionHierarchyTests, DcpTimeoutInheritsDcpError)
26{
27 EXPECT_TRUE((std::is_base_of_v<DCPError, DCPTimeoutError>));
28}
29
31TEST(ExceptionHierarchyTests, DcpDeviceNotFoundInheritsDcpError)
32{
33 EXPECT_TRUE((std::is_base_of_v<DCPError, DCPDeviceNotFoundError>));
34}
35
37TEST(ExceptionHierarchyTests, RpcErrorInheritsProfinetError)
38{
39 EXPECT_TRUE((std::is_base_of_v<ProfinetError, RPCError>));
40}
41
43TEST(ExceptionHierarchyTests, RpcTimeoutInheritsRpcError)
44{
45 EXPECT_TRUE((std::is_base_of_v<RPCError, RPCTimeoutError>));
46}
47
49TEST(ExceptionHierarchyTests, RpcFaultInheritsRpcError)
50{
51 EXPECT_TRUE((std::is_base_of_v<RPCError, RPCFaultError>));
52}
53
55TEST(ExceptionHierarchyTests, RpcConnectionInheritsRpcError)
56{
57 EXPECT_TRUE((std::is_base_of_v<RPCError, RPCConnectionError>));
58}
59
61TEST(ExceptionHierarchyTests, ValidationErrorInheritsProfinetError)
62{
63 EXPECT_TRUE((std::is_base_of_v<ProfinetError, ValidationError>));
64}
65
67TEST(ExceptionHierarchyTests, InvalidMacInheritsValidationError)
68{
69 EXPECT_TRUE((std::is_base_of_v<ValidationError, InvalidMACError>));
70}
71
73TEST(ExceptionHierarchyTests, InvalidIpInheritsValidationError)
74{
75 EXPECT_TRUE((std::is_base_of_v<ValidationError, InvalidIPError>));
76}
77
79TEST(ExceptionHierarchyTests, SocketErrorInheritsProfinetError)
80{
81 EXPECT_TRUE((std::is_base_of_v<ProfinetError, SocketError>));
82}
83
85TEST(ExceptionHierarchyTests, PermissionDeniedInheritsSocketError)
86{
87 EXPECT_TRUE((std::is_base_of_v<SocketError, PermissionDeniedError>));
88}
89
90// ============================================================================
91// RPCFaultError Tests
92// ============================================================================
93
95TEST(RPCFaultErrorTests, FaultCodeDefault)
96{
97 const RPCFaultError error("test error");
98 EXPECT_EQ(error.faultCode, 0U);
99}
100
102TEST(RPCFaultErrorTests, FaultCodeCustom)
103{
104 const RPCFaultError error("test error", 42);
105 EXPECT_EQ(error.faultCode, 42U);
106}
107
109TEST(RPCFaultErrorTests, Message)
110{
111 const RPCFaultError error("RPC fault occurred");
112 EXPECT_STREQ(error.what(), "RPC fault occurred");
113}
114
115// ============================================================================
116// Exception Catching Tests
117// ============================================================================
118
120TEST(ExceptionCatchingTests, CatchAllProfinetErrors)
121{
122 EXPECT_THROW(throw DCPError("dcp"), ProfinetError);
123 EXPECT_THROW(throw RPCError("rpc"), ProfinetError);
124 EXPECT_THROW(throw ValidationError("validation"), ProfinetError);
125 EXPECT_THROW(throw SocketError("socket"), ProfinetError);
126}
127
129TEST(ExceptionCatchingTests, CatchDcpVariants)
130{
131 EXPECT_THROW(throw DCPTimeoutError("timeout"), DCPError);
132 EXPECT_THROW(throw DCPDeviceNotFoundError("not found"), DCPError);
133}
134
136TEST(ExceptionCatchingTests, CatchRpcVariants)
137{
138 EXPECT_THROW(throw RPCTimeoutError("timeout"), RPCError);
139 EXPECT_THROW(throw RPCFaultError("fault"), RPCError);
140 EXPECT_THROW(throw RPCConnectionError("connection"), RPCError);
141 EXPECT_THROW(throw PNIOError("pnio", 0, 0, 0, 0), RPCError);
142}
143
144// ============================================================================
145// PNIOError Tests
146// ============================================================================
147
149TEST(PNIOErrorTests, PnioErrorInheritsRpcError)
150{
151 EXPECT_TRUE((std::is_base_of_v<RPCError, PNIOError>));
152}
153
155TEST(PNIOErrorTests, DefaultValues)
156{
157 const PNIOError error("test error", 0, 0, 0, 0);
158 EXPECT_EQ(error.errorCode, 0);
159 EXPECT_EQ(error.errorDecode, 0);
160 EXPECT_EQ(error.errorCode1, 0);
161 EXPECT_EQ(error.errorCode2, 0);
162}
163
165TEST(PNIOErrorTests, CustomValues)
166{
167 const PNIOError error("test", 0xDE, 0x80, 0xB2, 0x07);
168 EXPECT_EQ(error.errorCode, 0xDE);
169 EXPECT_EQ(error.errorDecode, 0x80);
170 EXPECT_EQ(error.errorCode1, 0xB2);
171 EXPECT_EQ(error.errorCode2, 0x07);
172}
173
175TEST(PNIOErrorTests, FromArgsStatusInvalidSlot)
176{
177 // Wire bytes [0x07, 0xB2, 0x80, 0xDE] -> big-endian 0x07B280DE -> swap -> 0xDE80B207
178 constexpr std::uint32_t argsStatus = 0x07B280DE;
179 const auto error = PNIOError::FromArgsStatus(argsStatus);
180
181 EXPECT_EQ(error.errorCode, 0xDE);
182 EXPECT_EQ(error.errorDecode, 0x80);
183 EXPECT_EQ(error.errorCode1, 0xB2);
184 EXPECT_EQ(error.errorCode2, 0x07);
185 EXPECT_NE(std::string(error.what()).find("Invalid slot number"), std::string::npos);
186}
187
189TEST(PNIOErrorTests, FromArgsStatusInvalidSubslot)
190{
191 // Wire bytes [0x08, 0xB2, 0x80, 0xDE] -> big-endian 0x08B280DE -> swap -> 0xDE80B208
192 constexpr std::uint32_t argsStatus = 0x08B280DE;
193 const auto error = PNIOError::FromArgsStatus(argsStatus);
194
195 EXPECT_EQ(error.errorCode, 0xDE);
196 EXPECT_EQ(error.errorDecode, 0x80);
197 EXPECT_EQ(error.errorCode1, 0xB2);
198 EXPECT_EQ(error.errorCode2, 0x08);
199 EXPECT_NE(std::string(error.what()).find("Invalid subslot number"), std::string::npos);
200}
201
203TEST(PNIOErrorTests, FromArgsStatusInvalidIndex)
204{
205 // Wire bytes [0x00, 0xB0, 0x80, 0xDE] -> big-endian 0x00B080DE -> swap -> 0xDE80B000
206 constexpr std::uint32_t argsStatus = 0x00B080DE;
207 const auto error = PNIOError::FromArgsStatus(argsStatus);
208
209 EXPECT_EQ(error.errorCode, 0xDE);
210 EXPECT_EQ(error.errorDecode, 0x80);
211 EXPECT_EQ(error.errorCode1, 0xB0);
212 EXPECT_EQ(error.errorCode2, 0x00);
213 EXPECT_NE(std::string(error.what()).find("Index not supported"), std::string::npos);
214}
215
217TEST(PNIOErrorTests, FromArgsStatusInvalidApi)
218{
219 // Wire bytes [0x06, 0xB4, 0x80, 0xDE] -> big-endian 0x06B480DE -> swap -> 0xDE80B406
220 constexpr std::uint32_t argsStatus = 0x06B480DE;
221 const auto error = PNIOError::FromArgsStatus(argsStatus);
222
223 EXPECT_EQ(error.errorCode, 0xDE);
224 EXPECT_EQ(error.errorDecode, 0x80);
225 EXPECT_EQ(error.errorCode1, 0xB4);
226 EXPECT_EQ(error.errorCode2, 0x06);
227 EXPECT_NE(std::string(error.what()).find("Invalid API number"), std::string::npos);
228}
229
231TEST(PNIOErrorTests, FromArgsStatusRmpmError)
232{
233 // Matches Hilscher PNIO_E_RMPM_CONNECT_UNKNOWN_BLOCKS = 0xDB814001
234 // Wire bytes [0x01, 0x40, 0x81, 0xDB] -> big-endian 0x014081DB -> swap -> 0xDB814001
235 constexpr std::uint32_t argsStatus = 0x014081DB;
236 const auto error = PNIOError::FromArgsStatus(argsStatus);
237
238 EXPECT_EQ(error.errorCode, 0xDB); // IODConnectRes
239 EXPECT_EQ(error.errorDecode, 0x81); // PNIO
240 EXPECT_EQ(error.errorCode1, 0x40); // RMPM
241 EXPECT_EQ(error.errorCode2, 0x01); // Unknown blocks
242 EXPECT_NE(std::string(error.what()).find("Unknown blocks in request"), std::string::npos);
243}
244
246TEST(PNIOErrorTests, FromArgsStatusUnknownError)
247{
248 // Wire bytes [0xFF, 0xB2, 0x80, 0xDE] -> big-endian 0xFFB280DE -> swap -> 0xDE80B2FF
249 constexpr std::uint32_t argsStatus = 0xFFB280DE;
250 const auto error = PNIOError::FromArgsStatus(argsStatus);
251
252 EXPECT_EQ(error.errorCode, 0xDE);
253 EXPECT_EQ(error.errorCode2, 0xFF);
254 EXPECT_NE(std::string(error.what()).find("Unknown"), std::string::npos);
255}
256
258TEST(PNIOErrorTests, StrFormat)
259{
260 const PNIOError error("Test message", 0xDE, 0x80, 0xB2, 0x07);
261 const std::string result = error.what();
262 EXPECT_NE(result.find("Test message"), std::string::npos);
263}
264
266TEST(PNIOErrorTests, ErrorConstants)
267{
268 EXPECT_EQ(ErrorDecode::PnioCm, static_cast<ErrorDecode>(0x40));
269 EXPECT_EQ(ErrorDecode::PnioRw, static_cast<ErrorDecode>(0x80));
270 EXPECT_EQ(ErrorDecode::Pnio, static_cast<ErrorDecode>(0x81));
271 EXPECT_EQ(PnioRwErrorCode1::InvalidIndex, static_cast<PnioRwErrorCode1>(0xB0));
272 EXPECT_EQ(PnioRwErrorCode1::Resource, static_cast<PnioRwErrorCode1>(0xB2));
273 EXPECT_EQ(PnioRwErrorCode1::Application, static_cast<PnioRwErrorCode1>(0xB4));
274}
275
276// ============================================================================
277// PNIOError::CreateFromCodes() — PNIO-CM
278// ============================================================================
279
281TEST(PNIOErrorTests, CreateFromCodesPnioCmAr)
282{
283 const std::array<std::uint8_t, 4> data{
284 0x01, 0x40, 0x01, 0x00};
285
286 const auto error = PNIOError::FromBytes(data);
287
288 EXPECT_EQ(error.errorCode, 0x01);
289 EXPECT_EQ(error.errorDecode, 0x40);
290 EXPECT_EQ(error.errorCode1, 0x01);
291 EXPECT_EQ(error.errorCode2, 0x00);
292 EXPECT_EQ(std::string(error.what()), "Invalid AR type");
293}
294
296TEST(PNIOErrorTests, CreateFromCodesPnioCmArResponse)
297{
298 const std::array<std::uint8_t, 4> data{
299 0x01, 0x40, 0x81, 0x00};
300
301 const auto error = PNIOError::FromBytes(data);
302
303 EXPECT_EQ(error.errorCode, 0x01);
304 EXPECT_EQ(error.errorDecode, 0x40);
305 EXPECT_EQ(error.errorCode1, 0x81);
306 EXPECT_EQ(error.errorCode2, 0x00);
307 EXPECT_EQ(std::string(error.what()), "Invalid AR type (in response)");
308}
309
311TEST(PNIOErrorTests, CreateFromCodesPnioCmIocr)
312{
313 const std::array<std::uint8_t, 4> data{
314 0x01, 0x40, 0x02, 0x04};
315
316 const auto error = PNIOError::FromBytes(data);
317
318 EXPECT_EQ(std::string(error.what()), "Invalid IO data length");
319}
320
322TEST(PNIOErrorTests, CreateFromCodesPnioCmIocrResponse)
323{
324 const std::array<std::uint8_t, 4> data{
325 0x01, 0x40, 0x82, 0x04};
326
327 const auto error = PNIOError::FromBytes(data);
328
329 EXPECT_EQ(std::string(error.what()), "Invalid IO data length (in response)");
330}
331
333TEST(PNIOErrorTests, CreateFromCodesPnioCmAlarmCr)
334{
335 const std::array<std::uint8_t, 4> data{
336 0x01, 0x40, 0x03, 0x01};
337
338 const auto error = PNIOError::FromBytes(data);
339
340 EXPECT_EQ(std::string(error.what()), "Out of AlarmCR resources");
341}
342
344TEST(PNIOErrorTests, CreateFromCodesPnioCmAlarmCrResponse)
345{
346 const std::array<std::uint8_t, 4> data{
347 0x01, 0x40, 0x83, 0x01};
348
349 const auto error = PNIOError::FromBytes(data);
350
351 EXPECT_EQ(std::string(error.what()), "Out of AlarmCR resources (in response)");
352}
353
355TEST(PNIOErrorTests, CreateFromCodesPnioCmExpectedSubmodule)
356{
357 const std::array<std::uint8_t, 4> data{
358 0x01, 0x40, 0x04, 0x04};
359
360 const auto error = PNIOError::FromBytes(data);
361
362 EXPECT_EQ(std::string(error.what()), "IO data length mismatch");
363}
364
366TEST(PNIOErrorTests, CreateFromCodesPnioCmDevice)
367{
368 const std::array<std::uint8_t, 4> data{
369 0x01, 0x40, 0x3F, 0x02};
370
371 const auto error = PNIOError::FromBytes(data);
372
373 EXPECT_EQ(std::string(error.what()), "Device already owned");
374}
375
377TEST(PNIOErrorTests, CreateFromCodesPnioCmFaultyBlock)
378{
379 const std::array<std::uint8_t, 4> data{
380 0x01, 0x40, 0xFF, 0x00};
381
382 const auto error = PNIOError::FromBytes(data);
383
384 EXPECT_EQ(std::string(error.what()), "Faulty block structure");
385}
386
388TEST(PNIOErrorTests, CreateFromCodesPnioCmUnknownErrorCode1)
389{
390 const std::array<std::uint8_t, 4> data{
391 0x01, 0x40, 0x0A, 0x00};
392
393 const auto error = PNIOError::FromBytes(data);
394
395 EXPECT_EQ(std::string(error.what()), "Unknown CM error in Unknown (0x0A)");
396}
397
398// ============================================================================
399// PNIOError::CreateFromCodes() — PNIO
400// ============================================================================
401
403TEST(PNIOErrorTests, CreateFromCodesPnioRmpm)
404{
405 const std::array<std::uint8_t, 4> data{
406 0x01, 0x81, 0x40, 0x02};
407
408 const auto error = PNIOError::FromBytes(data);
409
410 EXPECT_EQ(error.errorCode, 0x01);
411 EXPECT_EQ(error.errorDecode, 0x81);
412 EXPECT_EQ(error.errorCode1, 0x40);
413 EXPECT_EQ(error.errorCode2, 0x02);
414 EXPECT_EQ(std::string(error.what()), "Required IOCR block missing");
415}
416
418TEST(PNIOErrorTests, CreateFromCodesPnioPrmServer)
419{
420 const std::array<std::uint8_t, 4> data{
421 0x01, 0x81, 0x3D, 0x00};
422
423 const auto error = PNIOError::FromBytes(data);
424
425 EXPECT_EQ(std::string(error.what()), "Parameter server state conflict");
426}
427
429TEST(PNIOErrorTests, CreateFromCodesPnioUnknownErrorCode1)
430{
431 const std::array<std::uint8_t, 4> data{
432 0x01, 0x81, 0x0A, 0x00};
433
434 const auto error = PNIOError::FromBytes(data);
435
436 EXPECT_EQ(std::string(error.what()), "Unknown PNIO error");
437}
438
439// ============================================================================
440// PNIOError::CreateFromCodes() — PNIORW
441// ============================================================================
442
444TEST(PNIOErrorTests, CreateFromCodesPnioRwInvalidIndex)
445{
446 const std::array<std::uint8_t, 4> data{
447 0x01, 0x80, 0xB0, 0x05};
448
449 const auto error = PNIOError::FromBytes(data);
450
451 EXPECT_EQ(std::string(error.what()),
452 "Index exists but has not been written");
453}
454
456TEST(PNIOErrorTests, CreateFromCodesPnioRwWriteLength)
457{
458 const std::array<std::uint8_t, 4> data{
459 0x01, 0x80, 0xB1, 0x03};
460
461 const auto error = PNIOError::FromBytes(data);
462
463 EXPECT_EQ(std::string(error.what()),
464 "Write access denied (write protected)");
465}
466
468TEST(PNIOErrorTests, CreateFromCodesPnioRwResource)
469{
470 const std::array<std::uint8_t, 4> data{
471 0x01, 0x80, 0xB2, 0x08};
472
473 const auto error = PNIOError::FromBytes(data);
474
475 EXPECT_EQ(std::string(error.what()), "Invalid subslot number");
476}
477
479TEST(PNIOErrorTests, CreateFromCodesPnioRwAccess)
480{
481 const std::array<std::uint8_t, 4> data{
482 0x01, 0x80, 0xB3, 0x05};
483
484 const auto error = PNIOError::FromBytes(data);
485
486 EXPECT_EQ(std::string(error.what()),
487 "Access denied (invalid state for access)");
488}
489
491TEST(PNIOErrorTests, CreateFromCodesPnioRwApplication)
492{
493 const std::array<std::uint8_t, 4> data{
494 0x01, 0x80, 0xB4, 0x08};
495
496 const auto error = PNIOError::FromBytes(data);
497
498 EXPECT_EQ(std::string(error.what()), "Alarm pending");
499}
500
502TEST(PNIOErrorTests, CreateFromCodesPnioRwUnknownErrorCode1)
503{
504 const std::array<std::uint8_t, 4> data{
505 0x01, 0x80, 0x0A, 0x00};
506
507 const auto error = PNIOError::FromBytes(data);
508
509 EXPECT_EQ(std::string(error.what()), "Unknown PNIORW error");
510}
511
512// ============================================================================
513// PNIOError::CreateFromCodes() — unknown ErrorDecode
514// ============================================================================
515
517TEST(PNIOErrorTests, CreateFromCodesUnknownErrorDecode)
518{
519 const std::array<std::uint8_t, 4> data{
520 0x12, 0x7F, 0x34, 0x56};
521
522 const auto error = PNIOError::FromBytes(data);
523
524 EXPECT_EQ(error.errorCode, 0x12);
525 EXPECT_EQ(error.errorDecode, 0x7F);
526 EXPECT_EQ(error.errorCode1, 0x34);
527 EXPECT_EQ(error.errorCode2, 0x56);
528 EXPECT_EQ(std::string(error.what()), "Unknown error (Decode=0x7F)");
529}
530
531// ============================================================================
532// Raw byte preservation
533// ============================================================================
534
536TEST(PNIOErrorTests, FromBytesPreservesAllRawErrorBytes)
537{
538 const std::array<std::uint8_t, 4> data{
539 0xDA, 0x40, 0x03, 0x01};
540
541 const auto error = PNIOError::FromBytes(data);
542
543 EXPECT_EQ(error.errorCode, data[0]);
544 EXPECT_EQ(error.errorDecode, data[1]);
545 EXPECT_EQ(error.errorCode1, data[2]);
546 EXPECT_EQ(error.errorCode2, data[3]);
547}
548
550TEST(PNIOErrorTests, FromBytesUsesExpectedByteOrder)
551{
552 const std::array<std::uint8_t, 4> data{
553 0xAA, 0x40, 0x01, 0x00};
554
555 const auto error = PNIOError::FromBytes(data);
556
557 EXPECT_EQ(error.errorCode, 0xAA);
558 EXPECT_EQ(error.errorDecode, 0x40);
559 EXPECT_EQ(error.errorCode1, 0x01);
560 EXPECT_EQ(error.errorCode2, 0x00);
561}
562
563// ============================================================================
564// FromArgsStatus
565// ============================================================================
566
568TEST(PNIOErrorTests, FromArgsStatusReversesByteOrder)
569{
570 // After the byte swap this becomes:
571 //
572 // ErrorCode = 0x01
573 // ErrorDecode = 0x02
574 // ErrorCode1 = 0x03
575 // ErrorCode2 = 0x04
576 //
577 // Therefore the input ArgsStatus must be 0x04030201.
578 const auto error = PNIOError::FromArgsStatus(0x04030201U);
579
580 EXPECT_EQ(error.errorCode, 0x01);
581 EXPECT_EQ(error.errorDecode, 0x02);
582 EXPECT_EQ(error.errorCode1, 0x03);
583 EXPECT_EQ(error.errorCode2, 0x04);
584 EXPECT_EQ(std::string(error.what()), "Unknown error (Decode=0x02)");
585}
586
588TEST(PNIOErrorTests, FromArgsStatusDecodesPnioCmError)
589{
590 // Desired decoded bytes:
591 //
592 // ErrorCode = 0x01
593 // ErrorDecode = 0x40
594 // ErrorCode1 = 0x01
595 // ErrorCode2 = 0x00
596 //
597 // ArgsStatus therefore contains the reversed byte sequence.
598 const auto error = PNIOError::FromArgsStatus(0x00014001U);
599
600 EXPECT_EQ(error.errorCode, 0x01);
601 EXPECT_EQ(error.errorDecode, 0x40);
602 EXPECT_EQ(error.errorCode1, 0x01);
603 EXPECT_EQ(error.errorCode2, 0x00);
604 EXPECT_EQ(std::string(error.what()), "Invalid AR type");
605}
606
607// ============================================================================
608// IsCmError
609// ============================================================================
610
612TEST(PNIOErrorTests, IsCmErrorReturnsTrueForPnioCm)
613{
614 const std::array<std::uint8_t, 4> data{
615 0x01, 0x40, 0x01, 0x00};
616
617 const auto error = PNIOError::FromBytes(data);
618
619 EXPECT_TRUE(error.IsCmError());
620}
621
623TEST(PNIOErrorTests, IsCmErrorReturnsFalseForPnioRw)
624{
625 const std::array<std::uint8_t, 4> data{
626 0x01, 0x80, 0xB0, 0x00};
627
628 const auto error = PNIOError::FromBytes(data);
629
630 EXPECT_FALSE(error.IsCmError());
631}
632
634TEST(PNIOErrorTests, IsCmErrorReturnsFalseForPnio)
635{
636 const std::array<std::uint8_t, 4> data{
637 0x01, 0x81, 0x40, 0x00};
638
639 const auto error = PNIOError::FromBytes(data);
640
641 EXPECT_FALSE(error.IsCmError());
642}
643
645TEST(PNIOErrorTests, IsCmErrorReturnsFalseForUnknownDecode)
646{
647 const std::array<std::uint8_t, 4> data{
648 0x01, 0x7F, 0x01, 0x00};
649
650 const auto error = PNIOError::FromBytes(data);
651
652 EXPECT_FALSE(error.IsCmError());
653}
654
655// ============================================================================
656// BlockName
657// ============================================================================
658
660TEST(PNIOErrorTests, BlockNameReturnsArBlock)
661{
662 const std::array<std::uint8_t, 4> data{
663 0x01, 0x40, 0x01, 0x00};
664
665 const auto error = PNIOError::FromBytes(data);
666
667 EXPECT_EQ(error.BlockName(), "AR Block");
668}
669
671TEST(PNIOErrorTests, BlockNameReturnsIocrBlock)
672{
673 const std::array<std::uint8_t, 4> data{
674 0x01, 0x40, 0x02, 0x00};
675
676 const auto error = PNIOError::FromBytes(data);
677
678 EXPECT_EQ(error.BlockName(), "IOCR Block");
679}
680
682TEST(PNIOErrorTests, BlockNameReturnsArResponseBlock)
683{
684 const std::array<std::uint8_t, 4> data{
685 0x01, 0x40, 0x81, 0x00};
686
687 const auto error = PNIOError::FromBytes(data);
688
689 EXPECT_EQ(error.BlockName(), "AR Block Response");
690}
691
693TEST(PNIOErrorTests, BlockNameReturnsUnknownForUnknownCmErrorCode1)
694{
695 const std::array<std::uint8_t, 4> data{
696 0x01, 0x40, 0x0A, 0x00};
697
698 const auto error = PNIOError::FromBytes(data);
699
700 EXPECT_EQ(error.BlockName(), "Unknown (0x0A)");
701}
702
704TEST(PNIOErrorTests, BlockNameReturnsEmptyForPnioRwError)
705{
706 const std::array<std::uint8_t, 4> data{
707 0x01, 0x80, 0xB0, 0x00};
708
709 const auto error = PNIOError::FromBytes(data);
710
711 EXPECT_TRUE(error.BlockName().empty());
712}
713
715TEST(PNIOErrorTests, BlockNameReturnsEmptyForPnioError)
716{
717 const std::array<std::uint8_t, 4> data{
718 0x01, 0x81, 0x40, 0x00};
719
720 const auto error = PNIOError::FromBytes(data);
721
722 EXPECT_TRUE(error.BlockName().empty());
723}
724
726TEST(PNIOErrorTests, BlockNameReturnsEmptyForUnknownDecode)
727{
728 const std::array<std::uint8_t, 4> data{
729 0x01, 0x7F, 0x01, 0x00};
730
731 const auto error = PNIOError::FromBytes(data);
732
733 EXPECT_TRUE(error.BlockName().empty());
734}
735
736// ============================================================================
737// Direct PNIOError construction
738// ============================================================================
739
741TEST(PNIOErrorTests, DirectConstructionPreservesMessageAndCodes)
742{
743 const PNIOError error{
744 "test error",
745 0xDA,
746 0x40,
747 0x03,
748 0x01};
749
750 EXPECT_EQ(std::string(error.what()), "test error");
751 EXPECT_EQ(error.errorCode, 0xDA);
752 EXPECT_EQ(error.errorDecode, 0x40);
753 EXPECT_EQ(error.errorCode1, 0x03);
754 EXPECT_EQ(error.errorCode2, 0x01);
755}
756
758TEST(PNIOErrorTests, DirectConstructionIsCmError)
759{
760 const PNIOError error{
761 "test error",
762 0x01,
763 0x40,
764 0x01,
765 0x00};
766
767 EXPECT_TRUE(error.IsCmError());
768}
769
771TEST(PNIOErrorTests, DirectConstructionIsNotCmError)
772{
773 const PNIOError error{
774 "test error",
775 0x01,
776 0x81,
777 0x40,
778 0x00};
779
780 EXPECT_FALSE(error.IsCmError());
781}
782class PNIOErrorDirectTests : public ::testing::Test
783{
784 protected:
786 const std::uint8_t errorCode,
787 const std::uint8_t errorDecode,
788 const std::uint8_t errorCode1,
789 const std::uint8_t errorCode2)
790 {
792 errorCode,
793 errorDecode,
794 errorCode1,
795 errorCode2);
796 }
797
798 static std::string DecodePnioCm(
799 const std::uint8_t errorCode1,
800 const std::uint8_t errorCode2)
801 {
802 return PNIOError::DecodePnioCmError(errorCode1, errorCode2);
803 }
804
805 static std::string DecodePnio(
806 const std::uint8_t errorCode1,
807 const std::uint8_t errorCode2)
808 {
809 return PNIOError::DecodePnioError(errorCode1, errorCode2);
810 }
811
812 static std::string DecodePnioRw(
813 const std::uint8_t errorCode1,
814 const std::uint8_t errorCode2)
815 {
816 return PNIOError::DecodePnioRWError(errorCode1, errorCode2);
817 }
818};
819
821TEST_F(PNIOErrorDirectTests, DirectCreateFromCodesPnioCmAr)
822{
823 const auto error = CreateFromCodes(
824 0x01,
825 0x40,
826 0x01,
827 0x00);
828
829 EXPECT_EQ(error.errorCode, 0x01);
830 EXPECT_EQ(error.errorDecode, 0x40);
831 EXPECT_EQ(error.errorCode1, 0x01);
832 EXPECT_EQ(error.errorCode2, 0x00);
833 EXPECT_EQ(std::string(error.what()), "Invalid AR type");
834}
835
837TEST_F(PNIOErrorDirectTests, DirectCreateFromCodesPnioCmArResponse)
838{
839 const auto error = CreateFromCodes(
840 0x01,
841 0x40,
842 0x81,
843 0x00);
844
845 EXPECT_EQ(std::string(error.what()), "Invalid AR type (in response)");
846}
847
849TEST_F(PNIOErrorDirectTests, DirectCreateFromCodesPnioCmIocr)
850{
851 const auto error = CreateFromCodes(
852 0x01,
853 0x40,
854 0x02,
855 0x04);
856
857 EXPECT_EQ(std::string(error.what()), "Invalid IO data length");
858}
859
861TEST_F(PNIOErrorDirectTests, DirectCreateFromCodesPnioCmIocrResponse)
862{
863 const auto error = CreateFromCodes(
864 0x01,
865 0x40,
866 0x82,
867 0x04);
868
869 EXPECT_EQ(std::string(error.what()), "Invalid IO data length (in response)");
870}
871
873TEST_F(PNIOErrorDirectTests, DirectCreateFromCodesPnioCmAlarmCr)
874{
875 const auto error = CreateFromCodes(
876 0x01,
877 0x40,
878 0x03,
879 0x01);
880
881 EXPECT_EQ(std::string(error.what()), "Out of AlarmCR resources");
882}
883
885TEST_F(PNIOErrorDirectTests, DirectCreateFromCodesPnioCmAlarmCrResponse)
886{
887 const auto error = CreateFromCodes(
888 0x01,
889 0x40,
890 0x83,
891 0x01);
892
893 EXPECT_EQ(std::string(error.what()), "Out of AlarmCR resources (in response)");
894}
895
897TEST_F(PNIOErrorDirectTests, DirectCreateFromCodesPnioCmExpectedSubmodule)
898{
899 const auto error = CreateFromCodes(
900 0x01,
901 0x40,
902 0x04,
903 0x04);
904
905 EXPECT_EQ(std::string(error.what()), "IO data length mismatch");
906}
907
909TEST_F(PNIOErrorDirectTests, DirectCreateFromCodesPnioCmDevice)
910{
911 const auto error = CreateFromCodes(
912 0x01,
913 0x40,
914 0x3F,
915 0x02);
916
917 EXPECT_EQ(std::string(error.what()), "Device already owned");
918}
919
921TEST_F(PNIOErrorDirectTests, DirectCreateFromCodesPnioCmFaultyBlock)
922{
923 const auto error = CreateFromCodes(
924 0x01,
925 0x40,
926 0xFF,
927 0x00);
928
929 EXPECT_EQ(std::string(error.what()), "Faulty block structure");
930}
931
933TEST_F(PNIOErrorDirectTests, DirectCreateFromCodesPnioCmUnknownErrorCode1)
934{
935 const auto error = CreateFromCodes(
936 0x01,
937 0x40,
938 0x0A,
939 0x00);
940
941 EXPECT_EQ(std::string(error.what()), "Unknown CM error in Unknown (0x0A)");
942}
943
945TEST_F(PNIOErrorDirectTests, DirectCreateFromCodesPnioRmpm)
946{
947 const auto error = CreateFromCodes(
948 0x01,
949 0x81,
950 0x40,
951 0x02);
952
953 EXPECT_EQ(std::string(error.what()), "Required IOCR block missing");
954}
955
957TEST_F(PNIOErrorDirectTests, DirectCreateFromCodesPnioPrmServer)
958{
959 const auto error = CreateFromCodes(
960 0x01,
961 0x81,
962 0x3D,
963 0x00);
964
965 EXPECT_EQ(std::string(error.what()), "Parameter server state conflict");
966}
967
969TEST_F(PNIOErrorDirectTests, DirectCreateFromCodesPnioUnknownErrorCode1)
970{
971 const auto error = CreateFromCodes(
972 0x01,
973 0x81,
974 0x0A,
975 0x00);
976
977 EXPECT_EQ(std::string(error.what()), "Unknown PNIO error");
978}
979
981TEST_F(PNIOErrorDirectTests, DirectCreateFromCodesPnioRwInvalidIndex)
982{
983 const auto error = CreateFromCodes(
984 0x01,
985 0x80,
986 0xB0,
987 0x05);
988
989 EXPECT_EQ(std::string(error.what()), "Index exists but has not been written");
990}
991
993TEST_F(PNIOErrorDirectTests, DirectCreateFromCodesPnioRwWriteLength)
994{
995 const auto error = CreateFromCodes(
996 0x01,
997 0x80,
998 0xB1,
999 0x03);
1000
1001 EXPECT_EQ(std::string(error.what()), "Write access denied (write protected)");
1002}
1003
1005TEST_F(PNIOErrorDirectTests, DirectCreateFromCodesPnioRwResource)
1006{
1007 const auto error = CreateFromCodes(
1008 0x01,
1009 0x80,
1010 0xB2,
1011 0x08);
1012
1013 EXPECT_EQ(std::string(error.what()), "Invalid subslot number");
1014}
1015
1017TEST_F(PNIOErrorDirectTests, DirectCreateFromCodesPnioRwAccess)
1018{
1019 const auto error = CreateFromCodes(
1020 0x01,
1021 0x80,
1022 0xB3,
1023 0x05);
1024
1025 EXPECT_EQ(std::string(error.what()), "Access denied (invalid state for access)");
1026}
1027
1029TEST_F(PNIOErrorDirectTests, DirectCreateFromCodesPnioRwApplication)
1030{
1031 const auto error = CreateFromCodes(
1032 0x01,
1033 0x80,
1034 0xB4,
1035 0x08);
1036
1037 EXPECT_EQ(std::string(error.what()), "Alarm pending");
1038}
1039
1041TEST_F(PNIOErrorDirectTests, DirectCreateFromCodesPnioRwUnknownErrorCode1)
1042{
1043 const auto error = CreateFromCodes(
1044 0x01,
1045 0x80,
1046 0x0A,
1047 0x00);
1048
1049 EXPECT_EQ(std::string(error.what()), "Unknown PNIORW error");
1050}
1051
1053TEST_F(PNIOErrorDirectTests, DirectCreateFromCodesPnioCmPreservesRawCodes)
1054{
1055 const auto error = CreateFromCodes(
1056 0xDA,
1057 0x40,
1058 0x03,
1059 0x01);
1060
1061 EXPECT_EQ(error.errorCode, 0xDA);
1062 EXPECT_EQ(error.errorDecode, 0x40);
1063 EXPECT_EQ(error.errorCode1, 0x03);
1064 EXPECT_EQ(error.errorCode2, 0x01);
1065}
1066
1068TEST_F(PNIOErrorDirectTests, DirectCreateFromCodesPnioRwPreservesRawCodes)
1069{
1070 const auto error = CreateFromCodes(
1071 0xCF,
1072 0x80,
1073 0xB3,
1074 0x06);
1075
1076 EXPECT_EQ(error.errorCode, 0xCF);
1077 EXPECT_EQ(error.errorDecode, 0x80);
1078 EXPECT_EQ(error.errorCode1, 0xB3);
1079 EXPECT_EQ(error.errorCode2, 0x06);
1080}
1081
1083TEST_F(PNIOErrorDirectTests, DirectCreateFromCodesPnioPreservesRawCodes)
1084{
1085 const auto error = CreateFromCodes(
1086 0xDB,
1087 0x81,
1088 0x40,
1089 0x04);
1090
1091 EXPECT_EQ(error.errorCode, 0xDB);
1092 EXPECT_EQ(error.errorDecode, 0x81);
1093 EXPECT_EQ(error.errorCode1, 0x40);
1094 EXPECT_EQ(error.errorCode2, 0x04);
1095}
1096
1098TEST_F(PNIOErrorDirectTests, DecodePnioCmErrorAr)
1099{
1100 EXPECT_EQ(DecodePnioCm(static_cast<std::uint8_t>(PnioCmErrorCode1::Ar), 0x00), "Invalid AR type");
1101}
1102
1104TEST_F(PNIOErrorDirectTests, DecodePnioCmErrorArResponse)
1105{
1106 EXPECT_EQ(DecodePnioCm(static_cast<std::uint8_t>(PnioCmErrorCode1::ArResponse), 0x00), "Invalid AR type (in response)");
1107}
1108
1110TEST_F(PNIOErrorDirectTests, DecodePnioCmErrorArActive)
1111{
1112 EXPECT_EQ(DecodePnioCm(static_cast<std::uint8_t>(PnioCmErrorCode1::Ar), 0x01), "AR already active");
1113}
1114
1116TEST_F(PNIOErrorDirectTests, DecodePnioCmErrorArActiveResponse)
1117{
1118 EXPECT_EQ(DecodePnioCm(static_cast<std::uint8_t>(PnioCmErrorCode1::ArResponse), 0x01), "AR already active (in response)");
1119}
1120
1122TEST_F(PNIOErrorDirectTests, DecodePnioCmArErrorNoArResources)
1123{
1124 EXPECT_EQ(GetPnioCmErrorMessage(PnioCmArErrorCode2::NoArResources), "Out of AR resources");
1125}
1126
1128TEST_F(PNIOErrorDirectTests, DecodePnioCmArErrorNoProviderResources)
1129{
1130 EXPECT_EQ(GetPnioCmErrorMessage(PnioCmArErrorCode2::NoProviderResources), "Out of provider resources");
1131}
1132
1134TEST_F(PNIOErrorDirectTests, DecodePnioCmArErrorNoConsumerResources)
1135{
1136 EXPECT_EQ(GetPnioCmErrorMessage(PnioCmArErrorCode2::NoConsumerResources), "Out of consumer resources");
1137}
1138
1140TEST_F(PNIOErrorDirectTests, DecodePnioCmArErrorNoAlarmResources)
1141{
1142 EXPECT_EQ(GetPnioCmErrorMessage(PnioCmArErrorCode2::NoAlarmResources), "Out of alarm resources");
1143}
1144
1146TEST_F(PNIOErrorDirectTests, DecodePnioCmArErrorNoMemory)
1147{
1148 EXPECT_EQ(GetPnioCmErrorMessage(PnioCmArErrorCode2::NoMemory), "Out of memory");
1149}
1150
1152TEST_F(PNIOErrorDirectTests, DecodePnioCmArErrorInvalidSessionKey)
1153{
1154 EXPECT_EQ(GetPnioCmErrorMessage(PnioCmArErrorCode2::InvalidSessionKey), "Invalid session key");
1155}
1156
1158TEST_F(PNIOErrorDirectTests, DecodePnioCmArErrorArUuidConflict)
1159{
1160 EXPECT_EQ(GetPnioCmErrorMessage(PnioCmArErrorCode2::ArUuidConflict), "AR UUID conflict");
1161}
1162
1164TEST_F(PNIOErrorDirectTests, DecodePnioCmArErrorUnknownCode2)
1165{
1166 EXPECT_EQ(GetPnioCmErrorMessage(PnioCmArErrorCode2{0xFF}), "Unknown Error (0xFF)");
1167}
1169TEST_F(PNIOErrorDirectTests, DecodePnioCmErrorIocr)
1170{
1171 EXPECT_EQ(DecodePnioCm(static_cast<std::uint8_t>(PnioCmErrorCode1::Iocr), 0x04), "Invalid IO data length");
1172}
1173
1175TEST_F(PNIOErrorDirectTests, DecodePnioCmErrorIocrResponse)
1176{
1177 EXPECT_EQ(DecodePnioCm(static_cast<std::uint8_t>(PnioCmErrorCode1::IocrResponse), 0x04), "Invalid IO data length (in response)");
1178}
1179
1181TEST_F(PNIOErrorDirectTests, DecodePnioCmErrorAlarmCr)
1182{
1183 EXPECT_EQ(DecodePnioCm(static_cast<std::uint8_t>(PnioCmErrorCode1::AlarmCr), 0x01), "Out of AlarmCR resources");
1184}
1185
1187TEST_F(PNIOErrorDirectTests, DecodePnioCmErrorAlarmCrResponse)
1188{
1189 EXPECT_EQ(DecodePnioCm(static_cast<std::uint8_t>(PnioCmErrorCode1::AlarmCrResponse), 0x01), "Out of AlarmCR resources (in response)");
1190}
1191
1193TEST_F(PNIOErrorDirectTests, DecodePnioCmErrorExpectedSubmodule)
1194{
1195 EXPECT_EQ(DecodePnioCm(static_cast<std::uint8_t>(PnioCmErrorCode1::ExpectedSubmodule), 0x04), "IO data length mismatch");
1196}
1197
1199TEST_F(PNIOErrorDirectTests, DecodePnioCmErrorDevice)
1200{
1201 EXPECT_EQ(DecodePnioCm(static_cast<std::uint8_t>(PnioCmErrorCode1::CmDev), 0x02), "Device already owned");
1202}
1203
1205TEST_F(PNIOErrorDirectTests, DecodePnioCmErrorFaultyBlock)
1206{
1207 EXPECT_EQ(DecodePnioCm(static_cast<std::uint8_t>(PnioCmErrorCode1::FaultyBlock), 0x00), "Faulty block structure");
1208}
1209
1211TEST_F(PNIOErrorDirectTests, DecodePnioCmErrorUnknownCode1)
1212{
1213 EXPECT_EQ(DecodePnioCm(0x0A, 0x00), "Unknown CM error in Unknown (0x0A)");
1214}
1215
1217TEST_F(PNIOErrorDirectTests, DecodePnioErrorRmpm)
1218{
1219 EXPECT_EQ(DecodePnio(static_cast<std::uint8_t>(PnioErrorCode1::Rmpm), 0x02), "Required IOCR block missing");
1220}
1221
1223TEST_F(PNIOErrorDirectTests, DecodePnioErrorPrmServer)
1224{
1225 EXPECT_EQ(DecodePnio(static_cast<std::uint8_t>(PnioErrorCode1::PrmServer), 0x00), "Parameter server state conflict");
1226}
1227
1229TEST_F(PNIOErrorDirectTests, DecodePnioErrorUnknownCode1)
1230{
1231 EXPECT_EQ(DecodePnio(0x0A, 0x00), "Unknown PNIO error");
1232}
1234TEST_F(PNIOErrorDirectTests, DecodePnioRwErrorInvalidIndex)
1235{
1236 EXPECT_EQ(DecodePnioRw(static_cast<std::uint8_t>(PnioRwErrorCode1::InvalidIndex), 0x05), "Index exists but has not been written");
1237}
1238
1240TEST_F(PNIOErrorDirectTests, DecodePnioRwErrorWriteLength)
1241{
1242 EXPECT_EQ(DecodePnioRw(static_cast<std::uint8_t>(PnioRwErrorCode1::WriteLength), 0x03), "Write access denied (write protected)");
1243}
1244
1246TEST_F(PNIOErrorDirectTests, DecodePnioRwErrorResource)
1247{
1248 EXPECT_EQ(DecodePnioRw(static_cast<std::uint8_t>(PnioRwErrorCode1::Resource), 0x08), "Invalid subslot number");
1249}
1250
1252TEST_F(PNIOErrorDirectTests, DecodePnioRwErrorAccess)
1253{
1254 EXPECT_EQ(DecodePnioRw(static_cast<std::uint8_t>(PnioRwErrorCode1::Access), 0x05), "Access denied (invalid state for access)");
1255}
1256
1258TEST_F(PNIOErrorDirectTests, DecodePnioRwErrorApplication)
1259{
1260 EXPECT_EQ(DecodePnioRw(static_cast<std::uint8_t>(PnioRwErrorCode1::Application), 0x08), "Alarm pending");
1261}
1262
1264TEST_F(PNIOErrorDirectTests, DecodePnioRwErrorUnknownCode1)
1265{
1266 EXPECT_EQ(DecodePnioRw(0x0A, 0x00), "Unknown PNIORW error");
1267}
1268} // namespace profinet
Device not found via DCP.
Definition exceptions.h:563
DCP protocol errors.
Definition exceptions.h:539
DCP operation timed out.
Definition exceptions.h:551
static std::string DecodePnio(const std::uint8_t errorCode1, const std::uint8_t errorCode2)
static std::string DecodePnioCm(const std::uint8_t errorCode1, const std::uint8_t errorCode2)
static PNIOError CreateFromCodes(const std::uint8_t errorCode, const std::uint8_t errorDecode, const std::uint8_t errorCode1, const std::uint8_t errorCode2)
static std::string DecodePnioRw(const std::uint8_t errorCode1, const std::uint8_t errorCode2)
PNIO application error with error codes.
Definition exceptions.h:692
static PNIOError CreateFromCodes(std::uint8_t errorCode, std::uint8_t errorDecode, std::uint8_t errorCode1, std::uint8_t errorCode2)
Shared implementation for FromBytes()/FromArgsStatus(): look up the error message and construct the P...
static std::string DecodePnioError(const std::uint8_t &errorCode1, const std::uint8_t &errorCode2)
Decodes a PROFINET IO (PNIO) error.
static std::string DecodePnioRWError(const std::uint8_t &errorCode1, const std::uint8_t &errorCode2)
Decodes a PROFINET Read/Write (PNIO RW) error.
static std::string DecodePnioCmError(const std::uint8_t &errorCode1, const std::uint8_t &errorCode2)
Decodes a PROFINET Communication Manager (CM) error.
static PNIOError FromBytes(std::span< const std::uint8_t, 4 > data)
Create a PNIOError from a raw 4-byte error status.
static PNIOError FromArgsStatus(std::uint32_t argsStatus)
Create a PNIOError from the little-endian ArgsStatus field carried in a DCE/RPC PDU.
Base exception for all PROFINET errors.
Definition exceptions.h:527
Failed to establish RPC connection.
Definition exceptions.h:615
DCE/RPC protocol errors.
Definition exceptions.h:575
RPC returned a fault response.
Definition exceptions.h:599
RPC operation timed out.
Definition exceptions.h:587
Socket operation error.
Definition exceptions.h:663
Input validation error.
Definition exceptions.h:627
Declares exceptions and error types used by the PROFINET IO controller stack.
@ Iocr
IOCRBlock request.
@ AlarmCr
AlarmCRBlock request.
@ Ar
ARBlock request.
@ ArResponse
ARBlock response.
@ CmDev
Connection management device.
@ ExpectedSubmodule
ExpectedSubmoduleBlock request.
@ IocrResponse
IOCRBlock response.
@ AlarmCrResponse
AlarmCRBlock response.
@ FaultyBlock
Faulty block structure.
TEST_F(AlarmListenerTests, InitializesWithEndpoint)
TEST(AlarmEndpointTests, DefaultTransportIsLayer2)
ErrorDecode
PROFINET error decode values.
Definition exceptions.h:22
@ Pnio
General PNIO error.
@ PnioRw
PNIO read/write error.
@ PnioCm
PNIO connection management error.
@ PrmServer
Parameter server error.
@ Rmpm
Runtime parameter and module management (RMPM) error.
std::string GetPnioCmErrorMessage(PnioCmArErrorCode2 errorCode2)
Get the human-readable message for a PNIO-CM AR error.
PnioRwErrorCode1
PNIO read/write ErrorCode1 values.
Definition exceptions.h:46
@ WriteLength
Write length error.
@ Resource
Resource error.
@ Application
Application error.
@ InvalidIndex
Invalid or unsupported index.
PnioCmArErrorCode2
PNIO-CM AR ErrorCode2 values.
Definition exceptions.h:281
@ InvalidSessionKey
The session key is invalid.
@ NoAlarmResources
No alarm resources are available.
@ NoConsumerResources
No consumer resources are available.
@ NoMemory
No memory is available.
@ NoArResources
No AR resources are available.
@ NoProviderResources
No provider resources are available.
@ ArUuidConflict
The AR UUID conflicts with an existing AR.
asio::error_code error