pce.c
author viric <viriketo@gmail.com>
Sun, 24 Oct 2010 12:58:45 +0200
changeset 8 897b154201f8
parent 7 daa76fbc50aa
child 10 fc8a8cfe680a
permissions -rw-r--r--
More about the license, shown at program usage show.

/*
    PCE-HT71 programmer and data downloader for libusb
    Copyright (C) 2010  LluĂ­s Batlle i Rossell

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
    */
#include <usb.h>
#include <stdio.h>
#include <assert.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <time.h>

const int vendor=0x10c4;
const int product=0x0003;

usb_dev_handle *handle;
struct usb_device *device;

int ep_in = 1;
int ep_out = 2;

enum
{
    HELP,
    SET,
    DOWNLOAD
} action;

struct
{
    int nsamples;
    int time_per_sample;
    int immediate;
    char *download_file;
} config;

FILE *outfile;

int connect()
{
    struct usb_bus *bus;
    bus = usb_get_busses();

    while (bus != 0)
    {
        struct usb_device *dev;
        dev = bus->devices;
        while(dev != 0)
        {
            if (dev->descriptor.idVendor == vendor
                && dev->descriptor.idProduct == product)
            {
                handle = usb_open(dev);
                device = dev;
                return 0;
            }
            dev = dev->next;
        }
        bus = bus->next;
    }

    handle = 0;
    return -1;
}

int send_program()
{
    int res;
    res = usb_bulk_write(handle, ep_out, "\x01\x40\x00", 3, 1000);
    assert(res == 3);
}

int send_config()
{
    int res;
    char buf[64];
    struct tm *t;
    time_t tmp_time;
    tmp_time = time(NULL);
    t = localtime(&tmp_time);

    buf[0] = '\xce';
    buf[1] = 0;
    buf[2] = 0;
    buf[3] = 0;

    // Samples
    *( (int *) &buf[4]) = config.nsamples;
    // Samples got
    *( (int *) &buf[8]) = 0;
    // Sample rate
    *( (int *) &buf[12]) = config.time_per_sample;
    // Year
    *( (int *) &buf[16]) = t->tm_year + 1900;
    // Mintemp
    buf[20] = 0;
    buf[21] = 0;
    *( (short int *) &buf[22]) = 0x4120;
    // Maxtemp
    buf[24] = 0;
    buf[25] = 0;
    *( (short int *) &buf[26]) = 0x41a0;

    // Month
    buf[28] = t->tm_mon;
    // Day
    buf[29] = t->tm_mday;
    // hour
    buf[30] = t->tm_hour;
    // Minute
    buf[31] = t->tm_min;
    // second
    buf[32] = t->tm_sec;
    // Celsius (1 F)
    buf[33] = 0;
    // Pause between leds (300s)
    buf[34] = 0x1e;
    // Name
    buf[35] = 'A';
    buf[36] = '0';

    // Immediate
    buf[51] = config.immediate ? 2 : 1;
    // Minhum
    buf[52] = 0;
    buf[53] = 0;
    *( (short int *) &buf[54]) = 0x410f;
    // Maxhum
    buf[56] = 0;
    buf[57] = 0;
    *( (short int *) &buf[58]) = 0x4296;
    // final
    buf[60] = 0xce;
    buf[61] = 0x0;
    buf[62] = 0x0;
    buf[63] = 0x0;

    res = usb_bulk_write(handle, ep_out, buf, 64, 1000);
    assert(res == 64);

    res = usb_bulk_read(handle, ep_in, buf, 1, 1000);
    assert(res == 1);
}

void parse_data(char *data)
{
    fprintf(outfile, "# Start: %hi-%hhi-%hhi %hhi:%hhi:%hhi\n",
            *((short int *) (data + 16)),
            *((unsigned char *) (data + 28)),
            *((unsigned char *) (data + 29)),
            *((unsigned char *) (data + 30)),
            *((unsigned char *) (data + 31)),
            *((unsigned char *) (data + 32)));
    fprintf(outfile, "# Num Samples: %hi\n",
            *((short int *) (data + 8))
            );
    fprintf(outfile, "# Time between samples: %hi s\n",
            *((short int *) (data + 12))
            );
}

int
start_download()
{
    int res;

    res = usb_bulk_write(handle, ep_out, "\x00\x10\x01", 3, 1000);
    assert(res == 3);

    char data[100];
    res = usb_bulk_read(handle, ep_in, data, 3, 1000);
    assert(res == 3);
    fprintf(stderr, "Debug: %02hhx%02hhx%02hhx\n", data[0], data[1], data[2]);
    assert(data[0] == 2);

    int num = *((short int*) &data[1]);
    fprintf(stderr, "Found %i bytes = %i samples\n", num, num/4);

    if (num > 0)
    {
        int num_frames = (num + 63) / 64;
        fprintf(stderr, "%i frames\n", num_frames);

        /*
        res = usb_bulk_write(handle, ep_out, "\x00\x00\x01", 3, 1000);
        assert(res == 3);
        */

        res = usb_bulk_read(handle, ep_in, data, 64, 1000);
        assert(res == 64);

        parse_data(data);

        char frame[3];
        frame[0] = 0;
        frame[1] = 0;
        frame[2] = num_frames;

        res = usb_bulk_write(handle, ep_out, frame, 3, 1000);
        assert(res == 3);

        res = usb_bulk_read(handle, ep_in, data, 3, 1000);
        assert(res == 3);
        fprintf(stderr, "Debug: %02hhx%02hhx%02hhx\n", data[0], data[1], data[2]);
        assert(data[0] == 2);

        int i;
        int sec = 0;
        for(i=0; i < num_frames; ++i)
        {
            res = usb_bulk_read(handle, ep_in, data, 64, 1000);
            assert(res == 64);
            int take = (num >= 64) ? 64 : num;

            int j;
            for(j=0; j<take; j+=4)
            {
                float temp = *((short int *) (data + j)) / 10.;
                float hum = *((short int *) (data + j + 2)) / 10.;
                fprintf(outfile, "%i %g %g\n", sec, temp, hum);
                sec++;
            }
            num -= 64;
        }
    }
}

void
usage()
{
    fprintf(stderr, "pce v0.1 - PCE-HT71 programmer and data downloader\n");
    fprintf(stderr, "Copyright (C) 2010  Lluis Batlle i Rossell\n");
    fprintf(stderr, "This program comes with ABSOLUTELY NO WARRANTY.\n");
    fprintf(stderr, "This is free software, and you are welcome to redistribute it\n");
    fprintf(stderr, "under certain conditions; type `show c' for details.\n");
    fprintf(stderr, "\nusage: pce [-n maxsamples] [-t timepersample] [-i] <-d downloadfile | -s>\n");
}

int main(int argc, char **argv)
{
    int res;
    int opt;

    config.nsamples = 16000;
    config.immediate = 0;
    config.time_per_sample = 2;
    config.download_file = 0;
    action = HELP;
    while  ((opt = getopt(argc, argv, "n:d:t:si")) != -1) {
        switch (opt) {
            case 'n':
                config.nsamples = atoi(optarg);
                break;
            case 't':
                config.time_per_sample = atoi(optarg);
                break;
            case 'd':
                config.download_file = optarg;
                action = DOWNLOAD;
                break;
            case 's':
                action = SET;
                break;
            case 'i':
                config.immediate = 1;
                break;
            default:
                usage();
                return 1;
        }
    }

    if (action == HELP)
    {
        usage();
        return 0;
    }

    usb_init();

    usb_find_busses();
    usb_find_devices();
    
    connect();
    if (handle == 0)
    {
        fprintf(stderr, "Cannot find the PCE-HT71\n");
        return -1;
    }

    res = usb_claim_interface(handle,
        device->config->interface->altsetting->bInterfaceNumber);
    assert(res == 0 && "claim_interface");

    if (action == SET)
    {
        fprintf(stderr, "Settings: \n");
        fprintf(stderr, " Max samples: %i\n", config.nsamples);
        fprintf(stderr, " Time between samples: %i\n", config.time_per_sample);
        fprintf(stderr, " Mode: %s\n", config.immediate ? "immediate" : "manual");
        send_program();
        send_config();
    }
    else
    {
        outfile = fopen(config.download_file, "w");
        if (outfile != NULL)
        {
            start_download();
            fprintf(stderr, "File \"%s\" written\n", config.download_file);
            fclose(outfile);
        }
        else
        {
            fprintf(stderr, "Error opening file: %s", strerror(errno));
        }
    }

    res = usb_release_interface(handle,
        device->config->interface->altsetting->bInterfaceNumber);
    assert(res == 0 && "release_interface");
    usb_close(handle);
    handle = 0;
    return 0;
}