1 /// 2 module serialport.fiberready; 3 4 import serialport.base; 5 6 import std.traits : isSomeFunction, 7 FunctionAttribute, 8 functionAttributes; 9 10 /++ Serial Port Fiber Ready 11 +/ 12 class SerialPortFR : SerialPort 13 { 14 protected: 15 16 /++ Preform pause 17 18 If sleepFunc isn't null call it. Else use `Thread.sleep` or 19 `Fiber.yield` if code executes in fiber. 20 21 Params: 22 dt = sleep time 23 +/ 24 void sleep(Duration dt) @nogc 25 { 26 if (_sleepFunc is null) msleep(dt); 27 else _sleepFunc(dt); 28 } 29 30 /++ Calc pause for sleep in read and write loops 31 +/ 32 Duration ioPause() @nogc 33 { 34 auto cfg = config; 35 auto cnt = 1 + // start bit 36 cast(int)cfg.dataBits + 37 (cfg.parity == Parity.none ? 0 : 1) + 38 (cfg.stopBits == StopBits.one ? 1 : 39 cfg.stopBits == StopBits.onePointFive ? 1.5 : 2) + 40 1.5 // reserve 41 ; 42 return (cast(ulong)(cnt / cfg.baudRate * 1e6) + 100/+reserve+/).usecs; 43 } 44 45 void delegate(Duration) @nogc _sleepFunc; 46 47 public: 48 /// assume @nogc 49 deprecated 50 alias SleepFunc = void delegate(Duration); 51 52 /// 53 alias SleepFuncNoGC = void delegate(Duration) @nogc; 54 55 /// extended delegate for perform sleep 56 deprecated("sleep function must be @nogc") 57 void sleepFunc(SleepFunc dlg) @property 58 { _sleepFunc = cast(void delegate(Duration) @nogc)dlg; } 59 60 /// 61 deprecated("sleep function must be @nogc") 62 void sleepFunc(void function(Duration) fnc) @property 63 { _sleepFunc = (d){ (cast(void function(Duration) @nogc)fnc)(d); }; } 64 65 /// extended delegate for perform sleep 66 void sleepFunc(void delegate(Duration) @nogc dlg) @property 67 { _sleepFunc = dlg; } 68 69 /// ditto 70 void sleepFunc(void function(Duration) @nogc fnc) @property 71 { _sleepFunc = (d){ fnc(d); }; } 72 73 /// ditto 74 SleepFuncNoGC sleepFunc() @property { return _sleepFunc; } 75 76 /++ Construct SerialPortFR 77 78 See_Also: SerialPort.this 79 +/ 80 deprecated("sleep function must be @nogc") 81 this(F=SleepFunc)(string exmode, F sf) 82 if (isSomeFunction!F && !(functionAttributes!F & FunctionAttribute.nogc)) 83 { sleepFunc = sf; super(exmode); } 84 85 /// ditto 86 deprecated("sleep function must be @nogc") 87 this(F=SleepFunc)(string port, string mode, F sf) 88 if (isSomeFunction!F && !(functionAttributes!F & FunctionAttribute.nogc)) 89 { sleepFunc = sf; super(port, mode); } 90 91 /// ditto 92 deprecated("sleep function must be @nogc") 93 this(F=SleepFunc)(string port, uint baudRate, F sf) 94 if (isSomeFunction!F && !(functionAttributes!F & FunctionAttribute.nogc)) 95 { sleepFunc = sf; super(port, baudRate); } 96 97 /// ditto 98 deprecated("sleep function must be @nogc") 99 this(F=SleepFunc)(string port, uint baudRate, string mode, F sf) 100 if (isSomeFunction!F && !(functionAttributes!F & FunctionAttribute.nogc)) 101 { sleepFunc = sf; super(port, baudRate, mode); } 102 103 /// ditto 104 deprecated("sleep function must be @nogc") 105 this(F=SleepFunc)(string port, Config conf, F sf) 106 if (isSomeFunction!F && !(functionAttributes!F & FunctionAttribute.nogc)) 107 { sleepFunc = sf; super(port, conf); } 108 109 /// ditto 110 this(F=SleepFuncNoGC)(string exmode, F sf=null) 111 if (isSomeFunction!F) 112 { sleepFunc = sf; super(exmode); } 113 114 /// ditto 115 this(F=SleepFuncNoGC)(string port, string mode, F sf=null) 116 if (isSomeFunction!F && (functionAttributes!F & FunctionAttribute.nogc)) 117 { sleepFunc = sf; super(port, mode); } 118 119 /// ditto 120 this(F=SleepFuncNoGC)(string port, uint baudRate, F sf=null) 121 if (isSomeFunction!F && (functionAttributes!F & FunctionAttribute.nogc)) 122 { sleepFunc = sf; super(port, baudRate); } 123 124 /// ditto 125 this(F=SleepFuncNoGC)(string port, uint baudRate, string mode, F sf=null) 126 if (isSomeFunction!F && (functionAttributes!F & FunctionAttribute.nogc)) 127 { sleepFunc = sf; super(port, baudRate, mode); } 128 129 /// ditto 130 this(F=SleepFuncNoGC)(string port, Config conf, F sf=null) 131 if (isSomeFunction!F && (functionAttributes!F & FunctionAttribute.nogc)) 132 { sleepFunc = sf; super(port, conf); } 133 134 override void[] read(void[] buf, CanRead cr=CanRead.allOrNothing) 135 { 136 if (closed) throwPortClosedException(port); 137 138 size_t res; 139 const timeout = buf.length * readTimeoutMult + readTimeout; 140 const pause = ioPause(); 141 const sw = StopWatch(AutoStart.yes); 142 while (sw.peek < timeout) 143 { 144 res += m_read(buf[res..$]).length; 145 if (res == buf.length) return buf[]; 146 this.sleep(pause); 147 } 148 149 checkAbility(cr, res, buf.length); 150 151 return buf[0..res]; 152 } 153 154 override void write(const(void[]) arr) 155 { 156 if (closed) throwPortClosedException(port); 157 158 size_t written; 159 const timeout = arr.length * writeTimeoutMult + writeTimeout; 160 const pause = ioPause(); 161 const sw = StopWatch(AutoStart.yes); 162 while (sw.peek < timeout) 163 { 164 written += m_write(arr[written..$]); 165 if (written == arr.length) return; 166 this.sleep(pause); 167 } 168 169 throwTimeoutException(port, "write timeout"); 170 } 171 172 /++ Read data while available by parts, sleep between checks. 173 174 Sleep time calculates from baud rate and count of bits in one byte. 175 176 ------- 177 ------|--------|-----|------------|-----|------------> t 178 call | | | | 179 readContinues | | | | 180 | | | | | 181 | |<---------data receive---------->| 182 | |=== ===== ======| | |== =| data stream 183 | | | | | | | 184 |<--timeout--->| | | | | 185 | |<-1->| |<2>| |<-3->| 186 | | | | 187 | |<---readedData--->| | 188 | return 189 |<-------readAll work time------->| 190 191 (1) if readedData.length > 0 then continue reading 192 else if expectAnything throw TimeoutException 193 else return readedData (empty) 194 (2) silent time, if silent < frameGap then continue reading 195 (3) else if silent > frameGap then stop reading 196 and return readedData 197 ------- 198 199 Params: 200 buf = buffer for reading 201 startTimeout = timeout for first byte recive 202 frameGap = detect new data frame by silence period 203 expectAnything = function throw exception if no data 204 before startTimeout 205 206 Returns: slice of buf with readed data 207 208 Throws: 209 PortClosedException 210 ReadException 211 TimeoutException 212 213 See_Also: SerialPort.read 214 +/ 215 void[] readContinues(void[] buf, Duration startTimeout=1.seconds, 216 Duration frameGap=50.msecs, 217 bool expectAnything=true) 218 { 219 if (closed) throwPortClosedException(port); 220 221 ptrdiff_t readed; 222 223 auto pause = ioPause(); 224 225 StopWatch silence, full; 226 227 full.start(); 228 while (true) 229 { 230 const res = m_read(buf[readed..$]).length; 231 232 readed += res; 233 234 // buffer filled 235 if (readed == buf.length) return buf[]; 236 237 if (res == 0) 238 { 239 if (readed > 0 && silence.peek > frameGap) 240 return buf[0..readed]; 241 242 if (!silence.running) silence.start(); 243 } 244 else 245 { 246 silence.stop(); 247 silence.reset(); 248 } 249 250 if (readed == 0 && full.peek > startTimeout) 251 { 252 if (expectAnything) 253 throwTimeoutException(port, "read timeout"); 254 else 255 return buf[0..0]; 256 } 257 258 this.sleep(pause); 259 } 260 } 261 }