|
TStateMachine = class(TThread) public ControlTable:TStringlist; Fields:TStringlist; ActualState:string; Inputs:string; Outputs:string; pExtIOMap:TPString; InputMap:string; OutputMap:string; constructor Create(ExtIOMap:TPString;CStartState,CInputMap,COutputMap:string); destructor Destroy; procedure Execute; override; procedure MakeFields(InS:string; Separator:char; var Fields:TStringList); procedure RefreshState; procedure GetInputSlot; procedure SetOutputSlot; end; |
|
constructor TStateMachine.Create(ExtIOMap:TPString;CStartState,CInputMap,COutputMap:string); begin inherited Create(true); ActualState:=CStartState; pExtIOMAp:=ExtIOMap; InputMap:=CInputMap; OutputMap:=COutputMap; ControlTable:=TStringlist.Create; ControlTable.Clear; Fields:=TStringlist.Create; end; |
|
destructor TStateMachine.Destroy; begin Fields.Destroy; ControlTable.Destroy; inherited Destroy; end; |
|
procedure TStateMachine.Execute; var i:integer; begin synchronize(GetInputSlot); for i:=0 to ControlTable.Count-1 do begin MakeFields(ControlTable[i],'/',Fields); if ActualState=Fields[3] then begin Outputs:=Fields[2]; synchronize(SetOutputSlot); break; end; end; while not(Terminated) do RefreshState; end; |
|
procedure TStateMachine.RefreshState; var i:integer; begin sleep(1); synchronize(GetInputSlot); for i:=0 to ControlTable.Count-1 do if pos(ActualState+'/',ControlTable[i])=1 then begin Makefields(ControlTable[i],'/',Fields); if Inputs=Fields[1] then begin ActualState:=Fields[3]; Outputs:=Fields[2]; synchronize(SetOutputSlot); end; end; end; |
|
procedure TStateMachine.GetInputSlot; var i:integer; index:integer; begin index:=1; Inputs:=''; for i:=1 to length(InputMap) div 2 do begin Inputs:=Inputs+pExtIOMAp^[strtoint(copy(InputMap,index,2))]; inc(index,2); end; end; procedure TStateMachine.SetOutputSlot; var i:integer; index:integer; begin index:=1; for i:=1 to length(OutputMap) div 2 do begin pExtIOMAp^[strtoint(copy(OutputMap,index,2))]:=Outputs[i]; inc(index,2); end; end; |
|
procedure TStateMachine.MakeFields(InS:string; Separator:char; var Fields:TStringList); var SepaPositions:array[0..100] of integer; Indx:integer; i:integer; begin Indx:=0; InS:=Separator+InS+Separator; for i:=1 to length(InS) do if InS[i]=Separator then begin inc(Indx); SepaPositions[Indx]:=i; end; Fields.Clear; for i:=1 to Indx-1 do begin Fields.Add(copy(InS,SepaPositions[i]+1,SepaPositions[i+1]-SepaPositions[i]-1)); end; end; |
|
const MSWITCH_A = '01'; MSWITCH_B = '02'; MSWITCH_C = '03'; MSWITCH_D = '04'; VIRTUAL_W = '05'; TIMEOUT_T = '06'; REDLED_L = '07'; REDLED_R = '08'; GREENLED_G = '09'; RESETTMR_S = '10'; CRGATE_N = '11'; CRGATE_Z = '12'; CRGATE_F = '13'; CRGATE_E = '14'; RESETTMR_P = '15'; TIMEOUT_Q = '16'; GATE_OPENED = 120; GATE_CLOSED = 10; CI4A_HOST = 'localhost'; CI4A_IO_PORT = 7500; BIT0 = 8; BIT1 = 7; BIT2 = 6; BIT3 = 5; BIT4 = 4; BIT5 = 3; BIT6 = 2; BIT7 = 1; |
|
public IOMap:string; SERVO_POS:byte; PREV_OUT_LEDS,PREV_SERVO_POS:string; SM_PROC,SM_BLINK,SM_MOVE:TStateMachine; procedure RefreshScreenOuts; procedure SendDataToCI4A; function ByteStr2ValueStr(InStr:string):string; function ValueStr2ByteStr(InStr:string):string; end; |
|
procedure TForm1.FormCreate(Sender: TObject); begin IOCtrlSocket.Host:=CI4A_HOST; IOCtrlSocket.Port:=CI4A_IO_PORT; IOCtrlSocket.Active:=true; PREV_OUT_LEDS:=''; PREV_SERVO_POS:=''; IOMap:='0000000000000000'; SERVO_POS:=GATE_OPENED; SM_PROC:=TStateMachine.Create(@Form1.IOMap,'0000',MSWITCH_A+MSWITCH_B+MSWITCH_C +MSWITCH_D,VIRTUAL_W); SM_PROC.ControlTable.Add('0000/0001/0/0100'); SM_PROC.ControlTable.Add('0000/0010/0/0001'); SM_PROC.ControlTable.Add('0001/0001/0/0011'); SM_PROC.ControlTable.Add('0011/0000/0/0000'); SM_PROC.ControlTable.Add('0010/0010/1/0001'); SM_PROC.ControlTable.Add('0101/0100/1/0010'); SM_PROC.ControlTable.Add('0000/1000/0/0101'); SM_PROC.ControlTable.Add('0100/0010/1/0111'); SM_PROC.ControlTable.Add('0000/0100/0/1000'); SM_PROC.ControlTable.Add('0111/0100/1/1000'); SM_PROC.ControlTable.Add('1000/1000/0/0110'); SM_PROC.ControlTable.Add('0110/0000/0/0000'); SM_PROC.Resume; SM_BLINK:=TStateMachine.Create(@Form1.IOMap,'011',VIRTUAL_W+TIMEOUT_T+REDLED_L +REDLED_R+GREENLED_G,REDLED_L+REDLED_R+GREENLED_G+RESETTMR_S); SM_BLINK.ControlTable.Add('011/01000/0001/000'); SM_BLINK.ControlTable.Add('000/00000/0010/010'); SM_BLINK.ControlTable.Add('010/01001/0011/000'); SM_BLINK.ControlTable.Add('000/00001/0000/011'); SM_BLINK.ControlTable.Add('011/10000/0100/100'); SM_BLINK.ControlTable.Add('100/00010/0000/011'); SM_BLINK.ControlTable.Add('100/11010/0101/000'); SM_BLINK.ControlTable.Add('000/10100/0100/100'); SM_BLINK.ControlTable.Add('001/11100/1001/000'); SM_BLINK.ControlTable.Add('000/10010/1000/001'); SM_BLINK.ControlTable.Add('010/10001/1000/001'); SM_BLINK.ControlTable.Add('001/00100/0010/010'); SM_BLINK.Resume; SM_MOVE:=TStateMachine.Create(@Form1.IOMap,'00',VIRTUAL_W+TIMEOUT_Q+CRGATE_N+CRGATE_Z, CRGATE_F+CRGATE_E+RESETTMR_P); SM_MOVE.ControlTable.Add('00/1110/011/01'); SM_MOVE.ControlTable.Add('01/1000/010/11'); SM_MOVE.ControlTable.Add('11/1100/011/01'); SM_MOVE.ControlTable.Add('00/0101/101/10'); SM_MOVE.ControlTable.Add('10/0000/100/11'); SM_MOVE.ControlTable.Add('11/0100/101/10'); SM_MOVE.ControlTable.Add('01/1101/000/00'); SM_MOVE.ControlTable.Add('10/0110/000/00'); SM_MOVE.Resume; end; |
|
procedure TForm1.BlinkTimerTimer(Sender: TObject); begin if IOMAP[strtoint(RESETTMR_S)]='1' then begin IOMAP[strtoint(RESETTMR_S)]:='0'; IOMAP[strtoint(TIMEOUT_T)]:='0'; BlinkTimer.Tag:=0; end; BlinkTimer.Tag:=BlinkTimer.Tag+10; if BlinkTimer.Tag>=700 then begin IOMAP[strtoint(TIMEOUT_T)]:='1'; end; end; procedure TForm1.MoveTimerTimer(Sender: TObject); begin if IOMAP[strtoint(RESETTMR_P)]='1' then begin IOMAP[strtoint(RESETTMR_P)]:='0'; IOMAP[strtoint(TIMEOUT_Q)]:='0'; MoveTimer.Tag:=0; if IOMAP[strtoint(CRGATE_F)]='1' then inc(SERVO_POS,1); if IOMAP[strtoint(CRGATE_E)]='1' then dec(SERVO_POS,1); end; MoveTimer.Tag:=MoveTimer.Tag+1; if MoveTimer.Tag>=5 then begin IOMAP[strtoint(TIMEOUT_Q)]:='1'; end; if SERVO_POS=GATE_OPENED then IOMAP[strtoint(CRGATE_N)]:='1' else IOMAP[strtoint(CRGATE_N)]:='0'; if SERVO_POS=GATE_CLOSED then IOMAP[strtoint(CRGATE_Z)]:='1' else IOMAP[strtoint(CRGATE_Z)]:='0'; end; |
|
procedure TForm1.OutUpdTimer(Sender: TObject); begin RefreshScreenOuts; SendDataToCI4A; end; procedure TForm1.RefreshScreenOuts; begin if IOMAP[strtoint(GREENLED_G)]='1' then Shape3.Brush.Color:=ClGreen; if IOMAP[strtoint(GREENLED_G)]='0' then Shape3.Brush.Color:=ClWhite; if IOMAP[strtoint(REDLED_L)]='1' then Shape1.Brush.Color:=ClRed; if IOMAP[strtoint(REDLED_L)]='0' then Shape1.Brush.Color:=ClWhite; if IOMAP[strtoint(REDLED_R)]='1' then Shape2.Brush.Color:=ClRed; if IOMAP[strtoint(REDLED_R)]='0' then Shape2.Brush.Color:=ClWhite; Label1.Caption:=inttostr(SERVO_POS); end; procedure TForm1.SendDataToCI4A; var OutByteStr,OutValStr:string; begin if IOCtrlSocket.Socket.Connected then begin OutByteStr:='00000000'; OutByteStr[BIT1]:=IOMAP[strtoint(REDLED_L)]; OutByteStr[BIT2]:=IOMAP[strtoint(REDLED_R)]; OutByteStr[BIT3]:=IOMAP[strtoint(GREENLED_G)]; if OutByteStr<>PREV_OUT_LEDS then begin IOCtrlSocket.Socket.SendText('S0OB01V'+ByteStr2ValueStr(OutByteStr)+chr(13)); PREV_OUT_LEDS:=OutByteStr; sleep(10); end; OutValStr:=inttostr(SERVO_POS); if length(OutValStr)=1 then OutValStr:='00'+OutValStr; if length(OutValStr)=2 then OutValStr:='0'+OutValStr; if OutValStr<>PREV_SERVO_POS then begin IOCtrlSocket.Socket.SendText('S2OB01V'+OutValStr+chr(13)); PREV_SERVO_POS:=OutValStr; sleep(10); end; end; end; |
|
procedure TForm1.IOCtrlSocketRead(Sender: TObject; Socket: TCustomWinSocket); var InStr,InByteStr:string; begin InStr:=Socket.ReceiveText; if copy(InStr,1,7)='S0IB01V' then begin InByteStr:=ValueStr2ByteStr(copy(InStr,8,3)); IOMAP[strtoint(MSWITCH_A)]:=InByteStr[BIT0]; IOMAP[strtoint(MSWITCH_B)]:=InByteStr[BIT1]; IOMAP[strtoint(MSWITCH_C)]:=InByteStr[BIT2]; IOMAP[strtoint(MSWITCH_D)]:=InByteStr[BIT3]; end; end; |
|
procedure TForm1.ButtonDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var psa,psb,psc,psi:string; begin if Sender=Button_A then IOMap[strtoint(MSWITCH_A)]:='1'; if Sender=Button_B then IOMap[strtoint(MSWITCH_B)]:='1'; if Sender=Button_C then IOMap[strtoint(MSWITCH_C)]:='1'; if Sender=Button_D then IOMap[strtoint(MSWITCH_D)]:='1'; end; procedure TForm1.ButtonUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin if Sender=Button_A then IOMap[strtoint(MSWITCH_A)]:='0'; if Sender=Button_B then IOMap[strtoint(MSWITCH_B)]:='0'; if Sender=Button_C then IOMap[strtoint(MSWITCH_C)]:='0'; if Sender=Button_D then IOMap[strtoint(MSWITCH_D)]:='0'; end; |
|
procedure TForm1.IOCtrlSocketConnecting(Sender: TObject; Socket: TCustomWinSocket); begin Memo1.Lines.Add('Trying to connect to CI4A IO interface'); end; procedure TForm1.IOCtrlSocketConnect(Sender: TObject; Socket: TCustomWinSocket); begin Memo1.Lines.Add('CWB controller connected to CI4A IO interface'); end; procedure TForm1.IOCtrlSocketDisconnect(Sender: TObject; Socket: TCustomWinSocket); begin Memo1.Lines.Add('CWB controller disconnected from CI4A IO interface'); end; procedure TForm1.IOCtrlSocketError(Sender: TObject; Socket: TCustomWinSocket; ErrorEvent: TErrorEvent; var ErrorCode: Integer); begin Memo1.Lines.Add('IO socket error:'+inttostr(ErrorCode)); ErrorCode:=0; end; |
|
function TForm1.ByteStr2ValueStr(InStr:string):string; var i:integer; res:string; depo:byte; begin depo:=0; for i:=1 to 8 do if InStr[i]='1' then depo:=depo+byte(trunc(power(2,8-i))); res:=inttostr(depo); if length(res)=1 then res:='00'+res; if length(res)=2 then res:='0'+res; ByteStr2ValueStr:=res; end; function TForm1.ValueStr2ByteStr(InStr:string):string; var i:integer; depo,h:byte; res:string; begin res:=''; depo:=byte(strtoint(InStr)); for i:=7 downto 0 do begin h:=byte(trunc(power(2,i))); res:=res+inttostr((depo and h) div h); end; ValueStr2ByteStr:=res; end; |
|
procedure TForm1.FormDestroy(Sender: TObject); begin SM_PROC.Terminate; SM_BLINK.Terminate; SM_MOVE.Terminate; if IOCtrlSocket.Socket.Connected then IOCtrlSocket.Active:=false; end; |
|
|
Sorompó videó 1 (wmv 6.9MB) |
|
Sorompó videó 2 (wmv 16.7MB) |
class _Options: """Checks and stores command line options and arguments.""" def __init__(self, commandLine): """Initialize option defaults, start parse""" self._server = None self._portnum = 0 self._logname = None self._logwrite = False self._parseCommandLine(commandLine) def _parseCommandLine(self, commandLine): """Parsing command line, reading switches and parameters""" options, arguments = getopt.getopt(commandLine, "S:p:l:") if not options: raise Exception("ARGS_MISSED") for option in options: if option[0] == "-S": self._server = option[1] if option[0] == "-p": self._portnum = int(option[1]) if option[0] == "-l": self._logwrite = True self._logname = option[1] if not(self._server and self._portnum): raise Exception("ARGS_MISSED") |
class _Debug: """Debugger class""" def __init__(self, options, timewrite): """Open and append logfile for debugging""" self._timewrite = timewrite self._options = options def WriteToLog(self, text): """Write a debug string to logfile""" if self._options._logwrite: self._logfile = open(self._options._logname, "a") if self._timewrite: self._logfile.write(time.strftime('%X %x %Z')+" > ") self._logfile.write(text) self._logfile.close() |
class _TrafficLight: """Traffic light data and statechange times""" def __init__(self, Debug): self.Debug = Debug self.OutputData = \ { "N|N" : "S0OB01V000", "R|G" : "S0OB01V033", "R|Y" : "S0OB01V034", "R|R" : "S0OB01V036", "RY|R" : "S0OB01V052", "G|R" : "S0OB01V012", "Y|R" : "S0OB01V020", "R|RY" : "S0OB01V038", "Y|Y" : "S0OB01V018" } self.Normal = \ { 0 : "R|G", 10 : "R|Y", 12 : "R|R", 13 : "RY|R", 14 : "G|R", 25 : "Y|R", 26 : "R|R", 27 : "R|RY" } self.Semi = \ { 0 : "N|N", 1 : "Y|Y" } self.Off = \ { 0 : "N|N", 1 : "N|N" } def getoutputdata(self, TCRindex, Mode): dict = getattr(self, Mode) return self.OutputData.get(dict.get(TCRindex, "NOTHING"),"DO_NOTHING") |
class _WorkingThread(threading.Thread): def __init__(self, TCR, TrafficLight, CI4AComm, Debug): threading.Thread.__init__(self) self.RunFlag = True self.Mode = 'Off' self.TCR = TCR self.TrafficLight = TrafficLight self.CI4AComm = CI4AComm self.Debug = Debug self.Action = '' self.Debug.WriteToLog("working thread started\n") def run(self): Input = '' while self.RunFlag: Action = self.TrafficLight.getoutputdata(self.TCR.gettimecode(), self.Mode) if (Action != "DO_NOTHING") and (Action != self.Action): self.Debug.WriteToLog("sended command to CI4A: %s\n"%Action) self.CI4AComm.send(Action+'\r') self.Action = Action if self.CI4AComm.getinputflag(): Input = self.CI4AComm.getinputdata() self.CI4AComm.clearinputflag() self.Debug.WriteToLog('received command from CI4A: %s\n'%Input) if Input == 'S0IB01V001\r': self.setmode('Normal') if Input == 'S0IB01V002\r': self.setmode('Semi') if Input == 'S0IB01V004\r': self.setmode('Off') if Input == 'S0IB01V008\r': self.RunFlag = False time.sleep(0.1) def stop(self): self.RunFlag = False def setmode(self, Mode): self.Mode = Mode self.Debug.WriteToLog("change mode to %s\n"%Mode) if self.Mode == 'Normal': self.TCR.changereload(29) if (self.Mode == 'Semi') or (self.Mode == 'Off'): self.TCR.changereload(2) |
class _TCRThread(threading.Thread): def __init__(self, debug): threading.Thread.__init__(self) self.RunFlag = True self.TCR = 0 self.Reload = 100 self.Debug = debug self.Debug.WriteToLog("time code generator thread started\n") def run(self): while self.RunFlag: self.TCR += 1 if self.Reload <= self.TCR: self.TCR = 0 time.sleep(1) def stop(self): self.RunFlag = False def changereload(self, Value): self.TCR = 0 self.Reload = Value def gettimecode(self): return self.TCR |
class _CI4ACommThread(threading.Thread): def __init__(self, options, debug): threading.Thread.__init__(self) self.RunFlag = True self.InputFlag = False self.Comm = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: self.Comm.connect((options._server, options._portnum)) except: debug.WriteToLog("CI4A server not available on %s:%d\n"%(options._server, options._portnum)) debug.WriteToLog("tlctrl stopped with error\n\n") raise Exception("ERROR_IN_LOG") debug.WriteToLog("CI4A communication thread started\n") def run(self): while self.RunFlag: i, o, e = select.select([self.Comm], [], [], 0.01) for x in i: self.Input = x.recv(20) if self.Input: self.InputFlag = True self.Comm.close() def stop(self): self.RunFlag = False def send(self, text): self.Comm.send(text) def getinputflag(self): return(self.InputFlag) def clearinputflag(self): self.InputFlag = False def getinputdata(self): return(self.Input) def disconnect(self): self.Comm.disconnect() |
if __name__ == "__main__": """Main program""" exitCode = 0 try: Options = _Options(sys.argv[1:]) Debug = _Debug(Options, True) Debug.WriteToLog('tlctrl started\n') TrafficLight = _TrafficLight(Debug) CI4AComm = _CI4ACommThread(Options, Debug) CI4AComm.start() TCR = _TCRThread(Debug) TCR.start() WORKING = _WorkingThread(TCR, TrafficLight, CI4AComm, Debug) WORKING.start() while WORKING.RunFlag: time.sleep(0.1) CI4AComm.stop() TCR.stop() Debug.WriteToLog('tlctrl stopped normally\n\n') except Exception, e: if "ARGS_MISSED" in e.args: exitCode = 1 print print __doc__ print if "ERROR_IN_LOG" in e.args: exitCode = 2 print "Error, tlctrl stopped, see debug log for details!" sys.exit(exitCode) |
|
|
Közlekedési lámpa videó (wmv 11.6MB) |