1 /// 2 module modbus.exception; 3 4 import std..string : format; 5 import std.datetime : Duration; 6 7 import modbus.types; 8 9 public import serialport.exception; 10 11 /// 12 class ModbusException : Exception 13 { private this() @safe pure nothrow @nogc { super(""); } } 14 15 /// 16 class CloseTcpConnection : ModbusException 17 { private this() @safe pure nothrow @nogc { super(); } } 18 19 /// 20 class ModbusIOException : ModbusException 21 { 22 /// 23 ulong dev; 24 /// 25 ubyte fnc; 26 27 private this() @safe pure nothrow @nogc { super(); } 28 } 29 30 /// 31 class ModbusDevException : ModbusIOException 32 { 33 /// 34 private ubyte[260] writeBuffer; 35 /// 36 private size_t writeLength; 37 /// 38 private ubyte[260] readBuffer; 39 /// 40 private size_t readLength; 41 42 private this() @safe pure nothrow @nogc { super(); } 43 44 @property 45 { 46 void writed(const(void)[] b) 47 { 48 auto ln = b.length; 49 writeBuffer[0..ln] = cast(ubyte[])(b[0..ln]); 50 writeLength = ln; 51 } 52 53 const(void)[] writed() const 54 { return writeBuffer[0..writeLength]; } 55 56 void readed(const(void)[] b) 57 { 58 auto ln = b.length; 59 readBuffer[0..ln] = cast(ubyte[])(b[0..ln]); 60 readLength = ln; 61 } 62 63 const(void)[] readed() const 64 { return readBuffer[0..readLength]; } 65 } 66 } 67 68 /// 69 class CheckFailException : ModbusDevException 70 { private this() @safe pure nothrow @nogc { super(); } } 71 72 /// 73 class FunctionErrorException : ModbusDevException 74 { 75 /// 76 FunctionErrorCode code; 77 78 private this() @safe pure nothrow @nogc { super(); } 79 } 80 81 /// use this exception for throwing errors in modbus slave 82 class SlaveFuncProcessException : ModbusIOException 83 { 84 /// 85 FunctionErrorCode code; 86 87 private this() @safe pure nothrow @nogc { super(); } 88 } 89 90 /// 91 class ReadDataLengthException : ModbusDevException 92 { 93 /// 94 size_t expected, responseLength; 95 96 private this() @safe pure nothrow @nogc { super(); } 97 } 98 99 private E setFields(E: ModbusException)(E e, string msg, string file, 100 size_t line) 101 { 102 e.msg = msg; 103 e.file = file; 104 e.line = line; 105 return e; 106 } 107 108 private string extraFields(E, string[] fields)() 109 { 110 static if (fields.length == 0) return ""; 111 else 112 { 113 string ret; 114 115 static foreach (field; fields) 116 {{ 117 mixin(`alias ft = typeof(E.init.%s);`.format(field)); 118 ret ~= `%s %s, `.format(ft.stringof, field); 119 }} 120 121 return ret; 122 } 123 } 124 125 unittest 126 { 127 static assert(extraFields!(ModbusIOException, ["dev", "fnc"]) == 128 "ulong dev, ubyte fnc, "); 129 } 130 131 private string extraFieldsSet(string name, string[] fields) 132 { 133 if (fields.length == 0) return ""; 134 135 string ret; 136 137 foreach (field; fields) 138 ret ~= "%1$s.%2$s = %2$s;\n".format(name, field); 139 140 return ret; 141 } 142 143 import std.format; 144 145 enum preallocated; 146 147 private mixin template throwExcMix(E, string[] fields=[]) 148 if (is(E: ModbusException)) 149 { 150 enum name = E.stringof; 151 mixin(` 152 @preallocated 153 private %1$s %2$s%1$s; 154 void throw%1$s(%3$s string msg="", string file=__FILE__, 155 size_t line=__LINE__) @nogc 156 { 157 auto e = %2$s%1$s.setFields(msg, file, line); 158 %4$s 159 throw e; 160 } 161 `.format(name, "prealloc", extraFields!(E,fields), 162 extraFieldsSet("e", fields)) 163 ); 164 } 165 166 mixin throwExcMix!ModbusException; 167 mixin throwExcMix!CloseTcpConnection; 168 mixin throwExcMix!(ModbusIOException, ["dev", "fnc"]); 169 mixin throwExcMix!(ModbusDevException, ["dev", "fnc"]); 170 mixin throwExcMix!(CheckFailException, ["dev", "fnc"]); 171 mixin throwExcMix!(FunctionErrorException, ["dev", "fnc", "code"]); 172 mixin throwExcMix!(SlaveFuncProcessException, ["dev", "fnc", "code"]); 173 mixin throwExcMix!(ReadDataLengthException, ["dev", "fnc", "expected", 174 "responseLength"]); 175 176 static this() 177 { 178 import std.traits : getSymbolsByUDA; 179 static foreach (sym; getSymbolsByUDA!(mixin(__MODULE__), preallocated)) 180 sym = new typeof(sym); 181 }