I have created a Python 3 sketch to try and upload the current NTP time to STM32L476RG Nucleo. The sketch is as follows:
import serial
import glob
import sys
import time
from socket import AF_INET, SOCK_DGRAM
import socket
import struct
def serial_ports():
""" Lists serial port names
:raises EnvironmentError:
On unsupported or unknown platforms
:returns:
A list of the serial ports available on the system
"""
if sys.platform.startswith('win'):
ports = ['COM%s' % (i + 1) for i in range(256)]
elif sys.platform.startswith('linux') or sys.platform.startswith('cygwin'):
# this excludes your current terminal "/dev/tty"
ports = glob.glob('/dev/tty[A-Za-z]*')
elif sys.platform.startswith('darwin'):
ports = glob.glob('/dev/tty.*')
else:
raise EnvironmentError('Unsupported platform')
result = []
for port in ports:
try:
s = serial.Serial(port)
s.close()
result.append(port)
except (OSError, serial.SerialException):
print("OSError or Serial Exception raised, exiting...")
pass
return result
def getNTPTime(host = "pool.ntp.org"):
port = 123
buf = 1024
address = (host,port)
msg = '\x1b' + 47 * '\0'
# reference time (in seconds since 1900-01-01 00:00:00)
TIME1970 = 2208988800 # 1970-01-01 00:00:00
# connect to server
client = socket.socket( AF_INET, SOCK_DGRAM)
while True:
try:
client.sendto(msg.encode('utf-8'), address)
msg, address = client.recvfrom( buf )
t = struct.unpack( "!12I", msg )[10]
t -= TIME1970
return t
except (socket.gaierror):
print("Error! Internet connection not found, exiting...")
break
my_t_zone = -8
cur_ser = ''.join([s for s in serial_ports() if 'usbmodem' in s])
if(len(cur_ser)>0):
ser = serial.Serial(cur_ser)
if(not ser.isOpen()):
ser.open()
valid = 0
time.sleep(.5)
while(not valid):
ser.reset_input_buffer()
line = ser.readline().decode('utf-8').strip()
if(line=="Hello"):
ntp_time = ("DEA"+str(getNTPTime()+(my_t_zone*3600))+"L").encode('utf_8')
ser.write(ntp_time)
valid = 1
time.sleep(.5)
print("Done uploading time.")
ser.close()
else:
print("No compatible serial device found, exiting...")
The Mbed sketch running on the Nucleo board is as follows:
#include "mbed.h"
Serial pc(USBTX, USBRX);
const int kMaxBufferSize = 100;
char buffer[kMaxBufferSize];
int len = 0;
int contact = 1;
void removeChar(char *s, int c){
int j, n = strlen(s);
for (int i=j=0; i<n; i++)
if (s[i] != c)
s[j++] = s[i];
s[j] = '\0';
}
int main()
{
pc.baud(9600);
while(contact) {
pc.printf("Hello\n");
if (pc.readable() > 0) {
char new_char;
while(new_char != 'L') {
new_char = pc.getc();
buffer[len++] = new_char;
}
contact = 0;
}
}
removeChar(buffer, 'D');
removeChar(buffer, 'E');
removeChar(buffer, 'A');
removeChar(buffer, 'L');
int x = atoi(buffer);
while(!contact) {
pc.printf("%s\n",buffer);
}
}
The behavior of the system is unstable. I observe several things:
Most of the time this code snippet works fine and Mbed shows
the uploaded Posix timestamp properly after parsing.
Sometimes erroneous characters are shown in the parsed timestamp (e.g. symbols and other characters)
Sometimes the entire posix timestamp is not shown by Mbed and gets cut out.
Also, you can see the Python code uploads three characters before the timestamp. These are used to make sure the code works most of the time (i.e. without them first two digits of timestamps get cut out most of the time).
Can anyone suggest what’s wrong? Seems like a sync issue.
Related
I need a way to send data to and from my pi pico via bluetooth.
Here is the program I'm running on my pc.
Note: Everything on the pi is working correctly (tested with a bt serial terminal)
import bluetooth as bt
print("Scanning Bluetooth Devices....")
devices = bt.discover_devices(lookup_names=True)
for addr, name in devices:
print("%s : %s" % (name, addr))
dev_name = input("Enter device name: ")
dev = ""
check = False
for addr, name in devices:
if dev_name == name:
dev = addr
check = True
if not check:
print("Device Name Invalid!")
else:
print("Attempting to connect to %s : %s" % (dev_name, dev))
hostMACAddress = dev
port = 3
backlog = 1
size = 1024
s = bt.BluetoothSocket(bt.RFCOMM)
s.bind((hostMACAddress, port))
s.listen(backlog)
try:
client, clientInfo = s.accept()
while 1:
data = client.recv(size)
if data:
print(data)
client.send(data) # Echo back to client
except:
print("Closing socket")
client.close()
s.close()
It doesn't throw any errors but I don't get anything printed to the terminal when the pi should send "R"
Edit: Here is the working code for anyone interested :)
import bluetooth as bt
print("Scanning Bluetooth Devices....")
devices = bt.discover_devices(lookup_names=True)
for addr, name in devices:
print("%s : %s" % (name, addr))
dev_name = input("Enter device name: ")
dev = ""
check = False
for addr, name in devices:
if dev_name == name:
dev = addr
check = True
if not check:
print("Device Name Invalid!")
else:
print("Sending data to %s : %s" % (dev_name, dev))
hostMACAddress = dev
port = 1
backlog = 1
size = 8
s = bt.BluetoothSocket(bt.RFCOMM)
try:
s.connect((hostMACAddress, port))
except:
print("Couldn't Connect!")
s.send("T")
s.send("E")
s.send("S")
s.send("T")
s.send(".")
s.close()
The most straight forward (but not the most efficient way) is to convert the array of integer to a delimited C string and send it the way you are sending "Ready".
Let assume the array delimiters are "[" and "]" then the following array
int arr[] = {1,2,3};
can be converted to a string like the following
char str[] = "[010203]";
To convert array of integer to the delimited string you can do the following:
int arr[] = {1,2,3};
int str_length = 50; // Change the length of str based on your need.
char str[str_length] = {0};
int char_written = 0;
char_written = sprintf(str,'[');
for (int i = 0; i< sizeof(arr)/sizeof(int) - 1; i++){
char_written = sprintf(&str[char_written], "%02d", arr[i]);
char_written = sprintf(&str[char_written], ']');
Now you can use your existing code to send this string. In the receiving end, you need to process the string based on "[", "]", and the fact that each integer has width of 2 in the string.
Edit: Converting array to string and send the string via bluetooth via python.
To convert an array to string in python the following will do the job
a = [1,2,3,4,5]
a_string = "[" + "".join(f"{i:02d}" for i in a) + "]"
To send this string via python over bluetooth you need to use PyBlues library.
First you need to find the MAC address of the pico bluetooth
import bluetooth
# Make sure the only bluetooth device around is the pico.
devices = bluetooth.discover_devices()
print(devices)
Now that you know the MAC address, you need to connect to it
bt_mac = "x:x:x:x:x:x" # Replace with yours.
port = 1
sock=bluetooth.BluetoothSocket(bluetooth.RFCOMM)
sock.connect((bd_addr, port))
Know you can send strings like
sock.send(a_string.encode())
Finally, in the end of your python program close the socket
sock.close()
PS: I do not have bluetooth available to test it but it should work.
I'm making an application using android and Python.
android is client
python is server
i send image file to python and want to receive string from server
but No strings are coming from the server.
socketIn.readLine() This part does not work.
try { // 소켓을 생성하고 입출력 스트립을 소켓에 연결
clientSocket = Socket(ip , port)
Log.d("Socket>>>>>>", "ip and port open Success!!!!!")
//val inputStream = clientSocket.getInputStream()
val tempfile = file
try{
socketIn = BufferedReader(InputStreamReader(clientSocket.getInputStream(), "UTF-8"))
//socketOut = PrintWriter(BufferedWriter(OutputStreamWriter(clientSocket.getOutputStream())),true)
dis = DataInputStream(FileInputStream(tempfile))
dos = DataOutputStream(clientSocket.getOutputStream())
val buf = ByteArray(1024)
var read_length : Int = 0
do {
read_length = dis.read(buf)
if(read_length == -1)
break
dos.write(buf)
dos.flush()
} while(read_length > 0)
var line : String?
var StringBuilder = StringBuilder()
do {
line = socketIn.readLine()
if(line == null)
break
StringBuilder.append(line)
}while(line != null)
onApiResult(line)
} catch (e : Exception){
Log.d("error", "${e}")
onApiFailed()
} finally {
clientSocket.close()
}
this is my android client code. client send the image to python server using tcp.
The image is sent well but the string does not come.
There is an error here line = socketIn.readLine()
please tell me how to fix it
from socket import *
serverPort = 8000
serverSocket = socket(AF_INET, SOCK_STREAM)
serverSocket.bind(('123.234.345.456', serverPort))
serverSocket.listen(1)
print('The server is ready to receive')
msg = "hi"
while True:
connectionSocket, addr = serverSocket.accept()
img_file = open('hi.jpg', "wb")
while True:
sentence = connectionSocket.recv(1024)
data = sentence
img_file.write(sentence)
if sentence:
print("recving IMg....")
print(sentence)
sentence = connectionSocket.recv(1024)
img_file.write(sentence)
else:
print('Done')
img_file.close()
break
connectionSocket.sendall(bytes(msg, 'UTF-8'))
connectionSocket.close()
Just a guess -- you are sending binary data, but your client code uses java Reader/Writer classes (dedicated to reading text-like data). Use Streams, instead of Reader/Writer. There is no notion of 'endOfLine' when reading binary data. Also note, that client call to 'readLine()' assumes client platform dependent end-of-line, whatever it may be. If server and client platform differ, it will never work.
***Python code:***
import serial
import pandas as pd
import time
import re
import xlrd
from msvcrt import getch
import numpy as np
i = 0
x = 0
y = 0
df = pd.read_excel(r'C:\Users\lynchfamily\Desktop\mlglovesdata.xls')
# Read COM9
# Read from COM10 as well
# Readline() only works with a timeout (IMPORTANT)
serHC = serial.Serial('COM9', 115200,timeout=.250,parity=serial.PARITY_NONE,rtscts=1) # This is the JY
serRN = serial.Serial('COM10', 115200,timeout=.250,parity=serial.PARITY_NONE,rtscts=1) # This is the silvermate
def serialin():
# Sensor lists
sensor_names = list()
sensor_values = list()
global i
# Read a certain amount of bytes from serial and then continue
# Regular expressions for finding the proper data
while i < 6:
# print(i) for debugging
global serHC
global serRN
#searchObj = re.search(r'(A\d?\d*)?(\d*)?',serHC.read(4).decode(),re.I)
#searchObjRN = re.search(r'(A\d?\d*)?(\d*)?',serRN.read(4).decode(),re.I)
# Serial data stops while in loop
# The if statements keep the false values out of the program
#if searchObj.group(1):
sensor_names.append(serHC.read(2))
#if searchObj.group(2):
sensor_values.append(serHC.read(2))
#if searchObjRN.group(1):
sensor_names.append(serRN.read(2))
#if searchObjRN.group(2):
sensor_values.append(serRN.read(2))
i = i + 1
while 1:
# Get the key from the msvcrt module
key = getch().decode('ASCII')
# If key is pressed, do something
if key:
print(key)
# Zip them together
# Final 2D list
final_2d_list = zip(sensor_names,sensor_values)
print(list(sorted(final_2d_list)))
#vals = df.Dataframe([
#df.append(vals)
#print(sorted_array_1stdim[r])
#sensor_values = [0] * 10
# Thread for reading definition
break
# Fancy recursion
sensor_values.clear()
sensor_names.clear()
i = 0
serialin()
serialin()
Arduino Code:
// The device with green colored wires
void setup() {
Serial.begin(115200);
}
void loop() {
// It won't work with the I2C while loop for some reason. Perhaps it is getting stuck up on it
Serial.print("A4");
Serial.print(analogRead(0)); // Read the local analog signal
delay(5);
Serial.print("A5");
Serial.print(analogRead(1)); // Read the local analog signal
delay(5);
Serial.print("A6");
Serial.print(analogRead(2)); // Read the local analog signal
delay(5);
Serial.print("A7");
Serial.print(analogRead(3)); // Read the local analog signal
}
I'm trying to send analog data from sensors over through bluetooth silver mate from sparkfun, and HC-06 modules to python.
I have to read the analog data at a delay of 5 seconds between each, so that the readings aren't conflicted.
The data comes through serial ports COM9 and COM10. I know that serial in python can be blocking, that's why I attempted to read it first, and then put it in a list.
I also knows that once serial has been read through, it appears to be non-blocking. When I was using serHC.readline() and serRN.readline(), I was getting something like what I'd expect to see.
However, the data in the list were not updating according to the change in the sensors. I have to admit python is not my main programming language, so that is why I'm asking for help.
I thought maybe using multiple threads might work, but I wasn't able to get the serHC and serRN variables in the main thread.
Any help will be appreciated!!
As you have discovered it is not possible to read sequentially from serial ports: a blocking read over one port implies a loss of data simultaneous sent over the other port.
Use a thread based approach.
The following sketch should be enough to get started:
import serial
import time
import re
import threading
BYTES_TO_READ = 6
# read from serial port
def read_from_serial(board, port):
print("reading from {}: port {}".format(board, port))
payload = b''
ser = serial.Serial(port, 115200,timeout=.250, parity=serial.PARITY_NONE, rtscts=1)
bytes_count = 0
while bytes_count < BYTES_TO_READ:
read_bytes = ser.read(2)
# sum number of bytes returned (not 2), you have set the timeout on serial port
# see https://pythonhosted.org/pyserial/pyserial_api.html#serial.Serial.read
bytes_count = bytes_count + len(read_bytes)
payload = payload + read_bytes
# here you have the bytes, do your logic
# ...
print("READ from {}: [{}]".format(board, payload))
return
def main():
board = {
'JY': 'COM9',
'SILVER': 'COM10'
}
threads = []
for b in board:
t = threading.Thread(target=read_from_serial, args=(b, board[b],))
threads.append(t)
t.start()
# wait for all threads termination
for t in threads:
t.join()
main()
For learning about threading: https://pymotw.com/3/threading/
Periodic read from serials
Below a sketch for reading each TIME_PERIOD seconds.
A parte the infinite while loop around the read there is a "thread" loop with a nested try/catch block
for catching serials communication problems and retrying to connect after TIME_PERIOD.
Take it just as a starting example!
import serial
import time
import re
import threading
BYTES_TO_READ = 6
TIME_PERIOD = 5
def read_message(board, port, handle):
payload = b''
bytes_count = 0
while bytes_count < BYTES_TO_READ:
read_bytes = handle.read(2)
bytes_count = bytes_count + len(read_bytes)
payload = payload + read_bytes
# here you have the bytes, do your logic
# ...
print("READ from {}: [{}]".format(board, payload))
def serial_thread(board, port):
print("reading from {}: port {}".format(board, port))
while True:
try:
handle = serial.Serial(port, 115200,timeout=.250, parity=serial.PARITY_NONE, rtscts=1)
while True:
read_message(board, port, handle)
time.sleep(TIME_PERIOD)
except Exception as e:
print("ERROR: {}".format(e))
print("retrying in {} seconds".format(TIME_PERIOD))
handle.close()
time.sleep(TIME_PERIOD)
def main():
board = {
'JY': '/dev/ttyUSB0',
'SILVER': '/dev/ttyACM0'
}
threads = []
for b in board:
t = threading.Thread(target=serial_thread, args=(b, board[b],))
threads.append(t)
t.start()
# wait for all threads termination
for t in threads:
t.join()
main()
My current application involves a C client sending a file to a Python server using TCP. It will produce a hash of the file and send the information back. I can get it to work with a python client but I am having issues migrating the client into C. The python server is still unfinished (it needs to convert the file size string to int, error checking, etc).
My biggest issue right now is after the server calls hash_type = connbuff.get_utf8(), it gives me the first user input of the hash type, then closes the connection. I know it is an issue with get_utf8(), but I am stumped on how to fix this. Should I just send arbitrary amounts of data from the client every time? Please help me learn from the error of my ways! Any advice/suggestions are much appreciated! Thanks =)
Server.py
import socket
import os
import hashlib
import buffer
HOST = '127.0.0.1'
PORT = 2345
def getHash(fileName, hashType):
... hash algorithms ....
try:
os.mkdir('uploads')
except FileExistsError:
pass
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
s.listen(10)
print("Waiting for a connection.....")
while True:
conn, addr = s.accept()
print("Got a connection from ", addr)
connbuf = buffer.Buffer(conn)
while True:
hash_type = connbuf.get_utf8()
if not hash_type:
break
print('Hash Type: ', hash_type)
file_name = connbuf.get_utf8()
if not file_name:
break
print('File Name: ', file_name)
file_name = os.path.join('uploads', file_name)
file_size = connbuf.get_utf8()
file_size = int(file_size)
print('File Size: ', file_size)
with open(file_name, 'wb') as f:
remaining = file_size
while remaining:
if remaining >= 4096:
chunk_size = 4096
else:
chunk_size = remaining
chunk = connbuf.get_bytes(chunk_size)
if not chunk:
break
f.write(chunk)
remaining -= len(chunk)
if remaining:
print('File incomplete: MISSING', remaining, 'BYTES.')
else:
print('File received successfully.')
file_hash = getHash(file_name, hash_type)
response = file_name + ' ' + file_hash
connbuf.put_utf8(response)
print('Connection closed.')
conn.close()
My Buffer class get_utf8() and get_bytes() look like this...
def __init__(self,s):
self.sock = s
self.buffer = b''
def get_bytes(self,n):
while len(self.buffer) < n:
data = self.sock.recv(1024)
if not data:
data = self.buffer
self.buffer = b''
return data
self.buffer += data
data,self.buffer = self.buffer[:n],self.buffer[n:]
return data
def get_utf8(self):
while b'\x00' not in self.buffer:
data = self.sock.recv(1024)
if not data:
return ''
self.buffer += data
data,_,self.buffer = self.buffer.partition(b'\x00')
return data.decode()
Client.c
#include <sys/socket.h>
... more includes ...
#define PORT_NUMBER 2345
#define SERVER_ADDRESS "127.0.0.1"
char *inputString(FILE* fp, size_t size){
... string input code ...
}
int main () {
int server_socket, connection_status;
struct sockaddr_in serverAddress;
char *hashType;
char *fileName;
char send_buffer[4000];
FILE * file_to_send;
int file_size;
/* Connect to Server */
... connect to server code ...
/* Get Hash an File User Input */
printf("Enter hash type: ");
hashType = inputString(stdin, 10);
printf("Hash type: %s\n", hashType);
printf("Enter file name: ");
fileName = inputString(stdin, 10);
printf("File Name: %s\n");
/* Send User Input */
send(server_socket, hashType, sizeof(hashType), 0);
send(server_socket, fileName, sizeof(fileName), 0);
/* Open File, Get Size, Convert to String */
file_to_send = fopen(fileName, "rb");
fseek(file_to_send, 0, SEEK_END);
file_size = ftell(file_to_send);
fseek(file_to_send, 0, SEEK_SET);
int l = snprintf(NULL, 0, "%d", file_size);
char *str_file_size;
asprintf(&str_file_size, "%i", file_size);
printf("%s\n", str_file_size);
/* Send File Size and File */
send(server_socket, str_file_size, sizeof(str_file_size), 0);
while(!feof(file_to_send)) {
fread(send_buffer, 1, sizeof(send_buffer) - 1, file_to_send);
}
send(server_socket, send_buffer, sizeof(send_buffer), 0);
return 0;
}
get_utf8 expects to read a null-terminated UTF-8-encoded string from the socket. In the C code, you send sizeof(hashType). hashType is a pointer, so you are sending exactly 4 or 8 bytes (depending on 32- or 64-bit architecture). You probably need strlen(hashType)+1 (+1 for the NULL). Ditto for filename.
get_utf8 also reads until it sees a null. If it never sees one, it returns empty string, which then causes the receive code to break and closes the connection.
I am sending a double value from C through TCP using lwIP. To accomplish that, I am using an union between a double and one string of 8 bytes (because the lwIP's function to send data is of type 'char *'). Here te code:
void process_echo_request(void *p) {
int sd = (int)p;
int RECV_BUF_SIZE = 2048;
char recv_buf[RECV_BUF_SIZE];
int n, nwrote;
union {
double dval;
char sval[sizeof(double)];
} data_to_send;
data_to_send.dval = 1e+23;
while (1) {
/* read a max of RECV_BUF_SIZE bytes from socket */
if ((n = read(sd, recv_buf, RECV_BUF_SIZE)) < 0) {
xil_printf("%s: error reading from socket %d, closing socket\r\n", __FUNCTION__, sd);
break;
}
/* break if the recved message = "quit" */
if (!strncmp(recv_buf, "quit", 4))
break;
/* break if client closed connection */
if (n <= 0)
break;
data_to_send.dval += 1e+23;
/* handle request */
if ((nwrote = write(sd, data_to_send.sval, 8)) < 0) {
xil_printf("%s: ERROR responding to client echo request. received = %d, written = %d\r\n",
__FUNCTION__, n, nwrote);
xil_printf("Closing socket %d\r\n", sd);
break;
}
}
/* close connection */
close(sd);
vTaskDelete(NULL);
I am trying to read from a Python script, but I fail on get the double value. The code:
#!/usr/bin/env python
import socket
from ctypes import *
TCP_IP = '192.168.0.10'
TCP_PORT = 1000
BUFFER_SIZE = 8
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((TCP_IP, TCP_PORT))
s.send(" ")
data = s.recv(BUFFER_SIZE)
s.close()
print float(data)
It fails with the message ValueError: could not convert string to float: �J��-�D
I know, is because the string is not a literal representation of a real value. Any idea? I need the real (double) value.
For more information, the lwIP echo server is running in a Zynq 7000 FPGA+SoC. I am running the Python code from a Debian 8. The double value is a 64 bit temperature for a sensor.
-- EDIT --
The final working code is:
#!/usr/bin/env python
import socket
from struct import *
TCP_IP = '192.168.0.10'
TCP_PORT = 1000
BUFFER_SIZE = 8
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((TCP_IP, TCP_PORT))
s.send(" ")
data = s.recv(BUFFER_SIZE)
s.close()
print unpack("d",data)[0]
you're recieving the binary representation of the double, not the string one.
You have to unpack it using struct module and the double specifier which is d. struct.unpack returns a tuple, so take first & only value to get your float
my_value = struct.unpack("d",data)[0]
note that you can even fix the endianness with < or >, not necessary if you're on the same machine or CPU type for both programs.