Arducam 64MP and Raspberry Pi Kernel 6 (revisited)

Over a week after my first post and I was still without a working 64mp camera. The old method of running a script to install drivers still reported the same error, and the entry that used to be in my /boot/config.txt file wasn’t helping.

[all]
dtoverlay=arducam_64mp

I went back to look at the arducam forums and came across this post and found that when they went from the custom kernel module install to the standard module install they’ve changed from using an underscore to a hyphen:

[all]
dtoverlay=arducam-64mp

Now after booting, my camera is correctly recognized. The delay and lack of obvious information on their site has been frustrating, but at least I’m up and working and shouldn’t need to do anything special with further apt updates.

wim@WimPi4-Dev:~/WimsConstructionCam $ uname -a
Linux WimPi4-Dev 6.1.19-v8+ #1637 SMP PREEMPT Tue Mar 14 11:11:47 GMT 2023 aarch64 GNU/Linux
wim@WimPi4-Dev:~/WimsConstructionCam $ libcamera-still --list-cameras
Available cameras
-----------------
0 : arducam_64mp [9248x6944] (/base/soc/i2c0mux/i2c@1/arducam_64mp@1a)
    Modes: 'SRGGB10_CSI2P' : 1280x720 [30.00 fps - (0, 0)/0x0 crop]
                             1920x1080 [30.00 fps - (0, 0)/0x0 crop]
                             2312x1736 [30.00 fps - (0, 0)/0x0 crop]
                             3840x2160 [30.00 fps - (0, 0)/0x0 crop]
                             4624x3472 [30.00 fps - (0, 0)/0x0 crop]
                             9152x6944 [30.00 fps - (0, 0)/0x0 crop]

Raspberry Pi Kernel 6 and Arducam

I updated the software on my development machine this morning without thinking too much about it. After doing so, I checked my program that uses the camera to see if it was running properly. I’ve got an Arducam64mp camera that I’m using on that machine, and often when the kernel gets updated I need to reinstall the kernel drivers from Arducam. They have a script, so normally it runs easily enough.

wim@WimPi4-Dev:~ $ sudo ./install_pivariety_pkgs.sh -p 64mp_pi_hawk_eye_kernel_driver
=================================================
Hardware Revision: d03114
Kernel Version: 6.1.19-v8+
OS Codename: bullseye
ARCH: aarch64
=================================================

kernel:6.1.19-v8+
--2023-03-21 10:36:25--  https://github.com/ArduCAM/Arducam-Pivariety-V4L2-Driver/releases/download/install_script/64mp_pi_hawk_eye_kernel_driver_links.txt
Resolving github.com (github.com)... 192.30.255.112
Connecting to github.com (github.com)|192.30.255.112|:443... connected.
HTTP request sent, awaiting response... 302 Found
Location: https://objects.githubusercontent.com/github-production-release-asset-2e65be/353945933/a0487b40-ef2c-4923-b366-3e8d0b6f0c88?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIWNJYAX4CSVEH53A%2F20230321%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20230321T173626Z&X-Amz-Expires=300&X-Amz-Signature=f28c85b9e602c3789a04e891e7a91d43a0dd89759e7297b888093b54fee6670d&X-Amz-SignedHeaders=host&actor_id=0&key_id=0&repo_id=353945933&response-content-disposition=attachment%3B%20filename%3D64mp_pi_hawk_eye_kernel_driver_links.txt&response-content-type=application%2Foctet-stream [following]
--2023-03-21 10:36:26--  https://objects.githubusercontent.com/github-production-release-asset-2e65be/353945933/a0487b40-ef2c-4923-b366-3e8d0b6f0c88?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIWNJYAX4CSVEH53A%2F20230321%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20230321T173626Z&X-Amz-Expires=300&X-Amz-Signature=f28c85b9e602c3789a04e891e7a91d43a0dd89759e7297b888093b54fee6670d&X-Amz-SignedHeaders=host&actor_id=0&key_id=0&repo_id=353945933&response-content-disposition=attachment%3B%20filename%3D64mp_pi_hawk_eye_kernel_driver_links.txt&response-content-type=application%2Foctet-stream
Resolving objects.githubusercontent.com (objects.githubusercontent.com)... 185.199.108.133, 185.199.109.133, 185.199.110.133, ...
Connecting to objects.githubusercontent.com (objects.githubusercontent.com)|185.199.108.133|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 11382 (11K) [application/octet-stream]
Saving to: ‘64mp_pi_hawk_eye_kernel_driver_links.txt’

64mp_pi_hawk_eye_kernel_driver_links.txt   100%[======================================================================================>]  11.12K  --.-KB/s    in 0.001s

2023-03-21 10:36:26 (15.6 MB/s) - ‘64mp_pi_hawk_eye_kernel_driver_links.txt’ saved [11382/11382]


Cannot find the corresponding package, please send the following information to support@arducam.com
Hardware Revision: d03114
Kernel Version: 6.1.19-v8+
Package: 64mp_pi_hawk_eye_kernel_driver -- bullseye-arm64-v5
You are using an unsupported kernel version, please install the official SD Card image(do not execute rpi-update):
https://www.raspberrypi.com/software/operating-systems/

wim@WimPi4-Dev:~ $ uname -a
Linux WimPi4-Dev 6.1.19-v8+ #1637 SMP PREEMPT Tue Mar 14 11:11:47 GMT 2023 aarch64 GNU/Linux

Today, it didn’t fix the problem. The script reports an unknown kernel version. I noticed that it’s reporting kernel version 6, which seemed unusual to me. That’s when I switched to my other Pi that I have most of my long term stuff running.

wim@WimPi4:~ $ uname -a
Linux WimPi4 5.15.84-v8+ #1613 SMP PREEMPT Thu Jan 5 12:03:08 GMT 2023 aarch64 GNU/Linux

A major bump in kernel version from 5 to 6 was unexpected. Now I’m left with the decision of either waiting to get the 64mp camera working with the new kernel or switching back to one of the PiCamera Model 3 units I have collected recently. Because this is on my development machine, the camera is less important to me than on some of my other units.

I attempted removing the special hooks for arducam to see if the 64mp driver had made it into the standard kernel source tree but no luck with that either.

iMessage: Sent to Email Address

I forwarded a link to a contact via iMessage yesterday and it never got to him, though it gave me a status message I’d never seen before: Sent to Email Address.

iMessage screen capture

I’d last texted this contact three years ago, and the history of that message is a blue bubble. I’ve migrated everything from an iPhone 11 to an iPhone 14 since the original message was sent, so it looks like the history made the assumption it was pure iMessage. The picture I sent this morning went through properly as a text message. The contact information knows his phone number and his email.

I’m traveling in an area where I’m going in and out of cell coverage and may be on WiFi at times, or may be completely disconnected with my phone telling me it’s in S.O.S. Mode.

I wouldn’t have minded iMessage telling me that the message could not be delivered. I wouldn’t mind the message being delivered to his email address. I don’t like being told it was delivered and it not being so.

Enable Raspberry Pi Camera Module 3 Wide after Arducam 64mp

My development pi has had an Arducam 64mp camera connected for my camera software development. I liked the quality of the camera but have at various times been frustrated with the software requirements to use the camera. It’s required both a custom kernel driver and a custom fork of the libcamera software packages. That’s meant that to use the 64mp camera I needed to reinstall the arducam suite after nearly every apt upgrade cycle, and definitely ones where the system kernel got updated.

I spent several days trying to get the remnants of the arducam64mp removed from my development system. I’d even built a fresh sd card image of Raspian Bullseye to make sure that the hardware was all connected and working properly.

In the end the fix was rather simple, if obscure.

First, remove or comment out the dtoverlay line from the /boot/config.txt file and make sure camera auto detect is enabled.

# dtoverlay=arducam-64mp
camera_auto_detect=1

Then run apt install with the –reinstall option for the libcamera packages and the raspberry kernel package.

sudo apt install --reinstall -y libcamera-apps libcamera-dev libcamera0 raspberrypi-kernel
sudo systemctl reboot

Then reboot. That should be then allow you to run libcamera-hello and verify that the new camera is working.

I’d found a reference How To Enable RP Cam V2 After Arducam 64MP that didn’t seem to work for getting the V3 wide camera working, perhaps because the focus hardware in the V3 camera made the 64mp think it was active.

I asked the question of how to remove the drivers on the Arducam Forum and then answered my own question.

On to playing with my new Camera Module 3! (I bought the Arducam cases from Amazon because I really liked the fit. The new wide camera protrudes from the front with enough clearance for the focus to function.)

C++ IPv6 Ping Code Example

My previous code example for IPv4 needed a bunch of modifications to work for an IPv6 address. The thing that took me the longest to figure out was that because IPv6 seems to send a lot more ICMP messages on the local network, I needed to filter the response messages to only the type I was listening for.

bool send_ping6(const std::string& ping_ip, const std::string& HostName4Output, const bool bOutput = false)
{
    bool rval = false;
    if (bOutput)
        std::cout << "[" << getTimeExcelLocal() << "] " << "send_ping6(" << ping_ip << ", " << HostName4Output << ");" << std::endl;
    struct timespec tfs;
    clock_gettime(CLOCK_MONOTONIC, &tfs);
    auto ping_sockfd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
    if (ping_sockfd < 0)
    {
        if (bOutput)
            std::cout << "[" << getTimeExcelLocal() << "] " << "Socket file descriptor not received!!" << std::endl;
    }
    else
    {
        // set socket options at ip to TTL and value to 64,
        // change to what you want by setting ttl_val
        int ttl_val = 64;
        if (setsockopt(ping_sockfd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl_val, sizeof(ttl_val)) != 0)
        {
            if (bOutput)
                std::cerr << "[" << getTimeExcelLocal() << "] " << "Setting socket options to TTL failed!" << std::endl;
        }
        else
        {
            struct icmp6_filter filt;
            ICMP6_FILTER_SETBLOCKALL(&filt);
            ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filt);
            setsockopt(ping_sockfd, IPPROTO_ICMPV6, ICMP6_FILTER, &filt, sizeof(filt));

            // setting timeout of recv setting
            struct timeval tv_out;
            tv_out.tv_sec = RECV_TIMEOUT;
            tv_out.tv_usec = 0;
            setsockopt(ping_sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv_out, sizeof(tv_out));

            int msg_count = 0;
            int flag = 1;
            int msg_received_count = 0;
            // send icmp packet in a loop
            for (auto pingloop = 4; pingloop > 0; pingloop--)
            {
                // flag is whether packet was sent or not
                flag = 1;

                //filling packet
                struct ping_pkt pckt;
                bzero(&pckt, sizeof(pckt));
                for (auto i = 0; i < sizeof(pckt.msg) - 1; i++)
                    pckt.msg[i] = i + '0';
                pckt.msg[sizeof(pckt.msg) - 1] = 0;
                pckt.hdr.type = ICMP6_ECHO_REQUEST;
                pckt.hdr.un.echo.id = getpid();
                pckt.hdr.un.echo.sequence = msg_count++;
                pckt.hdr.checksum = checksum(&pckt, sizeof(pckt));

                usleep(PING_SLEEP_RATE);

                struct timespec time_start;
                clock_gettime(CLOCK_MONOTONIC, &time_start);

                struct sockaddr_in6 ping_addr;
                ping_addr.sin6_family = AF_INET6;
                ping_addr.sin6_port = htons(0);
                inet_pton(AF_INET6, ping_ip.c_str(), &ping_addr.sin6_addr);
                if (sendto(ping_sockfd, &pckt, sizeof(pckt), 0, (struct sockaddr*)&ping_addr, sizeof(ping_addr)) <= 0)
                {
                    if (bOutput)
                        std::cout << "[" << getTimeExcelLocal() << "] " << "Packet Sending Failed!" << std::endl;
                    flag = 0;
                }

                //receive packet
                struct sockaddr_in6 r_addr;
                auto addr_len = sizeof(r_addr);
                if (recvfrom(ping_sockfd, &pckt, sizeof(pckt), 0, (struct sockaddr*)&r_addr, (socklen_t*)&addr_len) <= 0 && msg_count > 1)
                {
                    if (bOutput)
                        std::cout << "[" << getTimeExcelLocal() << "] " << "Packet receive failed!" << std::endl;
                }
                else
                {
                    struct timespec time_end;
                    clock_gettime(CLOCK_MONOTONIC, &time_end);

                    double timeElapsed = ((double)(time_end.tv_nsec - time_start.tv_nsec)) / 1000000.0;
                    long double rtt_msec = (time_end.tv_sec - time_start.tv_sec) * 1000.0 + timeElapsed;

                    // if packet was not sent, don't receive
                    if (flag)
                    {
                        char szAddr[NI_MAXHOST] = { 0 };
                        inet_ntop(AF_INET6, &r_addr.sin6_addr, szAddr, sizeof(szAddr));
                        if (!(pckt.hdr.type == ICMP6_ECHO_REPLY && pckt.hdr.code == 0))
                        {
                            if (bOutput)
                                std::cout << "[" << getTimeExcelLocal() << "] " << "Error..Packet received from (" << szAddr << ") with ICMP type " << int(pckt.hdr.type) << " code " << int(pckt.hdr.code) << std::endl;
                        }
                        else
                        {
                            if (bOutput)
                                std::cout << "[" << getTimeExcelLocal() << "] " << PING_PKT_S << " bytes from (" << szAddr << ") (" << HostName4Output << ") msg_seq=" << msg_count << " ttl=" << "ttl_val" << " rtt= " << rtt_msec << " ms." << std::endl;
                            msg_received_count++;
                        }
                    }
                }
            }
            rval = msg_received_count > 0;
            struct timespec tfe;
            clock_gettime(CLOCK_MONOTONIC, &tfe);
            double timeElapsed = ((double)(tfe.tv_nsec - tfs.tv_nsec)) / 1000000.0;
            long double total_msec = (tfe.tv_sec - tfs.tv_sec) * 1000.0 + timeElapsed;
            if (bOutput)
                std::cout << "[" << getTimeExcelLocal() << "] " << "=== " << ping_ip << " ping statistics === " << msg_count << " packets sent, " << msg_received_count << " packets received, " << ((msg_count - msg_received_count) / msg_count) * 100.0 << " percent packet loss. Total time : " << total_msec << " ms." << std::endl;
        }
        close(ping_sockfd);
    }
    return(rval);
}

Because my calling routine is keeping the addresses for the hosts as strings, I’m calling each of these routines with those strings and converting them to proper addresses inside the function. I’m making a simple choice of whether it’s an IPv4 address or an IPv6 address by the fact that IPv4 addresses have “.” in them and IPv6 addresses have “:”.

bool send_ping(const std::string& ping_ip, const std::string& HostName4Output, const bool bOutput = false)
{
    bool rval = false;
    if (ping_ip.find('.') == std::string::npos)
        rval = send_ping6(ping_ip, HostName4Output, bOutput);
    else 
        rval = send_ping4(ping_ip, HostName4Output, bOutput);
    return(rval);
}

Here’s a bunch of links I found useful while creating this code:

C++ IPv4 Ping Code Example

I’ve written my own monitoring program to keep track of the availability of some of my machines. They register themselves in DNS using dynamic DNS protocols and occasionally change addresses. I realized that while recognizing when the address has changed is useful, I’d also like to know if the machine itself is reachable. Having code that would test the ICMP ping results directly in my code is useful, and this is what I ended up putting together after having found examples in variousl places on the web.

/ Define the Packet Constants
// ping packet size
#define PING_PKT_S 64
#define PING_SLEEP_RATE 1000000

// Gives the timeout delay for receiving packets in seconds
#define RECV_TIMEOUT 1

// ping packet structure
struct ping_pkt
{
    struct icmphdr hdr;
    char msg[PING_PKT_S - sizeof(struct icmphdr)];
};

// Calculating the Check Sum
unsigned short checksum(void* b, int len)
{
    unsigned short* buf = (unsigned short*) b;
    unsigned int sum = 0;

    for (sum = 0; len > 1; len -= 2)
        sum += *buf++;
    if (len == 1)
        sum += *(unsigned char*)buf;
    sum = (sum >> 16) + (sum & 0xFFFF);
    sum += (sum >> 16);
    unsigned short result = ~sum;
    return result;
}

bool send_ping4(const std::string& ping_ip, const std::string& HostName4Output, const bool bOutput = false)
{
    bool rval = false;
    if (bOutput)
        std::cout << "[" << getTimeExcelLocal() << "] " << "send_ping4(" << ping_ip << ", " << HostName4Output << ");" << std::endl;
    struct timespec tfs;
    clock_gettime(CLOCK_MONOTONIC, &tfs);
    auto ping_sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
    if (ping_sockfd < 0)
    {
        if (bOutput)
            std::cout << "[" << getTimeExcelLocal() << "] " << "Socket file descriptor not received!!" << std::endl;
    }
    else
    {
        // set socket options at ip to TTL and value to 64,
        // change to what you want by setting ttl_val
        int ttl_val = 64;
        if (setsockopt(ping_sockfd, SOL_IP, IP_TTL, &ttl_val, sizeof(ttl_val)) != 0)
        {
            if (bOutput)
                std::cout << "[" << getTimeExcelLocal() << "] " << "Setting socket options to TTL failed!" << std::endl;
        }
        else
        {
            // setting timeout of recv setting
            struct timeval tv_out;
            tv_out.tv_sec = RECV_TIMEOUT;
            tv_out.tv_usec = 0;
            setsockopt(ping_sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv_out, sizeof(tv_out));

            int msg_count = 0;
            int flag = 1;
            int msg_received_count = 0;
            // send icmp packet in a loop
            for (auto pingloop = 4; pingloop > 0; pingloop--)
            {
                // flag is whether packet was sent or not
                flag = 1;

                //filling packet
                struct ping_pkt pckt;
                bzero(&pckt, sizeof(pckt));
                for (auto i = 0; i < sizeof(pckt.msg) - 1; i++)
                    pckt.msg[i] = i + '0';
                pckt.msg[sizeof(pckt.msg) - 1] = 0;
                pckt.hdr.type = ICMP_ECHO;
                pckt.hdr.un.echo.id = getpid();
                pckt.hdr.un.echo.sequence = msg_count++;
                pckt.hdr.checksum = checksum(&pckt, sizeof(pckt));

                usleep(PING_SLEEP_RATE);

                struct timespec time_start;
                clock_gettime(CLOCK_MONOTONIC, &time_start);

                struct sockaddr_in ping_addr;
                ping_addr.sin_family = AF_INET;
                ping_addr.sin_port = htons(0);
                inet_pton(AF_INET, ping_ip.c_str(), &ping_addr.sin_addr.s_addr);

                if (sendto(ping_sockfd, &pckt, sizeof(pckt), 0, (struct sockaddr*)&ping_addr, sizeof(ping_addr)) <= 0)
                {
                    if (bOutput)
                        std::cout << "[" << getTimeExcelLocal() << "] " << "Packet Sending Failed!" << std::endl;
                    flag = 0;
                }
                //receive packet
                struct sockaddr_in r_addr;
                auto addr_len = sizeof(r_addr);
                if (recvfrom(ping_sockfd, &pckt, sizeof(pckt), 0, (struct sockaddr*)&r_addr, (socklen_t*)&addr_len) <= 0 && msg_count > 1)
                {
                    if (bOutput)
                        std::cout << "[" << getTimeExcelLocal() << "] " << "Packet receive failed!" << std::endl;
                }
                else
                {
                    struct timespec time_end;
                    clock_gettime(CLOCK_MONOTONIC, &time_end);

                    double timeElapsed = ((double)(time_end.tv_nsec - time_start.tv_nsec)) / 1000000.0;
                    long double rtt_msec = (time_end.tv_sec - time_start.tv_sec) * 1000.0 + timeElapsed;

                    // if packet was not sent, don't receive
                    if (flag)
                    {
                        if (!(pckt.hdr.type == 69 && pckt.hdr.code == 0))
                        {
                            if (bOutput)
                                std::cerr << "[" << getTimeExcelLocal() << "] " << "Error..Packet received with ICMP type " << int(pckt.hdr.type) << " code " << int(pckt.hdr.code) << std::endl;
                        }
                        else
                        {
                            char szAddr[NI_MAXHOST] = { 0 };
                            inet_ntop(AF_INET, &r_addr.sin_addr, szAddr, sizeof(szAddr));
                            if (bOutput)
                                std::cout << "[" << getTimeExcelLocal() << "] " << PING_PKT_S << " bytes from (" << szAddr << ") (" << HostName4Output << ") msg_seq=" << msg_count << " ttl=" << ttl_val << " rtt= " << rtt_msec << " ms." << std::endl;
                            msg_received_count++;
                        }
                    }
                }
            }
            rval = msg_received_count > 0;
            struct timespec tfe;
            clock_gettime(CLOCK_MONOTONIC, &tfe);
            double timeElapsed = ((double)(tfe.tv_nsec - tfs.tv_nsec)) / 1000000.0;
            long double total_msec = (tfe.tv_sec - tfs.tv_sec) * 1000.0 + timeElapsed;
            if (bOutput)
                std::cout << "[" << getTimeExcelLocal() << "] " << "=== " << ping_ip << " ping statistics === " << msg_count << " packets sent, " << msg_received_count << " packets received, " << ((msg_count - msg_received_count) / msg_count) * 100.0 << " percent packet loss. Total time : " << total_msec << " ms." << std::endl;
        }
        close(ping_sockfd);
    }
    return(rval);
}

That works great if my address is an IPv4 address, but I required doing a lot of investigation to get a successful IPv6 address.

Remote Desktop with Hotmail Account

I have been using a Microsoft Account to log into my personal workstation for the past few years because it makes working with OneDrive fairly seamless. The account I use for logging in has an @hotmail.com address. Because I have been using a Microsoft Surface as my primary machine for the past few years, I have also been taking advantage of the Windows Hello capable camera to log in with my face most of the time. I’m now in the process of migrating from a Surface 7 to a Surface 9.

There are always reasons to go back to the old machine and look at some particular setting or program. A Remote Desktop connection from my new machine to the old one is much easier than getting up and walking across the room to the other machine and allows copy and paste directly between machines. Both machines are running the Professional version of Windows so I can enable remote desktop.

I looked at who had access, it shows that my hotmail.com address already has access, as well as my local network account. When I tried to access it from the new machine, it prompted for my password, but rejected it. I repeated this process several times thinking I must be typing it incorrectly before searching for what might be happening.

I came across a solution which is very simple. I don’t understand what it’s doing, but it works. https://answers.microsoft.com/en-us/windows/forum/all/remote-desktop-not-working-with-microsoft-account/71f0c323-688a-4c97-8740-e80eb31ae11d

On the old machine I ran the command runas /u:MicrosoftAccount\MyAccount@hotmail.com winver it prompted me for my password, and then it displayed the standard windows version dialog box. I’m not sure why it worked, but I’m happy that I now can sit at my desk with the large monitor and keyboard and have access to both machines.

runas /u:MicrosoftAccount\MyAccount@hotmail.com winver

Updated: I also came across the same answer using cmd.exe instead of winver.exe as the target of runas, but for some reason it was more difficult for me to understand what was going on. I think it was simply due to the way the email address was obscured in the second one that made it more difficult for me to understand, even though it may have had more screen captures in the demonstration. https://nready.net/remote-desktop-on-windows-11-with-microsoft-account-mfa/

Thanks for the information:

Disk Usage, Raspberry Pi, and MRTG

I’ve used MRTG for many years to keep track of network and disk usage on various platoforms. I like it because it’s easy to set up and doesn’t require a database to be configured or maintained. The simple file structure and image creation means that I can easily have the images synchronized to a central web server even if they are generated on the remote device.

The weekly or monthly views of the disk usage are what I find most useful for recognizing trends of usage. I noticed that last Friday there was a huge jump in usage that I ought to spent a little time discovering what suddenly took over a large chunk of my disk.

sudo du --human-readable --max-depth=2 --one-file-system /

That command gave me a nice list of where the disk usage was allocated. Here’s a small section of the results that looked suspicious.

20G     /var
4.0K    /tmp/ssh-72XFLxsn7URe
8.0K    /tmp/systemd-private-e26b4caee9b7494e847b16a023d67460-systemd-timesyncd.service-Nuv83g
4.0K    /tmp/.Test-unix
8.0K    /tmp/systemd-private-e26b4caee9b7494e847b16a023d67460-systemd-logind.service-xl9zMh
88G     /tmp/mc-wim
4.0K    /tmp/.X11-unix
4.0K    /tmp/.font-unix
4.0K    /tmp/.ICE-unix
156K    /tmp/.qBittorrent
4.0K    /tmp/.XIM-unix
88G     /tmp

The 88G in a single directory under /tmp looks very much like the size bump I got last Friday, and I remember killing a process via a HUP signal directed at Midnight Commander which was trying to open a very large tar file. Deleting that temporary directory recovered the free space properly.

wim@WimPi4:/tmp $ df
Filesystem                             1K-blocks       Used  Available Use% Mounted on
/dev/root                              492885032  235012904  237825328  50% /
devtmpfs                                 1774272          0    1774272   0% /dev
tmpfs                                    1939136          4    1939132   1% /dev/shm
tmpfs                                     775656       2088     773568   1% /run
tmpfs                                       5120          4       5116   1% /run/lock
/dev/mmcblk0p1                            258096      50755     207341  20% /boot
tmpfs                                     387824          0     387824   0% /run/user/1000
tmpfs                                     387824          0     387824   0% /run/user/1002
tmpfs                                     387824          0     387824   0% /run/user/1001
wim@WimPi4:/tmp $ rm -r /tmp/mc-wim/
wim@WimPi4:/tmp $ df
Filesystem                             1K-blocks       Used  Available Use% Mounted on
/dev/root                              492885032  143584828  329253404  31% /
devtmpfs                                 1774272          0    1774272   0% /dev
tmpfs                                    1939136          4    1939132   1% /dev/shm
tmpfs                                     775656       2088     773568   1% /run
tmpfs                                       5120          4       5116   1% /run/lock
/dev/mmcblk0p1                            258096      50755     207341  20% /boot
tmpfs                                     387824          0     387824   0% /run/user/1000
tmpfs                                     387824          0     387824   0% /run/user/1002
tmpfs                                     387824          0     387824   0% /run/user/1001
wim@WimPi4:/tmp $

My MRTG configuration for keeping track of the disk usage on the Raspberry Pi root partition is:

######################################################################
#       Disk Monitoring
######################################################################
Options[_]: printrouter, gauge, noo, nolegend, transparent, pngdate
Factor[_]:
kMG[_]: ,k,M,G,T,P
YLegend[_]: Disk Usage
ShortLegend[_]: &nbsp;Bytes
LegendO[_]: &nbsp;Bytes
LegendI[_]: &nbsp;Bytes

Target[wimpi4_disk]: .1.3.6.1.2.1.25.2.3.1.6.31&.1.3.6.1.2.1.25.2.3.1.5.31:public@wimpi4.local * .1.3.6.1.2.1.25.2.3.1.4.31&.1.3.6.1.2.1.25.2.3.1.4.31:public@wimpi4.local
Title[wimpi4_disk]: Disk Usage -- WimPi4
MaxBytes[wimpi4_disk]: 504720539648

I got the correct size for MaxBytes by looking at the results from snmpwalk. Multiplying the cluster size (1.3.6.1.2.1.25.2.3.1.4.31) by the number of clusters (1.3.6.1.2.1.25.2.3.1.5.31) gets the total size. If I had multiple disks in the same machine that I wanted to monitor I’d be able to find the human readable name for the disk in this same output.

wim@WimPi4:/tmp $ snmpwalk -Os -c public -v 2c localhost 1.3.6.1.2.1.25.2
iso.3.6.1.2.1.25.2.2.0 = INTEGER: 3878272
iso.3.6.1.2.1.25.2.3.1.1.1 = INTEGER: 1
iso.3.6.1.2.1.25.2.3.1.1.3 = INTEGER: 3
iso.3.6.1.2.1.25.2.3.1.1.6 = INTEGER: 6
iso.3.6.1.2.1.25.2.3.1.1.7 = INTEGER: 7
iso.3.6.1.2.1.25.2.3.1.1.8 = INTEGER: 8
iso.3.6.1.2.1.25.2.3.1.1.10 = INTEGER: 10
iso.3.6.1.2.1.25.2.3.1.1.31 = INTEGER: 31
iso.3.6.1.2.1.25.2.3.1.1.37 = INTEGER: 37
iso.3.6.1.2.1.25.2.3.1.1.39 = INTEGER: 39
iso.3.6.1.2.1.25.2.3.1.1.40 = INTEGER: 40
iso.3.6.1.2.1.25.2.3.1.1.66 = INTEGER: 66
iso.3.6.1.2.1.25.2.3.1.1.67 = INTEGER: 67
iso.3.6.1.2.1.25.2.3.1.1.68 = INTEGER: 68
iso.3.6.1.2.1.25.2.3.1.1.72 = INTEGER: 72
iso.3.6.1.2.1.25.2.3.1.2.1 = OID: iso.3.6.1.2.1.25.2.1.2
iso.3.6.1.2.1.25.2.3.1.2.3 = OID: iso.3.6.1.2.1.25.2.1.3
iso.3.6.1.2.1.25.2.3.1.2.6 = OID: iso.3.6.1.2.1.25.2.1.1
iso.3.6.1.2.1.25.2.3.1.2.7 = OID: iso.3.6.1.2.1.25.2.1.1
iso.3.6.1.2.1.25.2.3.1.2.8 = OID: iso.3.6.1.2.1.25.2.1.1
iso.3.6.1.2.1.25.2.3.1.2.10 = OID: iso.3.6.1.2.1.25.2.1.3
iso.3.6.1.2.1.25.2.3.1.2.31 = OID: iso.3.6.1.2.1.25.2.1.4
iso.3.6.1.2.1.25.2.3.1.2.37 = OID: iso.3.6.1.2.1.25.2.1.4
iso.3.6.1.2.1.25.2.3.1.2.39 = OID: iso.3.6.1.2.1.25.2.1.4
iso.3.6.1.2.1.25.2.3.1.2.40 = OID: iso.3.6.1.2.1.25.2.1.4
iso.3.6.1.2.1.25.2.3.1.2.66 = OID: iso.3.6.1.2.1.25.2.1.4
iso.3.6.1.2.1.25.2.3.1.2.67 = OID: iso.3.6.1.2.1.25.2.1.4
iso.3.6.1.2.1.25.2.3.1.2.68 = OID: iso.3.6.1.2.1.25.2.1.4
iso.3.6.1.2.1.25.2.3.1.2.72 = OID: iso.3.6.1.2.1.25.2.1.4
iso.3.6.1.2.1.25.2.3.1.3.1 = STRING: "Physical memory"
iso.3.6.1.2.1.25.2.3.1.3.3 = STRING: "Virtual memory"
iso.3.6.1.2.1.25.2.3.1.3.6 = STRING: "Memory buffers"
iso.3.6.1.2.1.25.2.3.1.3.7 = STRING: "Cached memory"
iso.3.6.1.2.1.25.2.3.1.3.8 = STRING: "Shared memory"
iso.3.6.1.2.1.25.2.3.1.3.10 = STRING: "Swap space"
iso.3.6.1.2.1.25.2.3.1.3.31 = STRING: "/"
iso.3.6.1.2.1.25.2.3.1.3.37 = STRING: "/dev/shm"
iso.3.6.1.2.1.25.2.3.1.3.39 = STRING: "/run"
iso.3.6.1.2.1.25.2.3.1.3.40 = STRING: "/run/lock"
iso.3.6.1.2.1.25.2.3.1.3.66 = STRING: "/boot"
iso.3.6.1.2.1.25.2.3.1.3.67 = STRING: "/run/user/1000"
iso.3.6.1.2.1.25.2.3.1.3.68 = STRING: "/run/user/1001"
iso.3.6.1.2.1.25.2.3.1.3.72 = STRING: "/run/user/1002"
iso.3.6.1.2.1.25.2.3.1.4.1 = INTEGER: 1024
iso.3.6.1.2.1.25.2.3.1.4.3 = INTEGER: 1024
iso.3.6.1.2.1.25.2.3.1.4.6 = INTEGER: 1024
iso.3.6.1.2.1.25.2.3.1.4.7 = INTEGER: 1024
iso.3.6.1.2.1.25.2.3.1.4.8 = INTEGER: 1024
iso.3.6.1.2.1.25.2.3.1.4.10 = INTEGER: 1024
iso.3.6.1.2.1.25.2.3.1.4.31 = INTEGER: 4096
iso.3.6.1.2.1.25.2.3.1.4.37 = INTEGER: 4096
iso.3.6.1.2.1.25.2.3.1.4.39 = INTEGER: 4096
iso.3.6.1.2.1.25.2.3.1.4.40 = INTEGER: 4096
iso.3.6.1.2.1.25.2.3.1.4.66 = INTEGER: 512
iso.3.6.1.2.1.25.2.3.1.4.67 = INTEGER: 4096
iso.3.6.1.2.1.25.2.3.1.4.68 = INTEGER: 4096
iso.3.6.1.2.1.25.2.3.1.4.72 = INTEGER: 4096
iso.3.6.1.2.1.25.2.3.1.5.1 = INTEGER: 3878272
iso.3.6.1.2.1.25.2.3.1.5.3 = INTEGER: 3980668
iso.3.6.1.2.1.25.2.3.1.5.6 = INTEGER: 3878272
iso.3.6.1.2.1.25.2.3.1.5.7 = INTEGER: 2630604
iso.3.6.1.2.1.25.2.3.1.5.8 = INTEGER: 9624
iso.3.6.1.2.1.25.2.3.1.5.10 = INTEGER: 102396
iso.3.6.1.2.1.25.2.3.1.5.31 = INTEGER: 123221258
iso.3.6.1.2.1.25.2.3.1.5.37 = INTEGER: 484784
iso.3.6.1.2.1.25.2.3.1.5.39 = INTEGER: 193914
iso.3.6.1.2.1.25.2.3.1.5.40 = INTEGER: 1280
iso.3.6.1.2.1.25.2.3.1.5.66 = INTEGER: 516191
iso.3.6.1.2.1.25.2.3.1.5.67 = INTEGER: 96956
iso.3.6.1.2.1.25.2.3.1.5.68 = INTEGER: 96956
iso.3.6.1.2.1.25.2.3.1.5.72 = INTEGER: 96956
iso.3.6.1.2.1.25.2.3.1.6.1 = INTEGER: 3712960
iso.3.6.1.2.1.25.2.3.1.6.3 = INTEGER: 3815356
iso.3.6.1.2.1.25.2.3.1.6.6 = INTEGER: 15900
iso.3.6.1.2.1.25.2.3.1.6.7 = INTEGER: 2630604
iso.3.6.1.2.1.25.2.3.1.6.8 = INTEGER: 9624
iso.3.6.1.2.1.25.2.3.1.6.10 = INTEGER: 102396
iso.3.6.1.2.1.25.2.3.1.6.31 = INTEGER: 35973379
iso.3.6.1.2.1.25.2.3.1.6.37 = INTEGER: 1
iso.3.6.1.2.1.25.2.3.1.6.39 = INTEGER: 592
iso.3.6.1.2.1.25.2.3.1.6.40 = INTEGER: 1
iso.3.6.1.2.1.25.2.3.1.6.66 = INTEGER: 101509
iso.3.6.1.2.1.25.2.3.1.6.67 = INTEGER: 0
iso.3.6.1.2.1.25.2.3.1.6.68 = INTEGER: 0
iso.3.6.1.2.1.25.2.3.1.6.72 = INTEGER: 0
wim@WimPi4:/tmp $

Moving Visual Studio Cross Platform Development to a new Machine

I upgraded my workstation for the holidays and needed to get things moved over as easily as possible.

In Visual Studio, under the tools menu, there’s an option to be able to Import and Export Settings… which got me an output file that made my new installation look mostly like my old installation.

What it didn’t transfer was the details of my connections to my Raspberry Pi devices. The following image is after I managed to get a working connection. It didn’t have anything displayed under Default Host Name etc.

I’d already run ssh-keygen on my new machine, creating a default security key on the local machine. I’d already connected via ssh to each of the hosts I regularly work on and imported the public key into the authorized_keys file and verified all appeared working.

After entering all of the details in the dialog box I got a rather unhelpful set of red boxes indicating that something had gone wrong. (192.168.0.66 and 192.168.0.67 are the same host, wired and Wi-Fi, on my local network, and I may use them interchangeably for images and text here)

Searching on the web I found that there is a console program that will configure the same thing, and I assumed correctly that I might get more descriptive error messages using the console than I was getting here. https://learn.microsoft.com/en-us/cpp/linux/connectionmanager-reference?view=msvc-170

**********************************************************************
** Visual Studio 2022 Developer Command Prompt v17.4.2
** Copyright (c) 2022 Microsoft Corporation
**********************************************************************

C:\Program Files\Microsoft Visual Studio\2022\Enterprise>ConnectionManager.exe add visualstudio@192.168.0.66 --privatekey C:\Users\Wim\.ssh\id_rsa
Enter password (leave blank for no password):
Verifying connection with remote system.
Failed to add connection: Private key is invalid or is encrypted and no passphrase was given

I knew that the keys were good because I was using them to connect via SSH. I did some digging and realized that the physical file sizes on the new machine are larger than on the old machine. Looking at the length of the public keys themselves, I realized that my old keys were 2048 bits long, and the newly generated ones are 3072. I tried explicitly generating a new 2048 bit key with the command ssh-keygen -f id_rsa_2048 -b 2048 and using it, but I got similar results to what I was getting before. Finally, I copied my public and private key from the old machine and renamed them specifically for this usage on this machine.

C:\Program Files\Microsoft Visual Studio\2022\Enterprise>ConnectionManager.exe add visualstudio@192.168.0.66 --privatekey C:\Users\Wim\.ssh\id_rsa_visualstudio
Enter password (leave blank for no password):
Verifying connection with remote system.
The authenticity of host '192.168.0.66' can't be established.
ecdsa-sha2-nistp256 key fingerprint is SHA256:DGa1mVbMm3voQwVwtg06xHkANgs04zST9RP8CMfSoXY.
Are you sure you want to continue connecting (yes/no)? yes
Successfully added connection '1748855142;192.168.0.66 (username=visualstudio, port=22, authentication=PrivateKey)'.

That created the connection properly in Visual Studio. I went back into the Visual Studio interface, Tools->Options->Cross Platform->Connection Manager->Remote Headers Intellisense Manager and updated the headers and everything appears to be working now.

I don’t know why the keys I generated using the software on my new machine didn’t work, even when I specified the same number of bits.