/* * -*- linux-c -*- * Linux Kernel Module for the Audine Camera * Copyright (C) 2001 Peter Kirchgessner * http://www.kirchgessner.net, mailto:peter@kirchgessner.net * * Modified by F. Manenti for the use in the * NOVA environment (nova.sourceforge.net) * * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * The sample interface routines for the module have been taken from the * Linux Kernel Module Programming Guide by Ori Pomerantz contained * in the Linux Documentation Project. * */ #include "audineccd.h" #include "audinelib.h" #include #include #include #include #include #include #include #include #include #include #define AUD_DEVICE_FILE "/dev/audine" #define ERRNORET(a) return (errno = a, -(a)) #define AUD_HANDLE_CHECK(a) \ { if (!(a)) ERRNORET (EINVAL); if ((a)->fd < 0) ERRNORET (EBADF); } struct aud_handle_s { int fd; int single_read; }; AUD_HANDLE aud_open(void) { AUD_HANDLE aud = (AUD_HANDLE) calloc(1, sizeof(struct aud_handle_s)); if (!aud) return 0; aud->fd = open(AUD_DEVICE_FILE, O_RDWR); if (aud->fd < 0) { free(aud); return 0; } aud->single_read = 1; return aud; } void aud_close(AUD_HANDLE aud) { if (aud) { if (aud->fd >= 0) close(aud->fd); free(aud); } } char *aud_version(const AUD_HANDLE aud) { static struct ccd_capability Info; char *version = ""; int ret; if (aud) { ret = ioctl(aud->fd, CCD_RD_VER, &Info); if (ret == 0) version = &(Info.name[0]); } return version; } int aud_clear(const AUD_HANDLE aud, int nclear) { int ret = 0; if (nclear > 0) ret = ioctl(aud->fd, CCD_CLR, &nclear); return ret; } int aud_binning_set(const AUD_HANDLE aud, int vb, int hb) { struct ccd_capability Info; AUD_HANDLE_CHECK(aud); if ((vb < 1) || (vb > 4) || (hb < 1) || (hb > 4)) ERRNORET(EINVAL); Info.width = vb; Info.height = hb; return ioctl(aud->fd, CCD_SET_BNN, &Info); } int aud_binning_get(const AUD_HANDLE aud, int *vb, int *hb) { struct ccd_capability Info; int ret; AUD_HANDLE_CHECK(aud); Info.width = 0; Info.height = 0; ret = ioctl(aud->fd, CCD_SET_BNN, &Info); if (ret != 0) return ret; if (vb) *vb = Info.width; if (hb) *hb = Info.height; return 0; } int aud_geometry_set(const AUD_HANDLE aud, int x, int y, int width, int height) { struct ccd_capability Info; AUD_HANDLE_CHECK(aud); Info.minwidth = x; Info.minheight = y; Info.width = width; Info.height = height; return ioctl(aud->fd, CCD_SET_WND, &Info); } int aud_geometry_reset(const AUD_HANDLE aud) { AUD_HANDLE_CHECK(aud); return ioctl(aud->fd, CCD_RST_WND); } int aud_geometry_get(const AUD_HANDLE aud, int *xorigin, int *yorigin, int *winwidth, int *winheight, int *color) { struct ccd_capability Info; int ret; AUD_HANDLE_CHECK(aud); ret = ioctl(aud->fd, CCD_RD_GEOM, &Info); if (ret != 0) return ret; if (xorigin) *xorigin = Info.minwidth; if (yorigin) *yorigin = Info.minheight; if (winwidth) *winwidth = Info.width; if (winheight) *winheight = Info.height; if (color) *color = Info.color; return 0; } int aud_port_set(const AUD_HANDLE aud, int base) { AUD_HANDLE_CHECK(aud); if (base <= 0) return -EINVAL; return ioctl(aud->fd, CCD_SET_PRT, &base); } int aud_port_get(const AUD_HANDLE aud, int *base) { AUD_HANDLE_CHECK(aud); if (!base) return -1; *base = 0; return ioctl(aud->fd, CCD_SET_PRT, base); } static int aud_line_ctrl_set(const AUD_HANDLE aud, int cmd, int ctrl) { AUD_HANDLE_CHECK(aud); if ((ctrl != 1) && (ctrl != 2) && (ctrl != 4) && (ctrl != 8)) ERRNORET(EINVAL); return ioctl(aud->fd, cmd, &ctrl); } static int aud_line_set(const AUD_HANDLE aud, int cmd, int on_off) { AUD_HANDLE_CHECK(aud); if (on_off != 0) on_off = 1; return ioctl(aud->fd, cmd, &on_off); } int aud_amplifier_ctrl_set(const AUD_HANDLE aud, int ctrl) { return aud_line_ctrl_set(aud, CCD_SET_AMP, ctrl); } int aud_amplifier_set(const AUD_HANDLE aud, int on_off) { return aud_line_set(aud, CCD_SWTC_AMP, on_off); } int aud_shutter_ctrl_set(const AUD_HANDLE aud, int ctrl) { return aud_line_ctrl_set(aud, CCD_SET_SHT, ctrl); } int aud_shutter_set(const AUD_HANDLE aud, int on_off) { return aud_line_set(aud, CCD_SWTC_SHT, on_off); } int aud_aux0_ctrl_set(const AUD_HANDLE aud, int ctrl) { return aud_line_ctrl_set(aud, CCD_SET_AX0, ctrl); } int aud_aux0_set(const AUD_HANDLE aud, int on_off) { return aud_line_set(aud, CCD_SWTC_AX0, on_off); } int aud_aux1_ctrl_set(const AUD_HANDLE aud, int ctrl) { return aud_line_ctrl_set(aud, CCD_SET_AX1, ctrl); } int aud_aux1_set(const AUD_HANDLE aud, int on_off) { return aud_line_set(aud, CCD_SWTC_AX1, on_off); } int aud_ccd_info_get(const AUD_HANDLE aud, char **name, int *width, int *height, int *color) { static struct ccd_capability Info; int ret; AUD_HANDLE_CHECK(aud); if ((ret = ioctl(aud->fd, CCD_RD_CHIP, &Info)) != 0) return ret; if (name) *name = Info.name; if (width) *width = Info.width; if (height) *height = Info.height; if (color) *color = Info.color; return 0; } int aud_ccd_listentry_get(const AUD_HANDLE aud, int entry, char **name, int *width, int *height, int *color) { static struct ccd_capability Info; int ret; AUD_HANDLE_CHECK(aud); Info.color = entry; if ((ret = ioctl(aud->fd, CCD_RD_CCDL, &Info)) != 0) return ret; if (name) *name = Info.name; if (width) *width = Info.width; if (height) *height = Info.height; if (color) *color = Info.color; return 0; } void aud_single_read_set(AUD_HANDLE aud, int single_read) { if (aud) aud->single_read = single_read; } int aud_image_read(const AUD_HANDLE aud, char **buf, int *bufsize, int *width, int *height, int *color) { int ret; int nbytes, nread, len; char *imgbuf; AUD_HANDLE_CHECK(aud); if ((!buf) || (!bufsize)) ERRNORET(EINVAL); if ((!width) || (!height) || (!color)) ERRNORET(EINVAL); if ((ret = aud_geometry_get(aud, 0, 0, width, height, color)) != 0) return ret; /* We get 2 bytes per pixel */ nbytes = *width * *height * 2; /* Do we have to free the user buffer ? */ if ((*bufsize < nbytes) && (*buf)) { free(*buf); *buf = 0; *bufsize = 0; } /* If buffer not supplied, allocate buffer */ if (!(*buf)) { *buf = malloc(nbytes); if (!*buf) ERRNORET(ENOMEM); *bufsize = nbytes; } /* Start reading image */ if ((ret = ioctl(aud->fd, CCD_RD_IMG)) != 0) return ret; imgbuf = *buf; while (nbytes > 0) { if (aud->single_read) { nread = nbytes; } else { nread = *width * 2; if (nread > nbytes) nread = nbytes; } len = read(aud->fd, imgbuf, nread); if (len <= 0) return -1; nbytes -= len; imgbuf += len; } return 0; } static void aud_ccdstruct_log(const char *fct, int ret, const struct ccd_capability *info) { printf("\nFunction %s returned %d\n", fct, ret); if (ret != 0) return; printf("Name : %-32s\n", info->name); printf ("Width: %-6d Height: %-6d Minwidth: %-6d Minheight: %-6d Color: %d\n", info->width, info->height, info->minwidth, info->minheight, info->color); } void aud_ioctl_test(AUD_HANDLE aud) { int ret; struct ccd_capability info; char *buf = 0, *name; int bufsize = 0, width, height, color; int j; if ((!aud) || (aud->fd < 0)) return; /* Read driver version */ ret = ioctl(aud->fd, CCD_RD_VER, &info); aud_ccdstruct_log("CCD_RD_VER", ret, &info); /* Read chip information */ ret = ioctl(aud->fd, CCD_RD_CHIP, &info); aud_ccdstruct_log("CCD_RD_CHIP", ret, &info); /* Read geometry */ ret = ioctl(aud->fd, CCD_RD_GEOM, &info); aud_ccdstruct_log("CCD_RD_GEOM", ret, &info); /* Set Window */ info.minwidth = 1; info.minheight = 2; info.width = 200; info.height = 100; ret = ioctl(aud->fd, CCD_SET_WND, &info); printf("\nCalled CCD_SET_WND: (1,2) (200,100)\n"); /* Read geometry */ ret = ioctl(aud->fd, CCD_RD_GEOM, &info); aud_ccdstruct_log("CCD_RD_GEOM", ret, &info); /* Set binning */ info.width = 2; info.height = 3; printf("\nSet binning %dx%d", info.width, info.height); ret = ioctl(aud->fd, CCD_SET_BNN, &info); aud_ccdstruct_log("CCD_SET_BNN", ret, &info); /* Read geometry */ ret = ioctl(aud->fd, CCD_RD_GEOM, &info); aud_ccdstruct_log("CCD_RD_GEOM", ret, &info); /* (Re-)Set binning */ info.width = 1; info.height = 1; printf("\nSet binning %dx%d", info.width, info.height); ret = ioctl(aud->fd, CCD_SET_BNN, &info); aud_ccdstruct_log("CCD_SET_BNN", ret, &info); /* Read geometry */ ret = ioctl(aud->fd, CCD_RD_GEOM, &info); aud_ccdstruct_log("CCD_RD_GEOM", ret, &info); /* Clear two times */ info.width = 2; printf("\nStart clear %d times\n", info.width); fflush(stdout); ret = ioctl(aud->fd, CCD_CLR, &info.width); printf("Clear finished.\n"); /* Reading */ printf("Start reading image\n"); ret = aud_image_read(aud, &buf, &bufsize, &width, &height, &color); printf ("Finished reading: ret=%d width=%d height=%d color=%d bufsize=%d\n", ret, width, height, color, bufsize); /* Set binning */ info.width = 2; info.height = 3; printf("\nSet binning %dx%d", info.width, info.height); ret = ioctl(aud->fd, CCD_SET_BNN, &info); aud_ccdstruct_log("CCD_SET_BNN", ret, &info); /* Reading */ printf("Start reading small image\n"); ret = aud_image_read(aud, &buf, &bufsize, &width, &height, &color); printf ("Finished reading: ret=%d width=%d height=%d color=%d bufsize=%d\n", ret, width, height, color, bufsize); /* Reset window */ ret = ioctl(aud->fd, CCD_RST_WND); printf("\nReset window\n"); /* Reset binning */ info.width = 1; info.height = 1; printf("\nSet binning %dx%d", info.width, info.height); ret = ioctl(aud->fd, CCD_SET_BNN, &info); aud_ccdstruct_log("CCD_SET_BNN", ret, &info); /* Read geometry */ ret = ioctl(aud->fd, CCD_RD_GEOM, &info); aud_ccdstruct_log("CCD_RD_GEOM", ret, &info); /* Reading */ printf("Start reading large image\n"); ret = aud_image_read(aud, &buf, &bufsize, &width, &height, &color); printf ("Finished reading: ret=%d width=%d height=%d color=%d bufsize=%d\n", ret, width, height, color, bufsize); /* Read current port */ ret = aud_port_get(aud, &j); printf("\naud_port_get returned with %d. Port=0x%x\n", ret, j); printf("\nList of supported CCDs:\n"); j = 0; while (aud_ccd_listentry_get(aud, j, &name, &info.width, &info.height, &info.color) == 0) { printf("%d: %s, %dx%d, %d\n", j, name, info.width, info.height, info.color); j++; } } #define FITS_WRITE_BOOLCARD(fp,key,value) \ {char card[81]; \ sprintf (card, "%-8.8s= %20s%50s", key, value ? "T" : "F", " "); \ fwrite (card, 1, 80, fp); } #define FITS_WRITE_LONGCARD(fp,key,value) \ {char card[81]; \ sprintf (card, "%-8.8s= %20ld%50s", key, (long)value, " "); \ fwrite (card, 1, 80, fp); } #define FITS_WRITE_DOUBLECARD(fp,key,value) \ {char card[81], dbl[21], *istr; \ sprintf (dbl, "%20f", (double)value); istr = strstr (dbl, "e"); \ if (istr) *istr = 'E'; \ sprintf (card, "%-8.8s= %20.20s%50s", key, dbl, " "); \ fwrite (card, 1, 80, fp); } #define FITS_WRITE_STRINGCARD(fp,key,value) \ {char card[81]; int k;\ sprintf (card, "%-8.8s= \'%s", key, value); \ for (k = strlen (card); k < 81; k++) card[k] = ' '; \ k = strlen (key); if (k < 8) card[19] = '\''; else card[11+k] = '\''; \ fwrite (card, 1, 80, fp); } #define FITS_WRITE_CARD(fp,value) \ {char card[81]; \ sprintf (card, "%-80.80s", value); \ fwrite (card, 1, 80, fp); } int audine_fits_write(const char *fname, const char *img, int width, int height) { FILE *fp; char value[50]; unsigned short *us_img = (unsigned short *) img; unsigned short *row; int x, y, high, low; long pos; time_t timp; fp = fopen(fname, "w"); if (fp) { FITS_WRITE_BOOLCARD(fp, "SIMPLE", 1); FITS_WRITE_LONGCARD(fp, "BITPIX", 16); FITS_WRITE_LONGCARD(fp, "NAXIS", 2); FITS_WRITE_LONGCARD(fp, "NAXIS1", width); FITS_WRITE_LONGCARD(fp, "NAXIS2", height); FITS_WRITE_DOUBLECARD(fp, "BZERO", 0.0); FITS_WRITE_DOUBLECARD(fp, "BSCALE", 1.0); FITS_WRITE_DOUBLECARD(fp, "DATAMIN", 0.0); FITS_WRITE_DOUBLECARD(fp, "DATAMAX", 32767.0); FITS_WRITE_CARD(fp, " "); FITS_WRITE_CARD(fp, "HISTORY THIS FILE WAS GENERATED BY AUDINELIB"); FITS_WRITE_CARD(fp, " "); timp = time(NULL); strftime(value, sizeof(value), "%d/%m/%Y", gmtime(&timp)); FITS_WRITE_STRINGCARD(fp, "DATE", value); FITS_WRITE_CARD(fp, "END"); /* Fill up primary HDU to multiple of 2880 bytes */ fflush(fp); pos = ftell(fp) % 2880; if (pos != 0) { pos = 2880 - pos; while (pos-- > 0) putc(' ', fp); } /* FITS standard requires integer data to be most significant byte first, */ /* image origin bottom left. We want to create an astronomical oriented image (top is bottom, left is right) */ for (y = 0; y < height; y++) { row = us_img + y * width; for (x = width - 1; x >= 0; x--) { high = (row[x] >> 8) & 0xff; low = (row[x] & 0xff); putc(high, fp); putc(low, fp); } } /* Fill up file to multiple of 2880 bytes */ fflush(fp); pos = ftell(fp) % 2880; if (pos != 0) { pos = 2880 - pos; while (pos-- > 0) putc(0, fp); } fclose(fp); } else { return -1; } return 0; }