1 #ifndef LINT
2 static char *rcsid="$Id: eph_cmd.c,v 1.20 2001/08/28 06:28:01 crosser Exp $";
3 #endif
4 
5 /*
6 	Copyright (c) 1997-2000 Eugene G. Crosser
7 	Copyright (c) 1998 Bruce D. Lightner (DOS/Windows support)
8 
9 	You may distribute and/or use for any purpose modified or unmodified
10 	copies of this software if you preserve the copyright notice above.
11 
12 	THIS SOFTWARE IS PROVIDED AS IS AND COME WITH NO WARRANTY OF ANY
13 	KIND, EITHER EXPRESSED OR IMPLIED.  IN NO EVENT WILL THE
14 	COPYRIGHT HOLDER BE LIABLE FOR ANY DAMAGES RESULTING FROM THE
15 	USE OF THIS SOFTWARE.
16 */
17 
18 /*
19 	$Log: eph_cmd.c,v $
20 	Revision 1.20  2001/08/28 06:28:01  crosser
21 	try make zoom working on newer Oly
22 
23 	Revision 1.19  2000/05/09 13:20:54  crosser
24 	configure read() with alarm() better.
25 	Address signed vs. unsigned arguments
26 	other cleanups to make most notorious compilers happy
27 
28 	Revision 1.18  2000/05/02 22:26:35  crosser
29 	A few things incorporated from John Bowman's Nikon specific diffs
30 
31 	Revision 1.17  2000/05/02 12:13:32  crosser
32 	some better debugging output
33 	alarm() based timeouted read (build with "--without-select")
34 
35 	Revision 1.16  2000/02/13 11:15:01  crosser
36 	Kludge null setint for Nikon
37 
38 	Revision 1.15  1999/08/01 21:36:54  crosser
39 	Modify source to suit ansi2knr
40 	(I hate the style that ansi2knr requires but you don't expect me
41 	to write another smarter ansi2knr implementation, right?)
42 
43 	Revision 1.14  1999/07/28 19:56:31  crosser
44 	reorder includes
45 
46 	Revision 1.13  1999/03/21 20:22:09  crosser
47 	change retry logic for first block (for Agfa 307)
48 
49 	Revision 1.12  1999/03/06 13:37:08  crosser
50 	Convert to autoconf-style
51 
52 	Revision 1.11  1999/01/21 09:12:56  crosser
53 	fix of retry logic from Richard Sharman
54 
55 	Revision 1.10  1998/10/18 13:18:27  crosser
56 	Put RCS logs and I.D. into the source
57 
58 	Revision 1.9  1998/08/09 13:24:59  crosser
59 	cleanup for DOS
60 
61 	Revision 1.8  1998/08/09 12:57:56  crosser
62 	make right running report on 16bit architecture
63 
64 	Revision 1.7  1998/02/26 00:50:39  crosser
65 	extra error message
66 
67 	Revision 1.6  1998/02/16 06:15:44  lightner
68 	Parameterize tmpbuf size; fix tmpbuf memory leak
69 
70 	Revision 1.5  1998/02/08 19:58:38  crosser
71 	Support low memory: chunked saving etc.
72 
73 	Revision 1.4  1998/02/05 23:29:17  lightner
74 	Force 32-bit math in eph_getint()
75 	Only realloc() an extra 2048 bytes when buffer too small (DOS only)
76 
77 	Revision 1.3  1998/01/27 21:52:23  crosser
78 	add NANOSLEEP
79 
80 	Revision 1.2  1998/01/18 02:16:45  crosser
81 	DOS support
82 
83 	Revision 1.1  1997/08/17 08:59:54  crosser
84 	Initial revision
85 
86 */
87 
88 #ifdef HAVE_CONFIG_H
89 #include "config.h"
90 #endif
91 #include <stdio.h>
92 #include "eph_io.h"
93 #include "eph_priv.h"
94 
95 #define TMPBUF_SIZE (2048)
96 
97 #define MAYRETRY(rc) ((rc == -2) || (rc == NAK))
98 
99 int
eph_writecmd(eph_iob * iob,char * data,size_t length)100 eph_writecmd(eph_iob *iob,char *data,size_t length)
101 {
102 	return eph_writepkt(iob,PKT_CMD,SEQ_CMD,data,length);
103 }
104 
105 int
eph_writeicmd(eph_iob * iob,char * data,size_t length)106 eph_writeicmd(eph_iob *iob,char *data,size_t length)
107 {
108 	return eph_writepkt(iob,PKT_CMD,SEQ_INITCMD,data,length);
109 }
110 
111 int
eph_setispeed(eph_iob * iob,long val)112 eph_setispeed(eph_iob *iob,long val)
113 {
114 	unsigned char buf[6];
115 	int rc;
116 	int count=0;
117 
118 	buf[0]=CMD_SETINT;
119 	buf[1]=REG_SPEED;
120 	buf[2]=(val)&0xff;
121 	buf[3]=(val>>8)&0xff;
122 	buf[4]=(val>>16)&0xff;
123 	buf[5]=(val>>24)&0xff;
124 	do {
125 		if ((rc=eph_writeicmd(iob,buf,6))) return rc;
126 		rc=eph_waitack(iob,ACKTIMEOUT);
127 	} while (rc && (count++ < RETRIES));
128 	if (count >= RETRIES)
129 		eph_error(iob,ERR_EXCESSIVE_RETRY,
130 				"excessive retries on setispeed");
131 	if (iob->debug) printf("setispeed(%ld) rc=%d\n",val,rc);
132 	return rc;
133 }
134 
135 int
eph_setint(eph_iob * iob,int reg,long val)136 eph_setint(eph_iob *iob,int reg,long val)
137 {
138 	unsigned char buf[6];
139 	int rc;
140 	int count=0;
141 
142 	buf[0]=CMD_SETINT;
143 	buf[1]=reg;
144 	buf[2]=(val)&0xff;
145 	buf[3]=(val>>8)&0xff;
146 	buf[4]=(val>>16)&0xff;
147 	buf[5]=(val>>24)&0xff;
148 
149 writeagain:
150 	if ((rc=eph_writecmd(iob,buf,6))) return rc;
151 	rc=eph_waitack(iob,(reg == REG_FRAME)?BIGACKTIMEOUT:ACKTIMEOUT);
152 	if (MAYRETRY(rc) && (count++ < RETRIES)) goto writeagain;
153 	if (count >= RETRIES)
154 		eph_error(iob,ERR_EXCESSIVE_RETRY,
155 				"excessive retries on setint");
156 	if (iob->debug) printf("setint(%d,%ld) rc=%d\n",reg,val,rc);
157 	return rc;
158 }
159 
160 int
eph_setnullint(eph_iob * iob,int reg)161 eph_setnullint(eph_iob *iob,int reg)
162 {
163 	unsigned char buf[2];
164 	int rc;
165 	int count=0;
166 
167 	buf[0]=CMD_SETINT;
168 	buf[1]=reg;
169 
170 writeagain:
171 	if ((rc=eph_writecmd(iob,buf,2))) return rc;
172 	rc=eph_waitack(iob,(reg == REG_FRAME)?BIGACKTIMEOUT:ACKTIMEOUT);
173 	if (MAYRETRY(rc) && (count++ < RETRIES)) goto writeagain;
174 	if (count >= RETRIES)
175 		eph_error(iob,ERR_EXCESSIVE_RETRY,
176 				"excessive retries on setnullint");
177 	if (iob->debug) printf("setnullint(%d) rc=%d\n",reg,rc);
178 	return rc;
179 }
180 
181 int
eph_getint(eph_iob * iob,int reg,long * val)182 eph_getint(eph_iob *iob,int reg,long *val)
183 {
184 	unsigned char buf[4];
185 	eph_pkthdr pkt;
186 	int rc;
187 	size_t size=4;
188 	int count=0;
189 
190 	(*val)=0L;
191 	buf[0]=CMD_GETINT;
192 	buf[1]=reg;
193 
194 writeagain:
195 	if ((rc=eph_writecmd(iob,buf,2))) return rc;
196 readagain:
197 	rc=eph_readpkt(iob,&pkt,buf,&size,BIGDATATIMEOUT);
198 	if (MAYRETRY(rc) && (count++ < RETRIES)) goto writeagain;
199 	if ((rc == 0) && (pkt.typ == PKT_LAST) && (pkt.seq == 0)) {
200 		(*val)=((unsigned long)buf[0]) | ((unsigned long)buf[1]<<8) |
201 			((unsigned long)buf[2]<<16) | ((unsigned long)buf[3]<<24);
202 		eph_writeack(iob);
203 		rc=0;
204 		goto fin;
205 	} else if ((rc == -1) && (count++ < RETRIES)) {
206 		eph_writenak(iob);
207 		goto readagain;
208 	}
209 	if (count >= RETRIES)
210 		eph_error(iob,ERR_EXCESSIVE_RETRY,
211 				"excessive retries on getint");
212 fin:
213 	if (iob->debug) printf("getint(%d)=%ld, rc=%d\n",reg,*val,rc);
214 	return rc;
215 }
216 
217 int
eph_action(eph_iob * iob,int reg,char * val,size_t length)218 eph_action(eph_iob *iob,int reg,char *val,size_t length)
219 {
220 	unsigned char buf[2050];
221 	int rc;
222 	int count=0;
223 
224 	if (length > (sizeof(buf) - 2)) {
225 		eph_error(iob,ERR_DATA_TOO_LONG,"arg action length %ld",
226 				(long)length);
227 		return -1;
228 	}
229 
230 	buf[0]=CMD_ACTION;
231 	buf[1]=reg;
232 	memcpy(buf+2,val,length);
233 
234 writeagain:
235 	if ((rc=eph_writecmd(iob,buf,length+2))) return rc;
236 	rc=eph_waitack(iob,ACKTIMEOUT);
237 
238 	if (MAYRETRY(rc) && (count++ < RETRIES)) goto writeagain;
239 
240 	if (rc == 0) rc=eph_waitcomplete(iob);
241 	if (count >= RETRIES)
242 		eph_error(iob,ERR_EXCESSIVE_RETRY,
243 				"excessive retries on action");
244 	if (iob->debug) printf("action(%d,%p(0x%02x),%u) rc=%d\n",
245 				reg,val,
246 				(length==1)?(val[0]&0xff):0,
247 				(unsigned int)length,rc);
248 	return rc;
249 }
250 
251 int
eph_setvar(eph_iob * iob,int reg,char * val,off_t olength)252 eph_setvar(eph_iob *iob,int reg,char *val,off_t olength)
253 {
254 	unsigned char buf[2048];
255 	int rc=0,seq=-1;
256 	int count=0;
257 	int pkttyp,pktseq;
258 	size_t pktsize,maywrite;
259 	off_t written=0;
260 	off_t length=olength;
261 	unsigned char *getpoint,*putpoint;
262 
263 	getpoint=val;
264 	while (length && !rc) {
265 		if (seq == -1) {
266 			pkttyp=PKT_CMD;
267 			pktseq=SEQ_CMD;
268 			buf[0]=CMD_SETVAR;
269 			buf[1]=reg;
270 			putpoint=buf+2;
271 			maywrite=sizeof(buf)-2;
272 			pktsize=2;
273 		} else {
274 			pkttyp=PKT_DATA;
275 			pktseq=seq;
276 			putpoint=buf;
277 			maywrite=sizeof(buf);
278 			pktsize=0;
279 			(iob->runcb)(written);
280 		}
281 		if ((size_t)length <= maywrite) {
282 			maywrite=length;
283 			if (pkttyp == PKT_DATA) pkttyp=PKT_LAST;
284 		}
285 		memcpy(putpoint,getpoint,maywrite);
286 		pktsize+=maywrite;
287 		length-=maywrite;
288 		getpoint+=maywrite;
289 		written+=maywrite;
290 		seq++;
291 writeagain:
292 		if ((rc=eph_writepkt(iob,pkttyp,pktseq,buf,pktsize)))
293 			goto fin;
294 		rc=eph_waitack(iob,(reg==REG_ZOOM)?BIGACKTIMEOUT:ACKTIMEOUT);
295 		if (MAYRETRY(rc) && (count++ < RETRIES)) goto writeagain;
296 	}
297 	if (count >= RETRIES)
298 		eph_error(iob,ERR_EXCESSIVE_RETRY,
299 				"excessive retries on setvar");
300 fin:
301 	if (iob->debug) printf("setvar(%d,\"%.60s\",%lu) rc=%d\n",
302 				reg,val,(unsigned long)olength,rc);
303 	return rc;
304 }
305 
306 int
eph_getvar(eph_iob * iob,int reg,char ** buffer,off_t * bufsize)307 eph_getvar(eph_iob *iob,int reg,char **buffer,off_t *bufsize)
308 {
309 	unsigned char buf[2];
310 	eph_pkthdr pkt;
311 	int rc;
312 	int count=0;
313 	unsigned char expect=0;
314 	off_t index;
315 	size_t readsize;
316 	char *ptr;
317 	char *tmpbuf=NULL;
318 	size_t tmpbufsize=0;
319 
320 	if ((buffer == NULL) && (iob->storecb == NULL)) {
321 		eph_error(iob,ERR_BADARGS,
322 			"NULL buffer and no store callback for getvar");
323 		return -1;
324 	}
325 
326 	if (buffer == NULL) {
327 		tmpbuf=(iob->realloccb)(NULL,(size_t)TMPBUF_SIZE);
328 		tmpbufsize=TMPBUF_SIZE;
329 		if (tmpbuf == NULL) {
330 			eph_error(iob,ERR_NOMEM,
331 				"could not alloc %lu for tmpbuf in getvar",
332 				(long)TMPBUF_SIZE);
333 			return -1;
334 		}
335 	}
336 
337 	buf[0]=CMD_GETVAR;
338 	buf[1]=reg;
339 
340 writeagain:
341 	if ((rc=eph_writecmd(iob,buf,2))) return rc;
342 	index=0;
343 readagain:
344 	if (buffer) { /* read to memory reallocating it */
345 		if (((*bufsize) - index) < 2048) {
346 			if (iob->debug)
347 				printf("reallocing %lu",(unsigned long)(*bufsize));
348 #ifdef LOWMEMORY
349 			/* small memory! round up to next 2048 boundary */
350 			(*bufsize)=(((index + 2048)-1)/2048L+1)*2048L;
351 #else
352 			/* multiply current size by 2 and round up to 2048 boundary */
353 			(*bufsize)=((((*bufsize)*2)-1)/2048+1)*2048;
354 #endif
355 			if (iob->debug)
356 				printf(" -> %lu\n",(unsigned long)(*bufsize));
357 			(*buffer)=(iob->realloccb)(*buffer,(size_t)*bufsize);
358 			if ((*buffer) == NULL) {
359 				eph_error(iob,ERR_NOMEM,
360 					"could not realloc %lu for getvar",
361 					(long)*bufsize);
362 				return -1;
363 			}
364 		}
365 		ptr=(*buffer)+index;
366 		readsize=(*bufsize)-index;
367 	} else { /* pass data to store callback */
368 		ptr=tmpbuf;
369 		readsize=tmpbufsize;
370 	}
371 	rc=eph_readpkt(iob,&pkt,ptr,&readsize,
372 			(expect || ((reg != REG_IMG) || (reg != REG_TMN)))?
373 						DATATIMEOUT:BIGDATATIMEOUT);
374 	if (MAYRETRY(rc) && (expect == 0) && (count++ < RETRIES)) {
375 		eph_writenak(iob);
376 		if (rc == -2) goto readagain;
377 		else goto writeagain;
378 	}
379 	if ((rc == 0) &&
380 	    ((pkt.seq == expect) || (pkt.seq  == (expect-1)))) {
381 		count=0;
382 		if (pkt.seq == expect) {
383 			index+=readsize;
384 			expect++;
385 			(iob->runcb)(index);
386 			if (buffer == NULL) {
387 				if (iob->debug)
388 					printf("storing %lu at %08lx\n",
389 						(unsigned long)readsize,
390 						(unsigned long)ptr);
391 				if ((iob->storecb)(ptr,readsize))
392 					return -1;
393 			}
394 		}
395 		eph_writeack(iob);
396 		if (pkt.typ == PKT_LAST) {
397 			if (buffer) (*bufsize)=index;
398 			if (tmpbuf) free(tmpbuf);
399 			return 0;
400 		}
401 		else goto readagain;
402 	}
403 	if ((rc <= 0) && (count++ < RETRIES)) {
404 		eph_writenak(iob);
405 		goto readagain;
406 	}
407 	if (tmpbuf) free(tmpbuf);
408 	if (count >= RETRIES)
409 		eph_error(iob,ERR_EXCESSIVE_RETRY,
410 				"excessive retries on getvar");
411 	if (iob->debug) printf("getvar(%d) got %lu, rc=%d\n",
412 				reg,(unsigned long)(*bufsize),rc);
413 	return rc;
414 }
415