tests: add simple write tests
[pandora-misc.git] / op_test_inputs.c
index 923740b..a831a6a 100644 (file)
@@ -26,6 +26,7 @@
  */
 #define _GNU_SOURCE
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 
 #include "font.c"
 
+#define array_size(x) (sizeof(x) / sizeof(x[0]))
+
+/* this sucks, but EvilDragon wants it */
+#ifdef VALIDATION
+#define NUB_RANGE_REQ (256-8*3)
+#else
+#define NUB_RANGE_REQ 256
+#endif
+
 typedef struct {
        int x, y;
        int code;
-       int active;
+       unsigned int active:1;
+       unsigned int tested:1;
        const char *name;
 } key_item;
 
 static key_item key_items[] =
 {
-       {  66,  26, KEY_1, 0, "1" },
-       { 133,  26, KEY_2, 0, "2" },
-       { 200,  26, KEY_3, 0, "3" },
-       { 266,  26, KEY_4, 0, "4" },
-       { 333,  26, KEY_5, 0, "5" },
-       { 400,  26, KEY_6, 0, "6" },
-       { 466,  26, KEY_7, 0, "7" },
-       { 533,  26, KEY_8, 0, "8" },
-       { 600,  26, KEY_9, 0, "9" },
-       { 666,  26, KEY_0, 0, "0" },
-       { 733,  26, KEY_BACKSPACE, 0, "DEL" },
+       {  66,  26, KEY_1, 0, 0, "1" },
+       { 133,  26, KEY_2, 0, 0, "2" },
+       { 200,  26, KEY_3, 0, 0, "3" },
+       { 266,  26, KEY_4, 0, 0, "4" },
+       { 333,  26, KEY_5, 0, 0, "5" },
+       { 400,  26, KEY_6, 0, 0, "6" },
+       { 466,  26, KEY_7, 0, 0, "7" },
+       { 533,  26, KEY_8, 0, 0, "8" },
+       { 600,  26, KEY_9, 0, 0, "9" },
+       { 666,  26, KEY_0, 0, 0, "0" },
+       { 733,  26, KEY_BACKSPACE, 0, 0, "DEL" },
        //
-       {  10,  55, KEY_RIGHTSHIFT,0, "L" },
-       {  10,  75, KEY_KPPLUS,    0, "L2" },
-       { 758,  55, KEY_RIGHTCTRL, 0, "R" },
-       { 758,  75, KEY_KPMINUS,   0, "R2" },
-       {  10, 220, KEY_POWER,     0, "POWER" },
-       {  10, 240, KEY_COFFEE,    0, "HOLD" },
+       {  10,  55, KEY_RIGHTSHIFT,0, 0, "L" },
+       {  10,  75, KEY_KPPLUS,    0, 0, "L2" },
+       { 758,  55, KEY_RIGHTCTRL, 0, 0, "R" },
+       { 758,  75, KEY_KPMINUS,   0, 0, "R2" },
+       {  10, 220, KEY_POWER,     0, 0, "POWER" },
+       {  10, 240, KEY_COFFEE,    0, 0, "HOLD" },
        //
-       { 130,  94, KEY_UP,     0, "U" },
-       {  80, 163, KEY_LEFT,   0, "L" },
-       { 180, 163, KEY_RIGHT,  0, "R" },
-       { 130, 232, KEY_DOWN,   0, "D" },
-       { 376,  94, KEY_LEFTALT,0, "ALT" },
-       { 368, 163, KEY_LEFTCTRL,0,"CTRL" },
-       { 368, 232, KEY_MENU,   0, "MENU" },
-       { 700,  94, KEY_PAGEUP, 0, "1" },
-       { 650, 163, KEY_HOME,   0, "4" },
-       { 750, 163, KEY_END,    0, "2" },
-       { 700, 232, KEY_PAGEDOWN,0, "3" },
+       { 130,  94, KEY_UP,     0, 0, "U" },
+       {  80, 163, KEY_LEFT,   0, 0, "L" },
+       { 180, 163, KEY_RIGHT,  0, 0, "R" },
+       { 130, 232, KEY_DOWN,   0, 0, "D" },
+       { 376,  94, KEY_LEFTALT,0, 0, "ALT" },
+       { 368, 163, KEY_LEFTCTRL,0,0, "CTRL" },
+       { 368, 232, KEY_MENU,   0, 0, "MENU" },
+       { 700,  94, KEY_PAGEUP, 0, 0, "Y" },
+       { 650, 163, KEY_HOME,   0, 0, "A" },
+       { 750, 163, KEY_END,    0, 0, "B" },
+       { 700, 232, KEY_PAGEDOWN,0,0, "X" },
        //
-       {  92, 300, KEY_Q,      0, "Q" },
-       { 158, 300, KEY_W,      0, "W" },
-       { 225, 300, KEY_E,      0, "E" },
-       { 292, 300, KEY_R,      0, "R" },
-       { 358, 300, KEY_T,      0, "T" },
-       { 425, 300, KEY_Y,      0, "Y" },
-       { 492, 300, KEY_U,      0, "U" },
-       { 558, 300, KEY_I,      0, "I" },
-       { 625, 300, KEY_O,      0, "O" },
-       { 692, 300, KEY_P,      0, "P" },
+       {  92, 300, KEY_Q,      0, 0, "Q" },
+       { 158, 300, KEY_W,      0, 0, "W" },
+       { 225, 300, KEY_E,      0, 0, "E" },
+       { 292, 300, KEY_R,      0, 0, "R" },
+       { 358, 300, KEY_T,      0, 0, "T" },
+       { 425, 300, KEY_Y,      0, 0, "Y" },
+       { 492, 300, KEY_U,      0, 0, "U" },
+       { 558, 300, KEY_I,      0, 0, "I" },
+       { 625, 300, KEY_O,      0, 0, "O" },
+       { 692, 300, KEY_P,      0, 0, "P" },
        //
-       {  30, 369, KEY_LEFTSHIFT, 0, "SHIFT" },
-       { 133, 369, KEY_A,      0, "A" },
-       { 200, 369, KEY_S,      0, "S" },
-       { 266, 369, KEY_D,      0, "D" },
-       { 333, 369, KEY_F,      0, "F" },
-       { 400, 369, KEY_G,      0, "G" },
-       { 466, 369, KEY_H,      0, "H" },
-       { 533, 369, KEY_J,      0, "J" },
-       { 600, 369, KEY_K,      0, "K" },
-       { 666, 369, KEY_L,      0, "L" },
-       { 710, 369, KEY_ENTER,  0, "ENTER" },
+       {  30, 369, KEY_LEFTSHIFT, 0, 0, "SHIFT" },
+       { 133, 369, KEY_A,      0, 0, "A" },
+       { 200, 369, KEY_S,      0, 0, "S" },
+       { 266, 369, KEY_D,      0, 0, "D" },
+       { 333, 369, KEY_F,      0, 0, "F" },
+       { 400, 369, KEY_G,      0, 0, "G" },
+       { 466, 369, KEY_H,      0, 0, "H" },
+       { 533, 369, KEY_J,      0, 0, "J" },
+       { 600, 369, KEY_K,      0, 0, "K" },
+       { 666, 369, KEY_L,      0, 0, "L" },
+       { 710, 369, KEY_ENTER,  0, 0, "ENTER" },
        //
-       {  25, 437, KEY_COMMA,  0, "," },
-       {  92, 437, KEY_DOT,    0, "." },
-       { 158, 437, KEY_Z,      0, "Z" },
-       { 225, 437, KEY_X,      0, "X" },
-       { 292, 437, KEY_C,      0, "C" },
-       { 358, 437, KEY_V,      0, "V" },
-       { 425, 437, KEY_B,      0, "B" },
-       { 492, 437, KEY_N,      0, "N" },
-       { 558, 437, KEY_M,      0, "M" },
-       { 625, 437, KEY_SPACE,  0, "SPACE" },
-       { 758, 437, KEY_FN,     0, "Fn" },
+       {  25, 437, KEY_COMMA,  0, 0, "," },
+       {  92, 437, KEY_DOT,    0, 0, "." },
+       { 158, 437, KEY_Z,      0, 0, "Z" },
+       { 225, 437, KEY_X,      0, 0, "X" },
+       { 292, 437, KEY_C,      0, 0, "C" },
+       { 358, 437, KEY_V,      0, 0, "V" },
+       { 425, 437, KEY_B,      0, 0, "B" },
+       { 492, 437, KEY_N,      0, 0, "N" },
+       { 558, 437, KEY_M,      0, 0, "M" },
+       { 625, 437, KEY_SPACE,  0, 0, "SPACE" },
+       { 758, 437, KEY_FN,     0, 0, "Fn" },
 };
 
 #define KI_COUNT (sizeof(key_items) / sizeof(key_items[0]))
 
-static int ts_old_x = 0, ts_old_y = 0;
-static int lid_closed = 0;
+static int nub_range_hit, all_btns_tested, lid_tested, ts_tested;
+static int ts_old_x, ts_old_y;
+static int lid_closed;
 
 static void draw_ts_cross(unsigned short *fb, unsigned short col, int x, int y)
 {
@@ -129,7 +141,10 @@ static void draw_ts_cross(unsigned short *fb, unsigned short col, int x, int y)
        if (x >= 0 && x < 800)
                for (y1 = y - 5, i = 0; i < 11; i++, y1++)
                        if (y1 >= 0 && y1 < 480) fb[y1 * 800 + x] = col;
-       
+
+       if (x != ts_old_x && y != ts_old_y)
+               ts_tested = 1;
+
        ts_old_x = x;
        ts_old_y = y;
 }
@@ -191,23 +206,40 @@ static void text_out16_small(unsigned short *fb, int x, int y, unsigned short co
 static void redraw_nubs(unsigned short *fb, int x1, int y1, int x2, int y2)
 {
        char buff[32];
-       int y;
+       int fill = 0, y;
 
        fb += 90*800;
 
+       if (nub_range_hit == 0xff && all_btns_tested && lid_tested && ts_tested)
+               fill = 3;
+
        // clear areas
        for (y = 0; y < 140; y++) {
-               memset(fb + 800*y + 200, 0, (64+8)*2*2);
-               memset(fb + 800*y + 450, 0, (64+8)*2*2);
+               memset(fb + 800*y + 200, fill, (64+8)*2*2);
+               memset(fb + 800*y + 450, fill, (64+8)*2*2);
        }
 
        text_out16(fb + 200, 32*2 + x1/8, 32*2 + y1/8, 0x001f, "@");
        text_out16(fb + 450, 32*2 + x2/8, 32*2 + y2/8, 0x001f, "@");
 
-       snprintf(buff, sizeof(buff), "%2i, %2i", x1/8, y1/8);
-       text_out16_small(fb, 245, 130, 0x7bef, buff);
-       snprintf(buff, sizeof(buff), "%2i, %2i", x2/8, y2/8);
-       text_out16_small(fb, 495, 130, 0x7bef, buff);
+       if (x1 <= -NUB_RANGE_REQ) nub_range_hit |= 0x01;
+       if (x1 >=  NUB_RANGE_REQ) nub_range_hit |= 0x02;
+       if (y1 <= -NUB_RANGE_REQ) nub_range_hit |= 0x04;
+       if (y1 >=  NUB_RANGE_REQ) nub_range_hit |= 0x08;
+       if (x2 <= -NUB_RANGE_REQ) nub_range_hit |= 0x10;
+       if (x2 >=  NUB_RANGE_REQ) nub_range_hit |= 0x20;
+       if (y2 <= -NUB_RANGE_REQ) nub_range_hit |= 0x40;
+       if (y2 >=  NUB_RANGE_REQ) nub_range_hit |= 0x80;
+
+       snprintf(buff, sizeof(buff), "%3i", x1/8);
+       text_out16_small(fb, 235, 130, (nub_range_hit & 0x03) == 0x03 ? 0xce6f : 0x7bef, buff);
+       snprintf(buff, sizeof(buff), "%3i", y1/8);
+       text_out16_small(fb, 270, 130, (nub_range_hit & 0x0c) == 0x0c ? 0xce6f : 0x7bef, buff);
+
+       snprintf(buff, sizeof(buff), "%3i", x2/8);
+       text_out16_small(fb, 485, 130, (nub_range_hit & 0x30) == 0x30 ? 0xce6f : 0x7bef, buff);
+       snprintf(buff, sizeof(buff), "%3i", y2/8);
+       text_out16_small(fb, 520, 130, (nub_range_hit & 0xc0) == 0xc0 ? 0xce6f : 0x7bef, buff);
 }
 
 static void redraw_keys_lid(unsigned short *fb)
@@ -220,13 +252,14 @@ static void redraw_keys_lid(unsigned short *fb)
                key = &key_items[i];
 
                text_out16(fb, key->x, key->y,
-                       key->active ? 0x07e0 : 0x7bef, key->name);
+                       key->active ? 0x07e0 : (key->tested ? 0xce6f : 0x7bef),
+                       key->name);
        }
 
-       text_out16(fb, 10, 260, lid_closed ? 0x07e0 : 0x7bef, "LID");
+       text_out16(fb, 10, 260, lid_closed ? 0x07e0 : (lid_tested ? 0xce6f : 0x7bef), "LID");
 }
 
-static void setkey(int code, int val)
+static void set_key(int code, int val)
 {
        key_item *key = NULL;
        int i;
@@ -246,9 +279,125 @@ static void setkey(int code, int val)
        }
        else
        {
-               key->active = val;
+               key->active = !!val;
+               key->tested |= !!val;
                printf("%c %s\n", val ? '+' : '-', key->name);
        }
+
+       if (all_btns_tested)
+               return;
+
+       for (i = 0; i < KI_COUNT; i++)
+       {
+               if (key_items[i].code == KEY_MENU)
+                       continue;
+               if (key_items[i].code == KEY_KPPLUS || key_items[i].code == KEY_KPMINUS)
+                       continue;
+               if (!key_items[i].tested)
+                       break;
+       }
+
+       if (i == KI_COUNT)
+               all_btns_tested = 1;
+}
+
+/* sound test */
+#include <sys/soundcard.h>
+#include <pthread.h>
+
+static int snd_test_l, snd_test_r, snd_test_quit;
+static pthread_cond_t snd_cond = PTHREAD_COND_INITIALIZER;
+static pthread_mutex_t snd_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static void *sound_thread(void *arg)
+{
+       int i, ret, randfd, dspfd;
+       int frag, bits, stereo, rate;
+       short buf[8*1024];//2*22050 / 10];
+
+       randfd = open("/dev/urandom", O_RDONLY);
+       if (randfd == -1) {
+               perror("open(\"/dev/urandom\")");
+               return NULL;
+       }
+
+       dspfd = open("/dev/dsp", O_WRONLY);
+       if (dspfd == -1) {
+               perror("open(\"/dev/dsp\")");
+               close(randfd);
+               return NULL;
+       }
+
+       frag = (2 << 16) | 13;
+       ret = ioctl(dspfd, SNDCTL_DSP_SETFRAGMENT, &frag);
+       if (ret < 0)
+               perror("SNDCTL_DSP_SETFRAGMENT");
+
+       stereo = 1; bits = 16; rate = 22050;
+       ret = ioctl(dspfd, SNDCTL_DSP_STEREO, &stereo);
+       if (ret == 0)
+               ret = ioctl(dspfd, SNDCTL_DSP_SETFMT, &bits);
+       if (ret == 0)
+               ret = ioctl(dspfd, SNDCTL_DSP_SPEED, &rate);
+       if (ret < 0)
+               perror("failed to set audio format");
+
+       while (1) {
+               pthread_mutex_lock(&snd_mutex);
+               if (!snd_test_l && !snd_test_r)
+                       pthread_cond_wait(&snd_cond, &snd_mutex);
+               pthread_mutex_unlock(&snd_mutex);
+
+               if (snd_test_quit)
+                       break;
+
+               ret = read(randfd, buf, sizeof(buf));
+               if (ret == -1) {
+                       perror("urandom read");
+                       break;
+               }
+
+               if (!snd_test_l)
+                       for (i = 0; i < array_size(buf) / 2; i++)
+                               buf[i * 2] = 0;
+               if (!snd_test_r)
+                       for (i = 0; i < array_size(buf) / 2; i++)
+                               buf[i * 2 + 1] = 0;
+
+               ret = write(dspfd, buf, sizeof(buf));
+               if (ret == -1) {
+                       perror("dsp write");
+                       break;
+               }
+       }
+
+       close(randfd);
+       close(dspfd);
+
+       return NULL;
+}
+
+static void sound_init(void)
+{
+       pthread_t tid;
+       int ret;
+
+       ret = pthread_create(&tid, NULL, sound_thread, NULL);
+       if (ret != 0) {
+               fprintf(stderr, "pthread_create sound_thread: %d\n", ret);
+               return;
+       }
+       pthread_detach(tid);
+}
+
+static void sound_do(int l, int r)
+{
+       pthread_mutex_lock(&snd_mutex);
+       snd_test_l = l;
+       snd_test_r = r;
+       if (l || r || snd_test_quit)
+               pthread_cond_signal(&snd_cond);
+       pthread_mutex_unlock(&snd_mutex);
 }
 
 enum {
@@ -269,6 +418,7 @@ int main(int argc, char *argv[])
        int nubx[2] = {0,0}, nuby[2] = {0,0};
        int pressed_l = 0, pressed_r = 0;
        struct tsdev *ts = NULL;
+       int retval = 0;
 
        fbdev = open("/dev/fb0", O_RDWR);
        if (fbdev == -1)
@@ -286,6 +436,8 @@ int main(int argc, char *argv[])
 
        memset(screen, 0, 800*480*2);
 
+       sound_init();
+
        for (id = 0; ; id++)
        {
                char fname[64];
@@ -301,7 +453,7 @@ int main(int argc, char *argv[])
 
                ioctl(fd, EVIOCGNAME(sizeof(name)), name);
 
-               if (strcasestr(name, "pwrbutton") != NULL)
+               if (strcasestr(name, "power") != NULL || strcasestr(name, "pwrbutton") != NULL)
                {
                        ifd[DEV_PWRBTN] = fd;
                }
@@ -329,11 +481,11 @@ int main(int argc, char *argv[])
                        }
                        ifd[DEV_TS] = ts_fd(ts);
                }
-               else if (strcmp(name, "vsense66") == 0)
+               else if (strcmp(name, "nub0") == 0)
                {
                        ifd[DEV_LNUB] = fd;
                }
-               else if (strcmp(name, "vsense67") == 0)
+               else if (strcmp(name, "nub1") == 0)
                {
                        ifd[DEV_RNUB] = fd;
                }
@@ -348,19 +500,48 @@ int main(int argc, char *argv[])
 
        if (ifd[DEV_PWRBTN]  == -1) printf("Warning: couldn't find pwrbutton device\n");
        if (ifd[DEV_KEYPAD]  == -1) printf("Warning: couldn't find keypad device\n");
-       if (ifd[DEV_BUTTONS] == -1) printf("Warning: couldn't find button device\n");
        if (ifd[DEV_TS]      == -1) printf("Warning: couldn't find touchscreen device\n");
        if (ifd[DEV_LNUB]    == -1) printf("Warning: couldn't find nub1 device\n");
        if (ifd[DEV_RNUB]    == -1) printf("Warning: couldn't find nub2 device\n");
+       if (ifd[DEV_BUTTONS] == -1) {
+               printf("Error: couldn't find button device\n");
+               /* buttons needed to exit this, so bail out */
+               retval = -1;
+               goto end;
+       }
 
+#ifdef VALIDATION
+       int early_leave_attempt = 0;
+       text_out16_small(screen, 220, 3, 0x7bef,
+                        "press menu/pandora to exit");
+#else
        text_out16_small(screen, 320, 3, 0x7bef, "Press L+R to exit");
+#endif
 
+#ifdef VALIDATION
+       while (1)
+#else
        while (!pressed_l || !pressed_r)
+#endif
        {
                struct input_event ev[64];
                int fd = -1, rd, which, ret;
                fd_set fdset;
 
+#ifdef VALIDATION
+               if (early_leave_attempt > 1) {
+                       char buff[128];
+                       snprintf(buff, sizeof(buff), "not everything tested (%s%s%s%s), L+R to override",
+                               nub_range_hit == 0xff ? "" : "nubs", all_btns_tested ? "" : " buttons",
+                               lid_tested ? "" : " lid_switch", ts_tested ? "" : " touchscreen");
+                       memset(screen, 0, 800*12*2);
+                       if (nub_range_hit == 0xff && all_btns_tested && lid_tested && ts_tested)
+                               text_out16_small(screen, 220, 3, 0x07c0,
+                                       "press menu/pandora to exit");
+                       else
+                               text_out16_small(screen, 4, 3, 0xf800, buff);
+               }
+#endif
                draw_ts_cross(screen, 0x0000, ts_old_x, ts_old_y);
                redraw_keys_lid(screen);
                redraw_nubs(screen, nubx[0], nuby[0], nubx[1], nuby[1]);
@@ -414,11 +595,27 @@ int main(int argc, char *argv[])
                        case EV_SYN:
                                break;
                        case EV_KEY:
-                               setkey(ev[i].code, ev[i].value);
+                               set_key(ev[i].code, ev[i].value);
+
                                if (ev[i].code == KEY_RIGHTSHIFT)
                                        pressed_l = !!ev[i].value;
                                if (ev[i].code == KEY_RIGHTCTRL)
                                        pressed_r = !!ev[i].value;
+#ifdef VALIDATION
+                               if (ev[i].code == KEY_MENU && !!ev[i].value) {
+                                       if (nub_range_hit == 0xff && all_btns_tested && lid_tested && ts_tested)
+                                               goto end;
+                                       if (pressed_l && pressed_r) {
+                                               retval = 1;
+                                               goto end;
+                                       }
+                                       early_leave_attempt++;
+                               }
+#endif
+                               if (ev[i].code == KEY_LEFT)
+                                       sound_do(!!ev[i].value, snd_test_r);
+                               if (ev[i].code == KEY_RIGHT)
+                                       sound_do(snd_test_l, !!ev[i].value);
                                break;
                        case EV_ABS:
                                which = (fd == ifd[DEV_LNUB]) ? 0 : 1;
@@ -430,8 +627,10 @@ int main(int argc, char *argv[])
                                        printf("unexpected EV_ABS code: %i\n", ev[i].code);
                                break;
                        case EV_SW:
-                               if (ev[i].code == SW_LID)
+                               if (ev[i].code == SW_LID) {
                                        lid_closed = ev[i].value;
+                                       lid_tested |= ev[i].value;
+                               }
                                else
                                        printf("unexpected EV_SW code: %i\n", ev[i].code);
                                break;
@@ -446,6 +645,8 @@ int main(int argc, char *argv[])
                }
        }
 
+       snd_test_quit = 1;
+       sound_do(0, 0);
 
 end:
        if (ts != NULL)
@@ -455,6 +656,6 @@ end:
                        close(ifd[i]);
        munmap(screen, 800*480*2);
        close(fbdev);
-       return 0;
+       return retval;
 }