SDS100/SDS200: sds200, microSD, maintenance, tidy, ftp, Linux

n1moy

Member
Joined
Oct 19, 2022
Messages
69
Location
Plymouth Co, Massachusetts
Recording is continuously enabled on my sds200. The microSD card will eventually overflow without directory management. One user in this forum described the radio locking up and displaying, "SD Card Full". Others have described the process of removing the microSD card from the radio and using a computer to delete inactive files and directories. Have endeavored to utilize the Ethernet port and the ‘writable’ ftp account for this purpose.

Devised a Bash shell script to automate the deletion of aged microSD files and directories without removing the card from the radio. The script selects directories older than ~2 days to delete from the /audio/user_rec directory.

uniden-tidy.sh

gawk is the script's only dependency. The GNU implementation of awk is included by default in many Linux distributions. Both of the radio’s ftp server accounts are used. The ‘read only’ account to download a directory listing and the ‘writable’ for deletions. Five parameters are required at the top of the script; IP address, both account's username and password.

Reminder: The two ftp accounts are distinguished by different user names. [required]

Make the shell script executable by changing mode and access permissions.

Bash:
$ chmod a+x ~/uniden-tidy.sh

Execute the script from the command line interface [CLI] or ‘Terminal’.

Bash:
$ ./uniden-tidy.sh

The scanner will enter ‘ftp-mode’ during the deletion of files and directories. The CLI will acknowledge the deletion of each file and directory. At completion a warm reboot will return the radio to ‘scan-mode’. If the script does not detect aged directories to delete, it will instead print a current sorted list.

sds200.ftp.mode.jpg

Optional: Add the following line to your .bash_aliases file to enable the command ‘tidy’ in the CLI.

alias tidy='./uniden-tidy.sh'

Good luck,
 

n1moy

Member
Joined
Oct 19, 2022
Messages
69
Location
Plymouth Co, Massachusetts
Bash:
#!/bin/bash

# uniden-tidy.sh
# Bash script to delete inactive sds200/microSD files and directories. - n1moy

RADIO="192.168.24.40"    # IP address
READ="read.user"         # read only user
WRITE="write.user"       # writable user
RPASSWD="password"       # password-read
WPASSWD="password"       # password-write

SESSION=`ftp -inv <<ROUT
    open $RADIO
    user $READ $RPASSWD
    cd /audio/user_rec
    ls
    bye
ROUT`

# $DIR_LIST -- /audio/user_rec directory list
DIR_LIST=$(gawk '{if ($1 ~ /^d-{9}/ && ($9 !~ /\.{1,2}/ )) \
print "0x"$9}' <<< "$SESSION")
if [[ $DIR_LIST == "" ]] ; then
    echo "/audio/user_rec contains no recording directories"
    exit
fi

# $CRENT -- current recording directory
CRENT=$(( sort -d | tail -n 1) <<< "$DIR_LIST")
# $CRENT_DEC -- decimal value
CRENT_DEC=$(gawk '{print strtonum($1)}' <<< "$CRENT")
# $RMD_LIST -- directory list for deletion
RMD_LIST=($(gawk -v x=$CRENT_DEC 'BEGIN {FS="x"}; \
{if (strtonum($0) <= x-220000) print $2}' <<< "$DIR_LIST"))
if [[ $RMD_LIST == "" ]] ; then
    echo "/audio/user_rec contains no aged directories"
    DIR_LIST=$(echo "$SESSION" | sort -dk9)
    gawk '{if ($1 ~ /^d-{9}/ && ($9 !~ /\.{1,2}/)) \
    print "\t"$6, $7, $8, $9 }' <<< "$DIR_LIST"
    exit
fi

rm -f ~/.uniden-temp.sh
echo "#!/bin/bash" >> ~/.uniden-temp.sh
echo "ftp -inv <<WDEL" >> ~/.uniden-temp.sh
echo "open" $RADIO >> ~/.uniden-temp.sh
echo "user" $WRITE $WPASSWD >> ~/.uniden-temp.sh
echo "cd /audio/user_rec" >> ~/.uniden-temp.sh
for dir in "${RMD_LIST[@]}"; do
    echo "mdelete --ignore-fail-on-non-empty /audio/user_rec/"$dir >> ~/.uniden-temp.sh
    echo "rmdir /audio/user_rec/"$dir >> ~/.uniden-temp.sh
done
echo "bye" >> ~/.uniden-temp.sh
echo "WDEL" >> ~/.uniden-temp.sh

chmod a+x ~/.uniden-temp.sh
echo -e "GFM,UNIDEN\0015" > /dev/udp/$RADIO/50536
sleep 1
source ~/.uniden-temp.sh
echo -e "EFM,UNIDEN\0015" > /dev/udp/$RADIO/50536
rm -f ~/.uniden-temp.sh
exit
 

n1moy

Member
Joined
Oct 19, 2022
Messages
69
Location
Plymouth Co, Massachusetts
Have been unsuccessful locating documentation for the naming of the recording directories. The deficiency of this methodology makes it futile to calculate a name for a particular time.

As a result, the script only references the current recording directory to determine which others are to be deleted. If recording has been disabled, for a time, the script may not delete directories that are older than ~2 days.
 

ProScan

Software Provider
Premium Subscriber
Joined
Jul 2, 2006
Messages
8,049
Location
Ontario, Calif.
Have been unsuccessful locating documentation for the naming of the recording directories. The deficiency of this methodology makes it futile to calculate a name for a particular time.

As a result, the script only references the current recording directory to determine which others are to be deleted. If recording has been disabled, for a time, the script may not delete directories that are older than ~2 days.

Maybe this will help
 

belvdr

No longer interested in living
Joined
Aug 2, 2013
Messages
2,567
Yes! Contains the formula for the "hexadecimal time stamp" naming.

Thanks,
I'm no C guy, but there appears to be an error in their code. It takes a hex value and converts it to integer using base-10. Anyhow, this Python code (again 3.11.6) seems to convert correctly. I have not tested a lot of values:
Code:
def convert_dir_name(source_name):
    fat_time = int(source_name, 16)
    year = ((fat_time >> 25) & 0x7f) + 1980
    month = (fat_time >> 21) & 0xf
    day = (fat_time >> 16) & 0x1f
    hour = (fat_time >> 11) & 0x1f
    minute = (fat_time >> 5) & 0x3f
    second = (fat_time << 1) & 0x3f
    return f"{year:04d}-{month:02d}-{day:02d} {hour:02d}:{minute:02d}:{second:02d}"
 

belvdr

No longer interested in living
Joined
Aug 2, 2013
Messages
2,567
"It's possible to converting hexadecimal time stamp to "YYYY‐MM‐SS_mm_dd_ss" format."

I am considering the reverse.
Do you mean converting a time to their hex format?
 

n1moy

Member
Joined
Oct 19, 2022
Messages
69
Location
Plymouth Co, Massachusetts
Correct - The CURRENT time to the time stamp format.

"hexadecimal time stamp name format"
hexadecimal.time.stamp.png

This script appears to work ...

Bash:
#!/bin/bash

# dates.sh
# current time to hexadecimal time stamp

YY=$(date +%Y)
MM=$(date +%m)
DD=$(date +%d)
hh=$(date +%H)
mm=$(date +%M)
ss=$(date +%S)

YY=$(($YY - 1980))
ss=$(($ss / 2))

DEC=$(printf "%07d" $(dc -e "$YY 2op"))
DEC+=$(printf "%04d" $(dc -e "$MM 2op"))
DEC+=$(printf "%05d" $(dc -e "$DD 2op"))
DEC+=$(printf "%05d" $(dc -e "$hh 2op"))
DEC+=$(printf "%06d" $(dc -e "$mm 2op"))
DEC+=$(printf "%05d" $(dc -e "$ss 2op"))

printf '%X\n' "$((2#$DEC))"

exit

Bash:
$ ./scanner/dates
584591F2
 
Last edited:

belvdr

No longer interested in living
Joined
Aug 2, 2013
Messages
2,567
Why would you want to convert that way?
 

n1moy

Member
Joined
Oct 19, 2022
Messages
69
Location
Plymouth Co, Massachusetts
Condensed

Bash:
#!/bin/bash

# dates.sh
# current time to hexadecimal time stamp

BINARY=$(printf '%07d%04d%05d%05d%06d%05d' \
$(dc -e "$(($(date +%Y) - 1980)) 2op") $(dc -e "$(date +%m) 2op") \
$(dc -e "$(date +%d) 2op") $(dc -e "$(date +%H) 2op") \
$(dc -e "$(date +%M) 2op") $(dc -e "$(($(date +%S) / 2)) 2op"))

printf '%X\n' "$((2#$BINARY))"

exit

Need the value of a current recording directory name to determine which others should be deleted.

Are you thinking of a more straightfoward method to generate ?
 
Last edited:

belvdr

No longer interested in living
Joined
Aug 2, 2013
Messages
2,567
Need the value of a current recording directory name to determine which others should be deleted.

Are you thinking of a more straightfoward method to generate ?
It’s a hex value. If you want the latest one to stay, find the maximum value out the list and leave it.
 

n1moy

Member
Joined
Oct 19, 2022
Messages
69
Location
Plymouth Co, Massachusetts
Exactly!

The 'tidy' script uses the current [last] directory as a reference to determine which others should be deleted. Had realized the script would fail to meet a described objective if the user, for a time, disabled recording.

"The script selects directories older than ~2 days to delete from the /audio/user_rec directory."

The 'File Specification PDF' provided a solution with details of the time stamp format. I am currently testing a version with this alteration in place. Employing this level of preciseness may be unnecessary.

Considering a next script to download all recordings from the last ~20 minutes. This task may include recordings that could span two or more directories. Thinking that similar technics involving time stamps may prove to be beneficial.
 

belvdr

No longer interested in living
Joined
Aug 2, 2013
Messages
2,567
Exactly!

The 'tidy' script uses the current [last] directory as a reference to determine which others should be deleted. Had realized the script would fail to meet a described objective if the user, for a time, disabled recording.

"The script selects directories older than ~2 days to delete from the /audio/user_rec directory."
DYn't need to reference the last directory if all you want to delete are directories older than 2 days. Simply do a date comparison instead with the converted hex values.

The 'File Specification PDF' provided a solution with details of the time stamp format. I am currently testing a version with this alteration in place. Employing this level of preciseness may be unnecessary.
Still not sure why you need this. You have a list of hex values. If you don't want to touch the latest folder, sort them in reverse order, and skip the first line.

Considering a next script to download all recordings from the last ~20 minutes. This task may include recordings that could span two or more directories. Thinking that similar technics involving time stamps may prove to be beneficial.
Unless you're recording just one non-trunking system, this may not be very useful, due to not knowing what the recording is comprised of. For example, on a trunked P25 system, you'd lose the metadata about the TGID and RID. You might be able to derive that information, after listening to the system for some time though.

In my opinion, it would be better to utilize the serial or Ethernet interface to glean that info and have the program record it instead. In other words, ProScan for Linux.

In my humble opinion, recording on the SD card has limited value.
 

n1moy

Member
Joined
Oct 19, 2022
Messages
69
Location
Plymouth Co, Massachusetts
The hexadecimal stamp appears to be the simplest method to read or generate the directory creation times.

Not currently using my sds200 for any trunked reception.

Was generating a Uniden hexadecimal value for the current time. Did you have a more straightfoward method ?
 

belvdr

No longer interested in living
Joined
Aug 2, 2013
Messages
2,567
The hexadecimal stamp appears to be the simplest method to read or generate the directory creation times.
Agreed.

Not currently using my sds200 for any trunked reception.
Then downloading the wav files should be fine, as long as you can tell what they are from. Renaming them accordingly may be a pain though.

Was generating a Uniden hexadecimal value for the current time. Did you have a more straightfoward method ?
You said you're doing this so you don't modify the current recording directory. There's no need to generate anything according to Uniden's method. Grab the directory list, then sort the directory by name in reverse order and eliminate the top entry, then act on that. That will leave the latest directory intact.

Additionally, if you generate a hex value based on current time, then it likely won't match the directories on the SDS, because the directory was created in the past, even by a few seconds.
 

n1moy

Member
Joined
Oct 19, 2022
Messages
69
Location
Plymouth Co, Massachusetts
The script version that I am currently testing begins with a reference date-time -2 days ago.

Using Uniden's time stamp formula it calculates a cooresponding hexadecimal value. The deletion list is determined by testing if the directory name is less-than the hexadecimal reference value.

Did not need to consider the current [last] directory as part of the rule.
 
Last edited:

n1moy

Member
Joined
Oct 19, 2022
Messages
69
Location
Plymouth Co, Massachusetts
Hexadecimal time stamp version

Have received Uniden's hexadecimal time stamp documentation which enables the calculation and deciphering of directory names. As a result, this reissued version is able to more precisely delete directories that are older than ~2 days.

Otherwise, the procedure and operation are unaffected.

Bash:
#!/bin/bash

# uniden-tidy.sh    [hexadecimal time stamp version]
# Bash script to delete inactive sds200/microSD files and directories. - n1moy

RADIO="192.168.24.40"    # IP address
READ="read.user"         # read only user
WRITE="write.user"       # writable user
RPASSWD="password"       # password-read
WPASSWD="password"       # password-write

# $REF_DATE -- reference date-time
REF_DATE=$(date -d "-54 hours" "+%Y-%m-%d %H:%M")
# $BINARY -- reference binary time stamp
BINARY=$(printf '%07d%04d%05d%05d%06d%05d' \
$(dc -e "$(($(date -d "$REF_DATE" +%Y) - 1980)) 2op") $(dc -e "$(date -d "$REF_DATE" +%m) 2op") \
$(dc -e "$(date -d "$REF_DATE" +%d) 2op") $(dc -e "$(date -d "$REF_DATE" +%H) 2op") \
$(dc -e "$(date -d "$REF_DATE" +%M) 2op") $(dc -e "$(($(date -d "$REF_DATE" +%S) / 2)) 2op"))
# $REF_HEX -- reference hexadecimal time stamp
REF_HEX=$(printf '0x%X' "$((2#$BINARY))")

SESSION=`ftp -inv <<ROUT
    open $RADIO
    user $READ $RPASSWD
    cd /audio/user_rec
    ls
    bye
ROUT`

# $DIR_LIST -- /audio/user_rec directory list
DIR_LIST=$(gawk '{if ($1 ~ /^d-{9}/ && ($9 !~ /\.{1,2}/ )) \
print "0x"$9}' <<< "$SESSION")
if [[ $DIR_LIST == "" ]] ; then
    echo "/audio/user_rec contains no recording directories"
    exit
fi

# $RMD_LIST -- directory list for deletion
RMD_LIST=($(gawk -v x=$REF_HEX 'BEGIN {FS="x"}; \
{if ($0 <= x) print $2}' <<< "$DIR_LIST"))
if [[ $RMD_LIST == "" ]] ; then
    echo "/audio/user_rec contains no aged directories"
    DIR_LIST=$(echo "$SESSION" | sort -dk9)
    gawk '{if ($1 ~ /^d-{9}/ && ($9 !~ /\.{1,2}/)) \
    print "\t"$6, $7, $8, $9 }'  <<< "$DIR_LIST"
    exit
fi

rm -f ~/.uniden-temp.sh
echo "#!/bin/bash" >> ~/.uniden-temp.sh
echo "ftp -inv <<WDEL" >> ~/.uniden-temp.sh
echo "open" $RADIO >> ~/.uniden-temp.sh
echo "user" $WRITE $WPASSWD >> ~/.uniden-temp.sh
echo "cd /audio/user_rec" >> ~/.uniden-temp.sh
for dir in "${RMD_LIST[@]}"; do
    echo "mdelete --ignore-fail-on-non-empty /audio/user_rec/"$dir >> ~/.uniden-temp.sh
    echo "rmdir /audio/user_rec/"$dir >> ~/.uniden-temp.sh
done
echo "bye" >> ~/.uniden-temp.sh
echo "WDEL" >> ~/.uniden-temp.sh

chmod a+x ~/.uniden-temp.sh
echo -e "GFM,UNIDEN\0015" > /dev/udp/$RADIO/50536
sleep 1
source ~/.uniden-temp.sh
echo -e "EFM,UNIDEN\0015" > /dev/udp/$RADIO/50536
rm -f ~/.uniden-temp.sh
exit
 
Top