////////////////////////////////////////////////////////////////////////////////////////
//                           Digital Alarm Clock
//                Copyright (C) 2023 - Stefan Keller-Tuberg
//                       skt@keller-tuberg.homeip.net
//
// This file is part of the Digital Alarm Clock project.
//
// The Digital Alarm Clock project is free software: you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published by the
// Free Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// The Digital Alarm Clock project is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with
// the Digital Alarm Clock Project.  If not, see <http://www.gnu.org/licenses/>.
///////////////////////////////////////////////////////////////////////////////////////////

NOTE about Raspberry Pi Bookworm OS

I developed the clock and debugged the software using the Bullseye OS, and I have had
four clocks running for around six months using Bullseye, and no problems!

One week after the folks at Silicon Chip completed editing the magazine articles, I awoke
to a Raspberry Pi press release saying that they have released a new Pi5,
and a new Operating System would be released within weeks to support the Pi5 called
'Bookworm'. I'd been anticipating this, but the timing was legendary.

When Bookworm was released, I quickly found that significant changes had been made
to the way wifi and bluetooth worked, and the Pi's audio subsystem had significantly
changed. For the first few days after the release, bluetooth didn't work at all. For
a couple of weeks after the release, new behaviours would emerge every few days as a
rapid succession of updates were released. I have implemented work arounds for these
changes, but while Bookworm remains in a state of flux, its possible new things
are going to randomly be broken with future updates.

At the time I am typing this (late October 2023) changes are continuing to be pushed out.
Some of these are affecting the interaction between the clock programme and the operating
system, or affecting the Install_Clock.sh script behaviour. Hopefully by the time
you install this code, these issues will have been ironed out. If not, go back to the
Bullseye release which was still working just fine and check for updates on SC's web site
and / or try Bookworm again later.

You will find the Bullseye release in Raspberry Pi imager by clicking the "Operating
System" button on the main window, then "Raspberry Pi OS (other)", then scrolling down
to "Raspberry Pi OS (Legacy, XX-bit) Lite" where XX is either 32 or 64 as required.
///////////////////////////////////////////////////////////////////////////////////////////

Refer to the articles or to the PDF file within the project zipfile for more information
about how to prepare an SDMMC card for the Raspberry Pi, and about how to install the
alarm-clock software.

The information below assumes that you have successfully run the Install_Clock.sh
installation script.

The installation script sets up the Raspberry Pi to automatically run the pigpio daemon
and alarm-clock software every time the Raspberry Pi boots. It will also automatically
start the apache web server and samba file server. The systemctl daemon will restart any
of these processes if they crash for any reason. This is the normal way you will probably
want to use this software. The alarm-clock programme itself will reboot the Pi if it sees
its own daemon has stopped.

The web server can be accessed at http://<<CLOCK LOCAL NAME OR IP ADDRESS>>
The format of the CLOCK LOCAL NAME will depend on your home router, but a common format
would be CLOCK.local (if you named your Raspberry Pi 'CLOCK').

If you don't know or cannot find your clock's name on your local network, I've added a
function into release 3 of the clock software for the clock to tell you its own IP
address. To activate this, simultaneously press the alarm 1 and 4 buttons, or alternately
the alarm 2 and 3 buttons, and the clock will tell you the four numbers that comprise
its IP address - one number at a time. You can then surf to http://<<IP Address>> to
access the clock's web pages without knowing its local network name.

The samba file server can be accessed from any computer on your home network. There are
two fileshares that are available: the first is the whole Linux filesystem and it will
have the name 'PiFileSystem' when you go browsing the clock. The second will be the
home directory of the account that you created. To access the home directory, you will
need to supply the login credentials you used when setting up the SD card. The process
for finding the home account and logging into it via the file share will differ depending
upon your computer's operating system.

The USB ports on the Raspberry Pi are 'hot'. If you plug in a device and the Pi recognises
it, it will be automatically mounted under '/media' in the Pi's filesystem. There is no
eject function on the clock. If you have written to the USB device, you should wait a
little before pulling it out. The USB device is conservatively configured to permit these
'hostile' ejects. Because of this, writing to the USB device will be slower than it
would otherwise be. You're welcome to modify the configuration in the Install_Clock.sh
script if you know what you're doing. Reading speed should however be as you would normally
expect. You could use a USB drive to store playable media, for example.

///////////////////////////////////////////////////////////////////////////////////////////
Debug mode:

If you are curious, you may want to watch the alarm-clock programme running in real time,
to see how the different threads interact with each other. In order watch the activity,
you'll need to run the alarm clock from a bash shell using one of the command line options
that turns on the various debugging modes.


1. First stop the running alarm-clock instance that is being managed by the systemctl daemon.
   Issue the following command to temporarily stop the Operating System from managing the
   alarm-clock:

    sudo systemctl stop alarm-clock

   I have also included a script that will do this for you without you having to remember
   the command syntax:

    stop-alarm-clock

2. Now you can run the alarm-clock programme manually from the command line. You do this
   by issuing the following command:

    alarm-clock -h

   The -h option will cause alarm-clock to display some help and then stop. Read the various
   options and then rerun the alarm-clock programme with the options you are interested in.
   To turn on EVERY debugging option, you can run it like this:

    sudo alarm-clock -V

   To stop the programme in this mode, just hit CTRL-C.

   Having EVERY debugging option enabled can be overwhelming and maybe not so useful. You
   can instead choose just one or a couple of the indidual debugging options listed when you
   run alarm-clock -h.

3. As you interact with the web server and modify settings and alarms, you'll see
   corresponding activity in the debug output in the ssh session.

4. To revert to the normal system-managed version of the alarm-clock, reboot the Raspberry
   Pi. When the clock comes back on after the reboot, the operating system will be managing
   it once more.

   sudo reboot

///////////////////////////////////////////////////////////////////////////////////////////
Upgrading to a new version of the software (if a new version is released, that is)

1. If there is a new version of the software, you will need to copy it onto the Raspberry
   Pi and then recompile and install it. There are several ways of copying the tarball
   to the Pi.

   (a) You can power down the Pi, remove its SD card, plug the SD card into a computer,
       and copy the new version of the source code tarball onto the 'bootfs' partition
       visible on your other computer. When you put the SD card back into the Pi and
       reboot, follow a similar process as when you installed the clock software:

       For the Bullseye version of the operating system, the command is:
        tar zxf /boot/alarm-clock_v03.tgz (from within your home directory)

       For the Bookworm version of the operating system, the command is:
       tar zxf /boot/firmware/alarm-clock_v03.tgz (from within your home directory)

       You can then immediately move down to the compiling instructions.

   (b) You could copy the alarm-clock_vXX.tgz file onto the Pi using its samba share.
       First, attach to the Pi's samba share from your computer. The process will be the
       same as attaching to any other network share, but the process differs for every
       operating system, so I won't elaborate. Hint: Some windows versions are not so
       helpful in finding the samba shares. You'll need to create a drive letter for
       them, and their name will be based on the name that you called your clock. eg
       \\CLOCK\PiFileSystem and \\CLOCK\homes or your account name. For other operating
       systems, the two samba fileshares will just appear and you can connect. You'll
       need to supply your account username/password for logging into the homes share.
       The relevant username/password is your Pi username/password!

       Log into the homes share and save the tarball into the root of your home directory.
       Then follow the compiling instructions. If you don't first log into the samba
       share with your Pi username and password, the samba server will show you the
       filesystem but will not let you write to it! You must log in via the file
       system explorer first!

   (c) You can copy the tarball file onto a USB stick and then plug the USB stick into
       the Pi. The USB stick will be auto-mounted under the /media directory, so you
       can extract the contents directly from the USB stick by opening an ssh session
       in to you login on the Pi, then using the following command directly from the
       root of your home account:

        tar zxf /media/alarm-clock_v03.tgz

       You can then follow the compiling instructions.

2. You can modify / recompile and install the alarm-clock software. Issue the following
   commands in this current directory:

    cd alarm-clock (if you are not already in this sub-directory)
    make
    make install

    The alarm-clock programme will be compiled, then it will be installed with the last
    command, and the system will tell you it is going to reboot. You can hit CTRL-C to
    stop the system from rebooting, but its best to reboot after recompiling and reinstalling
    the software.

3. Note: if you access the web interface after running 'sudo systemctl stop alarm-clock' and
   while the alarm-clock is not running in a ssh session, the system will reboot itself! This
   is by design. The web server is checking to see if the clock has crashed, and reboots the
   Pi if so.
///////////////////////////////////////////////////////////////////////////////////////////
Automatic Raspberry Pi upgrades:

From time to time, updates are published for some of the software modules on the clock.
Common reasons for this include (a) a security fix, (b) fixing bugs, (c) timezone updates
including publishing of daylight savings / leap seconds and so on.

I have included a software moduled called 'unattended-upgrades' and configured it so that
it will check for any updates once every three days, downloading and applying any that
are found. If you don't want this behaviour, you will need to disable unattended-upgrades

 sudo apt remove unattended-upgrades

or you can edit its configuration to suit your needs - look in the Install_Clock script
for hints on what to change.

///////////////////////////////////////////////////////////////////////////////////////////
Mounting shared directories from *other* systems into the Pi filesystem.
(ie making other file servers appear as a directory trees on the Pi, and auto mounting them)

I will not provide instructions here about how to do this, but you can find instructions on the
Internet. You'll be getting quite deep into Linux configuration if you want to do this, so
be prepared for a 'journey' if you don't really know what you're doing. Each installation is going
to be a little different, hence no specific instructions here.

Hint:
One way to automatically mount a network share from another system is to add an entry into the
/etc/fstab file. Search for instructions about how to do this for your particular situation.
You will probably want to add an option that ignores errors (for example if the network
fileshare is not present when the Raspberry Pi boots and tries to mount it).

///////////////////////////////////////////////////////////////////////////////////////////
The files in the alarm-clock directory tree:

There are a number of sub-directories that include
  html and cgi code for the web server part of the clock
  reboot-seconds: tool to reboot the Pi after a short delay
  test_pigpio: examples to test the PiGPIO daemon
  test_pipes: examples of using Linux/Unix pipes to communicate with another process.
              Also example of communicating with bluetoothctl process
  test_pthread: examples to test posix threads under Linux
  test_udp: test sending and receiving UDP packets under Linux
  test_mpv: test the C interface to the mpv media player
  message_queue_status: tool to read Linux message queues that are set up by the clock

In those subdirectories that contain C code, run 'make' to compile the code. There is also
other readme files there. You can run the compiled programme by typing './name' where
name is the name of the compiled programme. Note the preceding './'

///////////////////////////////////////////////////////////////////////////////////////////
Security:

This project is unlikely to receive any awards for security. The install script grants
passwordless sudo access, and opens read/write permissions on some files under /etc. I
have done this to allow (for example) configuration of wifi connections via the web
server. This would be considered insecure practice on (for example) a corporate network
or anything facing the Internet.

I have added a question in the Install_Clock.sh script to enable an iptables firewall on
the Pi which causes the Pi to drop any packets that have a source address that is NOT from
the local subnet. This means that the web, ssh and samba servers on the clock will not be
accessible from the Internet even if you configure your home router/gateway to redirect
incoming ports to the web/ssh/samba servers on the Pi. If your home network has multiple
subnets, the clock will not be accessible to hosts on different subnets if the firewall
is enabled. However if that's an issue for you, you can edit the Install_Clock.sh script
to change the iptables rules so they work for you.

I have not done anything regarding IPv6 firewall rules. I assume your home network
does not permit incoming IPv6 connections. Modify the iptables rules if this too is a
problem for you.

In general, you are probably installing this in your home and you will not have configured
any incoming IPv4 connections through your home router. The firewall in your home router
will block and drop incoming connection attempts from the outside Internet. With the clock
firewall enabled, this probably means the clock will be safe. The Pi will only be vulnerable
if ANOTHER host on your home network is compromised first, and the attacker is sufficiently
determined to then go looking around your home network for additional vulnerabilities on
other hosts such as the Pi, and then works out how to get into the Pi. This would be a fair
bit of work for the hacker. If the hacker has already compromised a device on your home
network, they probably have other things in mind than to discover and hack your clock....

///////////////////////////////////////////////////////////////////////////////////////////
Acknowledgement and thanks:

The author acknowledges the assistance he received from Ingo Evers. Ingo suggested several
of the clock's features, built a prototype and helped find bugs with the installer and the
alarm-clock code. Without his assistance, I'm sure the clock wouldn't have turned out as
well as it did. It may still contain bugs, but they won't be Ingo's fault.

///////////////////////////////////////////////////////////////////////////////////////////
Bugs Confession:

In the history of software, no human ever has or ever will be able to write complicated
software that is bug-free. I have no reason to believe I am different or special. If you
encounter bugs, I'm sorry but neither of us should be too surprised.

In some cases, what you may consider to be a bug, I will consider to be a 'feature'. For
example, there are 'features' present because I have used the mpv media player library, and
the actual behaviour of mpv is not perfectly aligned with its documentation. In general,
I have found mpv to be excellent, and it is an extremely complex application, so its not as
bad as you may think from my comment. But there are documented 'features' I wanted to use
which simply do not exist in the libmpv implementation for the Raspberry Pi. One is the
ability to stop the media player without clearing the playlist. Another is its events
interface. There are other inconsistencies. I did my best to work around the 'features'
of mpv, but I cannot possibly fix or change mpv itself. If you can improve my mpv interface,
please let me know.

I may also be able to fix bugs in my own code if you let me know about them. Importantly,
in order to fix bugs, I will need to be able to *precisely* reproduce and understand them.
This may require you gathering debug information, sharing your configuration files, logs,
describing the detailed sequence of events leading up to the bug, whether you have more than
one clock on your network and so on. If you think you've found a problem, please gather the
information together with a detailed description about how I can reproduce the problem on my
own clock. You are very welcome to have a go at fixing any problems that you find and
letting me know what you fixed and how you fixed it. I will of course be appreciative.

The 32 bit Bullseye Raspberry Pi image carries with it the Y2038 calendar bug. The problem
doesn't exist in 64 bit versions of the Pi operating system and it has been fixed in the
32 bit Bookworm release. Notwithstanding comments above about bugs in Bookworm (which I
assume will eventually be fixed), its therefore recommended that you download and install
and then try the Bookworm release if you have an older Pi that's not compatible with 64 bit
code.

FYI: Even with the Y2038 bug, the clock will work fine until January 2038 and then it will
tell the wrong time and alarms won't work. The time_t bug arises because time_t is declared
as a 32 bit signed integer in older C libraries such as included in 32 bit Bullseye. A 32
bit time counter will roll over to become a negative number in Jan 2038. The issue doesn't
exist with the 64 bit versions of the C libraries because time_t has always been declared
as a 64 bit variable in these releases.
