udp works to netcat listener
This commit is contained in:
parent
6507956a83
commit
324aa59de4
|
@ -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()
|
|
@ -19,6 +19,9 @@ bee_power_pin.value(0)
|
||||||
|
|
||||||
class ModemError(Exception):
|
class ModemError(Exception):
|
||||||
def __init__(self, message: str, sent_command: bytes, response: list):
|
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}')
|
super().__init__(f'{message}: {sent_command} -> {response}')
|
||||||
|
|
||||||
|
|
||||||
|
@ -29,6 +32,8 @@ async def xb_toggle_power():
|
||||||
|
|
||||||
|
|
||||||
class CellularModem:
|
class CellularModem:
|
||||||
|
# TODO: add lock that is used in send_and_recieve as well as by things that do raw reading
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.uart = UART(2, baudrate=115200, timeout=4, rx=PIN_BEE_UART_RXD, tx=PIN_BEE_UART_TXD)
|
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''
|
data = b''
|
||||||
expected_not_found = 0
|
expected_not_found = 0
|
||||||
while time.ticks_diff(time.ticks_ms(), t) < timeout:
|
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 read and read != data_to_send:
|
||||||
if VERBOSE_XBEE_COMM:
|
if VERBOSE_XBEE_COMM:
|
||||||
print(f'<====@ {read}')
|
print(f'<====@ {read}')
|
||||||
data += 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
|
break
|
||||||
elif expected is not None:
|
elif expected is not None:
|
||||||
if data.endswith(expected):
|
if data.endswith(expected):
|
||||||
|
@ -123,9 +130,11 @@ async def cellular_signal_strength():
|
||||||
|
|
||||||
async def cellular_ip() -> str:
|
async def cellular_ip() -> str:
|
||||||
try:
|
try:
|
||||||
ip_resp = await cell_modem.send_and_receive(b'AT+IPADDR')
|
resp = await cell_modem.send_and_receive(b'AT+IPADDR')
|
||||||
if ip_resp[0].startswith('+IPADDR: '):
|
if len(resp) and resp[0].startswith('+IPADDR: '):
|
||||||
return ip_resp[0].strip('+IPADDR: ')
|
return resp[0].strip('+IPADDR: ')
|
||||||
|
else:
|
||||||
|
return '0.0.0.0'
|
||||||
except ModemError:
|
except ModemError:
|
||||||
return '0.0.0.0'
|
return '0.0.0.0'
|
||||||
|
|
||||||
|
@ -133,6 +142,7 @@ async def cellular_ip() -> str:
|
||||||
@runtime_timeout(CELLULAR_STARTUP_TIMEOUT)
|
@runtime_timeout(CELLULAR_STARTUP_TIMEOUT)
|
||||||
async def start_modem():
|
async def start_modem():
|
||||||
await xb_toggle_power()
|
await xb_toggle_power()
|
||||||
|
cell_modem.xb_purge()
|
||||||
while True:
|
while True:
|
||||||
logger('Setting up modem', source='CELL')
|
logger('Setting up modem', source='CELL')
|
||||||
failures = 0
|
failures = 0
|
||||||
|
@ -143,7 +153,10 @@ async def start_modem():
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
if DEBUG_XBEE:
|
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
|
failures += 1
|
||||||
if failures == 5:
|
if failures == 5:
|
||||||
return False
|
return False
|
||||||
|
@ -166,10 +179,13 @@ async def start_modem():
|
||||||
# Assuming model is SIM7600
|
# Assuming model is SIM7600
|
||||||
|
|
||||||
cpin = await cell_modem.send_and_receive(b'AT+CPIN?')
|
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)
|
logger('NO SIM CARD', source='CELL', level=LogLevel.error)
|
||||||
await asyncio.sleep(30)
|
await asyncio.sleep(30)
|
||||||
return False
|
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()
|
signal_strength = await cellular_signal_strength()
|
||||||
logger(f'Signal strength: {signal_strength}', source='CELL')
|
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)
|
logger(f'Modem start failed: {b"AT+CGACT?"} -> {cgact}', source='CELL', level=LogLevel.error)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
await cell_modem.send_and_receive(f'AT+CGSOCKCONT=1,"IP","{CELLULAR_APN}"'.encode())
|
try:
|
||||||
await cell_modem.send_and_receive(b'AT+CSOCKSETPN=1', read_until=None, expected=b'OK\r\n')
|
await cell_modem.send_and_receive(f'AT+CGSOCKCONT=1,"IP","{CELLULAR_APN}"'.encode())
|
||||||
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+CSOCKSETPN=1', 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')
|
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)
|
ip = None
|
||||||
if not ip_get.failure:
|
for i in range(10):
|
||||||
logger(f'IP: {ip_get.result}', source='CELL')
|
ip_get = await run_with_timeout(func=cellular_ip, timeout_sec=3)
|
||||||
else:
|
if not ip_get.failure and ip_get.result != '0.0.0.0':
|
||||||
logger(f'IP: 0.0.0.0', source='CELL')
|
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
|
return True
|
||||||
|
|
||||||
|
@ -229,11 +257,13 @@ async def start_modem_task():
|
||||||
while True:
|
while True:
|
||||||
if await start_modem():
|
if await start_modem():
|
||||||
break
|
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 xb_toggle_power()
|
||||||
await asyncio.sleep(2)
|
await asyncio.sleep(2)
|
||||||
|
logger('Modem ready', source='CELL')
|
||||||
|
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
await asyncio.sleep(100)
|
await asyncio.sleep(100)
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
def freematics_checksum(data):
|
||||||
|
cs = 0
|
||||||
|
for i in data:
|
||||||
|
cs += ord(i)
|
||||||
|
return '{:02x}'.format(cs & 0xFF)
|
Loading…
Reference in New Issue