Skip to content

Commit

Permalink
Test code system to test a compute module system using a Raspberry Pi
Browse files Browse the repository at this point in the history
  • Loading branch information
Gordon Hollingworth committed Nov 7, 2014
1 parent c701f1f commit b5a1b68
Show file tree
Hide file tree
Showing 3 changed files with 271 additions and 0 deletions.
3 changes: 3 additions & 0 deletions test_code/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
test_code: main.c
$(CC) -g -o $@ $<

59 changes: 59 additions & 0 deletions test_code/Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Raspberry Pi Test

This code is an example Compute Module test system designed to run on a Raspberry Pi. The idea is that the
test code talks to the unit under test through the serial port on the Raspberry Pi (/dev/ttyAMA0), this requires
that the test master is not already running a getty (i.e. a login prompt) on the serial port.

## Removing the getty from the serial port

First edit /etc/inittab and remove the line near the end which spawns and getty on /dev/ttyAMA0

## Connect UUT to Raspberry Pi

Connect the Unit Under Test to the Raspberry Pi through the USB, then use the tools/usbboot to run a buildroot
fat image on the compute module. See [usbboot](../usbboot/Readme.md)

```
$ sudo rpiboot -b fatimage -x ./test_code
```

What this will do is use the USB booting mechanism to boot the UUT and run the buildroot image. When it has
finished the downloading it then runs the test_code.

## Building the test code

To build the test code just use make

```
$ make
```

## What does it do?

There are a number of important functions defined in the test code in main.c

```
char * wait(int fd, char *string);
```

This function waits for the string (string) to come in from the file descriptor fd. On return it returns a pointer
to a static buffer containing all of the text received up to and including the search string.

So you can do something like:

```
str = wait(fd, "login:");
writes(fd, "root\n");
wait(fd, "Password:");
writes(fd, "raspberry");
```

This will then log into the Linux system...

For further testing then you can add functionality to the test_set structure, the first entry in the structure
is the instruction to send to the UUT, the second entry is a string to match the output against and the
third entry is a function to call to test the output of the test. You only need to provide the string or the test
function not both (the lsusb example provides a function to search for and count the number of "DEVICE" strings
to count the number of devices. This will only actually work of course if you''ve unplugged the UUT and plugged
in a device (or forced the switch on the compute module to switch back to host mode)

209 changes: 209 additions & 0 deletions test_code/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>

#define MAX_SEARCH 100
#define SAVED_SIZE 4096

// Block waiting for input from fd
void block(int fd)
{
fd_set fds;
struct timeval tv;

FD_ZERO(&fds);
FD_SET(fd, &fds);
tv.tv_sec = 100;

select(fd+1, &fds, NULL, NULL, &tv);
}

// Receive characters from fd waiting for search_str, return string
// containing total output until that point. The returned string
// is statically allocated so does not need to be free'd
//
char * wait(int fd, char * search_str)
{
char buf[MAX_SEARCH * 2];
int bytes, offs = 0;
int i, found = 0;
static char *saved = NULL;
static long saved_size;
int buf_pos = 0;

if(saved == NULL)
{
saved = malloc(SAVED_SIZE);
saved_size = SAVED_SIZE;
}

do
{
do
{
bytes = read(fd, buf + offs, MAX_SEARCH * 2 - offs);
if(bytes == -1)
block(fd);
}
while(bytes == -1);

for(i = 0; i < bytes; i++)
{
fputc(*(buf+offs+i), stdout);
if(buf_pos == saved_size)
{
// If we run out of space in our saved buffer then double
// the buffer size, simple solution
saved = realloc(saved, saved_size * 2);
saved_size *= 2;
}
// get rid of \r\n to match the written data
if(*(buf+offs+i) != '\r')
saved[buf_pos++] = *(buf+offs+i);
}
saved[buf_pos] = '\0';

*(buf + offs + bytes) = '\0';
// Read in up to 2 x max search size, search for the string if it's not
// there then copy down the top half to the bottom. This handles the case
// where you have the search string crossing the buffer length...
if(strstr(buf, search_str))
found = 1;
offs += bytes;
if(offs > MAX_SEARCH)
{
memcpy(buf, buf + offs - MAX_SEARCH, MAX_SEARCH);
offs=0;
}
}
while(!found);

return saved;
}

int writes(int fd, char *str)
{
return write(fd, str, strlen(str));
}

// Switch into standard serial mode
// stdin -> serial out
// serial in -> stdout
void serial_mode(int fd)
{
int bytes;
char buf[256];

while(1)
{
fd_set fds;

FD_ZERO(&fds);
FD_SET(fd, &fds);
FD_SET(fileno(stdin), &fds);

// Wait for input from either serial or stdin
if(select(fd+1, &fds, NULL, NULL, NULL) < 0)
{
return;
}

if(FD_ISSET(fd, &fds))
{
bytes = read(fd, buf, sizeof(buf));
if(bytes > 0)
write(fileno(stdout), buf, bytes);
}

if(FD_ISSET(fileno(stdin), &fds))
{
bytes = read(fileno(stdin), buf, sizeof(buf));
if(bytes > 0)
write(fd, buf, bytes);
}
}

}

// The lsusb test just checks for the correct number of devices, for
// model A it should just be the root hub (since the host is plugged)
// into it...
int lsusb_test(char *str)
{
int device_count = 0;
char *p;

for(p = str; (p = strstr(p, "Device")) != NULL; p++)
device_count++;

if(device_count == 1)
return 0;

return -1;
}

typedef int (* test_check) (char *reponse);

struct test_set_s {
char *instr;
char *response;
test_check check_result;
} test_set[] =
{
{ "lsusb", NULL, lsusb_test },
};

int main(int argc, char * argv[])
{
int fd;
char *str;
int i;
int device = 0;

fd = open("/dev/ttyAMA0", O_RDWR | O_NOCTTY | O_NONBLOCK);
if(fd == -1)
{
printf("Failed to open /dev/ttyAMA0\n");
exit(-1);
}

// Wait until there is something to read from the serial port
block(fd);

// Wait for the string login: skipping everything else
wait(fd, "login:");

// Output the string root with a carriage return
writes(fd, "root\n");

wait(fd, "Password:");

writes(fd, "raspberry\n");

wait(fd, "$");

for(i = 0; i < sizeof(test_set) / sizeof(*test_set); i++)
{
int result;

// Send the test command to the UUT
writes(fd, test_set[i].instr);

// Wait for the $ (meaning the end of the command) and return all the
// string output, this can be huge if needs be
str = wait(fd, "$") + strlen(test_set[i].instr);
if(test_set[i].response)
if(strcmp(test_set[i].response, str))
result = 0;
else
result = 1;
else
result = test_set[i].check_result(str);

printf("TEST_RESULT: %s\n", result ? "FAILED" : "PASSED");
}

serial_mode(fd);
}

0 comments on commit b5a1b68

Please sign in to comment.