|
1 | 1 | import logging
|
2 | 2 | import os
|
| 3 | +import queue |
3 | 4 | import socket
|
4 | 5 | import sys
|
| 6 | +import threading |
5 | 7 |
|
6 | 8 | logger = logging.getLogger(__name__)
|
7 | 9 |
|
8 | 10 | SERIAL_FREQ = 8192 # Hz
|
9 | 11 | CPU_FREQ = 4213440 # Hz
|
10 | 12 |
|
| 13 | +async_recv = queue.Queue() |
| 14 | + |
| 15 | + |
| 16 | +def async_comms(socket): |
| 17 | + while True: |
| 18 | + item = socket.recv(1) |
| 19 | + async_recv.put(item) |
| 20 | + |
11 | 21 |
|
12 | 22 | class Serial:
|
13 |
| - def __init__(self, serial_address, serial_bind, serial_interrupt_based=True): |
| 23 | + def __init__(self, serial_address, serial_bind, serial_interrupt_based): |
14 | 24 | self.SB = 0
|
15 | 25 | self.SC = 0
|
16 | 26 | self.connection = None
|
@@ -44,69 +54,91 @@ def __init__(self, serial_address, serial_bind, serial_interrupt_based=True):
|
44 | 54 | logger.info(f"Connecting to {serial_address}")
|
45 | 55 | self.connection.connect(address_tuple)
|
46 | 56 | logger.info(f"Connection successful!")
|
47 |
| - # self.connection.setblocking(False) |
48 | 57 |
|
49 |
| - def tick(self, cycles): |
50 | 58 | # if self.serial_interrupt_based:
|
51 |
| - # if self.SC & 1: # Master |
52 |
| - # if self.SC & 0x80: |
53 |
| - # logger.info(f'Master sending!') |
54 |
| - # self.connection.send(bytes([self.SB])) |
55 |
| - # # self.connection.setblocking(True) |
56 |
| - # data = self.connection.recv(1) |
57 |
| - # self.SB = data[0] |
58 |
| - # self.SC &= 0b0111_1111 |
59 |
| - # return True |
60 |
| - # else: |
61 |
| - # try: |
62 |
| - # if self.SC & 0x80: |
63 |
| - # # self.connection.setblocking(False) |
64 |
| - # logger.info(f'Slave recv!') |
65 |
| - # self.connection.send(bytes([self.SB])) |
66 |
| - # data = self.connection.recv(1) |
67 |
| - # self.SB = data[0] |
68 |
| - # self.SC &= 0b0111_1111 |
69 |
| - # return True |
70 |
| - # except BlockingIOError: |
71 |
| - # pass |
72 |
| - # return False |
73 |
| - # return False |
74 |
| - # else: |
75 |
| - # Check if serial is in progress |
| 59 | + # logger.info("Interrupt-based serial emulation active!") |
| 60 | + # self.recv_thread = threading.Thread(target=async_comms, args=(self.connection,)) |
| 61 | + # self.recv_thread.start() |
76 | 62 |
|
| 63 | + def tick(self, cycles): |
77 | 64 | if self.connection is None:
|
78 | 65 | return
|
79 | 66 |
|
80 |
| - if self.SC & 0x80 == 0: |
| 67 | + # self.cycles_count += 1 |
| 68 | + |
| 69 | + if self.serial_interrupt_based: |
| 70 | + if self.SC & 0x80 == 0: # Performance optimization. Games might not set this on slave |
| 71 | + return False |
| 72 | + |
| 73 | + self.cycles_count += 1 |
| 74 | + |
| 75 | + if (self.cycles_to_transmit() == 0): |
| 76 | + if self.SC & 1: # Master |
| 77 | + if self.SC & 0x80: |
| 78 | + logger.info(f"Master sending!") |
| 79 | + self.connection.send(bytes([self.SB])) |
| 80 | + data = self.connection.recv(1) |
| 81 | + self.SB = data[0] |
| 82 | + self.SC &= 0b0111_1111 |
| 83 | + self.cycles_count = 0 |
| 84 | + return True |
| 85 | + else: |
| 86 | + # try: |
| 87 | + # data = async_recv.get(block=False) |
| 88 | + # except queue.Empty: |
| 89 | + # return False |
| 90 | + try: |
| 91 | + data = self.connection.recv(1, socket.MSG_DONTWAIT) |
| 92 | + except BlockingIOError: |
| 93 | + return False |
| 94 | + |
| 95 | + logger.info(f"Slave recv!") |
| 96 | + self.connection.send(bytes([self.SB])) |
| 97 | + # data = self.connection.recv(1) |
| 98 | + self.SB = data[0] |
| 99 | + self.SC &= 0b0111_1111 |
| 100 | + self.cycles_count = 0 |
| 101 | + return True |
81 | 102 | return False
|
| 103 | + else: |
| 104 | + # Check if serial is in progress |
| 105 | + if self.SC & 0x80 == 0: |
| 106 | + return False |
82 | 107 |
|
83 |
| - self.cycles_count += 1 |
| 108 | + self.cycles_count += 1 |
84 | 109 |
|
85 |
| - if (self.cycles_to_transmit() == 0): |
86 |
| - # if self.SC & 1: # Master |
87 |
| - send_bit = bytes([(self.SB >> 7) & 1]) |
88 |
| - self.connection.send(send_bit) |
| 110 | + if (self.cycles_to_transmit() == 0): |
| 111 | + # if self.SC & 1: # Master |
| 112 | + send_bit = bytes([(self.SB >> 7) & 1]) |
| 113 | + self.connection.send(send_bit) |
89 | 114 |
|
90 |
| - data = self.connection.recv(1) |
91 |
| - self.SB = ((self.SB << 1) & 0xFF) | data[0] & 1 |
| 115 | + data = self.connection.recv(1) |
| 116 | + self.SB = ((self.SB << 1) & 0xFF) | data[0] & 1 |
92 | 117 |
|
93 |
| - logger.info(f"recv sb: {self.SB:08b}") |
94 |
| - self.trans_bits += 1 |
| 118 | + logger.info(f"recv sb: {self.SB:08b}") |
| 119 | + self.trans_bits += 1 |
95 | 120 |
|
96 |
| - self.cycles_count = 0 |
| 121 | + self.cycles_count = 0 |
97 | 122 |
|
98 |
| - if self.trans_bits == 8: |
99 |
| - self.trans_bits = 0 |
100 |
| - self.SC &= 0b0111_1111 |
101 |
| - return True |
| 123 | + if self.trans_bits == 8: |
| 124 | + self.trans_bits = 0 |
| 125 | + self.SC &= 0b0111_1111 |
| 126 | + return True |
| 127 | + return False |
102 | 128 | return False
|
103 | 129 |
|
104 | 130 | def cycles_to_transmit(self):
|
105 |
| - if self.SC & 0x80: |
106 |
| - return max(self.cycles_target - self.cycles_count, 0) |
| 131 | + if self.connection: |
| 132 | + if self.SC & 0x80: |
| 133 | + return max(self.cycles_target - self.cycles_count, 0) |
| 134 | + # return CPU_FREQ // SERIAL_FREQ |
| 135 | + else: |
| 136 | + return 1 << 16 |
107 | 137 | else:
|
108 | 138 | return 1 << 16
|
109 | 139 |
|
110 | 140 | def stop(self):
|
111 | 141 | if self.connection:
|
112 | 142 | self.connection.close()
|
| 143 | + # if self.serial_interrupt_based and self.recv_thread: |
| 144 | + # self.recv_thread.kill() |
0 commit comments