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.

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.

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.

IPv6 and Google Fi on SIM7600G-H and Raspberry Pi

I have been playing with a Raspberry Pi in a remote location that should be connected to a cellular network but I’ve had problems keeping it responding. I duplicated the system in my apartment to spend more time learning about what my options in configuring it may be. I’ve talked about the platform previously https://wimsworld.wordpress.com/2022/07/12/lte-wireless-on-sim7600g-h-4g-hat-b-for-raspberry-pi/ and https://wimsworld.wordpress.com/2022/07/16/more-networking-with-sim7600g-h-4g-hat-b-for-raspberry-pi/

The modem can be configured significantly differently via the CUSBPIDSWITCH command. According to the documentation, the available PIDS are:

  • 9000:Diag, NMEA, At, Modem, Audio, Rmnet
  • 9001:Diag, NMEA, At, Modem, Audio, Rmnet
  • 9002:Diag, NMEA, At, Modem, Audio, Rmnet
  • 9003:Diag, NMEA, At, Modem, Audio, MBIM
  • 9004:Diag, NMEA, At, Modem, Audio, GNSS, Rmnet
  • 9005:Diag, NMEA, At, Modem, Audio, GNSS, MBIM
  • 9006:Diag, NMEA, At,Modem
  • 9007:Diag, NMEA, At, Modem, Audio, Rmnet,mass_storage
  • 9011:RNDIS,Diag, NMEA, At, Modem, Audio
  • 9016:Diag, Rmnet
  • 9018:Diag, NMEA, At, Modem, Audio, Ecm
  • 9019:RNDIS
  • 901A: Diag, NMEA, At, Rmnet
  • 901B:NMEA, At, Rmnet
  • 9020: Diag, At, Modem
  • 9021: Diag, Modem
  • 9022: Diag, Modem, Rmnet
  • 9023: Modem
  • 9024: At, Modem
  • 9025: Modem,rmnet
  • 9026: Modem,Audio
  • 9027: Modem,Audio, Rmnet
  • 9028:Diag, Modem,Audio, Rmnet
  • 9029:Diag, Modem,Audio
  • 902A: At
  • 902B: Diag, NMEA, At, Modem, Rmnet,Usb-audio

If I query the modem possible modes, it responds with

AT+CUSBPIDSWITCH=?
+CUSBPIDSWITCH: (9000,9001,9002,9003,9004,9005,9006,9007,9011,9016,9018,9019,901A,901B,9020,9021,9022,9023,9024,9025,9026,9027,9028,9029,902A,902B),(0-1),(0-1)

OK

I’ve figured out I can switch between three different modem configurations on the linux system safely. 9001, 9011, and 9003. 9001 gives me qmi_wwan, 9011 gives me rndis_host, and 9003 give me cdc_mbim. RNDIS is the only one that is really plug and play on linux and produces the usb0 interface instead of wwan0. The method I’ve been configuring the device has been to connect to /dev/ttyUSB2 and issuing AT commands. When I have tried PID modes other than the ones I’ve called safe, Linux doesn’t provide /dev/ttyUSB* ports even though the device interfaces are displayed in the lsusb -t output.

Here’s what I get when I issue the command

AT+CUSBPIDSWITCH=9001,1,1

wim@WimPiZeroW-Wim:~ $ lsusb
Bus 001 Device 003: ID 1e0e:9001 Qualcomm / Option SimTech, Incorporated
Bus 001 Device 002: ID 1a40:0101 Terminus Technology Inc. Hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
wim@WimPiZeroW-Wim:~ $ lsusb -t
/:  Bus 01.Port 1: Dev 1, Class=root_hub, Driver=dwc_otg/1p, 480M
    |__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/4p, 480M
        |__ Port 1: Dev 3, If 0, Class=Vendor Specific Class, Driver=option, 480M
        |__ Port 1: Dev 3, If 1, Class=Vendor Specific Class, Driver=option, 480M
        |__ Port 1: Dev 3, If 2, Class=Vendor Specific Class, Driver=option, 480M
        |__ Port 1: Dev 3, If 3, Class=Vendor Specific Class, Driver=option, 480M
        |__ Port 1: Dev 3, If 4, Class=Vendor Specific Class, Driver=option, 480M
        |__ Port 1: Dev 3, If 5, Class=Vendor Specific Class, Driver=qmi_wwan, 480M
wim@WimPiZeroW-Wim:~ $ ip -o a
1: lo    inet 127.0.0.1/8 scope host lo\       valid_lft forever preferred_lft forever
1: lo    inet6 ::1/128 scope host \       valid_lft forever preferred_lft forever
2: wwan0    inet 169.254.128.15/16 brd 169.254.255.255 scope global noprefixroute wwan0\       valid_lft forever preferred_lft forever
2: wwan0    inet6 fe80::f9:71:4f35:8ef4/64 scope link \       valid_lft forever preferred_lft forever
3: wlan0    inet 192.168.0.63/24 brd 192.168.0.255 scope global dynamic noprefixroute wlan0\       valid_lft 5335sec preferred_lft 4660sec
3: wlan0    inet6 2604:4080:1304:8010:57c0:7b33:ef3:3f35/64 scope global dynamic mngtmpaddr noprefixroute \       valid_lft 1766sec preferred_lft 1766sec
3: wlan0    inet6 fe80::2f9e:ceef:76a0:1efa/64 scope link \       valid_lft forever preferred_lft forever

AT+CUSBPIDSWITCH=9011,1,1

wim@WimPiZeroW-Wim:~ $ lsusb
Bus 001 Device 003: ID 1e0e:9011 Qualcomm / Option SimTech, Incorporated
Bus 001 Device 002: ID 1a40:0101 Terminus Technology Inc. Hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
wim@WimPiZeroW-Wim:~ $ lsusb -t
/:  Bus 01.Port 1: Dev 1, Class=root_hub, Driver=dwc_otg/1p, 480M
    |__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/4p, 480M
        |__ Port 1: Dev 3, If 0, Class=Communications, Driver=rndis_host, 480M
        |__ Port 1: Dev 3, If 1, Class=CDC Data, Driver=rndis_host, 480M
        |__ Port 1: Dev 3, If 2, Class=Vendor Specific Class, Driver=option, 480M
        |__ Port 1: Dev 3, If 3, Class=Vendor Specific Class, Driver=option, 480M
        |__ Port 1: Dev 3, If 4, Class=Vendor Specific Class, Driver=option, 480M
        |__ Port 1: Dev 3, If 5, Class=Vendor Specific Class, Driver=option, 480M
        |__ Port 1: Dev 3, If 6, Class=Vendor Specific Class, Driver=option, 480M
wim@WimPiZeroW-Wim:~ $ ip -o a
1: lo    inet 127.0.0.1/8 scope host lo\       valid_lft forever preferred_lft forever
1: lo    inet6 ::1/128 scope host \       valid_lft forever preferred_lft forever
2: wlan0    inet 192.168.0.63/24 brd 192.168.0.255 scope global dynamic noprefixroute wlan0\       valid_lft 5371sec preferred_lft 4696sec
2: wlan0    inet6 2604:4080:1304:8010:57c0:7b33:ef3:3f35/64 scope global dynamic mngtmpaddr noprefixroute \       valid_lft 1767sec preferred_lft 1767sec
2: wlan0    inet6 fe80::2f9e:ceef:76a0:1efa/64 scope link \       valid_lft forever preferred_lft forever
3: usb0    inet 192.168.225.59/24 brd 192.168.225.255 scope global dynamic noprefixroute usb0\       valid_lft 43172sec preferred_lft 37772sec
3: usb0    inet6 2607:fb90:8069:ec7e:4a34:bb42:93a9:e27d/64 scope global mngtmpaddr noprefixroute \       valid_lft forever preferred_lft forever
3: usb0    inet6 fe80::b8ef:f02b:c580:1ebc/64 scope link \       valid_lft forever preferred_lft forever

AT+CUSBPIDSWITCH=9003,1,1

wim@WimPiZeroW-Wim:~ $ lsusb
Bus 001 Device 003: ID 1e0e:9003 Qualcomm / Option SimTech, Incorporated
Bus 001 Device 002: ID 1a40:0101 Terminus Technology Inc. Hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
wim@WimPiZeroW-Wim:~ $ lsusb -t
/:  Bus 01.Port 1: Dev 1, Class=root_hub, Driver=dwc_otg/1p, 480M
    |__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/4p, 480M
        |__ Port 1: Dev 3, If 0, Class=Vendor Specific Class, Driver=option, 480M
        |__ Port 1: Dev 3, If 1, Class=Vendor Specific Class, Driver=option, 480M
        |__ Port 1: Dev 3, If 2, Class=Vendor Specific Class, Driver=option, 480M
        |__ Port 1: Dev 3, If 3, Class=Vendor Specific Class, Driver=option, 480M
        |__ Port 1: Dev 3, If 4, Class=Vendor Specific Class, Driver=option, 480M
        |__ Port 1: Dev 3, If 5, Class=Communications, Driver=cdc_mbim, 480M
        |__ Port 1: Dev 3, If 6, Class=CDC Data, Driver=cdc_mbim, 480M
wim@WimPiZeroW-Wim:~ $ ip -o a
1: lo    inet 127.0.0.1/8 scope host lo\       valid_lft forever preferred_lft forever
1: lo    inet6 ::1/128 scope host \       valid_lft forever preferred_lft forever
2: wwan0    inet 169.254.175.62/16 brd 169.254.255.255 scope global noprefixroute wwan0\       valid_lft forever preferred_lft forever
2: wwan0    inet6 fe80::b43f:d4a3:f985:4f33/64 scope link \       valid_lft forever preferred_lft forever
3: wlan0    inet 192.168.0.63/24 brd 192.168.0.255 scope global dynamic noprefixroute wlan0\       valid_lft 5341sec preferred_lft 4666sec
3: wlan0    inet6 2604:4080:1304:8010:57c0:7b33:ef3:3f35/64 scope global dynamic mngtmpaddr noprefixroute \       valid_lft 1764sec preferred_lft 1764sec
3: wlan0    inet6 fe80::2f9e:ceef:76a0:1efa/64 scope link \       valid_lft forever preferred_lft forever

I have configured the modem to run the way I want with the following commands

AT&F
AT+CUSBPIDSWITCH=9011,1,1
AT+CGDCONT=1,"IPV4V6","h2g2"
AT+CGDCONT=6,"IPV4V6","h2g2"
AT+CGPSAUTO=1

There are multiple things I’m trying to understand about networking while running in 9011 mode. It gets a global scope ipv6 address that is reachable, but that address changes on a very frequent but random time. It gets a local ipv4 address that works for traffic over the internet. Obviously the ipv4 address is being converted by NAT between the raspberry and the internet. I don’t seem to have any way of configuring how that works. The post https://www.jeffgeerling.com/blog/2022/using-4g-lte-wireless-modems-on-raspberry-pi had a Built-in AP configuration that was accessible via http. I have run nmap against the internal gateway on my platform and the only port open is DNS.

Today I ran radvdump to listen for router advertisements from the internet and then later looked at my syslog results to see what happened on the network at the corresponding times.

# radvd configuration generated by radvdump 2.18
# based on Router Advertisement from fe80::fca7:efa4:eef4:655b
# received by interface usb0
#

interface usb0
{
        AdvSendAdvert on;
        # Note: {Min,Max}RtrAdvInterval cannot be obtained with radvdump
        AdvManagedFlag off;
        AdvOtherConfigFlag off;
        AdvReachableTime 0;
        AdvRetransTimer 0;
        AdvCurHopLimit 255;
        AdvDefaultLifetime 0;
        AdvHomeAgentFlag off;
        AdvDefaultPreference medium;
        AdvSourceLLAddress on;
        AdvLinkMTU 1500;

        prefix 2607:fb90:80ca:7753::ff00:0/0
        {
                AdvValidLifetime 2;
                AdvPreferredLifetime 1;
                AdvOnLink on;
                AdvAutonomous on;
                AdvRouterAddr off;
        }; # End of prefix definition

}; # End of interface definition


Nov 11 16:11:32 WimPiZeroW-Wim dhcpcd[701]: usb0: Router Advertisement from fe80::fca7:efa4:eef4:655b
Nov 11 16:11:32 WimPiZeroW-Wim dhcpcd[701]: usb0: adding address 5c5a:870:6182:d190:617e:1551:4cea:f6b6/0
Nov 11 16:11:32 WimPiZeroW-Wim dhcpcd[701]: ipv6_addaddr1: Invalid argument
Nov 11 16:11:32 WimPiZeroW-Wim dhcpcd[701]: usb0: adding route to 2607:fb90:80ca:7753::ff00:0/0
Nov 11 16:11:32 WimPiZeroW-Wim dhcpcd[701]: if_route (ADD): File exists

Almost immediately afterwards:

#
# radvd configuration generated by radvdump 2.18
# based on Router Advertisement from fe80::fc89:6dff:fe67:6dde
# received by interface usb0
#

interface usb0
{
        AdvSendAdvert on;
        # Note: {Min,Max}RtrAdvInterval cannot be obtained with radvdump
        AdvManagedFlag off;
        AdvOtherConfigFlag off;
        AdvReachableTime 0;
        AdvRetransTimer 0;
        AdvCurHopLimit 64;
        AdvDefaultLifetime 0;
        AdvHomeAgentFlag off;
        AdvDefaultPreference medium;
        AdvLinkMTU 1500;

        prefix 2607:fb90:80ca:7753::/64
        {
                AdvValidLifetime 2;
                AdvPreferredLifetime 1;
                AdvOnLink on;
                AdvAutonomous on;
                AdvRouterAddr off;
        }; # End of prefix definition


        RDNSS fd00:976a::9 fd00:976a::10
        {
                AdvRDNSSLifetime infinity; # (0xffffffff)
        }; # End of RDNSS definition

}; # End of interface definition

Nov 11 16:11:33 WimPiZeroW-Wim dhcpcd[701]: usb0: Router Advertisement from fe80::fc89:6dff:fe67:6dde
Nov 11 16:11:33 WimPiZeroW-Wim dhcpcd[701]: usb0: fe80::fc89:6dff:fe67:6dde: no longer a default router
Nov 11 16:11:33 WimPiZeroW-Wim dhcpcd[701]: usb0: adding route to 2607:fb90:80ca:7753::ff00:0/0
Nov 11 16:11:33 WimPiZeroW-Wim dhcpcd[701]: if_route (ADD): File exists
Nov 11 16:11:33 WimPiZeroW-Wim dhcpcd[701]: usb0: deleting default route via fe80::fc89:6dff:fe67:6dde
Nov 11 16:11:34 WimPiZeroW-Wim dhcpcd[701]: usb0: part of Router Advertisement expired
Nov 11 16:11:34 WimPiZeroW-Wim avahi-daemon[240]: Registering new address record for fe80::a3b3:ec14:47de:4692 on usb0.*.
Nov 11 16:11:35 WimPiZeroW-Wim dhcpcd[701]: usb0: expired address 2607:fb90:80ca:7753:ee71:7d12:766:2e98/64
Nov 11 16:11:35 WimPiZeroW-Wim dhcpcd[701]: usb0: part of Router Advertisement expired
Nov 11 16:11:35 WimPiZeroW-Wim dhcpcd[701]: usb0: deleting route to 2607:fb90:80ca:7753::/64
Nov 11 16:11:35 WimPiZeroW-Wim avahi-daemon[240]: Withdrawing address record for 2607:fb90:80ca:7753:ee71:7d12:766:2e98 on usb0.
Nov 11 16:11:35 WimPiZeroW-Wim avahi-daemon[240]: Leaving mDNS multicast group on interface usb0.IPv6 with address 2607:fb90:80ca:7753:ee71:7d12:766:2e98.
Nov 11 16:11:35 WimPiZeroW-Wim avahi-daemon[240]: Joining mDNS multicast group on interface usb0.IPv6 with address fe80::a3b3:ec14:47de:4692.

And a couple of minutes later:

# radvd configuration generated by radvdump 2.18
# based on Router Advertisement from fe80::fc89:6dff:fe67:6dde
# received by interface usb0
#

interface usb0
{
        AdvSendAdvert on;
        # Note: {Min,Max}RtrAdvInterval cannot be obtained with radvdump
        AdvManagedFlag off;
        AdvOtherConfigFlag on;
        AdvReachableTime 0;
        AdvRetransTimer 0;
        AdvCurHopLimit 64;
        AdvDefaultLifetime 65535;
        AdvHomeAgentFlag off;
        AdvDefaultPreference medium;
        AdvLinkMTU 1500;

        prefix 2607:fb90:80c8:82f8::/64
        {
                AdvValidLifetime infinity; # (0xffffffff)
                AdvPreferredLifetime infinity; # (0xffffffff)
                AdvOnLink on;
                AdvAutonomous on;
                AdvRouterAddr off;
        }; # End of prefix definition


        RDNSS fd00:976a::9 fd00:976a::10
        {
                AdvRDNSSLifetime infinity; # (0xffffffff)
        }; # End of RDNSS definition

}; # End of interface definition

Nov 11 16:13:42 WimPiZeroW-Wim dhcpcd[701]: usb0: Router Advertisement from fe80::fc89:6dff:fe67:6dde
Nov 11 16:13:42 WimPiZeroW-Wim dhcpcd[701]: usb0: adding address 2607:fb90:80c8:82f8:b87a:2c7a:ae2e:7e0e/64
Nov 11 16:13:42 WimPiZeroW-Wim avahi-daemon[240]: Leaving mDNS multicast group on interface usb0.IPv6 with address fe80::a3b3:ec14:47de:4692.
Nov 11 16:13:43 WimPiZeroW-Wim avahi-daemon[240]: Joining mDNS multicast group on interface usb0.IPv6 with address 2607:fb90:80c8:82f8:b87a:2c7a:ae2e:7e0e.
Nov 11 16:13:43 WimPiZeroW-Wim avahi-daemon[240]: Registering new address record for 2607:fb90:80c8:82f8:b87a:2c7a:ae2e:7e0e on usb0.*.
Nov 11 16:13:43 WimPiZeroW-Wim avahi-daemon[240]: Withdrawing address record for fe80::a3b3:ec14:47de:4692 on usb0.
Nov 11 16:13:43 WimPiZeroW-Wim dhcpcd[701]: usb0: adding route to 2607:fb90:80c8:82f8::/64
Nov 11 16:13:43 WimPiZeroW-Wim dhcpcd[701]: usb0: adding default route via fe80::fc89:6dff:fe67:6dde

Then it went almost a couple of hours before more changes to the network

Nov 11 18:01:54 WimPiZeroW-Wim dhcpcd[701]: usb0: Router Advertisement from fe80::c1e7:222d:69eb:c90c
Nov 11 18:01:54 WimPiZeroW-Wim dhcpcd[701]: usb0: adding address 5c5a:870:6182:d190:617e:1551:4cea:f6b6/0
Nov 11 18:01:54 WimPiZeroW-Wim dhcpcd[701]: ipv6_addaddr1: Invalid argument
Nov 11 18:01:54 WimPiZeroW-Wim dhcpcd[701]: usb0: adding route to 2607:fb90:80c8:82f8::ff00:0/0
Nov 11 18:01:54 WimPiZeroW-Wim dhcpcd[701]: if_route (ADD): File exists
Nov 11 18:01:55 WimPiZeroW-Wim dhcpcd[701]: usb0: Router Advertisement from fe80::fc89:6dff:fe67:6dde
Nov 11 18:01:55 WimPiZeroW-Wim dhcpcd[701]: usb0: fe80::fc89:6dff:fe67:6dde: no longer a default router
Nov 11 18:01:55 WimPiZeroW-Wim dhcpcd[701]: usb0: adding route to 2607:fb90:80c8:82f8::ff00:0/0
Nov 11 18:01:55 WimPiZeroW-Wim dhcpcd[701]: if_route (ADD): File exists
Nov 11 18:01:55 WimPiZeroW-Wim dhcpcd[701]: usb0: deleting default route via fe80::fc89:6dff:fe67:6dde
Nov 11 18:01:56 WimPiZeroW-Wim dhcpcd[701]: usb0: part of Router Advertisement expired
Nov 11 18:01:56 WimPiZeroW-Wim avahi-daemon[240]: Registering new address record for fe80::a3b3:ec14:47de:4692 on usb0.*.
Nov 11 18:01:57 WimPiZeroW-Wim dhcpcd[701]: usb0: expired address 2607:fb90:80c8:82f8:b87a:2c7a:ae2e:7e0e/64
Nov 11 18:01:57 WimPiZeroW-Wim dhcpcd[701]: usb0: part of Router Advertisement expired
Nov 11 18:01:57 WimPiZeroW-Wim dhcpcd[701]: usb0: deleting route to 2607:fb90:80c8:82f8::/64
Nov 11 18:01:57 WimPiZeroW-Wim avahi-daemon[240]: Withdrawing address record for 2607:fb90:80c8:82f8:b87a:2c7a:ae2e:7e0e on usb0.
Nov 11 18:01:57 WimPiZeroW-Wim avahi-daemon[240]: Leaving mDNS multicast group on interface usb0.IPv6 with address 2607:fb90:80c8:82f8:b87a:2c7a:ae2e:7e0e.
Nov 11 18:01:57 WimPiZeroW-Wim avahi-daemon[240]: Joining mDNS multicast group on interface usb0.IPv6 with address fe80::a3b3:ec14:47de:4692.
Nov 11 18:04:04 WimPiZeroW-Wim dhcpcd[701]: usb0: Router Advertisement from fe80::fc89:6dff:fe67:6dde
Nov 11 18:04:04 WimPiZeroW-Wim dhcpcd[701]: usb0: adding address 2607:fb90:80c3:42cc:11b:d753:e52a:40bb/64
Nov 11 18:04:04 WimPiZeroW-Wim avahi-daemon[240]: Leaving mDNS multicast group on interface usb0.IPv6 with address fe80::a3b3:ec14:47de:4692.
Nov 11 18:04:04 WimPiZeroW-Wim avahi-daemon[240]: Joining mDNS multicast group on interface usb0.IPv6 with address 2607:fb90:80c3:42cc:11b:d753:e52a:40bb.
Nov 11 18:04:04 WimPiZeroW-Wim avahi-daemon[240]: Registering new address record for 2607:fb90:80c3:42cc:11b:d753:e52a:40bb on usb0.*.
Nov 11 18:04:04 WimPiZeroW-Wim avahi-daemon[240]: Withdrawing address record for fe80::a3b3:ec14:47de:4692 on usb0.
Nov 11 18:04:04 WimPiZeroW-Wim dhcpcd[701]: usb0: adding route to 2607:fb90:80c3:42cc::/64
Nov 11 18:04:04 WimPiZeroW-Wim dhcpcd[701]: usb0: adding default route via fe80::fc89:6dff:fe67:6dde
Nov 11 18:29:11 WimPiZeroW-Wim dhcpcd[701]: usb0: failed to renew DHCP, rebinding
Nov 11 18:29:11 WimPiZeroW-Wim dhcpcd[701]: usb0: adding route to 192.168.225.0/24
Nov 11 18:29:11 WimPiZeroW-Wim dhcpcd[701]: usb0: adding default route via 192.168.225.1
ov 11 19:52:16 WimPiZeroW-Wim dhcpcd[701]: usb0: Router Advertisement from fe80::459a:7427:b0ae:7848
Nov 11 19:52:16 WimPiZeroW-Wim dhcpcd[701]: usb0: adding address 5c5a:870:6182:d190:617e:1551:4cea:f6b6/0
Nov 11 19:52:16 WimPiZeroW-Wim dhcpcd[701]: ipv6_addaddr1: Invalid argument
Nov 11 19:52:16 WimPiZeroW-Wim dhcpcd[701]: usb0: adding route to 2607:fb90:80c3:42cc::ff00:0/0
Nov 11 19:52:16 WimPiZeroW-Wim dhcpcd[701]: if_route (ADD): File exists
Nov 11 19:52:18 WimPiZeroW-Wim dhcpcd[701]: usb0: Router Advertisement from fe80::fc89:6dff:fe67:6dde
Nov 11 19:52:18 WimPiZeroW-Wim dhcpcd[701]: usb0: fe80::fc89:6dff:fe67:6dde: no longer a default router
Nov 11 19:52:18 WimPiZeroW-Wim dhcpcd[701]: usb0: adding route to 2607:fb90:80c3:42cc::ff00:0/0
Nov 11 19:52:18 WimPiZeroW-Wim dhcpcd[701]: if_route (ADD): File exists
Nov 11 19:52:18 WimPiZeroW-Wim dhcpcd[701]: usb0: deleting default route via fe80::fc89:6dff:fe67:6dde
Nov 11 19:52:18 WimPiZeroW-Wim dhcpcd[701]: usb0: part of Router Advertisement expired
Nov 11 19:52:19 WimPiZeroW-Wim avahi-daemon[240]: Registering new address record for fe80::a3b3:ec14:47de:4692 on usb0.*.
Nov 11 19:52:20 WimPiZeroW-Wim dhcpcd[701]: usb0: expired address 2607:fb90:80c3:42cc:11b:d753:e52a:40bb/64
Nov 11 19:52:20 WimPiZeroW-Wim dhcpcd[701]: usb0: part of Router Advertisement expired
Nov 11 19:52:20 WimPiZeroW-Wim dhcpcd[701]: usb0: deleting route to 2607:fb90:80c3:42cc::/64
Nov 11 19:52:20 WimPiZeroW-Wim avahi-daemon[240]: Withdrawing address record for 2607:fb90:80c3:42cc:11b:d753:e52a:40bb on usb0.
Nov 11 19:52:20 WimPiZeroW-Wim avahi-daemon[240]: Leaving mDNS multicast group on interface usb0.IPv6 with address 2607:fb90:80c3:42cc:11b:d753:e52a:40bb.
Nov 11 19:52:20 WimPiZeroW-Wim avahi-daemon[240]: Joining mDNS multicast group on interface usb0.IPv6 with address fe80::a3b3:ec14:47de:4692.
Nov 11 19:52:27 WimPiZeroW-Wim systemd[1]: session-3.scope: Succeeded.
Nov 11 19:52:27 WimPiZeroW-Wim systemd[1]: session-3.scope: Consumed 24.275s CPU time.
Nov 11 19:54:27 WimPiZeroW-Wim dhcpcd[701]: usb0: Router Advertisement from fe80::fc89:6dff:fe67:6dde
Nov 11 19:54:27 WimPiZeroW-Wim dhcpcd[701]: usb0: adding address 2607:fb90:8069:47ff:69ad:1e37:6fb5:7fa0/64
Nov 11 19:54:27 WimPiZeroW-Wim dhcpcd[701]: usb0: adding route to 2607:fb90:8069:47ff::/64
Nov 11 19:54:27 WimPiZeroW-Wim dhcpcd[701]: usb0: adding default route via fe80::fc89:6dff:fe67:6dde
Nov 11 19:54:27 WimPiZeroW-Wim avahi-daemon[240]: Leaving mDNS multicast group on interface usb0.IPv6 with address fe80::a3b3:ec14:47de:4692.
Nov 11 19:54:27 WimPiZeroW-Wim avahi-daemon[240]: Joining mDNS multicast group on interface usb0.IPv6 with address 2607:fb90:8069:47ff:69ad:1e37:6fb5:7fa0.
Nov 11 19:54:27 WimPiZeroW-Wim avahi-daemon[240]: Registering new address record for 2607:fb90:8069:47ff:69ad:1e37:6fb5:7fa0 on usb0.*.
Nov 11 19:54:27 WimPiZeroW-Wim avahi-daemon[240]: Withdrawing address record for fe80::a3b3:ec14:47de:4692 on usb0.

I do not understand why it gets router advertisements that change as frequently as it does, and especially why sometimes it gets a /0 prefix occasionally.

Here is a series of commands I’ve found useful to checking status on the modem

AT&V
AT+COPS?
AT+CPSI?
AT+CFUN?
AT+CGPSAUTO?
AT+CSQ
AT+CUSBPIDSWITCH=?
AT+CUSBPIDSWITCH?
AT+CGDCONT?

The command AT+CSQ returns the signal strength of the device. Possible values are:

  • 0 113 dBm or less
  • 1 111 dBm
  • 2…30 109… 53 dBm
  • 31 51 dBm or greater
  • 99 not known or not detectable

Value RSSI dBm Condition

  • 2 -109 Marginal
  • 3 -107 Marginal
  • 4 -105 Marginal
  • 5 -103 Marginal
  • 6 -101 Marginal
  • 7 -99 Marginal
  • 8 -97 Marginal
  • 9 -95 Marginal
  • 10 -93 OK
  • 11 -91 OK
  • 12 -89 OK
  • 13 -87 OK
  • 14 -85 OK
  • 15 -83 Good
  • 16 -81 Good
  • 17 -79 Good
  • 18 -77 Good
  • 19 -75 Good
  • 20 -73 Excellent
  • 21 -71 Excellent
  • 22 -69 Excellent
  • 23 -67 Excellent
  • 24 -65 Excellent
  • 25 -63 Excellent
  • 26 -61 Excellent
  • 27 -59 Excellent
  • 28 -57 Excellent
  • 29 -55 Excellent
  • 30 -53 Excellent

Some of the values on my system

AT&V
&C: 2; &D: 2; &E: 1; &F: 0; &S: 0; &W: 0; E: 1; L: 0; M: 0; Q: 0; V: 1;
X: 1; Z: 0; \Q: 3; \S: 0; \V: 0; O: 0; S0: 0; S2: 43; S3: 13; S4: 10;
S5: 8; S6: 2; S7: 0; S8: 2; S9: 6; S10: 14; S11: 95; S30: 0; S103: 1;
S104: 1; +FCLASS: 0; +ICF: 3,3; +IFC: 0,0; +IPR: 115200; +DR: 0;
+DS: 0,0,2048,6; +CMEE: 2; +WS46: 25; +CFUN:; +IPREX: 115200;
+CBST: 0,0,1; +CRLP: (61,61,48,6,0),(61,61,48,6,1),(240,240,52,6,2);
+CV120: 1,1,1,0,0,0; +CHSN: 0,0,0,0; +CSSN: 0,0; +CREG: 0; +CGREG: 0;
+CEREG: 0; +CSCS: "IRA"; +CSTA: 129;  +CR: 0; +CRC: 0;
+CGDCONT: (1,"IPV4V6","h2g2","0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0",0,0,0,0),(2,"IPV4V6","","0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0",0,0,0,0),(3,"IPV4V6","","0.0.0.0.0.0.0;
+CGDSCONT: ; +CGTFT: ; +CGEQREQ: ; +CGEQMIN: ; +CGEQOS: ; +CGQREQ: ;
+CGQMIN: ; +CGEREP: 0,0; +CGDATA: "PPP"; +CGCLASS: "A";  +CGPIAF: 0,0,0,0;
+CGSMS: 1; +CSMS: 0; +CMGF: 0; +CSAS: 0; +CRES: 0; +CSCA: "",;
+CSMP: ,,0,0; +CSDH: 0; +CSCB: 0,"",""; +CMGP: 4098,0,,0,; +ES: ,,;
+ESA: 0,,,,0,0,255,; +CMOD: 0; +CEMODE: 2; +CVHU: 1; ; ; ; ; ; ;
+CSCLK: 0; +CCUART: 0; +CFGRI: 0,60,120; +CUARTSD: 500; +CURCD: 0;
+CUARTLOG: 0; +CUARTRM: 0; +CFGRIDTM: 60,120; +CATR: 0; +CNMP: 2;
+CNRP: 255; +CNAOP: 0; +CNSDP: 2; +CNSMOD: 0; +CNLSA: 0; +CEXTEPLMN: 1;
+CSQFMT: 1; +AUTOCSQ: 0,0; +CSQDELTA: 5; +CPSI: 0; +CMGSI: 2;
+CMGRMI: 4,0; +MONI: 0; +CRUPSI: 0;  +CRUSET: 0; +CGPS: 1,1; +CGPSMSB: 1;
+CGPSINFO: 0; +CGPSINFOCFG: 0,0,0; +CGPSHOR: 50; +CGPSPMD: 65407;
+CGPSXD: 0; +CGNSSINFO: 0; +CSOCKAUTH: 1,0,""; +CGAUTH: 1,0,""; ;
+CIPHEAD: 1; +CIPSRIP: 1; +CIPCCFG: 10,0,0,1,0,0,500; +CIPENSRXGET: 0;
+CIPMODE: 0; +CPIN: ÿÿÿÿÿÿÿÿ,ÿÿÿÿÿÿÿÿ; +CMEC: 0,0,0,0;
+CIND: 0,3,1,1,0,0,1,0; +CMER: 0,0,0,0,0; +CGATT: 1;
+CGACT(1,1),(2,0),(3,0),(4,0),(5,0),(6,0); +CPBS: "SM";
+CPMS: "SM","SM","SM"; +CNMI: 2,1,0,0,0; +CMMS: 0; +CCUG: 0,0,0;
+COPS: 0,0,""; +CUSD: 0; +CAOC: 1; +CCWA: 0;  +CPOL: 0,2,"",0,0,0,0;
+CPLS: 0; +CTZR: 0; +CTZU: 0; +CLIP: 0; +COLP: 0; +CDIP: 0; +CLIR: 0;
+CSDF: 1; +CEN: 0; +CPSMS: 0,"","","",""; +CEDRXS: 0,1,""; +CCARDMA: 0;
+STK: 0; +CSALPHA: 0; +MORING: 0; +CWAKEUPSMSSWITCH: 0;
+CFILTERSMSSWITCH: 0; +EB: 1,0,30; +EFCS: 1; +ER: 0; +ESR: 1;
+ETBM: 1,1,20; +MA: ; +MR: 0; +MS: ; +MV18R: 0; +MV18S: 0,0,0; +CXT: 0;
+CDR: 0; +CDS: 0,1,2048,6; +CFC: 0; +CFG: ""; +CQD: 10; +CCRC: 0;
+QCMUX: C,2; +CTA: 0; +ILRR: 0; +QCPIN: ,; *CNTI: 0; ^PREFMODE: 0;
^DSCI: 0; ^MODE: 0;  ^CPIN: ,

OK
AT+COPS?
+COPS: 0,0,"Google Fi",7

OK
AT+CPSI?
+CPSI: LTE,Online,310-260,0x2C13,45023373,3,EUTRAN-BAND41,39874,5,5,-68,-947,-680,16

OK
AT+CGDCONT?
+CGDCONT: 1,"IPV4V6","h2g2","0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0",0,0,0,0
+CGDCONT: 2,"IPV4V6","","0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0",0,0,0,0
+CGDCONT: 3,"IPV4V6","","0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0",0,0,0,0
+CGDCONT: 4,"IPV4V6","","0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0",0,0,0,0
+CGDCONT: 5,"IPV4V6","","0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0",0,0,0,0
+CGDCONT: 6,"IPV4V6","h2g2","0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0",0,0,0,0

OK
AT+CSQ
+CSQ: 22,99

OK

If you have any suggestions to make my networking more stable, I would appreciate any help. When I tried these two PID modes I lost access to the ttyUSB ports and had to connect the device to a windows machine, force install questionable drivers for the device and then issue commands to reset the modem back to a PID mode I could work with. I would also appreciate any information on how to send AT commands to a USB port/device/interface if the operating system didn’t install tty drivers to make it easily accessible.

AT+CUSBPIDSWITCH=9002,1,1

wim@WimPiZeroW-Wim:~ $ lsusb -t
/:  Bus 01.Port 1: Dev 1, Class=root_hub, Driver=dwc_otg/1p, 480M
    |__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/4p, 480M
        |__ Port 1: Dev 4, If 0, Class=Vendor Specific Class, Driver=, 480M
        |__ Port 1: Dev 4, If 1, Class=Vendor Specific Class, Driver=, 480M
        |__ Port 1: Dev 4, If 2, Class=Vendor Specific Class, Driver=, 480M
        |__ Port 1: Dev 4, If 3, Class=Vendor Specific Class, Driver=, 480M
        |__ Port 1: Dev 4, If 4, Class=Vendor Specific Class, Driver=, 480M
        |__ Port 1: Dev 4, If 5, Class=Vendor Specific Class, Driver=, 480M

AT+CUSBPIDSWITCH=9018,1,1

wim@WimPiZeroW-Wim:~ $ lsusb
Bus 001 Device 003: ID 1e0e:9018 Qualcomm / Option SimTech, Incorporated
Bus 001 Device 002: ID 1a40:0101 Terminus Technology Inc. Hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
wim@WimPiZeroW-Wim:~ $ lsusb -t
/:  Bus 01.Port 1: Dev 1, Class=root_hub, Driver=dwc_otg/1p, 480M
    |__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/4p, 480M
        |__ Port 1: Dev 3, If 0, Class=Vendor Specific Class, Driver=, 480M
        |__ Port 1: Dev 3, If 1, Class=Vendor Specific Class, Driver=, 480M
        |__ Port 1: Dev 3, If 2, Class=Vendor Specific Class, Driver=, 480M
        |__ Port 1: Dev 3, If 3, Class=Vendor Specific Class, Driver=, 480M
        |__ Port 1: Dev 3, If 4, Class=Vendor Specific Class, Driver=, 480M
        |__ Port 1: Dev 3, If 5, Class=Communications, Driver=cdc_ether, 480M
        |__ Port 1: Dev 3, If 6, Class=CDC Data, Driver=cdc_ether, 480M

Moving a subdirectory from one git repository to an entirely new repository

I use Microsoft Visual Studio as my primary development environment. I’ve got a long-term repository that I maintain on Azure Devops at https://wimsworld.visualstudio.com/. When I create a new test project, I often create it as a subdirectory inside the main repository. That gives me version control, without the hassle of creating a new repository every time.

The downside is that when a project grows into a real program, I want to make public, I have to figure out what to do about the code. I could take a snapshot, losing all of the history, or I could jump through hoops to get the project exported from the Azure git platform and imported into the GitHub platform. I like the history of how I got from the start to where I am, so I chose to go thourgh the hoops.

I should describe this with examples. My default code repository is WimsWorld and I often create projects as directories of that, so WimsWorld/WimsConstructionCam in this case. I created this project in July, and then a couple of months later I realized I should have created the program in WimsWorld/Linux/WimsConstructionCam, so I moved it one level deeper in the repository. Git handles all of that fine and I could trace back the history of the file all the way back to creation.

Now that it’s time for me to decide I may be interested in sharing this project publicly, I looked for step by step instructions and came across a nice video doing what I wanted.

This was easiest to do on a linux box at the command line, and since I have a dev system that has its SSH keys already registered as me in both Azure Devops and GitHub I could repeat the process multiple times to get it right.

git clone WimsWorld@vs-ssh.visualstudio.com:v3/WimsWorld/WimsWorld/WimsWorld
cd WimsWorld/
git remote rm origin
git filter-branch --subdirectory-filter Linux/WimsConstructionCam -- --all
cd ..
mv WimsWorld WimsConstructionCam
cd WimsConstructionCam/
git remote add origin git@github.com:wcbonner/WimsConstructionCam.git
git pull origin master --allow-unrelated-histories
git push origin master

The git –filter-branch –subdirectory command got rid of all of the history except for what was in the Linux/WimsConstructionCam/ directory, which seemed right, since all the files I wanted history on currently lived in that directory.

I had previously created a repository in GitHub and this got what appeared to have history in GitHub. On closer inspection, the history only went back a couple of months, and not back to when I’d created the project. I deleted my project in github, deleted the repository directory on my local machine and started again after some research.

First I tried to manually delete everything I didn’t want from my cloned repository, move all the files to where I wanted, commit them, then connect to the new repo and push. I got a problem message about a file that was too large. Sometime in my past history, I’d managed to push a Visual Studio debug symbol database into my repository and while I’d deleted the file, I’d not deleted the history of the file from the repository. That issue was actually a good thing because it confirmed to me that method of getting the files looking the way I wanted could be leaking credentials that I might have somewhere in my private repository.

I found that I needed the git tool git-filter-repo to do what I needed to do.

wget https://raw.githubusercontent.com/newren/git-filter-repo/main/git-filter-repo
git clone WimsWorld@vs-ssh.visualstudio.com:v3/WimsWorld/WimsWorld/WimsWorld
cd WimsWorld/
git remote rm origin
python3 ~/git-filter-repo --force --path WimsConstructionCam --path Linux/WimsConstructionCam
cd Linux/WimsConstructionCam/
git mv * ../..
cd ../..
git commit .
cd ..
mv WimsWorld WimsConstructionCam
cd WimsConstructionCam/
git remote add origin git@github.com:wcbonner/WimsConstructionCam.git
git pull origin main --allow-unrelated-histories
git push origin master

Using the git-filter-repo program I was able to remove the history of everything that was outside of the original folder and the current folder. Then I moved all of the files from the current subdirectory to the repository root and committed the changes. Then I connected the repository to the new remote repository, pulled the remote, and then pushed to the remote.

A funny issue I ran into during my second try into a brand-new repository in GitHub. I’d originally created an empty repository a few weeks ago and the default branch was called master, which matched the default branch on my old repository. They’ve changed to use the current politically correct term for the default branch, and it’s named main. After I’d got both branches in GitHub, I had to merge the two so I’m working from a single branch.

List of links:

Arducam Red Tint Issue on Raspberry Pi

no tuning file

After writing up my issue yesterday I posted the question on the amazon product details. I received an answer with a link to this page overnight. It references a page with several custom tuning files for their lenses. There did not seem to be a tuning file that matched the 175° FOV lens on the package I got, but there was both a 160° and a 200° version. I downloaded both files and ran a test capture with each. On initial viewing, either will work for my solution. I need to focus the lens to see if there are any noticeable differences.

–tuning-file imx219_160.json
–tuning-file imx219_200.json

The commands I used to download and test the tuning files are

wget https://www.arducam.com/wp-content/uploads/2022/05/imx219_160.json
wget https://www.arducam.com/wp-content/uploads/2022/05/imx219_200.json
libcamera-still -v 2 --nopreview --hflip --vflip --thumb none --tuning-file imx219_160.json --output `hostname`-160.jpg
libcamera-still -v 2 --nopreview --hflip --vflip --thumb none --tuning-file imx219_200.json --output `hostname`-200.jpg

I got a message about the tuning file being an older version, with pointers on how to convert it to the updated version.

WARN RPiController controller.cpp:43 This format of the tuning file will be deprecated soon! Please use the convert_tuning.py utility to update to version 2.0.

I still need to decide how I want to handle this in my automated photo processing, but having the information is hugely useful.

Links in one place: