udp works to netcat listener

This commit is contained in:
Cyberes 2024-07-01 21:50:40 -06:00
parent 6507956a83
commit 324aa59de4
3 changed files with 145 additions and 19 deletions

View File

@ -0,0 +1,91 @@
import asyncio
from lib.logging import logger, LogLevel
from lib.networking.cell_modem import cell_modem, DEBUG_XBEE
from lib.runtime import runtime_timeout
async def cell_udp_open(host: str, port: int):
# Perform a DNS resolution to get the IP of the host
cdnsgip = (await cell_modem.send_and_receive(f'AT+CDNSGIP="{host}"'.encode(), timeout=10000))
if not len(cdnsgip):
logger(f'Failed to get IP of "{host}" -> {cdnsgip}', source='CELL', level=LogLevel.error)
return False
ip = None
if host in cdnsgip[0]:
# Find the start of the IP address
start = cdnsgip[0].find(',"', cdnsgip[0].find(host))
if start != -1:
start += 2 # Skip the ," characters
# Find the end of the IP address
end = cdnsgip[0].find('"', start)
if end != -1:
# Extract the IP address
ip = cdnsgip[start:end]
if not ip:
ip = host
cipopen = await cell_modem.send_and_receive(f'AT+CIPOPEN=0,"UDP","{ip}",{port},8000'.encode())
if cipopen[0] != '+CIPOPEN: 0,0':
logger(f'Failed to open UDP connection to "{host}:{port}" -> {cipopen}', source='CELL', level=LogLevel.error)
return False
return ip
async def cell_udp_send(host: str, port: int, data: bytes):
resolved_ip = await cell_udp_open(host, port)
if resolved_ip is False:
return False
buffer = b''
found = False
data_len = len(data)
cell_modem.uart.write(f'AT+CIPSEND=0,{data_len},"{resolved_ip}",{port}\r')
await asyncio.sleep(0.1)
cell_modem.uart.write(data)
while not found:
resp = await cell_modem.xb_read(1)
if resp:
if DEBUG_XBEE:
logger(f'cell_udp_send :: {resp}', source='CELL', level=LogLevel.debug)
buffer += resp
if b'\r\nERROR' in buffer:
return False
else:
for a in [b'OK\r\n\r\n+CIPSEND:', b'\r\nRECV FROM:']:
if a in buffer:
found = True
return buffer
async def cell_udp_close():
await cell_modem.send_and_receive(b'AT+CIPCLOSE=0')
async def cell_udp_receive(timeout: int):
@runtime_timeout(timeout)
async def inner():
buffer = b''
length = None
while True:
r = await cell_modem.xb_read(0.5)
if r:
buffer += r
response = buffer.decode('utf-8')
# If we haven't found the length yet, try to find it
if length is None:
start = response.find('+IPD')
if start > -1:
end = response.find('\r\n', start)
if end > -1: # We have found the length
length = int(response[start + 4:end])
response = response[end + 2:] # Remove '+IPD' and length from response
buffer = response.encode() # Update buffer
# If we know the length, check if we have received the entire message
if length is not None and len(buffer) >= length:
return response[:length]
return await inner()

View File

@ -19,6 +19,9 @@ bee_power_pin.value(0)
class ModemError(Exception):
def __init__(self, message: str, sent_command: bytes, response: list):
self.message = message
self.sent_command = sent_command
self.response = response
super().__init__(f'{message}: {sent_command} -> {response}')
@ -29,6 +32,8 @@ async def xb_toggle_power():
class CellularModem:
# TODO: add lock that is used in send_and_recieve as well as by things that do raw reading
def __init__(self):
self.uart = UART(2, baudrate=115200, timeout=4, rx=PIN_BEE_UART_RXD, tx=PIN_BEE_UART_TXD)
@ -69,12 +74,14 @@ class CellularModem:
data = b''
expected_not_found = 0
while time.ticks_diff(time.ticks_ms(), t) < timeout:
read = await self.xb_read(50)
read = await self.xb_read(0.5)
if read and read != data_to_send:
if VERBOSE_XBEE_COMM:
print(f'<====@ {read}')
data += read
if read_until is not None and data.endswith(read_until):
if b'ERROR' in data:
raise ModemError('Recieved error', sent_command=data_to_send, response=data)
elif read_until is not None and data.endswith(read_until):
break
elif expected is not None:
if data.endswith(expected):
@ -123,9 +130,11 @@ async def cellular_signal_strength():
async def cellular_ip() -> str:
try:
ip_resp = await cell_modem.send_and_receive(b'AT+IPADDR')
if ip_resp[0].startswith('+IPADDR: '):
return ip_resp[0].strip('+IPADDR: ')
resp = await cell_modem.send_and_receive(b'AT+IPADDR')
if len(resp) and resp[0].startswith('+IPADDR: '):
return resp[0].strip('+IPADDR: ')
else:
return '0.0.0.0'
except ModemError:
return '0.0.0.0'
@ -133,6 +142,7 @@ async def cellular_ip() -> str:
@runtime_timeout(CELLULAR_STARTUP_TIMEOUT)
async def start_modem():
await xb_toggle_power()
cell_modem.xb_purge()
while True:
logger('Setting up modem', source='CELL')
failures = 0
@ -143,7 +153,10 @@ async def start_modem():
break
else:
if DEBUG_XBEE:
logger(f'Modem start failed: {at}', source='CELL', level=LogLevel.debug)
msg = 'Modem start failed'
if len(at):
msg += str(at)
logger(msg, source='CELL', level=LogLevel.debug)
failures += 1
if failures == 5:
return False
@ -166,10 +179,13 @@ async def start_modem():
# Assuming model is SIM7600
cpin = await cell_modem.send_and_receive(b'AT+CPIN?')
if not cpin[0].endswith(': READY'):
if len(cpin) and not cpin[0].endswith(': READY'):
logger('NO SIM CARD', source='CELL', level=LogLevel.error)
await asyncio.sleep(30)
return False
elif not len(cpin):
logger(f'SIM card check failed: {cpin}', source='CELL', level=LogLevel.error)
return False
signal_strength = await cellular_signal_strength()
logger(f'Signal strength: {signal_strength}', source='CELL')
@ -211,16 +227,28 @@ async def start_modem():
logger(f'Modem start failed: {b"AT+CGACT?"} -> {cgact}', source='CELL', level=LogLevel.error)
return False
await cell_modem.send_and_receive(f'AT+CGSOCKCONT=1,"IP","{CELLULAR_APN}"'.encode())
await cell_modem.send_and_receive(b'AT+CSOCKSETPN=1', read_until=None, expected=b'OK\r\n')
await cell_modem.send_and_receive(b'AT+CIPMODE=0', read_until=None, expected=b'OK\r\n')
await cell_modem.send_and_receive(b'AT+NETOPEN', read_until=None, expected=b'OK\r\n')
try:
await cell_modem.send_and_receive(f'AT+CGSOCKCONT=1,"IP","{CELLULAR_APN}"'.encode())
await cell_modem.send_and_receive(b'AT+CSOCKSETPN=1', read_until=None, expected=b'OK\r\n')
await cell_modem.send_and_receive(b'AT+CIPMODE=0', read_until=None, expected=b'OK\r\n')
await cell_modem.send_and_receive(b'AT+NETOPEN', read_until=None, expected=b'OK\r\n')
except ModemError as e:
logger(f'Modem start failed: {e.message} :: {e.sent_command} -> {e.response}', source='CELL', level=LogLevel.error)
return False
ip_get = await run_with_timeout(func=cellular_ip, timeout_sec=3)
if not ip_get.failure:
logger(f'IP: {ip_get.result}', source='CELL')
else:
logger(f'IP: 0.0.0.0', source='CELL')
ip = None
for i in range(10):
ip_get = await run_with_timeout(func=cellular_ip, timeout_sec=3)
if not ip_get.failure and ip_get.result != '0.0.0.0':
ip = ip_get.result
logger(f'IP: {ip}', source='CELL')
break
if DEBUG_XBEE:
logger(f'Waiting for an IP', source='CELL', level=LogLevel.debug)
await asyncio.sleep(1)
if ip is None:
logger(f'Did not get an IP', source='CELL', level=LogLevel.error)
return False
return True
@ -229,11 +257,13 @@ async def start_modem_task():
while True:
if await start_modem():
break
if not (await cell_modem.send_and_receive(b'AT+CPOF')):
try:
if not (await cell_modem.send_and_receive(b'AT+CPOF')):
await xb_toggle_power()
except ModemError:
await xb_toggle_power()
await asyncio.sleep(2)
logger('Modem ready', source='CELL')
while True:
await asyncio.sleep(100)

View File

@ -0,0 +1,5 @@
def freematics_checksum(data):
cs = 0
for i in data:
cs += ord(i)
return '{:02x}'.format(cs & 0xFF)