Using Kermit to Transfer files to/from SIMH HP3000

After talking to another HP3000 SIMH user who had no viable way to transfer files to the HP3000, I set out to look for something a bit easier than create a simH tape. OK, using kermit still isn’t simple, but it is a little more accessible.

Back before the internet, files were transferred between mini computers, like the HP3000, and PCs using file transfer programs such as Kermit. There were others such as xmodem, ymodem, and zmodem. I’m using Kermit because I have access to a copy that will work on top of telnet.

Forgetting for a moment about telnet, here is roughly how kermit works. From your PC, you  connect to the HP3000 over a serial or modem connection. You run kermit on the hp3000, and tell it whether to send or receive a file. You then tell the local software whether to send or receive a file. The two programs would then perform the transfer for you. Pretty clumsy by today’s standards.

The first thing you will need is Kermit for the HP3000. I found the source for an HP3000 version at http://www.columbia.edu/kermit/archive.html#hp. This link includes just the source, but I’ve compiled it for you and put it on a simH format tape so it is easy to copy to the HP3000.

Note to self: this version of kermit requires the abortsess intrinsic which is not available on the old version of MPE being used by simH. I deleted those 2 lines which really shouldn’t be a problem as I’m not anticipating needing the HP3000 to abort my session after transfer is complete.

I assume you are running HP3000 SIMH from the distribution I made available in my blog. If not, you may need to alter directory locations in the examples.

Restore Kermit on HP3000

  • To get the HP3000 binary of kermit, download this zip file which contains the simH tape:

http://www.xyfyx.com/files/kermit.tap.zip

  • Inside of the zip file you will find a single file, kermit.tap. Move it to your c:\hp3000Sim directory.
C:\hp3000Sim>dir kermit.tap
 Volume in drive C is c180104
 Volume Serial Number is D6EF-2751

 Directory of C:\hp3000Sim

08/24/2019  09:55 AM            74,360 kermit.tap
               1 File(s)         74,360 bytes
               0 Dir(s)  354,664,509,440 bytes free
  • Fire up your HP3000 emulator if you haven’t already. Then mount the tape as read only:
HP3000 / MPE V E.01.00 (BASE E.01.00). FRI, AUG 23, 1991, 4:47 PM
: <<<press control-E>>>
Simulation stopped, P: 071144 (PAUS 0)
sim> attach -r ms0 kermit.tap
MS: unit is read only
sim> go

9:31/10/Vol (unlabelled) mounted on LDEV# 7
  • Log in as manager.sys and restore kermit:
:HELLO MANAGER.SYS

CPU=1. CONNECT=1. SAT, AUG 24, 1991, 10:01 AM
10:01/#S3/16/LOGOFF ON LDEV #20

10:01/#S4/17/LOGON FOR: MANAGER.SYS,PUB ON LDEV #20
HP3000 / MPE V E.01.00 (BASE E.01.00). SAT, AUG 24, 1991, 10:01 AM
:FILE T;DEV=7
:RESTORE *T;@.PUB.SYS;OLDDATE;SHOW;KEEP
?10:01/#S4/17/IS "T" ON LDEV#7 (Y/N)?
<<<NOTE: You must type control-A here to get the '=' prompt>>>
=REPLY 17,Y
<<<The '17' matches the reply request PIN# of 17 in the request to mount "T">>>
SAT, AUG 24, 1991, 10:01 AM

  FILES RESTORED = 3

    FILE    .GROUP   .ACCOUNT   LDN  ADDRESS
    KERMIT  .PUB     .SYS       1    %275302
    JOBINFOU.PUB     .SYS       1    %277142
    JOBINFOI.PUB     .SYS       1    %252747

  FILES NOT RESTORED = 0

:LISTF KERMIT,2
ACCOUNT=  SYS         GROUP=  PUB

FILENAME  CODE  ------------LOGICAL RECORD-----------  ----SPACE----
                  SIZE  TYP        EOF      LIMIT R/B  SECTORS #X MX
KERMIT    PROG    128W  FB         221        221   1      222  1  1

:LISTF JOBINFO@,2
ACCOUNT=  SYS         GROUP=  PUB
FILENAME  CODE  ------------LOGICAL RECORD-----------  ----SPACE----
                  SIZE  TYP        EOF      LIMIT R/B  SECTORS #X MX
JOBINFOI           72B  FA          18         18  18       12  1  1
JOBINFOU  USL     128W  FB          54        400   1      201  1  2

Test Kermit

Unless you’ve already installed the JOBINFO intrinsic, kermit will fail:

:RUN KERMIT
UNRESOLVED PROG EXTERNAL JOBINFO
SL BINDING ERROR (LOAD ERR 27)
UNABLE TO LOAD PROGRAM TO BE RUN. (CIERR 625)
:

That just means that kermit is trying to access the jobinfo intrinsic which is not part of this old version of MPE. Fortunately, Keven Miller wrote a freeware version we can install.

:SEGMENTER
HP32050A.01.08 SEGMENTER/3000 (C) HEWLETT-PACKARD CO 1985
-USL JOBINFOU
-SL SL.PUB.SYS
-ADDSL JOBINFO
-EXIT

END OF SUBSYSTEM
:

and now kermit will run:

:RUN KERMIT

HP 3000 KERMIT VERSION: 12 JULY 1994
Works best with PC Kermit V2.31 or newer.
You can now use PARM= on RUN stmt to specify TAKE file.

KERMIT3000>EXIT

END OF PROGRAM
:

Installing Kermit on Your PC

I found a version of Kermit that will run on top of telnet here:

http://www.kermit.wwarthen.com/Download.htm

If that link ever goes away, I kept a copy of the 32bit zip version here:

http://www.xyfyx.com/files/kw32v085.zip

My preference was to copy the zip file and unzip it into c:\kermit.

After installing, start the PC kermit and it will look like this:

Configure Kermit on Your PC

Kermit needs to be configured to use TCP/Telnet to access the host. This example assumes that you have the hp3000Sim on your local host and are using port 1054 for telnet access to the simulator.

  • In the menu, go to Configure | session and set the connection to tcpip:

  • Go to Configure | Communications and set host to localhost (or the proper value) and port to 1054:

  • Now go to Session | Connect. This should connect to the HP3000 and you will see
Connect to the HP3000 simulator ATCD device, line <n>
  • Press the Enter key a few times and you should get a ‘:’. In kermit, I suggest you always logon using term type 18:
:hello manager.sys;term=18

Term=18 tells the HP not to use the its proprietary flow control.

Now that the settings are correct, I saved mine using File | Save As and saved them as kermitsettings.krm for future use.

Test Download of A File

Let’s download a file from the HP3000 to verify everything works.

  • In Kermit for PC, type
:run kermit.pub.sys

HP 3000 KERMIT VERSION: 12 JULY 1994
Works best with PC Kermit V2.31 or newer.
You can now use PARM= on RUN stmt to specify TAKE file.

KERMIT3000>
  • We are going to download a file called dumpmini, so we tell Kermit for HP to SEND that file:
KERMIT3000>send dumpmini.pub.sys
Escape back to your local KERMIT and enter the RECEIVE command
  • The HP is now ready to send the file, so on kermit for PC, we select Kermit | Receive and the transfer occurs:

Note: When you type EXIT into the kermit for HP3000, you will see nothing. This is because Kermit has turned off echo.

On old character mode operating systems such as MPE, every character you type is sent to the HP3000 and then the HP3000 echos it back to the monitor so you can verify it was received properly. On an old 300 baud modem, noise sometimes garbled terminal I/O so this was a way for you to verify your input.

Echo during a file transfer would be bad, so it gets turned off. Oddly, kermit doesn’t turn it back on. No worries, just type ESC+: and echo is turned on. ESC+; turns it off.

Review the Downloaded File

Kermit for PC doesn’t have a way to specify where files are downloaded on the PC. If you manually set the configuration, files will get downloaded to the c:\kermit directory. If you open a settings file (.krm), then the files are downloaded to that directory. Crazy! When I figured this out, I put a copy of my krm file in c:\tmp, so files would download there.

Let’s take a quick look at the file downloaded to verify it looks right. Since I downloaded dumpmini.pub.sys, the file will be found in c:\tmp\dumpmini.pub.sys:

What the??? What are those numbers to the right? Welcome to the age of punched cards.

In MPE, ASCII files can be numbered or unnumbered. Source code for programs were almost always numbered. Most of the computer languages for the HP3000 allowed you to use columns 1-72 for code and then columns 73-80 contained a sequence number. This sequence number came directly from the days of punch cards and was held over on disk files. COBOL was a little different. The sequence number was in columns 1-6, giving you columns 7-80 for the program.

Sequence numbers on punched cards could sometimes be very handy if you dropped the card deck. You could run the cards thru a sorter to resequence the deck. Not that that was a particularly fast operation as you could only sort on one column at a time.

HP editors took sequence numbers into account and would display them in a nicer format:

/t dumpmini
  File numbered
  Record length: 80    bytes
  Number of records: 79
  File code: 0
/l all
    1     !JOB FIELD.SUPPORT,PUB
    2     !EDITOR
    3     S SHORT;AQ
    4                                                       S.O. Ref.#____________
    5
    6                             HP SERVICE REQUEST FORM   SR #_________(HP only)
    7
    8     ************************************************************************
    9     Customer report no.________________                     Date__________

Downloading Multiple Files from the HP3000

You can use kermit’s SERVE mode to download multiple files.

  • On kermit for HP3000, type SERVE:
KERMIT3000>serve
Entering SERVER mode - escape back to your local KERMIT
  • Now, in kermit for PC, select Kermit | Get. This brings up a window where you can type in a file name, or use a wild card such as jobinfo@

Note: In the Get windows, you cannot specify group/account name (e.g. jobinfo@.pub.sys). This means you must be logged into the group where the files reside to use the get command.

MPE’s File Structure

Before we can transmit files to the HP3000, you need to have a basic understanding of the file structure because it is very different from Linux/dos.

In Linux/dos, you only specify if a file is ASCII(text) or binary. Even that distinction is just a convention. In Linux an ASCII file is read sequentially and <LF><CR> indicates the end of the line.

On the HP3000, you specify if the file is ASCII or binary, and the length of each record. You can also specify how many records there are per block, the maximum number of records.

Further, a file must be built via the BUILD command, specifying all of these options before it can be accessed. Sometimes the program will do this for you, but it must be done.

A BUILD command with all options looks like:

                                                         F   BINARY
    :BUILD filereference[;REC=[recsize][,[blockfactor][,[U][,      ]]]]
                                                         V   ASCII

          [;DISC=[numrec][,[numextents[,[initalloc]]]]]

A normal ‘text’ file in MPE (such as for source code) would contain 80 byte fixed length ASCII records. Fixed length records are almost always used. Most editors work better with fixed length records. To build such a file with 1000 records, I would use:

:BUILD myfile;REC=-80,,F,ASCII;DISC=1000

As seen above, text records are normally a fixed length of 72 or 80 bytes. To get a Linux/DOS type file where the records are variable length, you could use:

:BUILD myfile;REC=-254,,F,ASCII;DISC=1000

Using Kermit Options to Specify File Structure Automatically

Fortunately, the writer of Kermit for HP3000 took into account this complexity and came up with a few standard formats you can automatically use:

KERMIT3000>set receive ?

The SET RECEIVE parameter is used to alter the
default conditions regarding file reception.
The various options are:

SET RECEIVE DEVICE
SET RECEIVE FCODE
SET RECEIVE BINARY
SET RECEIVE RECLEN
SET RECEIVE FIXREC
SET RECEIVE BLOCKF
SET RECEIVE MAXREC
SET RECEIVE MAXEXT
SET RECEIVE SAVESP
SET RECEIVE PROG
SET RECEIVE TEXT
SET RECEIVE TXT80
SET RECEIVE BIN128
SET RECEIVE EXPTAB

Before transmitting the file to the HP3000, you can specify one of these options to create the appropriate structure:

  • TXT80 – files are received in ASCII, fixed 80 byte record lengths. The normal format for HP text editors. Lines > 80 characters are truncated! If that is an issue, use TEXT.
  • TEXT – files are received in ASCII, variable record lengths (max 254). If you are sending a PC text file with long line lengths, this is the best format.
  • BIN128 – upload file as binary, variable 128 word (256byte) record lengths. This would allow transfer of binary PC files to the HP3000.
  • PROG – if you are trying to transfer a program between HP3000’s, you would download it from the source HP to the PC in binary form. Then upload it to the destination PC using the SET RECEIVE PROG option so the file is properly setup as an executable file.
  • MAXREC – specifies the maximum # of records. If the default (5000) results in a failure because the file is too small, increase the max using this setting.

Upload a File to HP3000

In this example, I’m going to upload source code for a pascal program that simply prints “Hello World” on my PC to the HP3000, then compile it on the HP3000.

To do the transfer, start Kermit for PC, open the settings file for TCPIP settings, login as manager.sys,tmp (we want the source code in the TMP.SYS group, not PUB.SYS which is meant for system files), and start kermit on the HP3000.

We will use SET RECEIVE TEXT to allow uploading of a normal PC file which may have line lengths > 80 bytes. Finally, tell Kermit for HP3000 to RECIEVE world.tmp:

Now use Kermit | Send to send the source file that is on the PC.

The file has been uploaded properly:

:listf world,2
ACCOUNT=  SYS         GROUP=  TMP       

FILENAME  CODE  ------------LOGICAL RECORD-----------  ----SPACE----
                  SIZE  TYP        EOF      LIMIT R/B  SECTORS #X MX
WORLD             254B  VA           8       5000   1      314  1 32

Because the file is in variable record format (VA as type in above example), I would like to convert it to fixed format using EDIT/3000 so my editor of choice, QUAD, will work.

I use EDIT/3000, which can handle variable length records, to convert from variable to fixed, set the record length to 72, and then keep it as a numbered file. I do this using SET FORMAT=DEFAULT.

I know my longest line is <= 72 bytes. If it were longer, after using SET FORMAT=DEFAULT I could then set the length using SET LENGTH=nn.

:editor
HP32201A.7.16 EDIT/3000 SAT, AUG 24, 1991, 1:57 PM
(C) HEWLETT-PACKARD CO. 1984
/t world
FILE UNNUMBERED
/set format=default
/set fixed
WARNING - 'LENGTH' 254RESET TO 72
WARNING - 'RIGHT' 254RESET TO 72
*** WARNING *** DEFAULT VALUES SET FOR LENGTH, RIGHT, FROM, DELTA, REAR.
/verify all
1 program world;
^(1 )
LINES = 60
POLL = TRUE (I.E. BATCH = FALSE)
REAR = TRUE (I.E. FRONT = FALSE)
DELTA = 1
CURRENT DEPTH = 0, THE DEPTH LIMIT = 10
RIGHT =72
LENGTH = 72
LONG = TRUE (I.E. SHORT = FALSE)
TIME = 50
TOTAL NUMBER OF CURRENT LINES = 8
FROM = 1
LEFT = 1
FIXED = TRUE(I.E. VARIABLE = FALSE)
SIZE = 0
DISPLAY = TRUE (I.E. QUIET = FALSE)
FORMAT=DEFAULT
NO TABS USED
FILES:
WORK: K2361357
KEEP:
TEXT: WORLD.TMP.SYS SAT, AUG 24, 1991, 1:57 PM
JOIN:
/k world2
/e

END OF SUBSYSTEM
:

Here is a look at the cleaned up file, using QUAD:

:t world2

QUAD -- JHK, Quest Software, KWS, Summit Information Systems, June, 1991

/TABS 8,12,16,20,24,28,32,36,40,44,48,52,56,60,64,68,72; T *QTEXT
/T *QTEXT
File numbered
Record length: 80 bytes
Number of records: 8
File code: 0
/l all
1 program world(input, output);
2
3 begin
4
5 writeln('Hello World');
6
7 end.
8
/e

END OF PROGRAM
:

Finally we will compile and run it. For MPE there are 3 steps to go from source to running a program: compile, prep (link in other O/Ses), and run. These can all be combined into a single command, PASCALGO:

:pascalgo world2

PAGE 1 HEWLETT-PACKARD HP32106A.01.32 PASCAL/V (C) HEWLETT-PACKARD
CO. 1985 SAT, AUG 24, 1991, 2:12 PM

0 1.000 0 program world(input, output); 
0 2.000 0 
0 3.000 1 begin 
0 4.000 1 
0 5.000 1 writeln('Hello World'); 
1 6.000 1 
1 7.000 1 end. 
1 8.000 0

NUMBER OF ERRORS = 0 NUMBER OF WARNINGS = 0
PROCESSOR TIME 0: 0: 0 ELAPSED TIME 0: 0: 0
NUMBER OF LINES = 8 LINES/MINUTE = 48000.0

END OF COMPILE

END OF PREPARE

Hello World

END OF PROGRAM
:

Works! My last step for this section is to save the executable program to disk because I’m going to want it again in the next section:

:save $oldpass,worldp
:listf worldp,2
ACCOUNT=  SYS         GROUP=  TMP
FILENAME  CODE  ------------LOGICAL RECORD-----------  ----SPACE----
                  SIZE  TYP        EOF      LIMIT R/B  SECTORS #X MX
WORLDP    PROG    128W  FB           7          7   1        8  1  1

Copying a Program Between Two SIMH HP3000’s

The last procedure I’d like to document is how to move a program file from one SIMH HP3000 to another. In this example, I’ll use the same SIMH HP3000 as source and destination, but you will get the idea. I will copy the WORLDP program I just compiled above.

Get Kermit running on your PC and on the HP3000. On Kermit for HP3000, type

KERMIT3000>send worldp.tmp

On kermit for PC, do a kermit | receive from the menu.

The worldp executable program is now in c:\tmp:

C:\tmp>dir worldp.tmp
Volume in drive C is c180104
Volume Serial Number is D6EF-2751

Directory of C:\tmp

08/24/2019 02:22 PM           1,792 WORLDP.TMP
           1 File(s)          1,792 bytes
           0 Dir(s) 354,643,628,032 bytes free

I will now upload the file to the same HP3000, renaming it WORLDX.

In Kermit for HP3000, type

SET RECEIVE PROG
RECEIVE WORLDX.TMP

In Kermit for PC select Kermit | Send from the menu.

Once done, you can check the download occurred. WORLDX should have the same characteristics as WORLDP:

:listf world@,2
ACCOUNT=  SYS         GROUP=  TMP       
FILENAME  CODE  ------------LOGICAL RECORD-----------  ----SPACE----
                  SIZE  TYP        EOF      LIMIT R/B  SECTORS #X MX
WORLD             254B  VA           8       5000   1      314  1 32
WORLD2             80B  FA           8          8   3        4  1  1
WORLDP    PROG    128W  FB           7          7   1        8  1  1
WORLDX    PROG    128W  FB           7          7   1        8  1  1

Finally run it as a test:

:run worldx

Hello World

END OF PROGRAM

 

Posted in c-retro | Tagged | Leave a comment

Copy files from an HP3000/XL Computer System to a SIMH HP3000/Classic

In my prior post, Instructions for Emulating an HP3000 with SIMH, my enclosed PDF of instructions discusses getting files onto the SIMH HP3000 using Reflections or creating a SIMH format tape.

Both of these options have limitations if you want to move files from a real HP3000 or a Stromasys VM HP3000.

Keven Miller, of http://www.3kranger.com, gave me a better way. I will document his procedure here.

You are going to need a couple of programs written by Keven to convert files between tape formats.

Installing the Tape Conversion Programs

To handle the tape conversions, you will need 2 programs: tapecpyv and tapesim.

Download the proper File

If you want to transmit the file to your real/stromasys HP3000 via ftp, download taputilt.std.bin.

If you want to transmit the file to your real/stromasys HP3000 via WRQ Reflections, download taputilt.std.wrq.

Uploading tapeutilt.std.bin via FTP

Transfer the tapeutilt file to the PUB.SYS directory of your HP3000. If you have FTP running on your HP3000, this is probably the easiest method:

C:\tmp>ftp hp3000
Connected to hp3000.xxxxxxx.net.
220 HP ARPA FTP Server [A0010A02] (C) Hewlett-Packard Co. 1990
User (hp3000.xxxxxxx.net:(none)): manager.sys
331 Password required for MANAGER.SYS. Syntax: userpass,acctpass
Password:
230 User logged on
ftp> bin
200 Type set to I.
ftp> put taputilt.std.bin taputilt.pub.sys;rec=128,,f,binary;code=store
200 PORT command ok.
150 File: taputilt.pub.sys;rec=128,,f,binary;code=store opened; data connection will be opened
226 Transfer complete.
ftp: 178944 bytes sent in 0.41Seconds 440.75Kbytes/sec.
ftp> quit
221 Server is closing command connection

Uploading taputilt.std.wrq via Reflections

  • Connect to your HP3000 and login as manager.sys.
  • File | Transfer and setup the transfer as follows:

Local name is the file on your PC to be uploaded. Host file name is the name of the file on your HP3000. Make sure you use the WRQ protocol and Labels.

Restore the TAPUTILT Store to Disk File

  • The taputilt file should now be on PUB.SYS:
HP3000  Release: C.65.00   User Version: C.65.00   SAT, JUL  6, 2019,  1:14 PM
MPE/iX  HP31900 C.25.06  Copyright Hewlett-Packard 1987.  All rights reserved.
:listf tap@.pub.sys,2
ACCOUNT=  SYS         GROUP=  PUB     

FILENAME  CODE  ------------LOGICAL RECORD-----------  ----SPACE----
                  SIZE  TYP        EOF      LIMIT R/B  SECTORS #X MX

TAPUTILT  STORE   128W  FB         699   16776959   1     1024  3 32


:
  • Verify tape contents:
:file t=taputilt;dev=disc
:restore *t;@.@.@;listdir
          >> TURBO-STORE/RESTORE  VERSION  C.65.05  B5152AA  <<
                    (C) 1986 HEWLETT-PACKARD CO.

RESTORE  *t;@.@.@;LISTDIR

SAT, JUL  6, 2019,  1:18 PM


MPE/iX MEDIA DIRECTORY

MEDIA NAME        : STORE/RESTORE-HP/3000.MPEXL  
MEDIA VERSION     : MPE/iX 08.50 FIXED ASCII
MEDIA NUMBER      : 1

MEDIA CREATION DATE
FRI, JUL  5, 2019,  6:20 PM

STORE  tape@;*t;show

MEDIA CREATED WITH THE FOLLOWING OPTIONS

MEDIA RECORD SIZE : 32768
INTERLEAVE DEPTH  : 1

FILENAME GROUP    ACCOUNT  CREATOR               MEDIA    SET
TAPECOPY.PUB     .SYS      MANAGER .SYS      >=      1      
TAPECPYV.PUB     .SYS      MANAGER .SYS      >=      1      
TAPESIM .PUB     .SYS      MANAGER .SYS      >=      1      
TAPESIMC.PUB     .SYS      MANAGER .SYS      >=      1      

:
  • Restore Files to PUB.SYS:
:restore *t;@.PUB.SYS;olddate;show;keep
>> TURBO-STORE/RESTORE VERSION C.65.05 B5152AA <<
(C) 1986 HEWLETT-PACKARD CO.

RESTORE *t;@.PUB.SYS;OLDDATE;SHOW;KEEP

SAT, JUL 6, 2019, 1:25 PM


WILL RESTORE 4 FILES ; NUMBER OF FILES ON MEDIA 4

FILENAME GROUP ACCOUNT VOLUME RESTRICTIONS SECTORS CODE MEDIA
TAPECOPY.PUB .SYS DISC :C 192 NMPRG 1
TAPECPYV.PUB .SYS DISC :C 176 PROG 1
TAPESIM .PUB .SYS DISC :C 128 NMPRG 1
TAPESIMC.PUB .SYS DISC :C 192 1

FILES RESTORED : 4

:

The Procedure

In this example, I’m going to move my TREK73 program from my Stromasys VM HP3000 to my SIMH HP3000. Here is the actual file as it exists on the Stromasys VM:

:listf trek@,2
ACCOUNT=  XXXXXXXX     GROUP=  PUB     

FILENAME  CODE  ------------LOGICAL RECORD-----------  ----SPACE----
                  SIZE  TYP        EOF      LIMIT R/B  SECTORS #X MX

TREK73    PROG    128W  FB         516        516   1      528  1  1

Store Files to Physical Tape in TRANSPORT Format

A classic HP3000 can only restore classic formatted tapes which are created using the STORE command with the TRANSPORT option. Unfortunately you can only use the TRANSPORT option when creating a physical tape.

So, if you have a real HP3000 you are going to create a physical tape. For the Stromasys VM we will do a normal store to tape which will create a file in the VMWare VM called /home/a202/ldev7.img.

  • Examine any existing ldev7.img file and move it as necessary. This procedure will overwrite any existing ldev7.img file.
  • Mount the tape using loadtape or online:
:x loadtape 7

LoadTape.A.05
Loading LDEV 7...
Putting LDEV 7 online...
LDEV 7 is (or soon will be) online.

END OF PROGRAM
:showdev 7
LDEV AVAIL OWNERSHIP VOLID DEN ASSOCIATION

7 AVAIL (W) (Nolabel) 1600
  • Set up file equation for tape drive:
:file t;dev=tape
  • Store the file to tape using the transport option:
:store trek73.pub.xxxxxxx;*t;transport;show
MPE-XL Transport Store-Restore, C.45.05 (C) Hewlett-Packard Co., 1988.
STORE TREK73.PUB.XXXXXXX;*T;TRANSPORT;SHOW
FRI, JUN 14, 2019, 3:57 PM

FILENAME.GROUP .ACCOUNT LDN ADDRESS REEL SECTORS CODE

TREK73  .PUB   .XXXXXXX * 1 $0000C537  1     517 PROG

FILES STORED: 1

Convert Physical Tape to SIMH formatted Tape

  • Reload the tape:
:x loadtape 7

LoadTape.A.05
Loading LDEV 7...
Putting LDEV 7 online...
LDEV 7 is (or soon will be) online.

END OF PROGRAM
:
  • The tape now contains trek73.pub.xxxxxxx, stored in a format that MPE/V can read. Now we copy that back to disk using tapecpyv:
:file tapein;dev=tape
:file diskout=trek73s
:tapecpyv td

TapeCopy 3.0s
!! Control-Y enabled
Opening tape "TAPEIN" 
Tape: TAPEIN Recsize 32760 Dev 7
Data: CMSTORE FRI, JUN 14, 2019, 3:57 PM Reel 1 Maxbuf 4096
File: TREK73S.PUB.XXXXXXX Recsize 256 EOF 0 Fcode CMSTR
Limit 16776959
20 blks 10 marks min/max 24/8192 519 diskrec 
Closing files ... done.

END OF PROGRAM
:listf trek@,2
ACCOUNT=  XXXXXXX     GROUP=  PUB     

FILENAME  CODE  ------------LOGICAL RECORD-----------  ----SPACE----
                  SIZE  TYP        EOF      LIMIT R/B  SECTORS #X MX

TREK73    PROG    128W  FB         516        516   1      528  1  1
TREK73S   2504    128W  FB         519        519   1      528  3  *
  • TREK73S now contains a disk image of a classic STORE tape.
  • Now use the tapesim program to convert the classic store tape to a SIMH formatted tape:
:tapesim "trek73s trek73t"
TAPESIM 1.02 Convert STD file to SIMH
Open trek73s read
Open trek73t write
!! Control-Y interrupt enabled.
!! Endian Big
Size 00020700 (519 records)
Posn 00020700 
Closing trek73t
Closing trek73s
:listf trek@,2
ACCOUNT= XXXXXXX GROUP= PUB

FILENAME CODE ------------LOGICAL RECORD----------- ----SPACE----
                   SIZE TYP EOF LIMIT R/B SECTORS #X MX

TREK73    PROG    128W  FB         516        516   1      528  1  1
TREK73S   2504    128W  FB         519        519   1      528  3  *
TREK73T   2508    128W  FB         519       1519   1      768  3  8
  • TREK73T contains the SIMH tape image.
  • Download the TREK73T file from the HP3000. Since mine is running FTP server, I will use FTP:
C:\>ftp hpdude
Connected to hpdude.xxxxxxx.net.
220 HP ARPA FTP Server [A0012H15] (C) Hewlett-Packard Co. 2000 [PASV SUPPORT]
User (hpdude.xxxxxx.net:(none)): dan.xxxxxxx
331 Password required for DAN.XXXXXXX. Syntax: [,]acctpass
Password:
230 User logged on
ftp> bin
200 Type set to I.
ftp> get trek73t trek73t.tap
200 PORT command ok.
150 File: trek73t opened; data connection will be opened
226 Transfer complete.
ftp: 132864 bytes received in 0.09Seconds 1413.45Kbytes/sec.
ftp> quit
221 Server is closing command connection

C:\>dir trek*
Volume in drive C is c180104
Volume Serial Number is D6EF-2751

Directory of C:\

07/05/2019 03:45 PM 132,864 trek73t.tap
              1 File(s) 132,864 bytes
              0 Dir(s) 351,378,993,152 bytes free

C:\>

Restore Files on the SIMH HP3000

Important: The Classic HP3000 RESTORE command can only restore files back to the same group/account they were stored from. Not only must you have the same group and account, but the user that created the original file as well.

  • Make sure you have the appropriate account structure implemented on the SIMH HP3000 before attempting to restore.
  • On the SIMH HP3000, attach the file to the tape drive:
<control-E>
Simulation stopped, P: 071264 (PAUS 0)
sim> attach -r ms0 c:\trek73t.tap
MS: unit is read only
Tape Image 'c:\trek73t.tap' scanned as SIMH format.
contains 132536 bytes of tape data (20 records, 8 tapemarks)
136 bytes of unexamined data remain in the tape image file
sim> go
15:51/10/Vol (unlabelled) mounted on LDEV# 7

:
  • Now restore the file to the SIMH HP3000:
:RESTORE *T;@.@.XXXXXXX;OLDDATE;SHOW;KEEP
?15:56/#S3/22/LDEV# FOR "T" ON TAPE (NUM)?
=REPLY 22,7
FRI, JUL 5, 1991, 3:57 PM

FILES RESTORED = 1

FILE .GROUP .ACCOUNT LDN ADDRESS

TREK73 .PUB .XXXXXXX 1 %603300

FILES NOT RESTORED = 0

:LISTF TREK73,2
ACCOUNT= XXXXXXX GROUP= PUB
FILENAME  CODE  ------------LOGICAL RECORD-----------  ----SPACE----
                  SIZE  TYP        EOF      LIMIT R/B  SECTORS #X MX

TREK73    PROG    128W  FB         516        516   1      517  1  1

:RUN TREK73

TREK73! DO YOU WANT INSTRUCTIONS ? N
CAPTAIN: MY LAST NAME IS

 

 

Posted in c-retro | Tagged | 2 Comments

How to Keep a Bolt from Falling out of your Socket Driver (Petroleum Jelly Bolt Holder)

Had to change the EGR valve in my diesel. Was reviewing a video on how to do this when the guy showed a totally cool ‘tip’ on how to keep bolts (or nuts) in a socket driver. I thought this was so cool I googled it and didn’t see anyone else discuss the tip, so I’ll post it myself.

This has been a forever issue for me. I’ve lost more bolts into my engine compartment than I can even remember. Without fail, they lodge somewhere deep where I cannot see them or get them. There must be a Murphy’s Law on this.

I’ve got some grabbers that work on tiny parts and my small drivers are usually magnetized, but larger bolts using my 1/4″ tools have always been problematic.

The guy’s tip is super simple: stick the bolt head in petroleum jelly. That will hold it in the socket. If that doesn’t have enough grip, stick the socket in. That should get you some reasonable holding power.

To give FordTechMaculoco credit, here is his video:

Posted in c-Misc | Tagged | 1 Comment

Instructions for Emulating an HP3000 with SIMH

The HP3000  minicomputer was the primary system I programmed from 1978 until 1993 when I moved into networking. I have so many fond memories of that system. I knew the hardware and software backward and forward. I was fortunate enough to have access to the operating system (MPE) source code so I really knew what made it tick. Let’s just say I was a serious HP3000 nerd!

Here is the HP3000 Series III that I used in the 1980’s:

The No Smoking sign was NECESSARY (and often ignored). We had several programmers that smoked like chimneys and they had no trouble sitting at the console while puffing away.

Any way, SIMH has recently added the HP3000 Classic architecture (16 bit stack-oriented) to their list of simulations.

I slogged through building a system and then adding several programs that are really necessary to use it such as PCLINK and QUAD.

Below is a link to a zip file that is my running HP3000 environment. You just need to unzip it into c:\hp3000Sim, and run the hp.bat file to bring the simulation up.

You will also find my HP3000 simh setup notes.pdf which explains how I made the changes I made (such as getting the PCLINK file transfer program installed). It also includes some usage notes and notes about the games that I installed as well.

https://drive.google.com/file/d/1-bVJwoXlVK5CG7eFpQ3-K24ajyTeoPu4/view?usp=sharing

Jul 2019 Update:

You find an alternative method of transferring files from a real HP3000 to the SIMH HP3000 here:

Copy files from an HP3000/XL Computer System to a SIMH HP3000/Classic

Posted in c-retro | Tagged | 26 Comments

Woof Off! – A Device to Control an Out-of-Control Barking Dog

A friend came to me a few months ago asking for help building something to stop his neighbor’s barking dog. I’ve been having the same problem for a few years now, so I was definitely interested.

I’m fortunate enough to have good neighbors, but they are not dog people. In fact, they never really wanted this dog. How they ended up with two dogs is a story not worth going into. But, the upshot is one dog barks, they really have no control over it, and see something like a bark collar as being cruel.

So I have to put up with a dog barking under my office window on a regular basis.

I had looked at some commercial products but just never felt they were going to work for me. So I did nothing. Now that someone else wanted something I had a little more incentive to figure out if ultrasonic sound might really be effective.

There are various circuits on the web that produce an ultrasonic (40kHz) signal. Mine is just a variation of these. I use a 555 timer to produce the signal, then an LM-386 to amplify it.

Some circuits just drive the speaker directly from the 555. I feel like a get a somewhat stronger signal from the LM-386, but not so much that I would say it is an absolute must.

Here is my schematic:


Schematic notes:

I use terminals to connect power and speakers which show up a little confusingly on the schematic. A diode protects the circuit from reversed polarity. I have found I can drive 2 speakers from the LM386 which effectively nearly doubles the output power so there are terminals for 2 speakers.

This circuit was tested using 12V. It will run on 9V, but the output volume will not be quite as high.

During initial testing of the circuit, I setup the 555 to emit a frequency I could hear, around 12KHz. Once I was ready for real testing, I needed speakers that would actually work at 40KHz. Regular speakers don’t.

I found this ultrasonic speaker on ebay which also has the advantage of being water proof:

I purchased mine from:

https://www.ebay.com/itm/6X-High-Power-Ultrasonic-Transmitter-Mosquito-Rat-Repellent-Speaker-Horn-40KHz/253259498948?ssPageName=STRK%3AMEBIDX%3AIT&_trksid=p2057872.m2749.l2649

The speaker was installed and the 555 set to produce 40kHz, I could no longer hear the signal. Was it really working? My dogs are not a good test subject as they are both deaf.

I ended up purchasing a set ultrasonic transmitter / receivers like this from Amazon:

I simply clipped my oscilloscope probes to one of the ultrasonic receiver to see how strong the signal was. This allowed me to do comparative testing to see if my output was stronger or weaker.

Once I had what I thought was a functioning unit, I needed to do a field test to see if dogs would really pay any attention to it. I produced a nice clean breadboard unit I could carry around.

This unit doesn’t match the final schematic exactly. To provide 12V, I used 2X 4LR44 6V batteries which fit perfectly in a single AA battery holder.

I tested this on a handful of dogs. Some hear it, some don’t (or at least pay no attention). The barker most definitely heard it. That gave me the green light to produce a final unit.

Using VeeCad, I converted the schematic into a strip board layout:

See How to use VeeCAD Stripboard Editor with CadSoft Eagle for more information.

I had forgotten how slow it is to build a circuit using stripoard. But it is still cheaper than PCB and way faster than waiting for the PCB to be created and mailed to me.

The final stripboard looked pretty nice:

I decided I could mount the unit inside my house and mount the speakers to the window. The ‘barker’ stands about 6′ from this window when she barks. By keeping the electronics inside the house, that solves weather proofing and power issues.

To control this, I wanted a remote control key fob that would work from my office. I purchased a cheap Chinese unit:

https://www.ebay.com/itm/12V-DC-ON-OFF-remote-control-wireless-12V-output-Relay-Switch-Kit/161723609765?ssPageName=STRK%3AMEBIDX%3AIT&_trksid=p2057872.m2749.l2649

The key fob batteries died IMMEDIATELY (I got around 10 key presses on either fob before it was dead). Irritating, but the vendor credited me the cost of new batteries.

Once the remote was working it was just a matter of cramming it all into a plastic project box and setting up some external jacks and a power LED.

Red Green says duct tape is the handy man’s secret weapon. I say it is Velcro tape and hot glue. Seems like every project ends up using one or both.

The last step was to slap a cheap graphic on the project!

Once the final unit was set up, I watched the dog when I turned the unit on. She would immediately perk up her ears and look directly at it. Even 1/2 way across the neighbor’s yard she could clearly hear it.

Using Woof Off!

One would be tempted to just turn this on and subject the barker continuously to the sound. However good that might feel to you (and I did consider it myself), it is the wrong way to go about getting effective results. Remember: it isn’t the dog’s fault it barks. It is the owner’s fault.

To effectively use Woof Off, you want to use it as a training tool. That’s going to take some time on your part, but you have a better chance of getting good results if you train the dog properly.

During the training period, I kept my key fob with me at all times. The dog is allowed to bark for about 5 seconds (you have to be realistic here – dogs are going to bark, you can’t expect zero tolerance).

If the dog continues to bark after about 5 seconds, I turn Woof Off! on for 10 seconds and switch it back off. And I repeat until the dog finally quits.

Within 3 days of training, the barks became tentative. You could just hear in the tone she wasn’t sure she really wanted to bark.

I’m now about 2 weeks into ‘training’. She still barks some, particularly when people walk by, but having her sit under my window ‘woofing’ every 5 seconds for an hour or more no longer occurs. The situation is back to being reasonable again.

Aug 2019 Update:

Göran Cronström has created PCB CAD files for the Woof Off! project. Please see:

https://bigdanzblog.wordpress.com/2019/08/29/woof-off-pcb-files/

As a follow up to the original project, I successfully trained the barker to the extent that she stayed on the other side of her house and still barked constantly there. Not perfect, but way better than her barking for multiple hours a day under my window. Of course the guy living on that side of the barker’s yard probably wouldn’t agree!

When I tried Woof Off recently after a lapse of probably more than 6 months, the barker didn’t seem to notice it. I suspect that, like humans, has she is getting older she can’t hear high frequencies as well.

Posted in c-electronics | Tagged , | 13 Comments

Watch Dog Timer (WDT) for Teensy 3.1 and 3.2

I have had an ongoing Teensy project that is rather complex. Once in a great while (months), one of the units will hang somewhere in networking code. This is unacceptable and I’ve needed to implement a WDT, but I’ve been hesitant because I’ve not seen an obvious and simple example and I’ve been under the impression it is easy to brick a Teensy if the WDT is not implemented correctly.

After two network hangs in a matter of weeks, I decided I couldn’t put off WDT any longer.

This post is a summary of my research of implementing WDT with (I hope) simple example programs to show how to implement it yourself.

Resources

My primary resources have been:

This Teensy forum thread:

https://forum.pjrc.com/threads/25370-Teensy-3-0-Watchdog-Timer

and the microcontroller manual.

WDT Initialization Code

For WDT to be available, it has to be initialized within 256 clock cycles after boot. Most of the example code I’ve seen deals with implementing a hook called start_early_hook which is called withing the 256 clock cycles. WDT is then enabled in that hook.

I really don’t want WDT resetting the MCU while everything is first coming up. If there is a hang during the initialization phase, rebooting probably isn’t going to make things better, at least for my own code. I’d rather not start the WDT until initialization is complete.

After doing some research I found the ‘default’ start_early_hook found in llwuh.c and it sets up the WDT to be disabled BUT allow future modifications to the settings:

void startup_early_hook( ) __attribute__ ((weak));
void startup_early_hook( ) {
    WDOG_STCTRLH = WDOG_STCTRLH_ALLOWUPDATE;
 
    if ( PMC_REGSC & PMC_REGSC_ACKISO ) {
        llwuFlag = llwu_clear_flags( );// clear flags
        llwu_disable( );
    }
}

This default is exactly what I want – to be able to startup WDT at the end of my initialization phase!

Simple WDT Timeout and Program Reset

Program to Illustrate WDT Usage

This is about the simplest program I can come up with to illustrate how to implement the WDT. Comments afterwards…

// This sample program shows how to use the watch dog timer (WDT).

// When program starts, it turns LED off for 1 seconds.
// It then turns LED on, and pauses for 5 seconds letting you know it is ready to start.
// WDT is initialized, and loop starts. It will flash led and reset wdt for the first 10 secs.
// After that, it stops resetting wdt. This causes the WDT to reboot and the cycle starts over.

const int           led                 = 13;

bool                ledState            = false;
unsigned long       timer;

void setup() {

    // initialize the digital pin as an output.
    pinMode(led, OUTPUT);

    // Indicate we are starting over by hold led off for 1s
    ledState = false;
    digitalWrite(led, ledState);
    delay(1000UL);

    // Indicate we are in setup by hold LED on
    ledState = true;
    digitalWrite(led, ledState);
    delay(5000UL);

    // Setup WDT
    noInterrupts();                                         // don't allow interrupts while setting up WDOG
    WDOG_UNLOCK = WDOG_UNLOCK_SEQ1;                         // unlock access to WDOG registers
    WDOG_UNLOCK = WDOG_UNLOCK_SEQ2;
    delayMicroseconds(1);                                   // Need to wait a bit..

    // for this demo, we will use 1 second WDT timeout (e.g. you must reset it in < 1 sec or a boot occurs)
    WDOG_TOVALH = 0x006d;
    WDOG_TOVALL = 0xdd00;

    // This sets prescale clock so that the watchdog timer ticks at 7.2MHz
    WDOG_PRESC  = 0x400;

    // Set options to enable WDT. You must always do this as a SINGLE write to WDOG_CTRLH
    WDOG_STCTRLH |= WDOG_STCTRLH_ALLOWUPDATE |
        WDOG_STCTRLH_WDOGEN | WDOG_STCTRLH_WAITEN |
        WDOG_STCTRLH_STOPEN | WDOG_STCTRLH_CLKSRC;
    interrupts();

}

void loop() {

timer = millis() + 10000UL;                                 // length of time we will reset WDT

while (true) {
    ledState = !ledState;
    digitalWrite(led, ledState);
    delay(100UL);
    if (millis() < timer) {                                 // Have we timed out yet?
        noInterrupts();                                     //   No - reset WDT
        WDOG_REFRESH = 0xA602;
        WDOG_REFRESH = 0xB480;
        interrupts();
        }
    } // while
}

Commentary

The idea behind this program is to setup WDT with a 1 second timeout, start flashing an LED, then after 10 seconds stop resetting WDT so it causes a reboot. You just watch the LED to verify the program works.

To setup WDT, disable interrupts, then write a 2 byte sequence to the WDOG_UNLOCK register. Once you write this sequence, you have 256 clock cycle to complete all WDT settings, so don’t do anything else except WDT setup.

Next I indicate how long I want the WDT timer to run, 1 second in this case. That means I must reset (e.g. kick or pat) the watch dog in < 1 sec or a reboot occurs.

I did a lot of messing around and found that if the prescaler (WDOG_PRESC) is set to 0x400, then the WDT timer runs at about 7.2MHz. (Using a prescaler of 0 gives a clock rate of 36MHz). Note that these values are for my Teensy’s clock of 72MHz. If you over clock, I would assume these values change.

So if I want a 1 second timeout, I would use 7,200,000 which is 0x006DDD00 which is what you see I assign to the WDOG_TOVALH and WDOG_TOVALL registers.

Finally I enable the WDT AND allow future modifications. You are only allowed 1 write to this register after you unlock it, so you must do a single assignment.

Don’t forget to turn interrupts back on.

The program should then be fairly self-explanatory down to the point where I reset the WDT.

To do the reset you are going to write a byte sequence to the WDOG_REFRESH register. This, too, must be done with interrupts off.

Now that I have it up and running, the Teensy WDT is just as easy as the Arduino’s!

Passing Information into the Program after a WDT Reset

Reset Reason

While researching WDT for the Teensy, I found one of “Duff’s” posts in the forum post mentioned in the resources to be quite interesting. He examines the RCM_SRS0 and RCM_SRS1 registers to display why the MCU was reset. I tested those that I could and here is a summary:

RCM_SRS1 & RCM_SRS1_SACKERR   Stop Mode Acknowledge Error Reset
RCM_SRS1 & RCM_SRS1_MDM_AP    MDM-AP Reset
RCM_SRS1 & RCM_SRS1_SW        Software Reset			True when reboot with SCB_AIRCR = 0x05FA0004
RCM_SRS1 & RCM_SRS1_LOCKUP    Core Lockup Event Reset
RCM_SRS0 & RCM_SRS0_POR       Power-on Reset			True when power removed/reapplied
RCM_SRS0 & RCM_SRS0_PIN       External Pin Reset		True when reboot due to software download
RCM_SRS0 & RCM_SRS0_WDOG      Watchdog(COP) Reset		True when WDT reboots MCU
RCM_SRS0 & RCM_SRS0_LOC       Loss of External Clock Reset
RCM_SRS0 & RCM_SRS0_LOL       Loss of Lock in PLL Reset
RCM_SRS0 & RCM_SRS0_LVD       Low-voltage Detect Reset		Also true when power removed/reapplied

Global DMAMEM Variables

It would be nice to know where I was in the code when the WDT occurred. When the WDT occurs, your program is re-initialized for the most part.

In the program I’m developing this for, I actually maintain a queue of the last <n> events the program processed. For argument’s sake,  let’s say I would like to save the last event so it is available to the program when it restarts.

It turns out that if you declare a variable DMAMEM (e.g. DMAMEM int), that variable will NOT be re-initialized when WDT occurs. This allows you to detect and

Here is the example program:

// This sample program shows how to use the watch dog timer (WDT).

// To use, download and start Teensy. LED will turn solid red meaning
// connect to Teensy with terminal.

// Once connected, some information will be printed. After done, you
// will be asked to disconnect to proceed with test.

// Once you disconnect, the LED will flash fast until WDT reboots the
// Teensy at which time the LED is on solid again, awaiting the terminal
// to be connected.

#include            <Arduino.h>
#include            <kinetis.h>                              // contains WDOG constants

const int           led                 = 13;

DMAMEM unsigned int dmaTest;
DMAMEM unsigned int dmaTestInit;
bool                ledState            = false;
unsigned long       timeOut             = 0UL;
unsigned long       timer               = 1000UL;

void setup() {

    pinMode(led, OUTPUT);                                   // initialize the digital pin as an output.

    ledState = true;                                        // while waiting for terminal to connect, hold LED on
    digitalWrite(led, ledState);

    while (!Serial.dtr()) {                                 // wait for terminal to connect
        }

    // notify user we are connected and running
    ledState = false;
    digitalWrite(led, ledState);
    Serial.println("Terminal Connected.");

    // Display reason the Teensy was last reset
    Serial.println();
    Serial.println("Reason for last Reset: ");

    if (RCM_SRS1 & RCM_SRS1_SACKERR)   Serial.println("Stop Mode Acknowledge Error Reset");
    if (RCM_SRS1 & RCM_SRS1_MDM_AP)    Serial.println("MDM-AP Reset");
    if (RCM_SRS1 & RCM_SRS1_SW)        Serial.println("Software Reset");                   // reboot with SCB_AIRCR = 0x05FA0004
    if (RCM_SRS1 & RCM_SRS1_LOCKUP)    Serial.println("Core Lockup Event Reset");
    if (RCM_SRS0 & RCM_SRS0_POR)       Serial.println("Power-on Reset");                   // removed / applied power
    if (RCM_SRS0 & RCM_SRS0_PIN)       Serial.println("External Pin Reset");               // Reboot with software download
    if (RCM_SRS0 & RCM_SRS0_WDOG)      Serial.println("Watchdog(COP) Reset");              // WDT timed out
    if (RCM_SRS0 & RCM_SRS0_LOC)       Serial.println("Loss of External Clock Reset");
    if (RCM_SRS0 & RCM_SRS0_LOL)       Serial.println("Loss of Lock in PLL Reset");
    if (RCM_SRS0 & RCM_SRS0_LVD)       Serial.println("Low-voltage Detect Reset");
    Serial.println();

    if (dmaTestInit != 0xaaaa) {
        // on first time run, dmaTestInit contains random data, not the 0xAAA(1010101010...)
        // we seek. When dmaTestInit is garbage, we give a warning and set it.
        Serial.println("dmaTest value is invalid.");
        dmaTestInit = 0xaaaa;
        }
    else {
        // If dmaTestInit is correct, dmaTest has a good value
        Serial.printf("Current dmaTest Value: %u\n\r", dmaTest);
        }

    // give dmaTest a random "good" value and let user know what it will be
    randomSeed(analogRead(0));
    dmaTest = random(0, 32768);
    Serial.printf("Next dmaTest Value: %u.\n\r", dmaTest);
    Serial.println();

    // You cannot allow Teensy to reboot with USB connected, to tell user to disconnect terminal.
    Serial.println("Disconnect terminal to proceed with WDT test!");
    while (Serial.dtr()) {}

    ledState = !ledState;                                   // init LED
    digitalWrite(led, ledState);

    // enable WDT
    noInterrupts();                                         // don't allow interrupts while setting up WDOG
    WDOG_UNLOCK = WDOG_UNLOCK_SEQ1;                         // unlock access to WDOG registers
    WDOG_UNLOCK = WDOG_UNLOCK_SEQ2;
    delayMicroseconds(1);                                   // Need to wait a bit..

    WDOG_TOVALH = 0x006d;                                   // 1 second WDT
    WDOG_TOVALL = 0xdd00;
    WDOG_PRESC  = 0x400;
    WDOG_STCTRLH |= WDOG_STCTRLH_ALLOWUPDATE |
        WDOG_STCTRLH_WDOGEN | WDOG_STCTRLH_WAITEN |
        WDOG_STCTRLH_STOPEN | WDOG_STCTRLH_CLKSRC;
    interrupts();
}

void loop() {

timer = millis() + 10000UL;                                 // length of time we will reset WDT

while (true) {
    ledState = !ledState;
    digitalWrite(led, ledState);
    delay(100UL);
    if (millis() < timer) {                                 // Have we timed out yet?
        noInterrupts();                                     //   No - reset WDT
        WDOG_REFRESH = 0xA602;
        WDOG_REFRESH = 0xB480;
        interrupts();
        }
    } // while
}

Commentary

I used the prior example as the base program, so the actual setup and usage of the WDT is the same.

All of the new code is in the setup function. First, the reason for the last reset is displayed using the RCM_SRC1 and RCM_SRS1 registers.

Next, we look to see if dmaTestInit has a valid value. If not, we can assume dmaTest is not properly set.

Regardless, we then set dmaTestInit to a known value and dmaTest value to some random integer which we tell the user so he can re-check the value of dmaTest on the next WDT reset.

Triggering WDOG Interrupt

In the prior example, I experimented with writing a value to RAM not EEPROM. Why? 2 reasons. First, writing to EEPROM is way slower, which may or may not be an issue depending on how fast my events occur. Second, there are a fixed number of EEPROM writes allowed, about 100,000 (https://www.pjrc.com/teensy/td_libs_EEPROM.html). So I don’t want to go crazy writing to EEPROM.

HOWEVER, it would be really nice to write the LAST event to EEPROM when a WDT reset occurs.

With the Arduino and ATTiny MCUs I’ve used, there has been no graceful way to handle the WDT reset (at least as far a I know). The WDT reset is the same as if the user simply reset power.

This example explores setting up an ISR to be called when the WDT resets. I won’t write EEPROM in this example – I just want to verify I could for when I implement this code into the production project.

Example Program

Here is the example program. It is very close to the prior program with just a few additions:

// This sample program shows how to use the watch dog timer (WDT).

// To use, download and start Teensy. LED will turn solid red meaning
// connect to Teensy with terminal.

// Once connected, some information will be printed. After done, you
// will be asked to disconnect to proceed with test.

// Once you disconnect, the LED will flash fast until WDT reboots the
// Teensy at which time the LED is on solid again, awaiting the terminal
// to be connected.

#include            <Arduino.h>
#include            <kinetis.h>                              // contains WDOG constants

const int           led                 = 13;

DMAMEM unsigned int dmaTest;
DMAMEM unsigned int dmaTestInit;
bool                ledState            = false;
unsigned long       timeOut             = 0UL;
unsigned long       timer               = 1000UL;

// This routine MUST be named watchdog_isr. It will be called
// when the WDT pops and the reset is intiated.

// This function must complete in < time than the WDT would take.
// In this example, I'm using a WDT timeout of 1s, so it must be done
// in < 1 second.

void watchdog_isr() {

// set dmaTest to 777, letting me know this function was called
dmaTest = 777;

}

void setup() {

    pinMode(led, OUTPUT);                                   // initialize the digital pin as an output.

    ledState = true;                                        // while waiting for terminal to connect, hold LED on
    digitalWrite(led, ledState);

    while (!Serial.dtr()) {                                 // wait for terminal to connect
        }

    // notify user we are connected and running
    ledState = false;
    digitalWrite(led, ledState);
    Serial.println("Terminal Connected.");

    // Display reason the Teensy was last reset
    Serial.println();
    Serial.println("Reason for last Reset: ");

    if (RCM_SRS1 & RCM_SRS1_SACKERR)   Serial.println("Stop Mode Acknowledge Error Reset");
    if (RCM_SRS1 & RCM_SRS1_MDM_AP)    Serial.println("MDM-AP Reset");
    if (RCM_SRS1 & RCM_SRS1_SW)        Serial.println("Software Reset");                   // reboot with SCB_AIRCR = 0x05FA0004
    if (RCM_SRS1 & RCM_SRS1_LOCKUP)    Serial.println("Core Lockup Event Reset");
    if (RCM_SRS0 & RCM_SRS0_POR)       Serial.println("Power-on Reset");                   // removed / applied power
    if (RCM_SRS0 & RCM_SRS0_PIN)       Serial.println("External Pin Reset");               // Reboot with software download
    if (RCM_SRS0 & RCM_SRS0_WDOG)      Serial.println("Watchdog(COP) Reset");              // WDT timed out
    if (RCM_SRS0 & RCM_SRS0_LOC)       Serial.println("Loss of External Clock Reset");
    if (RCM_SRS0 & RCM_SRS0_LOL)       Serial.println("Loss of Lock in PLL Reset");
    if (RCM_SRS0 & RCM_SRS0_LVD)       Serial.println("Low-voltage Detect Reset");
    Serial.println();


    if (dmaTestInit != 0xaaaa) {
        // on first time run, dmaTestInit contains random data, not the 0xAAA(1010101010...)
        // we seek. When dmaTestInit is garbage, we give a warning and set it.
        Serial.println("dmaTest value is invalid.");
        dmaTestInit = 0xaaaa;
        }
    else {
        // If dmaTestInit is correct, dmaTest has a good value
        Serial.printf("Current dmaTest Value: %u\n\r", dmaTest);
        }

    // give dmaTest a random "good" value and let user know what it will be
    randomSeed(analogRead(0));
    dmaTest = random(0, 32768);
    Serial.printf("Next dmaTest Value: %u.\n\r", dmaTest);
    Serial.println();

    // You cannot allow Teensy to reboot with USB connected, to tell user to disconnect terminal.
    Serial.println("Disconnect terminal to proceed with WDT test!");
    while (Serial.dtr()) {}

    ledState = !ledState;                                   // init LED
    digitalWrite(led, ledState);

    // enable WDT
    noInterrupts();                                         // don't allow interrupts while setting up WDOG
    WDOG_UNLOCK = WDOG_UNLOCK_SEQ1;                         // unlock access to WDOG registers
    WDOG_UNLOCK = WDOG_UNLOCK_SEQ2;
    delayMicroseconds(1);                                   // Need to wait a bit..

    WDOG_TOVALH = 0x006d;                                   // 1 second WDT
    WDOG_TOVALL = 0xdd00;
    WDOG_PRESC  = 0x400;
    WDOG_STCTRLH |= WDOG_STCTRLH_ALLOWUPDATE |
        WDOG_STCTRLH_WDOGEN | WDOG_STCTRLH_WAITEN |
        WDOG_STCTRLH_STOPEN | WDOG_STCTRLH_CLKSRC |
        WDOG_STCTRLH_IRQRSTEN;                              // Tell WDOG to trigger the interrupt
    interrupts();

    NVIC_ENABLE_IRQ(IRQ_WDOG);                              // enable the call to the watchdog_isr function

}

void loop() {

timer = millis() + 10000UL;                                 // length of time we will reset WDT

while (true) {
    ledState = !ledState;
    digitalWrite(led, ledState);
    delay(100UL);
    if (millis() < timer) {                                 // Have we timed out yet?
        noInterrupts();                                     //   No - reset WDT
        WDOG_REFRESH = 0xA602;
        WDOG_REFRESH = 0xB480;
        interrupts();
        }
    } // while

}

Commentary

To enable the IRQ, you must set the WDOG control register to transmit the WDOG interrupt. You must also call NVIC_ENABLE_IRQ to have the MCU process the interrupt and call the watchdog_isr service routing.

Once that is done, it is just a matter of putting the necessary code in the watchdog_isr.

In this example, I simply overwrite the value of dmaTest in the ISR so I can verify it was called.

This makes it evident the ISR was called. Here is example of the output:

Terminal Connected.

Reason for last Reset: 
Power-on Reset
Low-voltage Detect Reset

dmaTest value is invalid.
Next dmaTest Value: 1298.

Disconnect terminal to proceed with WDT test!


<Your 'COM30' connection has terminated>

Terminal Connected.

Reason for last Reset: 
Watchdog(COP) Reset

Current dmaTest Value: 777
Next dmaTest Value: 6826.

Disconnect terminal to proceed with WDT test!

The first time connecting to the Teensy, dmaTest is uninitialized and set to 1298.

The WDT resets, calls the ISR, and dmaTest is now set to 777. This is seen when reconnecting to the Teensy.

Conclusion

Implementing the Teensy watchdog timer is nearly as straight-forward as it is for the Arduino or ATTiny 85.

Unlike the Arduino the Teensy can to communicate a WDT reset and pass status via DMAMEM variable (actually maybe Arduino can do this as well and I just have never seen it).

Finally, being able to hook the WDT reset so code can be executed before hand will end up being very useful for my intended project.

As long as you use the default ‘start_early_hook’, it should be about impossible to brick the Teensy. Since it starts up with WDT disabled, loops interrupted by the WDT should not have a chance before you can force a software update.

Update

I implemented the WDT into my production code and found that the eeprom library I’m using isn’t working with the watchdog_isr. I used DMAMEM to pass what I needed to the newly started code and haven’t research the eeprom problem any further.

Nov 2017 Update

To disable WDT, use this code:

NVIC_DISABLE_IRQ(IRQ_WDOG);

noInterrupts(); // don't allow interrupts while setting up WDOG
 WDOG_UNLOCK = WDOG_UNLOCK_SEQ1; // unlock access to WDOG registers
 WDOG_UNLOCK = WDOG_UNLOCK_SEQ2;
 delayMicroseconds(1); // Need to wait a bit..

// Set options to enable WDT. You must always do this as a SINGLE write to WDOG_CTRLH
 WDOG_STCTRLH = WDOG_STCTRLH_ALLOWUPDATE;

interrupts();

 

Posted in c-teensy | Tagged , | 7 Comments

Using tcpdump with DD-WRT

I’ve been having a weird networking issue. I’m having trouble determining if it is Comcast’s issue or mine. I see the packets in question leave the remote client, but they never come out the inside ethernet port of my comcast router. I assume the problem is comcast’s but I need to really be sure. I need to monitor the outside interface of my comcast router.

I have a Buffalo router connected to a cable modem (comcast doesn’t supply any of my equipment because I want full control). The Buffalo router comes with dd-wrt pre-installed.

At first I was going to connect a hub between the router and modem so I could tap into the outside interface using wireshark (see Sniffing *ALL* Arduino Network Packets). The problem with tapping into the connection like that is the hub is a 10M device and I really don’t want to downgrade my service like that.

Then it occurred to me I might be able to use tcpdump on the router since it is really just a small unix device. I did a quick check and sure enough, Buffalo was kind enough to include tcpdump in the operating system.

I checked further and found my other (Rosewill) routers do NOT have tcpdump installed. To proceed, you may need to install tcpdump onto your router. If so, google something like ‘How to install tcpdump on dd-wrt’. Here is one such article: https://www.pentest.ro/installing-tcpdump-on-dd-wrt/ .

Enable USB

Unless you just want to watch the raw tcpdump, which is about as exciting as watching grass grow, you are going to want to redirect tcpdump’s output to a file and then examine the output file with wireshark.

On the Buffalo router, this is pretty easy. In Services | USB, just enable USB storage support:

When you insert a USB thumb drive you should see it mount and the path will also be displayed:

--- /dev/sda1
Block device, size 14.83 GiB (15927345152 bytes)
FAT32 file system (hints score 4 of 5)
Volume size 14.83 GiB (15923150848 bytes, 485936 clusters of 32 KiB)
/dev/sda1 mounted to /tmp/mnt/sda1

Determine the Proper tcpdump Command

With storage now available, next determine the tcpdump command you wish to use and test it.

telnet or ssh into your router and login as root (password is the same as the one you use for HTML login).  You’ll see something like:

login as: root
DD-WRT v3.0-r30355 std (c) 2016 NewMedia-NET GmbH
Release: 09/13/16
root@rtr's password:
<< GRAPHIC OMITTED >>
BusyBox v1.24.2 (2016-09-13 15:32:42 CEST) built-in shell (ash)

root@rtr:~#

I want to capture all traffic for tcp port 22 on the outside interface so try a tcpdump such as:

tcpdump -s 0 -i eth1 port 22

Generate some test traffic. If this works, then verify you can output to the USB drive:

tcpdump -s 0 -i eth1 -w /tmp/mnt/sda1/out.pcap port 22

Run tcpdump in the Background

Once you are satisfied with your tcpdump, the next step is to run that in the background so you don’t need to keep a telnet / ssh session open.

In dd-wrt, go to Admin | Command and enter the command WITH ‘&’ at the end:

Now click on Run Commands and the tcpdump will start running in the background.

Stopping tcpdump

The tcpdump is now going to run until you reboot the router or you kill the tcpdump process.

To kill the process use

ps | grep tcpdump

to find the process id (PID) of the tcpdump process. Then use

kill PID

replacing PID with the proper process id # and it will kill tcpdump.

 

Posted in c-Misc | Tagged | Leave a comment

Forcing Accelerator Key Labels ALWAYS ON in Linux Mate

Need to file this one away for future use.

In Linux Mint / Mate, the underscores for accelerators keys is only on when you hold down ALT. I invariably forget this because they aren’t obvious, and don’t make use of them which slows me down. I *hate* having to use the mouse.

Tonight I went looking to see if they could be forced to stay on.

The few instructions I’ve found tell you to set the gnome setting “automatic-mnemomics” to false. I tried that repeatedly w/ no luck.

Eureka! I am using MATE not gnome. Doh! went looking in the Mate section of dconf settings and found the exact same setting. Set that to false and now underscores are always on.

Note: install dconf-editor. This is much easier than using gsettings and typing everything by hand.

The specific tree to this setting is:

org.mate.desktop.interface automatic-mnemonics

Posted in c-Misc | Tagged | Leave a comment

Cermetek CH1724 Modem PTH Adapter Board

I need to solder pins to multiple CH1724 modems which look like this:

Image result for ch1724

I tried soldering header pins directly, but that was a cluster. So I designed this little adapter board:

You can layout header pins on a PCB, put the adapter board on the pins, then the modem on the adapter board like this:

ch1724adapter

and you end up with:

ch1724adapter-2

I’ve placed this adapter board on dirtypcbs.com so you can order your own. You can find it here.

If you need such a beast and you don’t want to order a minimum quantity of 10, check with me and I may have a spare I can send you cheap.

Posted in c-electronics | Tagged | 1 Comment

Making a Data Only Cable For Teensy/Arduino/Nano

Been working on a complicated teensy project that is going to the other side of the state for testing. So I’ve been building a testing platform that consists of a Raspberry Pi connected to the Teensy via USB. I can connect to the RPI and monitor/update the Teensy.

One of the requirements is that I be able to cycle power on the teensy just in case duty hits the fan. I’ve got this great little device for that very purpose:

found at http://www.digital-loggers.com/iot.html

The one problem I’ve realized with this idea is I cannot just remove power from my device to reset it because the RPI will continue to feed power to the Teensy via the USB cable. (Actually there is a way to have RPI kill power to its USB hub but it also kills power to the ethernet module. It has worked in testing but seems a little dicey to really rely upon).

I need to kill power from the USB cable. The obvious way to do this is to slice the USB cable open and cut the power line. Not too hard to do, but I really don’t want to send a unit out to the ‘customer’ with electrical tape around one of the cables. That’s not cool.

I was looking around for data only USB cables (which are available but kind of expensive) and stumbled across someone that was doing the reverse of what I wanted – he was getting rid of the data signal. BUT, his method was perfect. See http://www.instructables.com/id/USB-Condom/?ALLSTEPS.

I applied the same idea and cut a tiny piece of clear packing tape and applied it to the +5V contact on the A side of the USB cable:

dataOnlyYou should be able to see the tape covering the contact on the far right.

This works great and now when I kill power to the device, it actually turns off.

Nov 2016 Update:

The size of tape is pretty close to 3mm x 25mm.

Posted in c-arduino, c-rpi, c-teensy | Tagged | 1 Comment