1 ///
2 module modbus.exception;
3 
4 import std.string : format;
5 
6 enum MINIMUM_MODBUS_MSG_LENGTH = 5;
7 
8 ///
9 class ModbusException : Exception
10 {
11     ///
12     this(string msg, string file=__FILE__, size_t line=__LINE__)
13         @nogc @safe pure nothrow
14     { super(msg, file, line); }
15 }
16 
17 ///
18 class ModbusDevException : ModbusException
19 {
20     ///
21     ulong dev;
22     ///
23     ubyte fnc;
24     ///
25     this(ulong dev, ubyte fnc, string msg, string file=__FILE__, size_t line=__LINE__)
26     {
27         this.dev = dev;
28         this.fnc = fnc;
29         super(msg, file, line);
30     }
31 }
32 
33 ///
34 class CheckCRCException : ModbusDevException
35 {
36     ///
37     this(ulong dev, ubyte fnc, string file=__FILE__, size_t line=__LINE__)
38     {
39         super(dev, fnc, format("dev %d fnc %d(0x%x) recive msg CRC check fails",
40                     dev, fnc, fnc), file, line);
41     }
42 }
43 
44 ///
45 class FunctionErrorException : ModbusDevException
46 {
47     ///
48     ubyte res;
49     ///
50     FunctionErrorCode code;
51 
52     ///
53     this(ulong dev, ubyte fnc, ubyte res, ubyte code,
54             string file=__FILE__, size_t line=__LINE__)
55     {
56         this.res = res;
57         this.code = cast(FunctionErrorCode)code;
58 
59         super(dev, fnc, format("dev %d fnc %d(0x%x) recive fnc %d(0x%x) with exception code %s (%d)",
60         dev, fnc, fnc, res, res, code, code), file, line);
61     }
62 }
63 
64 ///
65 class ReadDataLengthException : ModbusDevException
66 {
67     size_t expected, responseLength;
68     ///
69     this(ulong dev, ubyte fnc, size_t exp, size_t res,
70             string file=__FILE__, size_t line=__LINE__)
71     {
72         expected = exp;
73         responseLength = res;
74         super(dev, fnc, format("dev %d fnc to %d(0x%x) recieves wrong"~
75                     " count of bytes (%d != expected %d or more what %d)",
76                     dev, fnc, fnc, res, exp, MINIMUM_MODBUS_MSG_LENGTH), file, line);
77     }
78 }
79 
80 ///
81 enum FunctionErrorCode : ubyte
82 {
83     ILLEGAL_FUNCTION     = 1, /// 1
84     ILLEGAL_DATA_ADDRESS = 2, /// 2
85     ILLEGAL_DATA_VALUE   = 3, /// 3
86     SLAVE_DEVICE_FAILURE = 4, /// 4
87     ACKNOWLEDGE          = 5, /// 5
88     SLAVE_DEVICE_BUSY    = 6, /// 6
89     MEMORY_PARITY_ERROR  = 8, /// 8
90     GATEWAY_PATH_UNAVAILABLE = 0xA, /// 0xA
91     GATEWAY_TARGET_DEVICE_FAILED_TO_RESPOND = 0xB, /// 0xB
92 }
93 
94 private version (modbus_use_prealloc_exceptions)
95 {
96     __gshared
97     {
98         auto preallocModbusException = new ModbusException("many args");
99         auto preallocCheckCRCException = new CheckCRCException(0, 0);
100         auto preallocReadDataLengthException = new ReadDataLengthException(0,0,0,0);
101         auto preallocFunctionErrorException = new FunctionErrorException(0,0,0,0);
102     }
103 }
104 
105 /// Returns: preallocated exception with new values of fields
106 ModbusException modbusException()(string msg, string file=__FILE__, size_t line=__LINE__)
107 {
108     version (modbus_use_prealloc_exceptions)
109     {
110         preallocModbusException.msg = msg;
111         preallocModbusException.file = file;
112         preallocModbusException.line = line;
113         return preallocModbusException;
114     }
115     else return new ModbusException(msg, file, line);
116 }
117 
118 /// Returns: preallocated exception with new values of fields
119 CheckCRCException checkCRCException()(ulong dev, ubyte fnc,
120                                     string file=__FILE__, size_t line=__LINE__)
121 {
122     version (modbus_use_prealloc_exceptions)
123     {
124         preallocCheckCRCException.msg = "check CRC fails";
125         preallocCheckCRCException.dev = dev;
126         preallocCheckCRCException.fnc = fnc;
127         preallocCheckCRCException.file = file;
128         preallocCheckCRCException.line = line;
129         return preallocCheckCRCException;
130     }
131     else return new CheckCRCException(dev, fnc, file, line);
132 }
133 
134 /// Returns: preallocated exception with new values of fields
135 FunctionErrorException functionErrorException()(ulong dev, ubyte fnc, ubyte res, ubyte code,
136                                                 string file=__FILE__, size_t line=__LINE__)
137 {
138     version (modbus_use_prealloc_exceptions)
139     {
140         preallocFunctionErrorException.msg = "error while read function response";
141         preallocFunctionErrorException.dev = dev;
142         preallocFunctionErrorException.fnc = fnc;
143         preallocFunctionErrorException.res = res;
144         preallocFunctionErrorException.code = cast(FunctionErrorCode)code;
145         preallocFunctionErrorException.file = file;
146         preallocFunctionErrorException.line = line;
147         return preallocFunctionErrorException;
148     }
149     else return new FunctionErrorException(dev, fnc, res, code, file, line);
150 }
151 
152 /// Returns: preallocated exception with new values of fields
153 ReadDataLengthException readDataLengthException()(ulong dev, ubyte fnc, size_t exp, size_t res,
154                                                 string file=__FILE__, size_t line=__LINE__)
155 {
156     version (modbus_use_prealloc_exceptions)
157     {
158         preallocReadDataLengthException.msg = "error while read function response: wrong length";
159         preallocReadDataLengthException.dev = dev;
160         preallocReadDataLengthException.fnc = fnc;
161         preallocReadDataLengthException.expected = exp;
162         preallocReadDataLengthException.responseLength = res;
163         preallocReadDataLengthException.file = file;
164         preallocReadDataLengthException.line = line;
165         return preallocReadDataLengthException;
166     }
167     else return new ReadDataLengthException(dev, fnc, exp, res, file, line);
168 }