
Using a 30 year old laptop in 2021:
As the MC400 has no native networking capability we can’t send tweets directly from the machine itself. But, if you attach to another computer that does have a twitter client via the serial link(s) then it becomes possible. I could have just used the terminal and tweeted directly from the Raspberry Pi command line but I wanted something that felt more like an actual twitter client running on the MC itself. This solution uses rainbowstream on the Pi to tweet so obviously requires it to be installed and configured as a prerequisite. The account that the tweets will come from is the one that is configured within rainbowstream.
I created an OPL program that asks the user for the tweet text. The progam writes the text to REM::C:\TWEET\INBOX\TWEET.TXT
directly on the Pi’s filesystem. This is possible as I have the DOS “MCLINK.EXE
” running on the Pi in the dosbos-x emulator, but this obviously relies on the Link app running on the MC400 too so the first thing the OPL does is check that it can see the Pi’s filesystem. The dosbox-x config uses the USB-serial adapter /dev/ttyUSB1
as COM1
and mounts /home/pi/mc400
as C:\
The OPL also implements “Bring” functionality – basically a one shot copy/paste: highlight some text in another application i.e. text processor switch back to TWITTER.OPO
and “bring” the text. This is based on some old OPL code from 1995 that utilises system calls (credit: Colly Myers, David Wood and Tom Dolbilin).
I found a generic Twitter icon on the web, resized it to 32 x 32 and converted it to PCX format using the GIMP, then converted it to the Psion .PIC format using Psion’s own DOS tool WSPCX.EXE
. Renaming it to .ICN allows the translated .OPO file to be installed in the MC400 system with this icon.
A script on the Pi watches /home/pi/mc400/TWEET/INBOX
using the inotifywait command (part of the inotify suite) and if it detects the file TWEET.TXT has been created it then runs some further commands to pipe the text through the rainbowstream twitter cleint.
Finally, the TWEET.TXT
file from the /home/pi/mc400/TWEET/INBOX
directory is moved to /home/pi/mc400/TWEET/OUTBOX
with the current date/time added to the filename.
The shell script to process the tweets is installed as services on the Pi, the service spec is included below too. Save this file as /lib/systemd/system/mc400_tweet.service
Then issue the commandssudo systemctl daemon-reload
sudo systemctl enable mc400_tweet.service
sudo systemctl start mc400_tweet.servicesudo systemctl status mc400_tweet.service
(all code also available on GitHub)
OPL code – TWITTER.OPL
:
REM
REM Simple Tweet sending from the Psion MC400
REM
REM - needs appropriate handling of files written
REM to an attached device to actually send tweets!
REM
REM v1.0.01 19/09/2021 @zedstarr
REM
PROC Tweeter:
LOCAL ret%,fName$(128),txt$(255),address%,version$(6)
LOCAL handle%,mode%,k%,len%
version$="1.0.01"
REM Check link connected
ONERR borked::
k%=EXIST("REM::C:\MCLINK.EXE")
borked::
ONERR OFF
IF NOT k%
PRINT
PRINT " PSION MC400 Simple Twitter Client v"+version$+" (c) 2021 @zedstarr"
PRINT
PRINT " ERROR: Can't connect to PsiBridge"
PRINT " Check serial connection."
GET
ELSE
fName$="REM::C:\TWEET\INBOX\TWEET.TXT"
SCREEN 80,12
WHILE NOT ERR
PRINT
PRINT " PSION MC400 Simple Twitter Client v"+version$+" (c) 2021 @zedstarr"
PRINT " (on a blank line - <ESC> to quit, L<Enter> to Bring data)"
PRINT
PRINT " Tweet:>",
TRAP EDIT txt$
IF ERR=-114
RETURN
ENDIF
IF txt$="L"
txt$=bring$:
CLS
ELSE
BREAK
ENDIF
ENDWH
mode% = $0001 OR $0020 OR $0100
ret%=IOOPEN(handle%,fName$,mode%)
IF ret%
Showerr:(ret%)
RETURN
ENDIF
address%=ADDR(txt$)+1 : len%=len(txt$)
ret%=IOWRITE(handle%,address%,len%)
IF ret%
Showerr:(ret%)
RETURN
ENDIF
ret%=IOCLOSE(handle%)
IF ret%
Showerr:(ret%)
RETURN
ENDIF
ENDIF
ENDP
PROC Showerr:(val%)
PRINT "Error: ",val%,err$(val%)
GET
ENDP
rem The following code is based on "LPC.OPL"
rem (Original code written by Colly Myers)
rem (Translated into OPL by Tom Dolbilin)
rem (adapted for the MC with help from David Wood at Psion)
PROC Bring$:
global srvPid% rem PID of Link server
global buf$(255) rem Buffer to receive data
global ioSem% rem The I/O semaphore handle
local wsrvPid% rem PID of Window server
local fmt& rem Message buffer
local pfmt% rem Pointer to message buffer
local name$(15),form%(3),n%,ret%,ret$(255)
local w%(2)
rem --- Get Shell's pid
rem Note: on the MC, SYS$SHLL.IMG holds Link server data
rem on the Series 3/3a SYS$WSRV.IMG holds Link Server data
rem change name$ to "SYS$WSRV.*" for Series 3/3a
name$="SYS$SHLL.*"
wsrvPid%=call($188,addr(name$)+1)
rem --- Get the handle of our I/O semaphore
call($78b,0,2,0,(call($88) and $fff)+33,addr(ioSem%))
rem --- Get the Link Server's pid
pfmt%=addr(fmt&)
srvPid%=call($683,wsrvPid%,4,0,addr(pfmt%)) rem MessSendReceiveWithWait
if srvPid%<0
showerr:(srvPid%)
return ""
elseif srvPid%=0
at 2,11
print "Nothing to bring"
pause 40
at 2,11
print " "
return ""
endif
rem --- Get the name of the Link Server
call($a88,srvPid%,0,0,0,addr(name$)+1)
pokeb addr(name$),call($b9,0,0,0,0,addr(name$)+1)
w%(1)=$2
rem --- Request a rendering
ret%=talk%:(w%(1),0)
if ret%=0
rem --- Server prepared to render data
while 1
ret%=talk%:(addr(buf$)+1,255) : rem Get the server data
if ret%<0
if ret%=-36 rem End of file
ret%=0 rem Avoid an error print
endif
break
endif
rem --- Display the data received
pokeb addr(buf$),ret%
ret$=peek$(addr(buf$))
endwh
endif
if ret%<0
showerr:(ret%)
endif
return ret$
ENDP
PROC Talk%:(a%,b%)
local arg1%,arg2% rem Message parameters - keep in order
local stat%,count%,ret%
arg1%=a%
arg2%=b%
call($0583,srvPid%,$21,0,addr(arg1%),addr(stat%)) rem MessSendReceiveAsynchronous
while 1
iowait
if stat%<>-46 : rem The result has been returned
ret%=stat%
break
else
count%=count%+1 : rem Count up all other signals
endif
endwh
rem --- Put back spare signals if any
while count%
iosignal
rem call($382,ioSem%,0,0,0,0) rem SemSignalOnce
count%=count%-1
endwh
return ret%
ENDP
Shell script –/home/pi/mc400/scripts/mc400_watch_tweet.sh
:
#!/bin/bash
/usr/bin/inotifywait -m /home/pi/mc400/TWEET/INBOX/ -e create |
while read dir action file; do
if [[ "$file" == "TWEET.TXT" ]] ; then
sleep 3
content=`cat /home/pi/mc400/TWEET/INBOX/TWEET.TXT`
/usr/bin/printf "\nt $content\nexit()" | /usr/local/bin/rainbowstream
sleep 12
mv /home/pi/mc400/TWEET/INBOX/TWEET.TXT /home/pi/mc400/TWEET/OUTBOX/TWEET`date +"%Y-%m-%d-%H%M%S"`.TXT
fi
done
mc400_tweet.service
file:
[Unit]
Description=PSION MC400 tweet helper
[Service]
Restart=on-failure
RestartSec=10
ExecStart=/home/pi/mc400/scripts/mc400_watch_tweet.sh
WorkingDirectory=/home/pi/mc400
SyslogIdentifier=mc400
User=pi
Group=pi
StandardOutput=null
[Install]
WantedBy=multi-user.target