FlexBASIC P2 rtc WiFi
When I load this and run it, for some reason the 'input #2, inBuff', is not working as expected.
I am using a telnet client program (putty) to access the P2 WiFi, and for some reason when I try the getdate or getime command, it is not waitng for the input, it just does a CR. Is there something wrong with input #2, or is there something weird with the telnet client program.
Ray
' rtc_wifi.bas
dim cr2 as class using "spin/SmartSerial.spin"
cr2.startx(63, 62, 0, 115200)
open SendRecvDevice(@cr2.tx,@cr2.rx) as #2
dim inBuff as string
' hours, minutes, seconds: 00-23, 00-59, 00-59
dim as ubyte hours, mins, secs
' month, day in month: 1-12, 1-31
dim as ubyte MM, DD
' year: 4 digits
dim as integer YYYY
dim s$ as string
dim date as string
dim time as string
dim tmpYYYY, tmpMM, tmpDD, tmpHOURS, tmpMINS, tmpSECS as ulong
dim stack_rtc(10)
dim cpuID_3 as long
cpuID_3 = cpu(updateClock, @stack_rtc(1))
do
print #2, "> ";
input #2, inBuff
if inBuff = "setdate" then
input #2, "Enter year, month and day as YYYY-MM-DD ",s$
s$ = ltrim$(rtrim$(lcase$(s$)))
if len(s$) <> 10 then
print #2, "Illegal date format: Date should be YYYY-MM-DD"
else
YYYY = val(left$(s$, 4))
MM = val(mid$(s$, 6, 2))
DD = val(right$(s$, 2))
end if
else if inBuff = "settime" then
input #2, "Enter time as HH:MM:SS ",s$
s$ = ltrim$(rtrim$(lcase$(s$)))
if len(s$) <> 8 then
print #2, "Illegal time format: Should be HH:MM:SS!"
else
HOURS = val(left$(s$, 2))
MINS = val(mid$(s$, 4, 2))
SECS = val(right$(s$, 2))
end if
else if inBuff = "getdate" then
getdate()
else if inBuff = "gettime" then
gettime()
else
print #2, "??"
end if
loop
end
'' RTC
'' helper subroutine; return number of days in month
''
function daysInMonth() as uinteger
' february special case
if MM = 2 then
if (YYYY mod 4 = 0) then
if (YYYY mod 100 <> 0) or (YYYY mod 1000 = 0) then
return 29
endif
endif
return 28
endif
if (MM = 4) or (MM=6) or (MM=9) or (MM=11) return 30
return 31
end function
'''''''''''''''
'' RTC
'' routine to keep the clock up to date
''
sub updateClock
dim nextSecond
dim FREQUENCY
FREQUENCY = clkfreq
nextSecond = getcnt() + FREQUENCY
do
waitcnt(nextSecond)
nextSecond = nextSecond + FREQUENCY
secs = secs + 1
if (secs >= 60) then
secs = 0
mins = mins + 1
if (mins >= 60) then
mins = 0
hours = hours + 1
if (hours >= 24) then
hours = 0
DD = DD + 1
endif
endif
endif
if (DD > daysInMonth()) then
DD = 1
MM = MM + 1
if (MM > 12) then
MM = 1
YYYY = YYYY + 1
endif
endif
loop
end sub
'''''''''''''''
sub getdate
print #2, "Current date: ";
print #2, using "%%/%%/%%%%"; MM; DD; YYYY
end sub
'''''''''''''''
sub gettime
print #2, "Current time: ";
print #2, using "%%:%%:%%"; hours; mins; secs
end sub
'''''''''''''''
Comments
My bet is the terminal program is putting a CRLF at the end of the line. Set the terminal program to emit only a CR at the end of the line and see what happens.
Also: you can replace rtrim$(ltrim$(X$)) with just trim$(). And for integer-only inputs to val() you can more efficiently use val%()
I have access to putty and TeraTerm programs.
In putty I could not find the correct CRLF control for the program to work with my program. It looks like that control has to be done on the FlexBASIC side, somehow.
In TeraTerm, it has more control on the CRLF, but what is offered is not the correct combination for making it work with FlexBASIC. So....
Not sure which way to go, in order to resolve this issue, any ideas? I was playing around with Python code using socket, but did not make to much headway with that. I noticed there is code examples for Python telnet program, not sure if that would be any different then the socket stuff.
Ray
I saw the same issue. The nice think about the Wifi module is you can connect two devices at the same time.
I was not able to get putty to work.
Telnet from the command line on windows works just fine though.
I see flex props telnet session does not echo characters.
I tried simpleIDE terminal session and that also works just fine.
Mike
You could write a character-by-character handler. Have it inspect each char as it comes in, toss the char if its a control code or an LF, and append whatever is “normal” text it to a buffer. When you get a CR, process the string as you would have if it came from an INPUT. Sort of your own version of “input” if you will.
I cobbled together a Python program to verify that I can connect to the P2 WiFi, to access the P2 FlexBASIC rtc program. It seems to be working as expected.
I tried out the setdate and settime commands, working as expected. I added a connect2 command, which provides some data about the WiFi card? The next thing, I guess, would be, is to set up the program so I could get the internet time and date, and have inserted into the P2 FlexBASIC rtc program.
Ray
# newone.py import socket import sys host = '192.168.xx.xxx' port2 = 80 # web port = 23 # WiFi global s def connect1(): # create socket print('# Creating socket') try: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) except socket.error: print('Failed to create socket') sys.exit() print('# Getting remote IP address') try: remote_ip = socket.gethostbyname( host ) except socket.gaierror: print('Hostname could not be resolved. Exiting') sys.exit() # Connect to remote server print('# Connecting to server, ' + host + ' (' + remote_ip + ')') s.connect((remote_ip , port)) def connect2(): print('# Creating socket') #s.quit() try: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #s.close() #s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) except socket.error: print('Failed to create socket') sys.exit() print('# Getting remote IP address') try: remote_ip = socket.gethostbyname( host ) except socket.gaierror: print('Hostname could not be resolved. Exiting') sys.exit() # Connect to remote server print('# Connecting to server, ' + host + ' (' + remote_ip + ')') s.connect((remote_ip , port2)) def send_data2(): remote_ip = socket.gethostbyname( host ) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((remote_ip , port2)) request = "GET / HTTP/1.0\r\n\r\n" try: s.sendall(request.encode("utf-8")) except socket.error: print('Send failed') sys.exit() # Receive data print('# Receive data from server') reply = s.recv(4096) print(reply.decode("utf-8")) def send_data(indata): remote_ip = socket.gethostbyname( host ) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((remote_ip , port)) # Send data to remote server print('# Sending data to server') print('\n') #request = "GET / HTTP/1.0\r\n\r\n" request = indata try: s.sendall(request.encode("utf-8")) except socket.error: print('Send failed') sys.exit() # Receive data print('# Receive data from server') reply = s.recv(4096) print(reply.decode("utf-8")) while True: inBuff = input(": ") if inBuff == "connect": connect1() elif inBuff == "connect2": connect2() send_data2() elif inBuff == "gettime": send_data("gettime\n") elif inBuff == "setdate": send_data("setdate\n") setdate=input() send_data(setdate + "\n") elif inBuff == ("settime"): send_data("settime\n") settime=input() send_data(settime + "\n") elif inBuff == "getdate": send_data("getdate\n") else: print("??")
How about using an NTP server on the internet to get the time.
Here is an example I made some time ago that explains it not very good but should work with your Wifi board.
getting-the-date-and-time-with-parallax-wifi-module
Mike
@iseries, is there a simple way to set up 2 Parallax WiFi Modules in a pass-through mode like a pair of XBees? Can we avoid all the SEND/GET web style code and just connect 2 modules and have them act as serial interfaces? As Ray has done, we can easily connect to 1 WiFi module from a PC via Python or another language. Can we do the same between 2 WiFi modules hooked up to our P2s (or P1s)?
dgately
@dgately ,
The simple answer is no. For telent to work between two units or more is that one has to be the host and the other the client. In this case the host is the Wifi unit and it is listening on port 23. The client end is using some random port that is assigned when the connection is started.
You can however setup to Wifi modules to talk to each other with very simple code that is explained in this discussion.
what can I do with a parallax-wx module
Mike
THx Mike! Had not read that posting...
The reason that I chose Python for this experiment was, there is greater flexibility for expanding the scope of the project, via Python. The P2 is a powerful little chip, but it has its limitations. Basically, you will need a more robust assistant system if you want to go on to bigger things.
Like I mentioned earlier, having the P2 rtc (software) updated by the internet clock; now that I thought about it, it should be very easy to do, I may end up regretting what I just said.
Another thing that I am thinking about is, I have an interest in AI/Machine Learning. The P2 may be able to do that on a very small scale, by itself, but I think a better option is to have a PC do the hard work, and funnel the data down to the P2, when needed. Just a couple of things to think about.
Now I am wondering if I can turn the Python program into a GUI presentation.
Ray
The below Python code now has a GUI component. It is not professional quality, but you should get a good idea of how Python works.
In the GUI, the top left side, white space, you enter your wifi address, then hit the 'Get text' button. That makes the wifi address available for the program to work. I use Geany, so a little terminal opens up, and the GUI part shows up. The 'Set Date' and 'Set Time' buttons now load the internet time and date to the rtc program.
You can use the rtc P2 FlexBASIC code, from my first post. On my set up this is working as expected. I hope somebody finds this useful.
Ray
# newtwo.py # March 14, 2022 import socket import sys #import datetime from datetime import datetime import tkinter as tk from tkinter import * from tkinter import ttk root = Tk() # Use the get_text button to insert host wifi address #host = '192.168.35.111' port2 = 80 # web port = 23 # WiFi global s global host def connect1(): # create socket print('# Creating socket') try: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) except socket.error: print('Failed to create socket') sys.exit() print('# Getting remote IP address') try: remote_ip = socket.gethostbyname( host ) except socket.gaierror: print('Hostname could not be resolved. Exiting') sys.exit() # Connect to remote server print('# Connecting to server, ' + host + ' (' + remote_ip + ')') s.connect((remote_ip , port)) def connect2(): print('# Creating socket') try: s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #s.close() #s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) except socket.error: print('Failed to create socket') sys.exit() print('# Getting remote IP address') try: remote_ip = socket.gethostbyname( host ) myinputvalue(remote_ip) except socket.gaierror: print('Hostname could not be resolved. Exiting') sys.exit() # Connect to remote server print('# Connecting to server, ' + host + ' (' + remote_ip + ')') s.connect((remote_ip , port2)) def send_data2(): remote_ip = socket.gethostbyname( host ) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((remote_ip , port2)) request = "GET / HTTP/1.0\r\n\r\n" try: s.sendall(request.encode("utf-8")) except socket.error: print('Send failed') sys.exit() # Receive data print('# Receive data from server') reply = s.recv(4096) myinputvalue(reply) print(reply.decode("utf-8")) def send_data(indata): remote_ip = socket.gethostbyname( host ) s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((remote_ip , port)) # Send data to remote server print('# Sending data to server') print('\n') #request = "GET / HTTP/1.0\r\n\r\n" request = indata try: s.sendall(request.encode("utf-8")) except socket.error: print('Send failed') sys.exit() # Receive data print('# Receive data from server') reply = s.recv(4096) print(reply.decode("utf-8")) newdata = reply.decode("utf-8") myinputvalue(newdata) def myinputvalue(indata): result = indata myTKtext.delete("1.0","end") # Clears the text box #myTKtext.insert(END, result + '\n') myTKtext.insert(END, result) def Set_date(): #print("debug") send_data("setdate\n") now = datetime.now() date_val = now.strftime("%Y-%m-%d") send_data(date_val+"\n") def Set_time(): send_data("settime\n") now = datetime.now() time_val = now.strftime("%H:%M:%S") send_data(time_val + "\n") def Getp2_date(): send_data("getdate\n") def Getp2_time(): send_data("gettime\n") ## GUI portion ############## def Get_MyInputValue(): result = MyEntryBox.get() #Gets the entry myTKtext.insert(END, result + '\n') #Inserts in Text window with a CR global host host = result # Create Tkinter Entry Widget MyEntryBox = Entry(root, width=20) MyEntryBox.place(x=5, y=6) #myTKtext window myTKtext = Text(root, height = 22, width = 40, bg = "light cyan") myTKtext.place(x=4, y=62) #command will call the defined function MyTkButton = Button(root, height=1, width=10, text="Get text", \ command=Get_MyInputValue) MyTkButton.place(x=200, y=6) MyTkButton2 = Button(root, height=1, width=10, text="Set Date", \ command=Set_date) MyTkButton2.place(x=400, y=6) MyTkButton3 = Button(root, height=1, width=10, text="Set Time", \ command=Set_time) MyTkButton3.place(x=550, y=6) MyTkButton4 = Button(root, height=1, width=10, text="Get P2 Date", \ command=Getp2_date) MyTkButton4.place(x=400, y=40) MyTkButton5 = Button(root, height=1, width=10, text="Get P2 Time", \ command=Getp2_time) MyTkButton5.place(x=550, y=40) ## End of GUI portion ##################### if __name__ == "__main__": #root = tk.Tk() root.title("tkTERM ") root.geometry("800x500") #root.mainloop() while True: inBuff = input(": ") if inBuff == "connect": connect1() elif inBuff == "connect2": connect2() send_data2() elif inBuff == "gettime": send_data("gettime\n") elif inBuff == "setdate": send_data("setdate\n") ## manual input ## #setdate=input() #send_data(set_date + "\n") ## ## Auto input ## now = datetime.now() date_val = now.strftime("%Y-%m-%d") send_data(date_val+"\n") ## elif inBuff == ("settime"): send_data("settime\n") ## Manual input ## #settime=input() #send_data(settime + "\n") ## ## Auto input ## now = datetime.now() time_val = now.strftime("%H:%M:%S") send_data(time_val + "\n") ## elif inBuff == "getdate": send_data("getdate\n") elif inBuff == "testit": myinputvalue() else: print("??") root.mainloop()
@dgately
" is there a simple way to set up 2 Parallax WiFi Modules in a pass-through mode like a pair of XBees?"
I was browsing through the Parallax wifi firmware pdf, and it shows a possible way of connecting two wifi's, and maybe having a sort of serial connection. I think if you setup the wifi's in AP mode, that might get you what you are looking for. Not sure how simple that would be to do, but that might be an interesting way to go.
My theory, if you have two P2 wifi's, you set one up in STA-AP, that creates an address. On the second P2 wifi, you set that up with a link to the first ones address. Since both would have a hard serial connect to the respective P2, hopefully the wifi firmware would allow a connection between the two P2's, in a pseudo serial manner. Now using a serial program, on each P2, maybe that should be able to talk too each other. This sounds way to simple, maybe dgately can give it a try. I do not have two P2's or two wifi's, to try this out myself.
Ray
Thanks Ray!
Yes, that's basically what I'm working on. I've got the start of a connection between 2 WiFI Modules using Mike's "what can I do with a parallax-wx module" and Clock Loop's code from this post: https://forums.parallax.com/discussion/comment/1520117/#Comment_1520117. I'm converting that code to Spin2 and am starting to have success! Once I have good results I'll post to the PASM2/SPin2 (P2) discussions...