|
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