def _startup_i2c_clock(self): while self.lib.dgtpicom_init() < 0: logging.warning('Init() failed - Jack half connected?') MsgDisplay.show(Message.DGT_JACK_ERROR()) time.sleep(0.5) # dont flood the log if self.lib.dgtpicom_configure() < 0: logging.warning('Configure() failed - Jack connected back?') MsgDisplay.show(Message.DGT_JACK_ERROR()) MsgDisplay.show(Message.DGT_CLOCK_VERSION(main=2, sub=2, dev='i2c', text=None))
def _setup_serial_port(self): def _success(device: str): self.device = device logging.debug('(ser) board connected to %s', self.device) return True waitchars = ['/', '-', '\\', '|'] if self.watchdog_timer.is_running(): logging.debug('watchdog timer is stopped now') self.watchdog_timer.stop() if self.serial: return True with self.lock: if self.given_device: if self._open_serial(self.given_device): return _success(self.given_device) else: for file in listdir('/dev'): if file.startswith('ttyACM') or file.startswith('ttyUSB') or file == 'rfcomm0': dev = path.join('/dev', file) if self._open_serial(dev): return _success(dev) if self._open_bluetooth(): return _success('/dev/rfcomm123') # text = self.dgttranslate.text('N00_noboard', 'Board' + waitchars[self.wait_counter]) bwait = 'Board' + waitchars[self.wait_counter] text = Dgt.DISPLAY_TEXT(l='no e-' + bwait, m='no' + bwait, s=bwait, wait=True, beep=False, maxtime=0.1, devs={'i2c', 'web'}) MsgDisplay.show(Message.DGT_EBOARD_ERROR(text=text)) self.wait_counter = (self.wait_counter + 1) % len(waitchars) return False
def display_move_on_clock(self, message): """Display a move on the web clock.""" is_new_rev2 = self.dgtboard.is_revelation and self.dgtboard.enable_revelation_pi if self.enable_dgt3000 or is_new_rev2 or self.enable_dgtpi: bit_board, text = self.get_san(message, not self.enable_dgtpi) points = '...' if message.side == ClockSide.RIGHT else '.' if self.enable_dgtpi: text = '{:3d}{:s}{:s}'.format(bit_board.fullmove_number, points, text) else: text = '{:2d}{:s}{:s}'.format(bit_board.fullmove_number % 100, points, text) else: text = message.move.uci() if message.side == ClockSide.RIGHT: text = text[:2].rjust(3) + text[2:].rjust(3) else: text = text[:2].ljust(3) + text[2:].ljust(3) if self.get_name() not in message.devs: logging.debug('ignored %s - devs: %s', text, message.devs) return True self.clock_show_time = False self._create_clock_text() logging.debug('[%s]', text) self.shared['clock_text'] = text result = {'event': 'Clock', 'msg': text} DisplayMsg.show(Message.DISPLAY_TEXT(text=result)) EventHandler.write_to_clients(result) return True
def process_console_command(self, raw): cmd = raw.lower() try: # Here starts the simulation of a dgt-board! # Let the user send events like the board would do if cmd.startswith('fen:'): fen = raw.split(':')[1].strip() # dgt board only sends the basic fen => be sure it's same no matter what fen the user entered fen = fen.split(' ')[0] bit_board = chess.Board() # valid the fen bit_board.set_board_fen(fen) EvtObserver.fire(Event.KEYBOARD_FEN(fen=fen)) # end simulation code elif cmd.startswith('go'): if 'last_dgt_move_msg' in self.shared: fen = self.shared['last_dgt_move_msg']['fen'].split(' ')[0] EvtObserver.fire(Event.KEYBOARD_FEN(fen=fen)) # TEST webserver with 2 clocks (web & i2c) - doesnt work anymore with normal dgt board! elif cmd.startswith('but:'): button = raw.split(':')[1].strip() MsgDisplay.show(Message.DGT_BUTTON(button=button, dev='i2c')) else: # Event.KEYBOARD_MOVE tranfers "move" to "fen" and then continues with "Message.DGT_FEN" move = chess.Move.from_uci(cmd) EvtObserver.fire(Event.KEYBOARD_MOVE(move=move)) except (ValueError, IndexError): logging.warning('Invalid user input [%s]', raw)
def __init__(self, shared, dgtboard: DgtBoard): super(WebVr, self).__init__(dgtboard) self.shared = shared self.virtual_timer = None self.enable_dgtpi = dgtboard.is_pi sub = 2 if dgtboard.is_pi else 0 DisplayMsg.show( Message.DGT_CLOCK_VERSION(main=2, sub=sub, dev='web', text=None)) self.clock_show_time = True # keep the last time to find out errorous DGT_MSG_BWTIME messages (error: current time > last time) self.r_time = 3600 * 10 # max value cause 10h cant be reached by clock self.l_time = 3600 * 10 # max value cause 10h cant be reached by clock
def display_text_on_clock(self, message): """Display a text on the web clock.""" is_new_rev2 = self.dgtboard.is_revelation and self.dgtboard.enable_revelation_pi if self.enable_dgtpi or is_new_rev2: text = message.l else: text = message.m if self.enable_dgt3000 else message.s if self.get_name() not in message.devs: logging.debug('ignored %s - devs: %s', text, message.devs) return True self.clock_show_time = False self._create_clock_text() logging.debug('[%s]', text) self.shared['clock_text'] = text result = {'event': 'Clock', 'msg': text} EventHandler.write_to_clients(result) DisplayMsg.show(Message.DISPLAY_TEXT(text=result)) return True
def display_text_on_clock(self, message): """Display a text on the web clock.""" if self.enable_dgtpi: text = message.l else: text = message.m if self.enable_dgt3000 else message.s if text is None: text = message.m if self.get_name() not in message.devs: logging.debug('ignored %s - devs: %s', text, message.devs) return True self.clock_show_time = False self._create_clock_text() self.shared['clock_text'] = text result = {'event': 'Clock', 'msg': text} DisplayMsg.show(Message.DISPLAY_TEXT(text=result)) EventHandler.write_to_clients(result) return True
def _runclock(self): if self.side_running == ClockSide.LEFT: time_left = self.l_time - 1 if time_left <= 0: logging.info('negative/zero time left: %s', time_left) self.virtual_timer.stop() time_left = 0 self.l_time = time_left if self.side_running == ClockSide.RIGHT: time_right = self.r_time - 1 if time_right <= 0: logging.info('negative/zero time right: %s', time_right) self.virtual_timer.stop() time_right = 0 self.r_time = time_right logging.info('(web) clock new time received l:%s r:%s', hms_time(self.l_time), hms_time(self.r_time)) DisplayMsg.show( Message.DGT_CLOCK_TIME(time_left=self.l_time, time_right=self.r_time, connect=True, dev='web')) self._display_time(self.l_time, self.r_time)
def __init__(self, dgtboard: DgtBoard): super(DgtCn, self).__init__(dgtboard) MsgDisplay.show(Message.DGT_CLOCK_VERSION(main=2, sub=2, dev='i2c', text=None))
def _process_board_message(self, message_id: int, message: tuple, message_length: int): if False: # switch-case pass elif message_id == DgtMsg.DGT_MSG_VERSION: if message_length != 2: logging.warning('illegal length in data') board_version = str(message[0]) + '.' + str(message[1]) logging.debug('(ser) board version %0.2f', float(board_version)) self.write_command([DgtCmd.DGT_SEND_BRD ]) # Update the board => get first FEN if self.device.find('rfc') == -1: text_l, text_m, text_s = 'USB e-Board', 'USBboard', 'ok usb' self.channel = 'USB' else: btname5 = self.bt_name[-5:] if 'REVII' in self.bt_name: text_l, text_m, text_s = 'RevII ' + btname5, 'Rev' + btname5, 'b' + btname5 self.is_revelation = True self.write_command([DgtCmd.DGT_RETURN_LONG_SERIALNR]) elif 'DGT_BT' in self.bt_name: text_l, text_m, text_s = 'DGTBT ' + btname5, 'BT ' + btname5, 'b' + btname5 else: text_l, text_m, text_s = 'BT e-Board', 'BT board', 'ok bt' self.channel = 'BT' self.ask_battery_status() self.bconn_text = Dgt.DISPLAY_TEXT(l=text_l, m=text_m, s=text_s, wait=True, beep=False, maxtime=1.1, devs={'i2c', 'web' }) # serial clock lateron DisplayMsg.show( Message.DGT_EBOARD_VERSION(text=self.bconn_text, channel=self.channel)) self.startup_serial_clock() # now ask the serial clock to answer if self.watchdog_timer.is_running(): logging.warning('watchdog timer is already running') else: logging.debug('watchdog timer is started') self.watchdog_timer.start() elif message_id == DgtMsg.DGT_MSG_BWTIME: if message_length != 7: logging.warning('illegal length in data') if ((message[0] & 0x0f) == 0x0a) or ((message[3] & 0x0f) == 0x0a): # Clock ack message # Construct the ack message ack0 = ((message[1]) & 0x7f) | ((message[3] << 3) & 0x80) ack1 = ((message[2]) & 0x7f) | ((message[3] << 2) & 0x80) ack2 = ((message[4]) & 0x7f) | ((message[0] << 3) & 0x80) ack3 = ((message[5]) & 0x7f) | ((message[0] << 2) & 0x80) if ack0 != 0x10: logging.warning('(ser) clock ACK error %s', (ack0, ack1, ack2, ack3)) if self.last_clock_command: logging.debug( '(ser) clock resending failed message [%s]', self.last_clock_command) self.write_command(self.last_clock_command) self.last_clock_command = [] # only resend once return else: logging.debug('(ser) clock ACK okay [%s]', DgtAck(ack1)) if self.last_clock_command: cmd = self.last_clock_command[3] # type: DgtClk if cmd.value != ack1 and ack1 < 0x80: logging.warning( '(ser) clock ACK [%s] out of sync - last: [%s]', DgtAck(ack1), cmd) # @todo these lines are better as what is done on DgtHw but it doesnt work # if ack1 == DgtAck.DGT_ACK_CLOCK_SETNRUN.value: # logging.info('(ser) clock out of set time now') # self.in_settime = False if ack1 == DgtAck.DGT_ACK_CLOCK_BUTTON.value: # this are the other (ack2-ack3) codes # 05-49 33-52 17-51 09-50 65-53 | button 0-4 (single) # 37-52 21-51 13-50 69-53 | button 0 + 1-4 # 49-51 41-50 97-53 | button 1 + 2-4 # 25-50 81-53 | button 2 + 3-4 # 73-53 | button 3 + 4 if ack3 == 49: logging.info('(ser) clock button 0 pressed - ack2: %i', ack2) DisplayMsg.show(Message.DGT_BUTTON(button=0, dev='ser')) if ack3 == 52: logging.info('(ser) clock button 1 pressed - ack2: %i', ack2) DisplayMsg.show(Message.DGT_BUTTON(button=1, dev='ser')) if ack3 == 51: logging.info('(ser) clock button 2 pressed - ack2: %i', ack2) DisplayMsg.show(Message.DGT_BUTTON(button=2, dev='ser')) if ack3 == 50: logging.info('(ser) clock button 3 pressed - ack2: %i', ack2) DisplayMsg.show(Message.DGT_BUTTON(button=3, dev='ser')) if ack3 == 53: if ack2 == 69: logging.info( '(ser) clock button 0+4 pressed - ack2: %i', ack2) DisplayMsg.show( Message.DGT_BUTTON(button=0x11, dev='ser')) else: logging.info( '(ser) clock button 4 pressed - ack2: %i', ack2) DisplayMsg.show( Message.DGT_BUTTON(button=4, dev='ser')) if ack1 == DgtAck.DGT_ACK_CLOCK_VERSION.value: self.enable_ser_clock = True main = ack2 >> 4 sub = ack2 & 0x0f logging.debug('(ser) clock version %0.2f', float(str(main) + '.' + str(sub))) if self.bconn_text: self.bconn_text.devs = { 'ser' } # Now send the (delayed) message to serial clock dev = 'ser' else: dev = 'err' DisplayMsg.show( Message.DGT_CLOCK_VERSION(main=main, sub=sub, dev=dev, text=self.bconn_text)) elif any(message[:7]): r_hours = message[0] & 0x0f r_mins = (message[1] >> 4) * 10 + (message[1] & 0x0f) r_secs = (message[2] >> 4) * 10 + (message[2] & 0x0f) l_hours = message[3] & 0x0f l_mins = (message[4] >> 4) * 10 + (message[4] & 0x0f) l_secs = (message[5] >> 4) * 10 + (message[5] & 0x0f) r_time = r_hours * 3600 + r_mins * 60 + r_secs l_time = l_hours * 3600 + l_mins * 60 + l_secs errtim = r_hours > 9 or l_hours > 9 or r_mins > 59 or l_mins > 59 or r_secs > 59 or l_secs > 59 if errtim: # complete illegal package received logging.warning('(ser) clock illegal new time received %s', message) elif r_time > self.r_time or l_time > self.l_time: # the new time is higher as the old => ignore logging.warning( '(ser) clock strange old time received %s l:%s r:%s', message, hms_time(self.l_time), hms_time(self.r_time)) if self.in_settime: logging.info( '(ser) clock still in set mode, ignore received time' ) errtim = True elif r_time - self.r_time > 3600 or l_time - self.l_time > 3600: logging.info( '(ser) clock new time over 1h difference, ignore received time' ) errtim = True else: logging.info('(ser) clock new time received l:%s r:%s', hms_time(l_time), hms_time(r_time)) status = message[6] & 0x3f connect = not status & 0x20 if connect: right_side_down = -0x40 if status & 0x02 else 0x40 if self.lever_pos != right_side_down: logging.debug( '(ser) clock button status: 0x%x old lever: %s', status, self.lever_pos) if self.lever_pos is not None: DisplayMsg.show( Message.DGT_BUTTON(button=right_side_down, dev='ser')) self.lever_pos = right_side_down else: logging.info( '(ser) clock not connected, sending old time l:%s r:%s', hms_time(self.l_time), hms_time(self.r_time)) l_time = self.l_time r_time = self.r_time if self.in_settime: logging.info( '(ser) clock still in set mode, sending old time l:%s r:%s', hms_time(self.l_time), hms_time(self.r_time)) l_time = self.l_time r_time = self.r_time DisplayMsg.show( Message.DGT_CLOCK_TIME(time_left=l_time, time_right=r_time, connect=connect, dev='ser')) if not self.enable_ser_clock: dev = 'rev' if 'REVII' in self.bt_name else 'ser' if self.watchdog_timer.is_running( ): # a running watchdog means: board already found logging.info('(%s) clock restarting setup', dev) self.startup_serial_clock() else: logging.info( '(%s) clock sends messages already but (%s) board still not found', dev, dev) if not errtim: self.r_time = r_time self.l_time = l_time else: logging.debug('(ser) clock null message ignored') if self.clock_lock: logging.debug('(ser) clock unlocked after %.3f secs', time.time() - self.clock_lock) self.clock_lock = False elif message_id == DgtMsg.DGT_MSG_BOARD_DUMP: if message_length != 64: logging.warning('illegal length in data') piece_to_char = { 0x01: 'P', 0x02: 'R', 0x03: 'N', 0x04: 'B', 0x05: 'K', 0x06: 'Q', 0x07: 'p', 0x08: 'r', 0x09: 'n', 0x0a: 'b', 0x0b: 'k', 0x0c: 'q', 0x0d: '$', 0x0e: '%', 0x0f: '&', 0x00: '.' } board = '' for character in message: board += piece_to_char[character & 0x0f] logging.debug('\n' + '\n'.join( board[0 + i:8 + i] for i in range(0, len(board), 8))) # Show debug board # Create fen from board fen = '' empty = 0 for square in range(0, 64): if message[square] != 0 and message[ square] < 0x0d: # @todo for the moment ignore the special pieces if empty > 0: fen += str(empty) empty = 0 fen += piece_to_char[message[square] & 0x0f] else: empty += 1 if (square + 1) % 8 == 0: if empty > 0: fen += str(empty) empty = 0 if square < 63: fen += '/' # Attention! This fen is NOT flipped logging.debug('raw fen [%s]', fen) DisplayMsg.show(Message.DGT_FEN(fen=fen, raw=True)) elif message_id == DgtMsg.DGT_MSG_FIELD_UPDATE: if message_length != 2: logging.warning('illegal length in data') if self.field_timer_running: self.stop_field_timer() self.start_field_timer() elif message_id == DgtMsg.DGT_MSG_SERIALNR: if message_length != 5: logging.warning('illegal length in data') DisplayMsg.show( Message.DGT_SERIAL_NR( number=''.join([chr(elem) for elem in message]))) elif message_id == DgtMsg.DGT_MSG_LONG_SERIALNR: if message_length != 10: logging.warning('illegal length in data') number = ''.join([chr(elem) for elem in message]) self.enable_revelation_pi = float( number[:4]) >= 3.25 # "3.250010001"=yes "0000000001"=no logging.info('(rev) clock in PiMode: %s - serial: %s', 'yes' if self.enable_revelation_pi else 'no', number) elif message_id == DgtMsg.DGT_MSG_BATTERY_STATUS: if message_length != 9: logging.warning('illegal length in data') DisplayMsg.show(Message.BATTERY(percent=message[0])) else: # Default logging.warning('message not handled [%s]', DgtMsg(message_id))
def _process_incoming_clock_forever(self): but = c_byte(0) buttime = c_byte(0) clktime = create_string_buffer(6) counter = 0 logging.info('incoming_clock ready') while True: with self.lib_lock: # get button events res = self.lib.dgtpicom_get_button_message( pointer(but), pointer(buttime)) if res > 0: ack3 = but.value if ack3 == 0x01: logging.info('(i2c) clock button 0 pressed') DisplayMsg.show(Message.DGT_BUTTON(button=0, dev='i2c')) if ack3 == 0x02: logging.info('(i2c) clock button 1 pressed') DisplayMsg.show(Message.DGT_BUTTON(button=1, dev='i2c')) if ack3 == 0x04: logging.info('(i2c) clock button 2 pressed') DisplayMsg.show(Message.DGT_BUTTON(button=2, dev='i2c')) if ack3 == 0x08: logging.info('(i2c) clock button 3 pressed') DisplayMsg.show(Message.DGT_BUTTON(button=3, dev='i2c')) if ack3 == 0x10: logging.info('(i2c) clock button 4 pressed') DisplayMsg.show(Message.DGT_BUTTON(button=4, dev='i2c')) if ack3 == 0x20: logging.info('(i2c) clock button on/off pressed') self.lib.dgtpicom_configure( ) # restart the clock - cause its OFF DisplayMsg.show( Message.DGT_BUTTON( button=0x20, dev='i2c')) # WD Fehlerbereinigung if ack3 == 0x11: logging.info('(i2c) clock button 0+4 pressed') DisplayMsg.show( Message.DGT_BUTTON(button=0x11, dev='i2c')) if ack3 == 0x40: logging.info( '(i2c) clock lever pressed > right side down') DisplayMsg.show( Message.DGT_BUTTON(button=0x40, dev='i2c')) if ack3 == -0x40: logging.info( '(i2c) clock lever pressed > left side down') DisplayMsg.show( Message.DGT_BUTTON(button=-0x40, dev='i2c')) if res < 0: logging.warning('GetButtonMessage returned error %i', res) # get time events self.lib.dgtpicom_get_time(clktime) times = list(clktime.raw) counter = (counter + 1) % 10 if counter == 0: l_hms = times[:3] r_hms = times[3:] logging.info('(i2c) clock new time received l:%s r:%s', l_hms, r_hms) if self.in_settime: logging.info( '(i2c) clock still not finished set time, sending old time' ) else: # DgtPi needs 2secs for a stopped clock to return the correct(!) time # we make it easy here and just set the time from the side counting down if self.side_running == ClockSide.LEFT: self.l_time = l_hms[0] * 3600 + l_hms[1] * 60 + l_hms[2] if self.side_running == ClockSide.RIGHT: self.r_time = r_hms[0] * 3600 + r_hms[1] * 60 + r_hms[2] text = Message.DGT_CLOCK_TIME(time_left=self.l_time, time_right=self.r_time, connect=True, dev='i2c') DisplayMsg.show(text) time.sleep(0.1)
def run(self): logging.info('evt_queue ready') print('#' * 42 + ' PicoChess v' + version + ' ' + '#' * 42) print('To play a move enter the from-to squares like "e2e4". To play this move on board, enter "go".') print('When the computer displays its move, also type "go" to actually do it on the board (see above).') print('Other commands are:') print('newgame:<w|b>, print:<fen>, setup:<fen>, fen:<fen>, button:<0-5>, lever:<l|r>, plug:<in|off>') print('') print('This console mode is mainly for development. Better activate picochess together with a DGT-Board ;-)') print('#' * 100) print('') while True: raw = input('PicoChess v'+version+':>').strip() if not raw: continue cmd = raw.lower() try: if cmd.startswith('print:'): fen = raw.split(':')[1] print(chess.Board(fen)) else: if not self.board_plugged_in and not cmd.startswith('plug:'): print('The command isnt accepted cause the virtual board is not plugged in') continue if cmd.startswith('newgame:'): side = cmd.split(':')[1] if side == 'w': self.flip_board = False self.fire(Event.DGT_FEN(fen='rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR')) elif side == 'b': self.flip_board = True self.fire(Event.DGT_FEN(fen='RNBKQBNR/PPPPPPPP/8/8/8/8/pppppppp/rnbkqbnr')) else: raise ValueError(side) elif cmd.startswith('setup:'): fen = raw.split(':')[1] uci960 = False # make it easy for the moment bit_board = chess.Board(fen, uci960) if bit_board.is_valid(): self.fire(Event.SETUP_POSITION(fen=bit_board.fen(), uci960=uci960)) else: raise ValueError(fen) # Here starts the simulation of a dgt-board! # Let the user send events like the board would do elif cmd.startswith('fen:'): fen = raw.split(':')[1] # dgt board only sends the basic fen => be sure # it's same no matter what fen the user entered self.fire(Event.DGT_FEN(fen=fen.split(' ')[0])) elif cmd.startswith('button:'): button = int(cmd.split(':')[1]) if button not in range(6): raise ValueError(button) if button == 5: # make it to power button button = 0x11 self.fire(Event.KEYBOARD_BUTTON(button=button, dev = 'ser')) elif cmd.startswith('lever:'): lever = cmd.split(':')[1] if lever not in ('l', 'r'): raise ValueError(lever) button = 0x40 if lever == 'r' else -0x40 self.fire(Event.KEYBOARD_BUTTON(button=button, dev = 'ser')) elif cmd.startswith('plug:'): plug = cmd.split(':')[1] if plug not in ('in', 'off'): raise ValueError(plug) if plug == 'in': self.board_plugged_in = True self.rt.stop() text_l, text_m, text_s = 'VirtBoard ', 'V-Board ', 'VBoard' text = Dgt.DISPLAY_TEXT(l=text_l, m=text_m, s=text_s, wait=True, beep=False, maxtime=1) DisplayMsg.show(Message.EBOARD_VERSION(text=text, channel='console')) if plug == 'off': self.board_plugged_in = False self.rt.start() elif cmd.startswith('go'): if keyboard_last_fen is not None: self.fire(Event.KEYBOARD_FEN(fen=keyboard_last_fen)) else: print('last move already send to virtual board') elif cmd.startswith('shutdown'): self.fire(Event.SHUTDOWN()) # end simulation code else: # move => fen => virtual board sends fen move = chess.Move.from_uci(cmd) self.fire(Event.KEYBOARD_MOVE(move=move)) except ValueError as e: logging.warning('Invalid user input [%s]', raw)
def fire_no_board_connection(self): s = 'Board!' text = Dgt.DISPLAY_TEXT(l='no e-' + s, m='no' + s, s=s, wait=True, beep=False, maxtime=0) DisplayMsg.show(Message.NO_EBOARD_ERROR(text=text, is_pi=self.is_pi))