[Vm-dev] [commit][3045] add unix plugins for Pi/Scratch - Camera,
Scratch, Unicode
commits at squeakvm.org
commits at squeakvm.org
Wed Jul 16 23:09:05 UTC 2014
Revision: 3045
Author: rowledge
Date: 2014-07-16 16:09:05 -0700 (Wed, 16 Jul 2014)
Log Message:
-----------
add unix plugins for Pi/Scratch - Camera, Scratch, Unicode
Added Paths:
-----------
branches/Cog/platforms/unix/plugins/CameraPlugin/
branches/Cog/platforms/unix/plugins/CameraPlugin/README.CameraPlugin
branches/Cog/platforms/unix/plugins/CameraPlugin/sqCamera-linux.c
branches/Cog/platforms/unix/plugins/GdbARMPlugin/
branches/Cog/platforms/unix/plugins/GdbARMPlugin/Makefile.inc
branches/Cog/platforms/unix/plugins/ScratchPlugin/
branches/Cog/platforms/unix/plugins/ScratchPlugin/unixScratchOps.c
branches/Cog/platforms/unix/plugins/ScratchPlugin/unixSeriaPort2Ops.c
branches/Cog/platforms/unix/plugins/UnicodePlugin/
branches/Cog/platforms/unix/plugins/UnicodePlugin/Makefile.inc
branches/Cog/platforms/unix/plugins/UnicodePlugin/README.UnicodePlugin
branches/Cog/platforms/unix/plugins/UnicodePlugin/UnicodeOps-linux.c
branches/Cog/platforms/unix/plugins/UnicodePlugin/acinclude.m4
Added: branches/Cog/platforms/unix/plugins/CameraPlugin/README.CameraPlugin
===================================================================
--- branches/Cog/platforms/unix/plugins/CameraPlugin/README.CameraPlugin (rev 0)
+++ branches/Cog/platforms/unix/plugins/CameraPlugin/README.CameraPlugin 2014-07-16 23:09:05 UTC (rev 3045)
@@ -0,0 +1,43 @@
+CameraPlugin, 17th May 2010 11:00:00
+
+- Rewrote for more general use (Squeak, Etoys, XO, etc)
+
+- Supports multiple simultaneously open cameras
+
+- Dependency on libv4l2 dropped but...
+
+- Code now attempts to open libv4l2 and uses it available
+
+- Additional pixel format conversions (if no libv4l2)
+
+- Redesigned so future version can do frame skipping without
+ incurring conversion delays on skipped frames. To support
+ this the Scratch API would need to change...
+
+ CameraGetFrame(int camNum, unsigned char* buf, int pixelCount)
+
+ to...
+
+ CameraGetFrame(int camNum, unsigned char* buf, int pixelCount, int skipFrameCount)
+
+- Why is frame skipping required? To support "snapshot" type
+ use-cases such as the following and particularly when the
+ camera would be shut down between uses to preserve power:
+
+ - taking a picture at any ad hoc moment,
+ - taking a picture at a specific/precise time,
+ - taking a picture at periodically, eg, time-lapse photgraphy
+
+ Webcams are generally designed for streaming and drivers
+ typically use various degrees of buffering to improve
+ performance. Buffering can mean that, eg, a five second
+ time-lapse captured image could actually be five, ten or
+ more seconds old. In one such test I needed to skip 20
+ frames to get the latest one! Some cameras/ drivers are
+ designed for this type of operation but "CameraPlugin"
+ is being specifically designed for maximum general use
+ across various hw platforms and many different types of
+ camera.
+
+- More info: http://info.scratch.mit.edu/Linux_installer/Linux_Camera_Plug-in
+
Added: branches/Cog/platforms/unix/plugins/CameraPlugin/sqCamera-linux.c
===================================================================
--- branches/Cog/platforms/unix/plugins/CameraPlugin/sqCamera-linux.c (rev 0)
+++ branches/Cog/platforms/unix/plugins/CameraPlugin/sqCamera-linux.c 2014-07-16 23:09:05 UTC (rev 3045)
@@ -0,0 +1,900 @@
+/* sqCamera-linux.c -- plugin for hardware camera on Linux
+ *
+ * Author: Derek O'Connell <doc at doconnel.f9.co.uk>
+ *
+ * Copyright (C) 2010 by Derek O'Connel
+ * All rights reserved.
+ *
+ * This file is part of Unix Squeak.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Last edited: 2012-07-30 14:59:01 by piumarta on emilia
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include <getopt.h>
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include <dlfcn.h>
+
+#include <asm/types.h> /* for videodev2.h */
+
+#include <linux/videodev2.h>
+
+
+#define sqInt int
+#define true 1
+#define false 0
+
+
+/* >>>>> USE_TEST_PATTERN >>>>
+/
+/ Helps check Squeak is capturing and displaying the
+/ latest frame. See CameraGetFrame() which will
+/ return single colour frames in the sequence RGB.
+/
+/ Remove the "x" to enable...
+*/
+
+#define USE_TEST_PATTERNx
+
+#ifdef USE_TEST_PATTERN
+ static int tstColourIdx = 0;
+#endif
+
+
+/* >>>>> LIBV4L2 USAGE >>>>>
+/
+/ Attempting to get best-of-all-worlds so
+/ explicitly loading libv4l2 if available
+/ to avoid build-time dependency.
+/
+*/
+
+void *hLibv4l2 = NULL;
+
+int (*vd_open)(const char *, int, ...);
+int (*vd_close)(int);
+int (*vd_dup)(int);
+int (*vd_ioctl)(int, unsigned long int, ...);
+ssize_t (*vd_read)(int, void *, size_t);
+void * (*vd_mmap)(void *, size_t, int, int, int, int64_t);
+int (*vd_munmap)(void *, size_t);
+
+
+/* >>>>>>> MULTI-CAMERA SUPPORT >>>>> */
+
+#define CLEAR(x) memset (&(x), 0, sizeof (x))
+
+typedef enum {
+ IO_METHOD_READ,
+ IO_METHOD_MMAP,
+ IO_METHOD_USERPTR,
+} io_method;
+
+struct buffer {
+ void * start;
+ size_t length;
+};
+
+struct camInfo_t {
+ unsigned int isOpen;
+ unsigned int devNum;
+ int fileDesc;
+ unsigned int bmWidth, bmHeight;
+
+ io_method ioMethod;
+ int pixelformat;
+ struct buffer *buffers;
+ unsigned int nBuffers;
+
+ struct v4l2_buffer vBuf;
+ void *inBuffer;
+ unsigned long inBufferSize;
+
+ void *sqBuffer;
+ unsigned long sqBufferBytes;
+ unsigned long sqPixels;
+
+ unsigned long frameCount;
+} camInfo[10];
+
+typedef struct camInfo_t *camPtr;
+
+static char * videoDevName0 = "/dev/video0";
+
+struct v4l2_buffer tmpVBuf;
+
+
+/* >>>>>>>> FUNCTION PROTOTYPES >>>>>>>> */
+
+/* LIBRARY CONSTRUCTOR/DESCTRUCTOR */
+void __attribute__ ((constructor)) libCon(void);
+void __attribute__ ((destructor)) libDes(void);
+
+/* SQUEAK INTERFACE */
+sqInt CameraGetParam(int camNum, int paramNum);
+sqInt CameraGetFrame(int camNum, unsigned char* buf, int pixelCount);
+sqInt CameraExtent(int camNum);
+char* CameraName(int camNum);
+void CameraClose(int camNum);
+sqInt CameraOpen(int camNum, int frameWidth, int frameHeight);
+
+
+/* ========================================================= */
+/* ========================================================= */
+/* ========================================================= */
+
+/* >>>>>>>>>>> UTILITY */
+
+inline int camIsOpen(camPtr cam) { return ( cam->isOpen); }
+inline int camIsClosed(camPtr cam) { return (!cam->isOpen); }
+
+
+static void
+vBufReset(struct v4l2_buffer *buf)
+{
+ CLEAR (*buf);
+ buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ buf->memory = V4L2_MEMORY_MMAP;
+}
+
+
+/* >>>>>>>>>>> LIB CONSTRUCTOR/DESTRUCTOR */
+
+void __attribute__ ((constructor))
+libCon(void)
+{
+ int devNum;
+ camPtr cam;
+
+ vd_open = open;
+ vd_close = close;
+ vd_dup = dup;
+ vd_ioctl = ioctl;
+ vd_read = read;
+ vd_mmap = mmap;
+ vd_munmap = munmap;
+
+ /* Use libv4l2: use if available... */
+
+ hLibv4l2 = dlopen("libv4l2.so.0", RTLD_LAZY);
+ if (hLibv4l2) {
+ vd_open = dlsym(hLibv4l2, "v4l2_open");
+ vd_close = dlsym(hLibv4l2, "v4l2_close");
+ vd_dup = dlsym(hLibv4l2, "v4l2_dup");
+ vd_ioctl = dlsym(hLibv4l2, "v4l2_ioctl");
+ vd_read = dlsym(hLibv4l2, "v4l2_read");
+ vd_mmap = dlsym(hLibv4l2, "v4l2_mmap");
+ vd_munmap = dlsym(hLibv4l2, "v4l2_munmap");
+ }
+
+ /* Init camInfo array... */
+
+ for (devNum = 0; devNum < 10; ++devNum) {
+ cam = &camInfo[devNum];
+
+ CLEAR(*cam);
+
+ cam->isOpen = false;
+ cam->devNum = devNum;
+ cam->ioMethod = IO_METHOD_MMAP;
+ cam->nBuffers = 2;
+ vBufReset(&(cam->vBuf));
+ /* Pixel format auto selected for ease/speed of conversion */
+
+/*
+ cam->fileDesc = 0;
+ cam->bmWidth = 0;
+ cam->bmHeight = 0;
+ cam->buffers = NULL;
+ cam->nBuffers = 0;
+ cam->vBuf = NULL;
+ cam->pixelformat = V4L2_PIX_FMT_YUYV;
+ cam->pixelformat = V4L2_PIX_FMT_RGB24;
+ cam->sqBuffer = 0;
+ cam->sqBufferBytes = 0;
+ cam->sqPixels = 0;
+ cam->frameCount = 0;
+*/
+ }
+}
+
+
+void __attribute__ ((destructor))
+libDes(void)
+{
+ int camNum;
+ for (camNum = 1; camNum < 11; ++camNum)
+ if (camIsOpen(&camInfo[camNum-1]))
+ CameraClose(camNum);
+
+/*
+/ Closing libv4l2 causes a crash, so it must
+/ already be closed by this point.
+*/
+/*
+ if (hLibv4l2) dlclose(hLibv4l2);
+*/
+}
+
+
+/* >>>>>>>>>>> PIXEL FORMAT CONVERSION, SQ BUFFER TRANSFER */
+
+/* YUV CONVERSION:
+/
+/ from: palettes.c in VideoForLinuxPlugin
+/ from: http://en.wikipedia.org/wiki/YUV422
+/
+*/
+
+inline unsigned char
+clipPixel(const int pixel) {
+ int result;
+ result = ((pixel < 0) ? 0 : pixel);
+ return (unsigned char) ((result > 255) ? 255: result);
+}
+
+
+inline void
+convertPixelYUV444toARGB32(
+ const unsigned char y,
+ const unsigned char u,
+ const unsigned char v,
+ unsigned char* dest)
+{
+ const int C = (y - 16) * 298 + 128;
+ const int D = u - 128;
+ const int E = v - 128;
+
+ /* ARGB */
+ dest[0] = clipPixel(( C + 516 * D ) >> 8);
+ dest[1] = clipPixel(( C - 100 * D - 208 * E) >> 8);
+ dest[2] = clipPixel(( C + 409 * E) >> 8);
+ dest[3] = 255;
+}
+
+
+inline void
+convertImageYUYVToARGB32 (camPtr cam)
+{
+ int i;
+
+ const unsigned char* src = cam->inBuffer;
+ unsigned char* dst = cam->sqBuffer;
+ unsigned long int *pdst;
+ unsigned long int pixelCount = cam->sqPixels;
+
+ unsigned char u, y1, v, y2;
+
+ for (i = 0; i < pixelCount; i += 2) {
+ y1 = *src++;
+ u = *src++;
+ y2 = *src++;
+ v = *src++;
+
+ convertPixelYUV444toARGB32(y1, u, v, dst);
+ pdst = (unsigned long *)dst;
+ dst += 4;
+
+ if (y2 == y1)
+ *(unsigned long *)dst = *pdst;
+ else
+ convertPixelYUV444toARGB32(y2, u, v, dst);
+
+ dst += 4;
+ }
+}
+/* <<<<<<<<< YUV CONVERSION <<<<<<<< */
+
+
+static void
+convertImageRGB24toARGB32 (camPtr cam)
+{
+ unsigned char *src = cam->inBuffer;
+ unsigned long int *dst = cam->sqBuffer;
+ unsigned long int pixelCount = cam->sqPixels;
+ unsigned long int pixel;
+ int i;
+
+ if (0 == dst) return;
+
+ for ( i = 0; i < pixelCount; i++) {
+ pixel = 0xFF000000 | (*src++ << 16);
+ pixel = pixel | (*src++ << 8);
+ *dst++ = pixel | *src++;
+ }
+}
+
+
+static void
+convertImageRGB444toARGB32 (camPtr cam)
+{
+ unsigned char *src = cam->inBuffer;
+ unsigned long int *dst = cam->sqBuffer;
+ unsigned long int pixelCount = cam->sqPixels;
+ unsigned long int r,g,b,pixel;
+ int i;
+
+ if (0 == dst) return;
+
+ /* Byte0: (g)ggg(b)bbb, Byte1: xxxx(r)rrr */
+
+ for ( i = 0; i < pixelCount; i++) {
+ r = *src << 4;
+ g = *src++ & 0xF0;
+ b = (*src++ & 0x0F) << 4;
+ pixel = 0xFF000000;
+ pixel |= (r << 16);
+ pixel |= (g << 8);
+ pixel |= b;
+ *dst++ = pixel;
+ }
+}
+
+
+static void
+convertImageRGB565toARGB32 (camPtr cam)
+{
+ unsigned char *src = cam->inBuffer;
+ unsigned long int *dst = cam->sqBuffer;
+ unsigned long int pixelCount = cam->sqPixels;
+ unsigned long int r,g,b,pixel;
+ int i;
+
+ if (0 == dst) return;
+
+ /* Byte0: ggg(r)rrrr, Byte1: (b)bbbb(g)gg */
+
+ for ( i = 0; i < pixelCount; i++) {
+ r = (*src & 0x1F) << 3;
+ g = (*src++ & 0xE0) >> 5;
+ g |= (*src & 0x07) << 5;
+ b = *src++ & 0xF8;
+ pixel = 0xFF000000;
+ pixel |= (b << 16);
+ pixel |= (g << 8);
+ pixel |= r;
+ *dst++ = pixel;
+ }
+}
+
+
+void
+convertImage (camPtr cam)
+{
+ /* func pts to be used at later date */
+
+ if (cam->pixelformat == V4L2_PIX_FMT_YUYV) {
+ convertImageYUYVToARGB32 (cam);
+ return;
+ }
+
+ if (cam->pixelformat == V4L2_PIX_FMT_RGB565) {
+ convertImageRGB565toARGB32 (cam);
+ return;
+ }
+
+ if (cam->pixelformat == V4L2_PIX_FMT_RGB444) {
+ convertImageRGB444toARGB32 (cam);
+ return;
+ }
+
+ if (cam->pixelformat == V4L2_PIX_FMT_RGB24) {
+ convertImageRGB24toARGB32 (cam);
+ return;
+ }
+}
+
+
+/* >>>>>>>>>>> V4L ACCESS */
+
+static int
+xioctl (camPtr cam, int request, void * arg)
+{
+ int r;
+ do r = vd_ioctl (cam->fileDesc, request, arg);
+ while (-1 == r && EINTR == errno);
+ return (0 == r);
+}
+
+
+inline static int
+queueBuffer(camPtr cam, struct v4l2_buffer *bufPtr)
+{
+ return xioctl (cam, VIDIOC_QBUF, bufPtr);
+}
+
+
+inline static int
+dequeueBuffer(camPtr cam, struct v4l2_buffer *bufPtr)
+{
+ return xioctl (cam, VIDIOC_DQBUF, bufPtr);
+}
+
+
+inline static int
+read_frame (camPtr cam)
+{
+ struct v4l2_buffer *bufPtr = &(cam->vBuf);
+
+ cam->frameCount += 1;
+
+ vBufReset(bufPtr);
+
+ if (!dequeueBuffer(cam, bufPtr)) {
+ switch (errno) {
+ case EAGAIN:
+ case EIO:
+ return false;
+ default:
+ return false;
+ }
+ }
+/* Not convinced this check is needed...
+ if (bufPtr->index < cam->nBuffers)
+*/
+ /* Quickly copy incoming frame and requeue immediately */
+ memcpy(cam->inBuffer, cam->buffers[bufPtr->index].start, cam->inBufferSize);
+ queueBuffer(cam, bufPtr);
+ /* Conversion not triggered here, see comment on CameraGetFrame() */
+
+ return true;
+}
+
+
+static
+int
+getFrame(camPtr cam)
+{
+ int fd = cam->fileDesc;
+ unsigned int retry;
+ fd_set fds;
+ struct timeval tv;
+ int r;
+
+ retry = 1;
+ while (retry-- > 0) {
+ FD_ZERO (&fds);
+ FD_SET (fd, &fds);
+
+ /* Timeout. */
+ tv.tv_sec = 0;
+ tv.tv_usec = 20000;
+
+ errno = 0;
+ if (-1 == (r = select (fd + 1, &fds, NULL, NULL, &tv))) {
+ /* try again on EINTR */
+ if ((EINTR == errno) | (EAGAIN == errno))
+ continue;
+ return false;
+ }
+
+ if (0 == r)
+ return false;
+
+ if (FD_ISSET(fd, &fds))
+ return read_frame (cam);
+
+ return false;
+ }
+
+ return false;
+}
+
+
+static int
+stream_off (camPtr cam)
+{
+ enum v4l2_buf_type streamType = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ return xioctl (cam, VIDIOC_STREAMOFF, &streamType);
+}
+
+
+static int
+stream_on (camPtr cam)
+{
+ enum v4l2_buf_type streamType = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ return xioctl (cam, VIDIOC_STREAMON, &streamType);
+}
+
+
+static int
+uninit_device (camPtr cam)
+{
+ unsigned int i;
+
+ if (cam->buffers)
+ for (i = 0; i < cam->nBuffers; ++i)
+ if (vd_munmap (cam->buffers[i].start, cam->buffers[i].length))
+ return false;
+
+ free (cam->buffers);
+ free (cam->inBuffer);
+
+ return true;
+}
+
+
+static int
+queueAllBuffers (camPtr cam)
+{
+ struct v4l2_buffer *bufPtr = &(cam->vBuf);
+
+ vBufReset(bufPtr);
+ for (bufPtr->index = 0; bufPtr->index < cam->nBuffers; (bufPtr->index)++)
+ if (!queueBuffer(cam, bufPtr)) return false;
+ return true;
+}
+
+
+static int
+init_mmap (camPtr cam)
+{
+ struct v4l2_buffer *bufPtr = &tmpVBuf;
+ struct v4l2_requestbuffers req;
+
+ CLEAR (req);
+ req.count = cam->nBuffers;
+ req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ req.memory = V4L2_MEMORY_MMAP;
+
+ if (!xioctl(cam, VIDIOC_REQBUFS, &req)) return false;
+/* Left in for debugging >>>
+ {
+ if (EINVAL == errno) {
+ return false;
+ } else {
+ return false;
+ }
+ }
+<<< */
+
+ if (req.count < cam->nBuffers) return false;
+ if (cam->nBuffers < req.count)
+ printf("Excess Buffers: %i\n", req.count);
+
+ if (!(cam->buffers = calloc (req.count, sizeof (struct buffer))))
+ return false;
+
+ vBufReset(bufPtr);
+ for (bufPtr->index = 0; bufPtr->index < req.count; bufPtr->index++) {
+
+ if (!xioctl(cam, VIDIOC_QUERYBUF, bufPtr)) return false;
+
+ cam->buffers[bufPtr->index].length = bufPtr->length;
+ cam->buffers[bufPtr->index].start = vd_mmap (
+ NULL /* start anywhere */,
+ bufPtr->length,
+ PROT_READ | PROT_WRITE /* required */,
+ MAP_SHARED /* recommended */,
+ cam->fileDesc,
+ bufPtr->m.offset);
+
+ if (MAP_FAILED == cam->buffers[bufPtr->index].start) return false;
+ }
+
+ return true;
+}
+
+
+static int
+set_format (camPtr cam, struct v4l2_format *fmt, int pixelformat, int w, int h)
+{
+ fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ fmt->fmt.pix.width = w;
+ fmt->fmt.pix.height = h;
+ fmt->fmt.pix.pixelformat = pixelformat;
+ fmt->fmt.pix.field = V4L2_FIELD_NONE;
+ if (!xioctl (cam, VIDIOC_S_FMT, fmt)) return false;
+
+ /* Note VIDIOC_S_FMT may change width and height. */
+ if ((w != fmt->fmt.pix.width) | (h != fmt->fmt.pix.height)
+ | (fmt->fmt.pix.pixelformat != pixelformat))
+ return false;
+
+ cam->pixelformat = pixelformat;
+
+ return true;
+}
+
+
+static int
+init_device (camPtr cam, int w, int h)
+{
+ struct v4l2_capability cap;
+ struct v4l2_cropcap cropcap;
+ struct v4l2_crop crop;
+ struct v4l2_format fmt;
+ int bpp;
+ unsigned int min;
+
+ if (!xioctl (cam, VIDIOC_QUERYCAP, &cap)) return false;
+/* left in for debugging >>>
+ {
+ if (EINVAL == errno) {
+ return -1;
+ } else {
+ return -1;
+ }
+ }
+<<< */
+
+ if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) return false;
+ if (!(cap.capabilities & V4L2_CAP_STREAMING)) return false;
+
+ /* Select video input, video standard and tune here. */
+
+ CLEAR (cropcap);
+ cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ if (xioctl (cam, VIDIOC_CROPCAP, &cropcap)) {
+ crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ crop.c = cropcap.defrect; /* reset to default */
+ if (!xioctl (cam, VIDIOC_S_CROP, &crop)) {
+ if (EINVAL == errno) {
+ /* Cropping not supported (ignored) */
+ } else {
+ /* Errors ignored. */
+ }
+ }
+ } else {
+ /* Errors ignored. */
+ }
+
+ CLEAR (fmt);
+ /* The order of preference of formats... */
+ if (!set_format(cam, &fmt, V4L2_PIX_FMT_RGB24, w, h))
+ if (!set_format(cam, &fmt, V4L2_PIX_FMT_YUYV, w, h))
+ if (!set_format(cam, &fmt, V4L2_PIX_FMT_RGB565, w, h))
+ if (!set_format(cam, &fmt, V4L2_PIX_FMT_RGB444, w, h))
+ return false;
+
+ /* For reference:
+ V4L2_PIX_FMT_RGB24 : 3 bytes == 1 dst pixel
+ V4L2_PIX_FMT_RGB565: 2 bytes == 1 dst pixel
+ V4L2_PIX_FMT_RGB444: 2 bytes == 1 dst pixel
+ V4L2_PIX_FMT_YUYV : 4 bytes == 2 dst pixels
+ */
+
+ switch (fmt.fmt.pix.pixelformat) {
+ case V4L2_PIX_FMT_RGB24: /* printf("V4L2_PIX_FMT_RGB24\n"); */
+ bpp = 3;
+ break;
+ case V4L2_PIX_FMT_RGB565: /* printf("V4L2_PIX_FMT_RGB565\n"); */
+ bpp = 2;
+ break;
+ case V4L2_PIX_FMT_RGB444: /* printf("V4L2_PIX_FMT_RGB444\n"); */
+ bpp = 2;
+ break;
+ case V4L2_PIX_FMT_YUYV: /* printf("V4L2_PIX_FMT_YUYV\n"); */
+ bpp = 4;
+ break;
+ }
+
+ /* Buggy driver paranoia >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> */
+ min = fmt.fmt.pix.width * bpp;
+ if (fmt.fmt.pix.bytesperline < min) fmt.fmt.pix.bytesperline = min;
+ min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height;
+ if (fmt.fmt.pix.sizeimage < min) fmt.fmt.pix.sizeimage = min;
+ /* <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */
+
+ if (!(cam->inBuffer = calloc (min, 1))) return false;
+ cam->inBufferSize = min;
+
+ if (!init_mmap(cam)) return false;
+
+ if (!queueAllBuffers(cam)) return false;
+
+ /* cache returned dims */
+ cam->bmWidth = fmt.fmt.pix.width;
+ cam->bmHeight = fmt.fmt.pix.height;
+ cam->sqPixels = cam->bmWidth * cam->bmHeight;
+ cam->sqBufferBytes = cam->sqPixels * 4; /* Bytes to tx to Squeak (always RGB32) */
+
+ return true;
+}
+
+
+static int
+close_device (camPtr cam)
+{
+ vd_close (cam->fileDesc);
+ cam->fileDesc = 0;
+ return true;
+}
+
+
+static int
+open_device (camPtr cam)
+{
+ char deviceName[12];
+ struct stat st;
+
+ strcpy(deviceName, videoDevName0);
+ deviceName[10] = cam->devNum + '0';
+
+ if (stat (deviceName, &st)) return false;
+ if (!S_ISCHR (st.st_mode)) return false;
+
+ return (-1 != (cam->fileDesc = vd_open (deviceName, O_RDWR /* required */ | O_NONBLOCK, 0)));
+}
+
+
+int
+initCamera(camPtr cam, int w, int h)
+{
+ if (!open_device(cam)) return false;
+
+ if (!init_device(cam, w, h)) {
+ close_device(cam);
+ return false;
+ }
+
+ if (!stream_on(cam)) {
+ uninit_device(cam);
+ close_device(cam);
+ return false;
+ }
+
+ return true;
+}
+
+
+/* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> */
+/* >>>>>>>>>>>>>>>>> SCRATCH I/F >>>>>>>>>>>>>>>>> */
+/* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> */
+
+sqInt
+CameraGetParam(int camNum, int paramNum)
+{
+ camPtr cam = &camInfo[camNum-1];
+ return false;
+}
+
+
+/*
+/ Spec from Scratch protocol...
+/
+/ "Copy a camera frame into the given Bitmap. The Bitmap should be for a Form
+/ of depth 32 that is the same width and height as the current camera frame.
+/ Fail if the camera is not open or if the bitmap is not the right size. If
+/ successful, answer the number of frames received from the camera since the
+/ last call. If this is zero, then there has been no change."
+/
+/ This version:
+/ - designed to fail silently
+/ - coded so that a future version can skip frames and do so *without* incurring
+/ delays due to conversion.
+*/
+sqInt
+CameraGetFrame(int camNum, unsigned char* buf, int pixelCount)
+{
+#ifdef USE_TEST_PATTERN
+ unsigned long f,i;
+ unsigned long *d;
+#endif
+
+ camPtr cam = &camInfo[camNum-1];
+
+ if (camIsClosed(cam)) return 0;
+ if (pixelCount != cam->sqPixels) return 0;
+
+ cam->sqBuffer = (void *)buf;
+
+#ifdef USE_TEST_PATTERN
+printf("%i\n", tstColourIdx);
+ switch (tstColourIdx) {
+ case 0:
+ f = 0xFFFF0000;
+ break;
+ case 1:
+ f = 0xFF00FF00;
+ break;
+ case 2:
+ f = 0xFF0000FF;
+ break;
+ }
+ d = (unsigned long *)buf;
+ for (i = 0; i < pixelCount; i++)
+ *d++ = f;
+ tstColourIdx = (tstColourIdx == 2 ? 0: tstColourIdx + 1);
+ return 1;
+#endif
+
+/* OPTION 1: ALL FRAMES, SKIP IMAGE-SIDE, INCUR CONVERSION COST... */
+
+ if (getFrame(cam)) {
+ convertImage (cam);
+ return 1;
+ }
+ return 0;
+
+
+/* OPTION 2: ONLY LATEST FRAME, AVOIDS CONVERSION OF SKIPPED FRAMES... */
+
+ /* getFrame() buffers & eventually fails leaving the latest/last frame */
+/*
+ while (getFrame(cam));
+ convertImage (cam);
+ return 1;
+*/
+
+}
+
+
+sqInt
+CameraExtent(int camNum)
+{
+ camPtr cam = &camInfo[camNum-1];
+ if (camIsClosed(cam)) return false;
+ return (cam->bmWidth << 16) + cam->bmHeight;
+}
+
+
+char*
+CameraName(int camNum)
+{
+ camPtr cam = &camInfo[camNum-1];
+ if (camIsClosed(cam)) return "camera not open";
+ return "default camera";
+}
+
+
+void
+CameraClose(int camNum)
+{
+ camPtr cam = &camInfo[camNum-1];
+ if (camIsClosed(cam)) return;
+ stream_off(cam);
+ uninit_device(cam);
+ close_device(cam);
+ cam->isOpen = false;
+}
+
+
+sqInt
+CameraOpen(int camNum, int frameWidth, int frameHeight)
+{
+ camPtr cam = &camInfo[camNum-1];
+
+ if (camIsOpen(cam)) return false;
+ if (!initCamera(cam, frameWidth, frameHeight)) return false;
+ cam->isOpen = true;
+
+ while (!getFrame(cam));
+
+#ifdef USE_TEST_PATTERN
+ tstColourIdx = 0;
+#endif
+ return true;
+}
+
Added: branches/Cog/platforms/unix/plugins/GdbARMPlugin/Makefile.inc
===================================================================
--- branches/Cog/platforms/unix/plugins/GdbARMPlugin/Makefile.inc (rev 0)
+++ branches/Cog/platforms/unix/plugins/GdbARMPlugin/Makefile.inc 2014-07-16 23:09:05 UTC (rev 3045)
@@ -0,0 +1,13 @@
+# edit this to suit your system; it really ought to use relative paths
+# or some other convenience
+GDBBUILDFOLDER = /mnt/hgfs/tim/Documents/Squeak/Rasbian-VM/gdb-7.6
+XCFLAGS = -m32 -DNEED_UI_LOOP_HOOK
+
+XINCLUDES += -I$(GDBBUILDFOLDER)/include
+XINCLUDES += -I$(GDBBUILDFOLDER)/sim/arm
+XINCLUDES := -I$(GDBBUILDFOLDER)/bfd $(XINCLUDES)
+
+XLDFLAGS= $(GDBBUILDFOLDER)/sim/arm/libsim.a \
+ $(GDBBUILDFOLDER)/opcodes/libopcodes.a \
+ -lbfd -liberty \
+ -Wl,-wrap,ARMul_OSHandleSWI
Property changes on: branches/Cog/platforms/unix/plugins/GdbARMPlugin/Makefile.inc
___________________________________________________________________
Added: svn:executable
+ *
Added: branches/Cog/platforms/unix/plugins/ScratchPlugin/unixScratchOps.c
===================================================================
--- branches/Cog/platforms/unix/plugins/ScratchPlugin/unixScratchOps.c (rev 0)
+++ branches/Cog/platforms/unix/plugins/ScratchPlugin/unixScratchOps.c 2014-07-16 23:09:05 UTC (rev 3045)
@@ -0,0 +1,98 @@
+/* unixScratchOps.c -- Scratch operations for unix based OSes.
+ *
+ *
+ * Copyright (C) 2011 Massachusetts Institute of Technology
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "ScratchPlugin.h"
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+void OpenURL(char *url) {
+ // Open a browser on the given URL.
+#ifdef I_REALLY_DONT_CARE_HOW_UNSAFE_THIS_IS
+ char cmd[1000] = "xdg-open ";
+ strcat( cmd, url);
+ system(cmd);
+#else
+ // Implement a secure way here.
+ // IMHO it would be best to call a script that the user or
+ // package maintainer can customize. But in any case,
+ // DO NOT call system() with an unchecked URL. --bf
+#endif
+}
+
+void SetScratchWindowTitle(char *title) {
+ // Set the text in the window title bar. Not yet implemented.
+}
+
+void GetFolderPathForID(int folderID, char *path, int maxPath) {
+ // Get the full path for a special folder:
+ // 1 - user's home folder
+ // 2 - user's desktop folder
+ // 3 - user's document folder
+ // 4 - user's photos or pictures folder (does Linux have a convention for this?)
+ // 5 - user's music folder (does Linux have a convention for this?)
+ // path is filled in with a zero-terminated string of max length maxPath
+
+ char *s = NULL;
+
+ path[0] = 0; // a zero-length path indicates failure
+
+ // get the user's HOME directory
+ s = getenv("HOME");
+ if ((s == NULL) || (strlen(s) == 0)) return;
+
+ strncat(path, s, maxPath); // home folder
+
+ if (folderID == 1) return;
+ if (folderID == 2) strncat(path, "/Desktop", maxPath);
+ if (folderID == 4) strncat(path, "/Pictures", maxPath);
+ if (folderID == 5) strncat(path, "/Music", maxPath);
+
+ if (folderID == 3) {
+ s = getenv("SUGAR_ACTIVITY_ROOT");
+ if (s != NULL) {
+ // On XO, return the writeable activity "data" directory
+ strncat(path, s, maxPath);
+ strncat(path, "/data", maxPath);
+ } else {
+ strncat(path, "/Documents", maxPath);
+ }
+ }
+}
+
+int WinShortToLongPath(char *shortPath, char* longPath, int maxPath) {
+ return -1; // fail on non-Windows platforms
+}
+
+int IsFileOrFolderHidden(char *fullPath) {
+ // Always return false on Linux
+ return 0;
+}
+
+void SetUnicodePasteBuffer(short int *utf16, int count) {
+ // Store the given Unicode UTF16 string in the paste buffer.
+ // No longer needed; use clipboard methods in UnicodePlugin.
+}
Property changes on: branches/Cog/platforms/unix/plugins/ScratchPlugin/unixScratchOps.c
___________________________________________________________________
Added: svn:executable
+ *
Added: branches/Cog/platforms/unix/plugins/ScratchPlugin/unixSeriaPort2Ops.c
===================================================================
--- branches/Cog/platforms/unix/plugins/ScratchPlugin/unixSeriaPort2Ops.c (rev 0)
+++ branches/Cog/platforms/unix/plugins/ScratchPlugin/unixSeriaPort2Ops.c 2014-07-16 23:09:05 UTC (rev 3045)
@@ -0,0 +1,356 @@
+/* unixSerialPort2Ops.c -- Scratch operations for unix based OSes. Support
+ * for SerialPort2 primitives under Unix, including OSX and Linux.
+ *
+ *
+ * Copyright (C) 2011 Massachusetts Institute of Technology
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "ScratchPlugin.h"
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <termios.h>
+#include <unistd.h>
+
+// support for systems with a single hardware flow control bit
+// on such systems setting hardware handshaking for input sets it for output as well
+#ifndef CRTS_IFLOW
+# define CRTS_IFLOW CRTSCTS
+#endif
+#ifndef CCTS_OFLOW
+# define CCTS_OFLOW CRTSCTS
+#endif
+
+
+// globals
+#define PORT_COUNT 32
+static int gFileDescr[PORT_COUNT] = { // file descriptors for open serial ports
+ -1, -1, -1, -1, -1, -1, -1, -1, // the portNum kept by Squeak is an index
+ -1, -1, -1, -1, -1, -1, -1, -1, // into this array. -1 marks unused entries.
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1};
+static struct termios gOrigTermios[PORT_COUNT]; // original termios settings for open ports
+
+#define PRIM_FAILED -1
+
+// helper function declarations
+int FileDescrForEntry(int portNum);
+int OpenPortNamed(const char *bsdPath, int baudRate, int entryIndex);
+int isPrefix(char *prefix, char *s);
+int isSerialPortDev(char *s);
+
+int SerialPortCount(void) {
+ DIR *dirPtr;
+ struct dirent *entryPtr;
+ int cnt = 0;
+
+ if ((dirPtr = opendir("/dev")) == NULL) return 0;
+
+ while ((entryPtr = readdir(dirPtr)) != NULL) {
+ if (isSerialPortDev(entryPtr->d_name)) cnt++;
+ }
+
+ closedir(dirPtr);
+ return cnt;
+}
+
+// Find the name of the given port number. Fill in bsdPath if successful.
+// Otherwise, make bsdPath be the empty string.
+void SerialPortName(int portIndex, char *bsdPath, int maxPathSize) {
+ DIR *dirPtr;
+ struct dirent *entryPtr;
+ int cnt = 0;
+
+ *bsdPath = '\0'; // result is the empty string if port not found
+
+ if (portIndex < 1) return;
+ if ((dirPtr = opendir("/dev")) == NULL) return;
+
+ while ((entryPtr = readdir(dirPtr)) != NULL) {
+ if (isSerialPortDev(entryPtr->d_name)) cnt++;
+ if (cnt == portIndex) {
+ strncat(bsdPath, "/dev/", maxPathSize);
+ strncat(bsdPath, entryPtr->d_name, maxPathSize);
+ closedir(dirPtr);
+ return;
+ }
+ }
+
+ closedir(dirPtr);
+}
+
+int SerialPortOpenPortNamed(char *portName, int baudRate) {
+ int entryIndex;
+
+ // scan for first free entry
+ for (entryIndex = 0; entryIndex < PORT_COUNT; entryIndex++) {
+ if (gFileDescr[entryIndex] == -1) break;
+ }
+ if (entryIndex >= PORT_COUNT) return PRIM_FAILED; // no free entry
+
+ if (!OpenPortNamed(portName, baudRate, entryIndex)) return PRIM_FAILED;
+ return entryIndex;
+}
+
+void SerialPortClose(int portNum) {
+ int fDescr;
+
+ if ((fDescr = FileDescrForEntry(portNum)) < 0) return; // already closed
+
+ // restore the serial port settings to their original state
+ tcsetattr(fDescr, TCSANOW, &gOrigTermios[portNum]);
+ close(fDescr);
+ gFileDescr[portNum] = -1;
+}
+
+int SerialPortIsOpen(int portNum) {
+ return FileDescrForEntry(portNum) != -1;
+}
+
+int SerialPortRead(int portNum, char *bufPtr, int bufSize) {
+ int fDescr, count = 0;
+
+ if ((fDescr = FileDescrForEntry(portNum)) < 0) return 0;
+
+ count = read(fDescr, bufPtr, bufSize);
+ if (count < 0) return 0; // read error
+ return count;
+}
+
+int SerialPortWrite(int portNum, char *bufPtr, int bufSize) {
+ int fDescr, count = 0;
+
+ if ((fDescr = FileDescrForEntry(portNum)) < 0) return 0;
+
+ count = write(fDescr, bufPtr, bufSize);
+ if (count < 0) return 0; // write error
+ return count;
+}
+
+// Port options for SetOption/GetOption:
+// 1. baud rate
+// 2. data bits
+// 3. stop bits
+// 4. parity type
+// 5. input flow control type
+// 6. output flow control type
+// 20-25: handshake line bits (DTR, RTS, CTS, DSR, CD, RD)
+
+int SerialPortSetOption(int portNum, int optionNum, int newValue) {
+ int fDescr, handshake;
+ struct termios options;
+
+ if ((fDescr = FileDescrForEntry(portNum)) < 0) return PRIM_FAILED;
+ if (tcgetattr(fDescr, &options) == -1) return PRIM_FAILED;
+
+ switch (optionNum) {
+ case 1: // baud rate
+ if (cfsetspeed(&options, newValue) == -1) return PRIM_FAILED;
+ break;
+ case 2: // # of data bits
+ switch(newValue) {
+ case 5:
+ options.c_cflag = (options.c_cflag & ~CSIZE) | CS5;
+ break;
+ case 6:
+ options.c_cflag = (options.c_cflag & ~CSIZE) | CS6;
+ break;
+ case 7:
+ options.c_cflag = (options.c_cflag & ~CSIZE) | CS7;
+ break;
+ case 8:
+ options.c_cflag = (options.c_cflag & ~CSIZE) | CS8;
+ break;
+ }
+ break;
+ case 3: // 1 or 2 stop bits
+ if (newValue > 1) options.c_cflag |= CSTOPB; // two stop bits
+ else options.c_cflag &= ~CSTOPB; // one stop bit
+ break;
+ case 4: // parity
+ options.c_cflag &= ~(PARENB | PARODD); // no parity
+ if (newValue == 1) options.c_cflag |= (PARENB | PARODD); // odd parity
+ if (newValue == 2) options.c_cflag |= PARENB; // even parity
+ break;
+ case 5: // input flow control
+ options.c_iflag &= ~IXOFF; // disable xoff input flow control
+ options.c_cflag &= ~CRTS_IFLOW; // disable RTS (hardware) input flow control
+ if (newValue == 1) options.c_iflag |= IXOFF; // enable xoff input flow control
+ if (newValue == 2) {
+ options.c_cflag |= CRTS_IFLOW; // enable RTS (hardware) input flow control
+ if (CRTS_IFLOW == CCTS_OFLOW) { // on systems with a single hardware flow control bit:
+ options.c_iflag &= ~(IXON | IXOFF); // disable xon/xoff flow control
+ }
+ }
+ break;
+ case 6: // output flow control
+ options.c_iflag &= ~IXON; // disable xon output flow control
+ options.c_cflag &= ~CCTS_OFLOW; // disable CTS (hardware) output flow control
+ if (newValue == 1) options.c_iflag |= IXON; // enable xon output flow control
+ if (newValue == 2) {
+ options.c_cflag |= CCTS_OFLOW; // enable CTS (hardware) output flow control
+ if (CRTS_IFLOW == CCTS_OFLOW) { // on systems with a single hardware flow control bit:
+ options.c_iflag &= ~(IXON | IXOFF); // disable xon/xoff flow control
+ }
+ }
+ break;
+
+ case 20: // set DTR line state
+ if (ioctl(fDescr, TIOCMGET, &handshake) == -1) return PRIM_FAILED;
+ handshake = newValue ? (handshake | TIOCM_DTR) : (handshake & ~TIOCM_DTR);
+ if (ioctl(fDescr, TIOCMSET, &handshake) == -1) return PRIM_FAILED;
+ break;
+ case 21: // set RTS line state
+ if (ioctl(fDescr, TIOCMGET, &handshake) == -1) return PRIM_FAILED;
+ handshake = newValue ? (handshake | TIOCM_RTS) : (handshake & ~TIOCM_RTS);
+ if (ioctl(fDescr, TIOCMSET, &handshake) == -1) return PRIM_FAILED;
+ break;
+ }
+ if (tcsetattr(fDescr, TCSANOW, &options) == -1) return PRIM_FAILED;
+ return 0;
+}
+
+int SerialPortGetOption(int portNum, int optionNum) {
+ int fDescr, handshake = -1;
+ struct termios options;
+
+ if ((fDescr = FileDescrForEntry(portNum)) < 0) return PRIM_FAILED;
+ if (tcgetattr(fDescr, &options) == -1) return PRIM_FAILED;
+ if (ioctl(fDescr, TIOCMGET, &handshake) == -1) return PRIM_FAILED;
+
+ switch (optionNum) {
+ case 1: return (int) cfgetispeed(&options);
+ case 2:
+ if ((options.c_cflag & CSIZE) == CS5) return 5;
+ if ((options.c_cflag & CSIZE) == CS6) return 6;
+ if ((options.c_cflag & CSIZE) == CS7) return 7;
+ if ((options.c_cflag & CSIZE) == CS8) return 8;
+ return PRIM_FAILED;
+ case 3: return (options.c_cflag & CSTOPB) ? 2 : 1;
+ case 4:
+ if (!(options.c_cflag & PARENB)) return 0;
+ return (options.c_cflag & PARODD) ? 1 : 2;
+ case 5:
+ if (options.c_iflag & IXOFF) return 1;
+ if (options.c_cflag & CRTS_IFLOW) return 2;
+ return 0;
+ case 6:
+ if (options.c_iflag & IXON) return 1;
+ if (options.c_cflag & CCTS_OFLOW) return 2;
+ return 0;
+
+ case 20: return (handshake & TIOCM_DTR) > 0;
+ case 21: return (handshake & TIOCM_RTS) > 0;
+ case 22: return (handshake & TIOCM_CTS) > 0;
+ case 23: return (handshake & TIOCM_DSR) > 0;
+ case 24: return (handshake & TIOCM_CD) > 0;
+ case 25: return (handshake & TIOCM_RI) > 0;
+ }
+ return PRIM_FAILED;
+}
+
+// ***** helper functions *****
+
+// Return the file descriptor for the given entry or -1 if either the
+// given port number (index) is out of range or the port is not open.
+int FileDescrForEntry(int portNum) {
+ if ((portNum < 0) || (portNum >= PORT_COUNT)) return PRIM_FAILED;
+ return gFileDescr[portNum];
+}
+
+// Given the path to a serial device, open the device and configure it for
+// using given entryIndex. Answer 1 if the operation succeeds, 0 if it fails.
+int OpenPortNamed(const char *bsdPath, int baudRate, int entryIndex) {
+ int fDescr = -1;
+ struct termios options;
+
+ // open the serial port read/write with no controlling terminal; don't block
+ fDescr = open(bsdPath, O_RDWR | O_NOCTTY | O_NONBLOCK);
+ if (fDescr == -1) {
+ printf("Error opening serial port %s - %s(%d).\n", bsdPath, strerror(errno), errno);
+ goto error;
+ }
+
+ // request exclusive access to the port
+ if (ioctl(fDescr, TIOCEXCL) == -1) {
+ printf("Error setting TIOCEXCL on %s - %s(%d).\n", bsdPath, strerror(errno), errno);
+ goto error;
+ }
+
+ // save port settings so we can restore them later
+ if (tcgetattr(fDescr, &gOrigTermios[entryIndex]) == -1) {
+ printf("Error getting attributes %s - %s(%d).\n", bsdPath, strerror(errno), errno);
+ goto error;
+ }
+
+ // port settings are made by modifying a copy of the termios struct
+ // and then calling tcsetattr() to make those changes take effect.
+ options = gOrigTermios[entryIndex];
+
+ // set the baud rate
+ if (cfsetspeed(&options, baudRate) == -1) {
+ printf("Error setting speed %d %s - %s(%d).\n", baudRate, bsdPath, strerror(errno), errno);
+ goto error;
+ }
+
+ // set raw input (non-canonical) mode, with writes not blocking.
+ cfmakeraw(&options);
+ options.c_cc[VMIN] = 0;
+ options.c_cc[VTIME] = 0;
+
+ // install the new port settings
+ if (tcsetattr(fDescr, TCSANOW, &options) == -1) {
+ printf("Error setting attributes %s - %s(%d).\n", bsdPath, strerror(errno), errno);
+ goto error;
+ }
+ gFileDescr[entryIndex] = fDescr;
+ return 1; // success!
+
+error:
+ if (fDescr != -1) close(fDescr);
+ return 0;
+}
+
+int isSerialPortDev(char *s) {
+ return isPrefix("ttyusb", s);
+}
+
+int isPrefix(char *prefix, char *s) {
+ int prefixC, c;
+ while (1) {
+ prefixC = *prefix++;
+ c = *s++;
+ if (prefixC == 0) return 1; // match!
+ if (c == 0) return 0; // s is shorter than prefix
+ if (c != prefixC) {
+ if (('a' <= c) && (c <= 'z')) c -= 32;
+ if (('a' <= prefixC) && (prefixC <= 'z')) prefixC -= 32;
+ if (c != prefixC) return 0; // non-match
+ }
+ }
+}
Property changes on: branches/Cog/platforms/unix/plugins/ScratchPlugin/unixSeriaPort2Ops.c
___________________________________________________________________
Added: svn:executable
+ *
Added: branches/Cog/platforms/unix/plugins/UnicodePlugin/Makefile.inc
===================================================================
--- branches/Cog/platforms/unix/plugins/UnicodePlugin/Makefile.inc (rev 0)
+++ branches/Cog/platforms/unix/plugins/UnicodePlugin/Makefile.inc 2014-07-16 23:09:05 UTC (rev 3045)
@@ -0,0 +1,2 @@
+XCPPFLAGS= -I/usr/include/cairo -I/usr/include/pango-1.0 -I/usr/include/glib-2.0 -I/usr/lib/arm-linux-gnueabihf/glib-2.0/include
+XLDFLAGS= -lpangocairo-1.0 -lcairo -lpango-1.0 -lgobject-2.0 -lglib-2.0
Added: branches/Cog/platforms/unix/plugins/UnicodePlugin/README.UnicodePlugin
===================================================================
--- branches/Cog/platforms/unix/plugins/UnicodePlugin/README.UnicodePlugin (rev 0)
+++ branches/Cog/platforms/unix/plugins/UnicodePlugin/README.UnicodePlugin 2014-07-16 23:09:05 UTC (rev 3045)
@@ -0,0 +1 @@
+In order to build the Unicode plugin on Linux, you'll need a collection of Pango, Cairo, and glib header and library files. These can often be found in the GTK+ development package in the package repository for your version of Linux.
Property changes on: branches/Cog/platforms/unix/plugins/UnicodePlugin/README.UnicodePlugin
___________________________________________________________________
Added: svn:executable
+ *
Added: branches/Cog/platforms/unix/plugins/UnicodePlugin/UnicodeOps-linux.c
===================================================================
--- branches/Cog/platforms/unix/plugins/UnicodePlugin/UnicodeOps-linux.c (rev 0)
+++ branches/Cog/platforms/unix/plugins/UnicodePlugin/UnicodeOps-linux.c 2014-07-16 23:09:05 UTC (rev 3045)
@@ -0,0 +1,280 @@
+/* UnicodeOps-linux.c
+ *
+ *
+ * Copyright (C) 2011 Massachusetts Institute of Technology
+ * All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+
+#include <pango/pangocairo.h>
+#include <glib/gprintf.h>
+#include <string.h>
+
+/* entry points */
+
+int unicodeClipboardGet(unsigned short *utf16, int utf16Length);
+void unicodeClipboardPut(unsigned short *utf16, int utf16Length);
+int unicodeClipboardSize(void);
+void unicodeDrawString(char *utf8, int utf8Length, int *wPtr, int *hPtr, unsigned int *bitmapPtr);
+int unicodeGetFontList(char *str, int strLength);
+int unicodeGetXRanges(char *utf8, int utf8Length, int *resultPtr, int resultLength);
+void unicodeMeasureString(char *utf8, int utf8Length, int *wPtr, int *hPtr);
+void unicodeSetColors(int fgRed, int fgGreen, int fgBlue, int bgRed, int bgGreen, int bgBlue, int mapBGToTransparent);
+void unicodeSetFont(char *fontName, int fontSize, int boldFlag, int italicFlag, int antiAliasFlag);
+
+/* globals */
+
+PangoLayout *cachedLayout = NULL; // used for measuring
+PangoFontDescription *fontDescr = NULL;
+cairo_font_options_t* fontOptions = NULL;
+
+int g_bgRed = 255, g_bgGreen = 255, g_bgBlue = 255;
+int g_fgRed = 0, g_fgGreen = 0, g_fgBlue = 0;
+int g_bgRGB = 0; // Squeak format
+int g_bgTransparent = 0;
+
+/* helper procedures */
+
+void computeLayout(PangoLayout *layout, char *utf8, int utf8Length, int *wPtr, int *hPtr, int *xOffsetPtr, int *yOffsetPtr, int *layoutDetailsPtr) {
+ PangoRectangle inkRect, logicalRect;
+ int left, top, right, bottom, baseline;
+ PangoLayoutIter *iter;
+
+ if (fontDescr == NULL) unicodeSetFont("Verdana", 18, 0, 0, 1);
+ pango_cairo_context_set_font_options(pango_layout_get_context(layout), fontOptions);
+ pango_layout_set_font_description(layout, fontDescr);
+ pango_layout_set_text(layout, utf8, utf8Length);
+ pango_layout_get_pixel_extents(layout, &inkRect, &logicalRect);
+
+ left = (inkRect.x < logicalRect.x) ? inkRect.x : logicalRect.x;
+ top = (inkRect.y < logicalRect.y) ? inkRect.y : logicalRect.y;
+ right = inkRect.x + inkRect.width;
+ if ((logicalRect.x + logicalRect.width) > right) right = logicalRect.x + logicalRect.width;
+ bottom = inkRect.y + inkRect.height;
+ if ((logicalRect.y + logicalRect.height) > bottom) bottom = logicalRect.y + logicalRect.height;
+
+ iter = pango_layout_get_iter(layout);
+ baseline = PANGO_PIXELS(pango_layout_iter_get_baseline(iter));
+ pango_layout_iter_free(iter);
+
+ if (left < 0) {
+ inkRect.x = inkRect.x - left;
+ logicalRect.x = logicalRect.x - left;
+ }
+ if (top < 0) {
+ inkRect.y = inkRect.y - top;
+ logicalRect.y = logicalRect.y - top;
+ baseline = baseline - top;
+ }
+
+ if (layoutDetailsPtr != NULL) {
+ layoutDetailsPtr[0] = inkRect.x;
+ layoutDetailsPtr[1] = inkRect.y;
+ layoutDetailsPtr[2] = inkRect.width;
+ layoutDetailsPtr[3] = inkRect.height;
+
+ layoutDetailsPtr[4] = logicalRect.x;
+ layoutDetailsPtr[5] = logicalRect.y;
+ layoutDetailsPtr[6] = logicalRect.width;
+ layoutDetailsPtr[7] = logicalRect.height;
+
+ layoutDetailsPtr[8] = baseline;
+ }
+
+ *wPtr = right - left;
+ *hPtr = bottom - top;
+ *xOffsetPtr = left < 0 ? -left : 0;
+ *yOffsetPtr = top < 0 ? -top : 0;
+}
+
+int unicodeLength(char *utf8, int utf8Length) {
+ int count, i, ch;
+
+ count = i = 0;
+ while (i < utf8Length) {
+ count++;
+ ch = utf8[i];
+ if ((ch & 0xE0) == 0xC0) i += 2;
+ else if ((ch & 0xF0) == 0xE0) i += 3;
+ else if ((ch & 0xF8) == 0xF0) i += 4;
+ else i += 1;
+ }
+ return count;
+}
+
+/* entry points */
+
+// Clipboard operations are not yet implemented
+int unicodeClipboardGet(unsigned short *utf16, int utf16Length) { return 0; }
+void unicodeClipboardPut(unsigned short *utf16, int utf16Length) { }
+int unicodeClipboardSize(void) { return 0; }
+
+int unicodeGetFontList(char *str, int strLength) {
+ PangoFontMap *fontMap;
+ PangoFontFamily **fontFomilies;
+ int count, i;
+
+ str[0] = '\0';
+
+ if (cachedLayout == NULL) {
+ cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_A8, 1, 1);
+ cairo_t *cr = cairo_create(surface);
+ cachedLayout = pango_cairo_create_layout(cr);
+ }
+
+ fontMap = pango_context_get_font_map(pango_layout_get_context(cachedLayout));
+ pango_font_map_list_families(fontMap, &fontFomilies, &count);
+
+ for (i = 0; i < count; i++) {
+ strncat(str, pango_font_family_get_name(fontFomilies[i]), strLength);
+ strncat(str, "\n", strLength);
+ }
+ g_free(fontFomilies);
+ return strlen(str);
+}
+
+void unicodeDrawString(char *utf8, int utf8Length, int *wPtr, int *hPtr, unsigned int *bitmapPtr) {
+ int w = *wPtr;
+ int h = *hPtr;
+ int pixelCount = w * h;
+ int offsetX, offsetY;
+ unsigned int *pixelPtr, *lastPtr;
+
+ cairo_surface_t *surface = cairo_image_surface_create_for_data((unsigned char *) bitmapPtr, CAIRO_FORMAT_RGB24, w, h, (4 * w));
+ cairo_t *cr = cairo_create(surface);
+ PangoLayout *layout = pango_cairo_create_layout(cr);
+
+ computeLayout(layout, utf8, utf8Length, wPtr, hPtr, &offsetX, &offsetY, NULL);
+
+ // fill with background color if not transparent
+ if (g_bgRGB != 0) {
+ cairo_set_source_rgb(cr, g_bgRed / 255.0, g_bgGreen / 255.0, g_bgBlue / 255.0);
+ cairo_paint(cr);
+ }
+
+ cairo_translate(cr, offsetX, offsetY);
+ cairo_set_source_rgb(cr, g_fgRed / 255.0, g_fgGreen / 255.0, g_fgBlue / 255.0);
+ pango_cairo_show_layout(cr, layout);
+
+ // map bg color pixels to transparent if so desired
+ if (g_bgTransparent) {
+ pixelPtr = bitmapPtr;
+ lastPtr = pixelPtr + pixelCount;
+ while (pixelPtr < lastPtr) {
+ if (*pixelPtr == g_bgRGB) *pixelPtr = 0;
+ pixelPtr++;
+ }
+ }
+
+ g_object_unref(layout);
+ cairo_destroy(cr);
+ cairo_surface_destroy(surface);
+}
+
+int unicodeGetXRanges(char *utf8, int utf8Length, int *resultPtr, int resultLength) {
+ int w, h, offsetX, offsetY;
+ int count, ch, i, j;
+ PangoRectangle rect;
+
+ count = unicodeLength(utf8, utf8Length);
+ if (resultLength < (2 * count)) return -1;
+
+ if (cachedLayout == NULL) {
+ cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_A8, 1, 1);
+ cairo_t *cr = cairo_create(surface);
+ cachedLayout = pango_cairo_create_layout(cr);
+ }
+
+ computeLayout(cachedLayout, utf8, utf8Length, &w, &h, &offsetX, &offsetY, NULL);
+
+ i = j = 0;
+ while ((i < utf8Length) && (j < (resultLength - 1))) {
+ pango_layout_index_to_pos(cachedLayout, i, &rect);
+ ch = utf8[i];
+ if ((ch & 0xE0) == 0xC0) i += 2;
+ else if ((ch & 0xF0) == 0xE0) i += 3;
+ else if ((ch & 0xF8) == 0xF0) i += 4;
+ else i += 1;
+ resultPtr[j] = PANGO_PIXELS(rect.x);
+ resultPtr[j + 1] = PANGO_PIXELS(rect.x + rect.width);
+ j += 2;
+ }
+
+ return count;
+}
+
+void unicodeMeasureString(char *utf8, int utf8Length, int *wPtr, int *hPtr) {
+ int offsetX, offsetY;
+
+ if (cachedLayout == NULL) {
+ cairo_surface_t *surface = cairo_image_surface_create(CAIRO_FORMAT_A8, 1, 1);
+ cairo_t *cr = cairo_create(surface);
+ cachedLayout = pango_cairo_create_layout(cr);
+ }
+
+ computeLayout(cachedLayout, utf8, utf8Length, wPtr, hPtr, &offsetX, &offsetY, NULL);
+}
+
+void unicodeSetColors(int fgRed, int fgGreen, int fgBlue, int bgRed, int bgGreen, int bgBlue, int mapBGToTransparent) {
+ g_fgRed = fgRed & 255;
+ g_fgGreen = fgGreen & 255;
+ g_fgBlue = fgBlue & 255;
+ g_bgRed = bgRed & 255;
+ g_bgGreen = bgGreen & 255;
+ g_bgBlue = bgBlue & 255;
+ g_bgRGB = (g_bgRed << 16) | (g_bgGreen << 8) | g_bgBlue; // Squeak pixel format
+ g_bgTransparent = mapBGToTransparent;
+}
+
+void unicodeSetFont(char *fontName, int fontSize, int boldFlag, int italicFlag, int antiAliasFlag) {
+ char description[200];
+ g_sprintf(description, "%s, %s %s %dpx",
+ fontName,
+ (boldFlag ? "bold" : ""),
+ (italicFlag ? "italic" : ""),
+ fontSize);
+
+ if (fontDescr != NULL) pango_font_description_free(fontDescr);
+ fontDescr = pango_font_description_from_string(description);
+
+ if (fontOptions == NULL) {
+ fontOptions = cairo_font_options_create();
+ // Note: On Mac OS, the default hint style and metrics looked the best. Also, using
+ // the default allows the user to control the look via the OS settings.
+ /*
+ styles:
+ CAIRO_HINT_STYLE_DEFAULT Use the default hint style for for font backend and target device
+ CAIRO_HINT_STYLE_NONE Do not hint outlines
+ CAIRO_HINT_STYLE_SLIGHT Hint outlines slightly to improve contrast while retaining good fidelity to the original shapes.
+ CAIRO_HINT_STYLE_MEDIUM Hint outlines with medium strength giving a compromise between fidelity to the original shapes and contrast
+ CAIRO_HINT_STYLE_FULL Hint outlines to maximize contrast
+ metrics:
+ CAIRO_HINT_METRICS_DEFAULT Hint metrics in the default manner for the font backend and target device
+ CAIRO_HINT_METRICS_OFF Do not hint font metrics
@@ Diff output truncated at 50000 characters. @@
More information about the Vm-dev
mailing list