d81d1a80a91c492fda3386a776bc176cd7d17afc
[libam7xxx.git] / am7xxx.c
1 /* am7xxx - communication with AM7xxx based USB Pico Projectors and DPFs
2  *
3  * Copyright (C) 2011  Antonio Ospite <ospite@studenti.unina.it>
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18
19 #include <stdio.h>
20 #include <endian.h>
21 #include <errno.h>
22
23 #include "am7xxx.h"
24
25 #define AM7XXX_VENDOR_ID  0x1de1
26 #define AM7XXX_PRODUCT_ID 0xc101
27
28 #if 1
29 static uint8_t reference_image_header[] = {
30         0x02, 0x00, 0x00, 0x00,
31         0x00,
32         0x10,
33         0x3e,
34         0x10,
35         0x01, 0x00, 0x00, 0x00,
36         0x20, 0x03, 0x00, 0x00,
37         0xe0, 0x01, 0x00, 0x00,
38         0x53, 0xE8, 0x00, 0x00
39 };
40 #endif
41
42 static void dump_image_header(struct am7xxx_image_header *i)
43 {
44         if (i == NULL)
45                 return;
46
47         printf("Image header:\n");
48         printf("format:      0x%08x (%u)\n", i->format, i->format);
49         printf("width:       0x%08x (%u)\n", i->width, i->width);
50         printf("height:      0x%08x (%u)\n", i->height, i->height);
51         printf("image size:  0x%08x (%u)\n", i->image_size, i->image_size);
52 }
53
54 static void dump_header(struct am7xxx_header *h)
55 {
56         if (h == NULL)
57                 return;
58
59         printf("packet_type: 0x%08x (%u)\n", h->packet_type, h->packet_type);
60         printf("unknown0:    0x%02hhx (%hhu)\n", h->unknown0, h->unknown0);
61         printf("header_len:  0x%02hhx (%hhu)\n", h->header_len, h->header_len);
62         printf("unknown2:    0x%02hhx (%hhu)\n", h->unknown2, h->unknown2);
63         printf("unknown3:    0x%02hhx (%hhu)\n", h->unknown3, h->unknown3);
64
65         switch(h->packet_type) {
66         case AM7XXX_PACKET_TYPE_IMAGE:
67                 dump_image_header(&(h->header_data.image));
68                 break;
69
70         default:
71                 printf("Packet type not supported!\n");
72                 break;
73         }
74
75         fflush(stdout);
76 }
77
78 static inline unsigned int in_80chars(unsigned int i)
79 {
80         return ((i+1) % (80/3));
81 }
82
83 static void dump_buffer(uint8_t *buffer, unsigned int len)
84 {
85         unsigned int i;
86
87         if (buffer == NULL || len == 0)
88                 return;
89
90         for (i = 0; i < len; i++) {
91                 printf("%02hhX%c", buffer[i], (in_80chars(i) && (i < len - 1)) ? ' ' : '\n');
92         }
93         fflush(stdout);
94 }
95
96 static int send_data(am7xxx_device dev, uint8_t *buffer, unsigned int len)
97 {
98         int ret;
99         int transferred;
100
101         dump_buffer(buffer, len);
102
103         ret = libusb_bulk_transfer(dev, 1, buffer, len, &transferred, 0);
104         if (ret != 0 || (unsigned int)transferred != len) {
105                 fprintf(stderr, "Error: ret: %d\ttransferred: %d (expected %u)\n",
106                         ret, transferred, len);
107                 return ret;
108         }
109
110         return 0;
111 }
112
113 static int send_header(am7xxx_device dev, struct am7xxx_header *h)
114 {
115         union {
116                 struct am7xxx_header header;
117                 uint8_t buffer[sizeof (struct am7xxx_header)];
118         } data;
119
120         data.header = *h;
121
122         return send_data(dev, data.buffer, sizeof (struct am7xxx_header));
123 }
124
125 am7xxx_device am7xxx_init(void)
126 {
127         am7xxx_device dev;
128
129         libusb_init(NULL);
130         libusb_set_debug(NULL, 3);
131
132         dev = libusb_open_device_with_vid_pid(NULL,
133                                               AM7XXX_VENDOR_ID,
134                                               AM7XXX_PRODUCT_ID);
135         if (dev == NULL) {
136                 errno = ENODEV;
137                 perror("libusb_open_device_with_vid_pid");
138                 goto out_libusb_exit;
139         }
140
141         libusb_set_configuration(dev, 1);
142         libusb_claim_interface(dev, 0);
143
144         return dev;
145
146 out_libusb_exit:
147         libusb_exit(NULL);
148         return NULL;
149 }
150
151 void am7xxx_shutdown(am7xxx_device dev)
152 {
153         if (dev) {
154                 libusb_close(dev);
155                 libusb_exit(NULL);
156         }
157 }
158
159 int am7xxx_send_image(am7xxx_device dev,
160                       am7xxx_image_format format,
161                       unsigned int width,
162                       unsigned int height,
163                       uint8_t *image,
164                       unsigned int size)
165 {
166         int ret;
167         struct am7xxx_header h = {
168                 .packet_type = htole32(AM7XXX_PACKET_TYPE_IMAGE),
169                 .unknown0    = 0x00,
170                 .header_len  = sizeof(struct am7xxx_image_header),
171                 .unknown2    = 0x3e,
172                 .unknown3    = 0x10,
173                 .header_data = {
174                         .image = {
175                                 .format     = htole32(format),
176                                 .width      = htole32(width),
177                                 .height     = htole32(height),
178                                 .image_size = htole32(size),
179                         },
180                 },
181         };
182
183         dump_header(&h);
184         printf("\n");
185
186         printf("Dump Buffers\n");
187         dump_buffer(reference_image_header, sizeof(struct am7xxx_header));
188
189         ret = send_header(dev, &h);
190         if (ret < 0)
191                 return ret;
192
193         if (image == NULL || size == 0)
194                 return 0;
195
196         return send_data(dev, image, size);
197 }