]> Untitled Git - hvrtc.git/commitdiff
Add test option
authorHugo Villeneuve <hvilleneuve@dimonoff.com>
Mon, 9 Mar 2026 19:34:16 +0000 (15:34 -0400)
committerHugo Villeneuve <hvilleneuve@dimonoff.com>
Tue, 10 Mar 2026 18:52:02 +0000 (14:52 -0400)
Signed-off-by: Hugo Villeneuve <hvilleneuve@dimonoff.com>
src/main.c
src/options.c
src/options.h

index e824131f4ea56e4ec3fbeb0ed05889fc4446308b..2c6b453a4c5e578d446b0aecddf7a4e5aa4f8768 100644 (file)
@@ -81,227 +81,297 @@ static int rtc_param_set_bsm(int fd, int value)
        return 0;
 }
 
-int
-main(int argc, char **argv)
+static int rtc_test_uie(int fd)
 {
+       unsigned long data;
+       int irqcount = 0;
        int rc;
-       int i, fd, retval, irqcount = 0;
-       unsigned long tmp, data;
-       struct rtc_time rtc_tm;
-
-       rc = parse_command_line_options(argc, argv);
-       if (rc)
-               exit(EXIT_FAILURE);
-
-       fd = open(options.rtc_path, O_RDONLY);
-       if (fd ==  -1) {
-               perror(options.rtc_path);
-               exit(errno);
-       }
-
-       if (options.bsm) {
-               if (options.bsm_arg >= 0) {
-                       retval = rtc_param_set_bsm(fd, options.bsm_arg);
-                       if (retval < 0)
-                               exit(retval);
-               } else {
-                       retval = rtc_param_get_bsm(fd);
-                       if (retval < 0)
-                               exit(retval);
-               }
-       }
-
-       printf("RTC test\n");
-
-       /* Test for backup conditions */
-       retval = ioctl(fd, RTC_VL_READ, &tmp);
-       if (retval < 0) {
-               fprintf(stderr, "\n...RTC_VL_READ ioctl not supported.\n");
-       } else {
-               fprintf(stderr, "RTC_VL_READ: $%02lX\n", tmp);
-
-               if (tmp & RTC_VL_BACKUP_LOW)
-                       fprintf(stderr, "Backup low voltage detected, check/replace RTC battery\n");
-
-               if (tmp & RTC_VL_BACKUP_SWITCH)
-                       fprintf(stderr, "Backup switchover happened\n");
-
-               if (tmp & RTC_VL_DATA_INVALID)
-                       fprintf(stderr, "Voltage too low, RTC data is invalid\n");
-       }
+       int i;
 
        /* Turn on update interrupts (one per second) */
-       retval = ioctl(fd, RTC_UIE_ON, 0);
-       if (retval == -1) {
+       rc = ioctl(fd, RTC_UIE_ON, 0);
+       if (rc == -1) {
                if (errno == ENOTTY) {
-                       fprintf(stderr,
-                               "\n...Update IRQs not supported.\n");
-                       goto test_READ;
+                       fprintf(stderr, "Update IRQs not supported\n");
+                       return 0;
                }
                perror("RTC_UIE_ON ioctl");
-               exit(errno);
+               return -errno;
        }
-       fprintf(stderr, "Counting 5 update (1/sec) interrupts from reading %s:",
-                       options.rtc_path);
-       fflush(stderr);
-       for (i=1; i<6; i++) {
+
+       printf("Counting 5 update (1/sec) interrupts from %s:", options.rtc_path);
+       fflush(stdout);
+
+       for (i = 1; i < 6; i++) {
                /* This read will block */
-               retval = read(fd, &data, sizeof(unsigned long));
-               if (retval == -1) {
+               rc = read(fd, &data, sizeof(unsigned long));
+               if (rc == -1) {
+                       printf("\n");
                        perror("read");
-                       exit(errno);
+                       return -errno;
                }
-               fprintf(stderr, " %d",i);
-               fflush(stderr);
+
+               printf(" %d", i);
+               fflush(stdout);
                irqcount++;
        }
-       fprintf(stderr, "\nAgain, from using select(2) on /dev/rtc:");
-       fflush(stderr);
-       for (i=1; i<6; i++) {
+
+       printf("\n");
+
+       printf("Again, using select(2) from %s:", options.rtc_path);
+       fflush(stdout);
+
+       for (i = 1; i < 6; i++) {
                struct timeval tv = {5, 0};     /* 5 second timeout on select */
                fd_set readfds;
                FD_ZERO(&readfds);
                FD_SET(fd, &readfds);
                /* The select will wait until an RTC interrupt happens. */
-               retval = select(fd+1, &readfds, NULL, NULL, &tv);
-               if (retval == -1) {
+               rc = select(fd+1, &readfds, NULL, NULL, &tv);
+               if (rc == -1) {
+                       printf("\n");
                        perror("select");
-                       exit(errno);
+                       return -errno;
                }
+
                /* This read won't block unlike the select-less case above. */
-               retval = read(fd, &data, sizeof(unsigned long));
-               if (retval == -1) {
+               rc = read(fd, &data, sizeof(unsigned long));
+               if (rc == -1) {
+                       printf("\n");
                        perror("read");
-                       exit(errno);
+                       return -errno;
                }
-               fprintf(stderr, " %d",i);
-               fflush(stderr);
+
+               printf(" %d", i);
+               fflush(stdout);
                irqcount++;
        }
+
+       printf("\n");
+
        /* Turn off update interrupts */
-       retval = ioctl(fd, RTC_UIE_OFF, 0);
-       if (retval == -1) {
+       rc = ioctl(fd, RTC_UIE_OFF, 0);
+       if (rc == -1) {
                perror("RTC_UIE_OFF ioctl");
-               exit(errno);
+               return -errno;
        }
-test_READ:
+
+       return 0;
+}
+
+static int rtc_test_read(int fd)
+{
+       struct rtc_time rtc_tm;
+       unsigned long data;
+       int rc;
+
        /* Read the RTC time/date */
-       retval = ioctl(fd, RTC_RD_TIME, &rtc_tm);
-       if (retval == -1) {
+       rc = ioctl(fd, RTC_RD_TIME, &rtc_tm);
+       if (rc == -1) {
                perror("RTC_RD_TIME ioctl");
-               exit(errno);
+               return -errno;
        }
-       fprintf(stderr, "\n\nCurrent RTC date/time is %d-%d-%d, %02d:%02d:%02d.\n",
-               rtc_tm.tm_mday, rtc_tm.tm_mon + 1, rtc_tm.tm_year + 1900,
-               rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec);
+
+       printf("Current RTC date/time: %d-%d-%d, %02d:%02d:%02d\n",
+              rtc_tm.tm_mday, rtc_tm.tm_mon + 1, rtc_tm.tm_year + 1900,
+              rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec);
+
        /* Set the alarm to 5 sec in the future, and check for rollover */
        rtc_tm.tm_sec += 5;
        if (rtc_tm.tm_sec >= 60) {
                rtc_tm.tm_sec %= 60;
                rtc_tm.tm_min++;
        }
+
        if (rtc_tm.tm_min == 60) {
                rtc_tm.tm_min = 0;
                rtc_tm.tm_hour++;
        }
+
        if (rtc_tm.tm_hour == 24)
                rtc_tm.tm_hour = 0;
-       retval = ioctl(fd, RTC_ALM_SET, &rtc_tm);
-       if (retval == -1) {
+
+       rc = ioctl(fd, RTC_ALM_SET, &rtc_tm);
+       if (rc == -1) {
                if (errno == ENOTTY) {
-                       fprintf(stderr,
-                               "\n...Alarm IRQs not supported.\n");
-                       goto test_PIE;
+                       fprintf(stderr, "Alarm IRQs not supported\n");
+                       return 0;
                }
                perror("RTC_ALM_SET ioctl");
-               exit(errno);
+               return -errno;
        }
+
        /* Read the current alarm settings */
-       retval = ioctl(fd, RTC_ALM_READ, &rtc_tm);
-       if (retval == -1) {
+       rc = ioctl(fd, RTC_ALM_READ, &rtc_tm);
+       if (rc == -1) {
                perror("RTC_ALM_READ ioctl");
-               exit(errno);
+               return -errno;
        }
-       fprintf(stderr, "Alarm time now set to %02d:%02d:%02d.\n",
-               rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec);
+
+       printf("Alarm time: %02d:%02d:%02d\n",
+              rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec);
 
        /* Enable alarm interrupts */
-       retval = ioctl(fd, RTC_AIE_ON, 0);
-       if (retval == -1) {
+       rc = ioctl(fd, RTC_AIE_ON, 0);
+       if (rc == -1) {
                perror("RTC_AIE_ON ioctl");
-               exit(errno);
+               return -errno;
        }
-       fprintf(stderr, "Waiting 5 seconds for alarm...");
-       fflush(stderr);
+
+       printf("Waiting 5 seconds for alarm... ");
+       fflush(stdout);
+
        /* This blocks until the alarm ring causes an interrupt */
-       retval = read(fd, &data, sizeof(unsigned long));
-       if (retval == -1) {
+       rc = read(fd, &data, sizeof(unsigned long));
+       if (rc == -1) {
+               printf("\n");
                perror("read");
-               exit(errno);
+               return -errno;
        }
-       irqcount++;
-       fprintf(stderr, " okay. Alarm rang.\n");
+
+       printf("Ok: Alarm rang\n");
+
        /* Disable alarm interrupts */
-       retval = ioctl(fd, RTC_AIE_OFF, 0);
-       if (retval == -1) {
+       rc = ioctl(fd, RTC_AIE_OFF, 0);
+       if (rc == -1) {
                perror("RTC_AIE_OFF ioctl");
-               exit(errno);
+               return -errno;
        }
-test_PIE:
+
+       return 0;
+}
+
+static int rtc_test_pie(int fd)
+{
+       unsigned long data;
+       unsigned long tmp;
+       int rc;
+       unsigned int i;
+
        /* Read periodic IRQ rate */
-       retval = ioctl(fd, RTC_IRQP_READ, &tmp);
-       if (retval == -1) {
+       rc = ioctl(fd, RTC_IRQP_READ, &tmp);
+       if (rc == -1) {
                /* not all RTCs support periodic IRQs */
                if (errno == ENOTTY) {
-                       fprintf(stderr, "\nNo periodic IRQ support\n");
-                       goto done;
+                       printf("No periodic IRQ support\n");
+                       return -errno;
                }
                perror("RTC_IRQP_READ ioctl");
-               exit(errno);
+               return -errno;
        }
-       fprintf(stderr, "\nPeriodic IRQ rate is %ldHz.\n", tmp);
-       fprintf(stderr, "Counting 20 interrupts at:");
-       fflush(stderr);
+
+       printf("Periodic IRQ rate is %ldHz\n", tmp);
+
+       printf("Counting 20 interrupts at:");
+       fflush(stdout);
+
        /* The frequencies 128Hz, 256Hz, ... 8192Hz are only allowed for root. */
-       for (tmp=2; tmp<=64; tmp*=2) {
-               retval = ioctl(fd, RTC_IRQP_SET, tmp);
-               if (retval == -1) {
+       for (tmp = 2; tmp <= 64; tmp *= 2) {
+               rc = ioctl(fd, RTC_IRQP_SET, tmp);
+               if (rc == -1) {
                        /* not all RTCs can change their periodic IRQ rate */
                        if (errno == ENOTTY) {
-                               fprintf(stderr,
-                                       "\n...Periodic IRQ rate is fixed\n");
-                               goto done;
+                               printf("\n");
+                               printf("Periodic IRQ rate is fixed\n");
+                               return -errno;
                        }
                        perror("RTC_IRQP_SET ioctl");
-                       exit(errno);
+                       return -errno;
                }
-               fprintf(stderr, "\n%ldHz:\t", tmp);
-               fflush(stderr);
+
+               printf("\n");
+               printf("%ldHz:\t", tmp);
+               fflush(stdout);
+
                /* Enable periodic interrupts */
-               retval = ioctl(fd, RTC_PIE_ON, 0);
-               if (retval == -1) {
+               rc = ioctl(fd, RTC_PIE_ON, 0);
+               if (rc == -1) {
+                       printf("\n");
                        perror("RTC_PIE_ON ioctl");
-                       exit(errno);
+                       return -errno;
                }
-               for (i=1; i<21; i++) {
+
+               for (i = 1; i < 21; i++) {
                        /* This blocks */
-                       retval = read(fd, &data, sizeof(unsigned long));
-                       if (retval == -1) {
+                       rc = read(fd, &data, sizeof(unsigned long));
+                       if (rc == -1) {
+                               printf("\n");
                                perror("read");
-                               exit(errno);
+                               return -errno;
                        }
-                       fprintf(stderr, " %d",i);
-                       fflush(stderr);
-                       irqcount++;
+                       printf(" %d", i);
+                       fflush(stdout);
                }
+
                /* Disable periodic interrupts */
-               retval = ioctl(fd, RTC_PIE_OFF, 0);
-               if (retval == -1) {
+               rc = ioctl(fd, RTC_PIE_OFF, 0);
+               if (rc == -1) {
+                       printf("\n");
                        perror("RTC_PIE_OFF ioctl");
-                       exit(errno);
+                       return -errno;
                }
        }
-done:
+
+       printf("\n");
+
+       return 0;
+}
+
+static int rtc_test(int fd)
+{
+       int rc;
+
+       printf("RTC test:\n");
+
+       rc = rtc_test_uie(fd);
+       if (rc)
+               return rc;
+
+       rc = rtc_test_read(fd);
+       if (rc)
+               return rc;
+
+       rc = rtc_test_pie(fd);
+       if (rc)
+               return rc;
+
+       return 0;
+}
+
+int
+main(int argc, char **argv)
+{
+       int rc;
+       int fd;
+
+       rc = parse_command_line_options(argc, argv);
+       if (rc)
+               exit(EXIT_FAILURE);
+
+       fd = open(options.rtc_path, O_RDONLY);
+       if (fd ==  -1) {
+               perror(options.rtc_path);
+               exit(errno);
+       }
+
+       if (options.bsm) {
+               if (options.bsm_arg >= 0) {
+                       rc = rtc_param_set_bsm(fd, options.bsm_arg);
+                       if (rc < 0)
+                               exit(rc);
+               } else {
+                       rc = rtc_param_get_bsm(fd);
+                       if (rc < 0)
+                               exit(rc);
+               }
+       }
+
+       if (options.test) {
+               rc = rtc_test(fd);
+               if (rc < 0)
+                       exit(rc);
+       }
+
        close(fd);
 
        return 0;
index e92f3a1fdc11b7d0207b1c28b74e9e6f26c02319..0dff2d781ba229a606ab9424f889cad92aed9a18 100644 (file)
@@ -46,6 +46,7 @@ static const char args_doc[] = "";
 static struct argp_option argp_options[] = {
        {"bsm",   'b', "value", OPTION_ARG_OPTIONAL, "Get/Set  Backup Switch Mode (BSM)", 0},
        {"dev",   'd', "path", 0, "RTC device path (optional)", 0},
+       {"test",  't', 0,         0, "Test RTC", 0},
        { 0 }
 };
 
@@ -104,6 +105,9 @@ parse_opt(int key, char *arg, struct argp_state *state)
                /* We do not support any arguments after the options. */
                argp_usage(state);
                break;
+       case 't':
+               options.test = true;
+               break;
        default:
                return ARGP_ERR_UNKNOWN;
        }
index a4077ff7049357c8ea0844495f7f03cd9506daa0..44c967b8d0fd9e64b6db658c9f5421af86db8cd6 100644 (file)
@@ -19,6 +19,7 @@ struct options_t {
        char *rtc_path;
        int bsm;
        int bsm_arg;
+       int test;
 };
 
 int parse_command_line_options(int argc, char *argv[]);