The source code of the program for the PC & lt; code class = & quot; cpp & quot; & gt; #include & lt; stdlib.h & gt; #include & lt; sys / time.h & gt; #include & lt; time.h & gt; #include & lt; stdio.h & gt; #include & lt; string.h & gt; #include & lt; libusb-1.0 / libusb.h & gt; #include & lt; iostream & gt; #include & lt; string & gt; #include & lt; vector & gt; #define MAGIC 0x41444C49 static inline uint16_t swapshort (uint16_t v) {return (v & gt; & gt; 8) | (v & lt; & lt; 8); } Float scale = 1.0; typedef struct {uint32_t magic; uint8_t pad1 [3]; uint8_t format; char name [8]; char company [8]; uint16_t count; uint16_t frameno; uint16_t framecount; uint8_t scanner; uint8_t pad2; } __attribute __ ((Packed)) ilda_hdr; #define BLANK 0x40 #define LAST 0x80 typedef struct {int16_t x; int16_t y; int16_t z; uint8_t state; uint8_t color; } __attribute __ ((Packed)) icoord3d; typedef struct coord3d {int16_t x; int16_t y; int16_t z; uint8_t state; coord3d (int16_t x, int16_t y, int16_t z, uint8_t state): x (x), y (y), z (z), state (state) {}} coord3d; typedef struct {std :: vector & lt; coord3d & gt; points; int position; } Frame; frame rframe; int subpos; int divider = 1; int loadildahdr (FILE * ild, ilda_hdr & amp; hdr) {if (fread (& amp; hdr, sizeof (hdr), 1, ild)! = 1) {std :: cerr & lt; & lt; & quot; Error while reading header & quot; & lt; & lt; std :: endl; return -1; } If (hdr.magic! = MAGIC) {std :: cerr & lt; & lt; & quot; Invalid magic & quot; & lt; & lt; std :: endl; return -1; } If (hdr.format! = 0) {fprintf (stderr, & quot; Unsupported section type% d \ n & quot ;, hdr.format); return -1; } Hdr.count = swapshort (hdr.count); hdr.frameno = swapshort (hdr.frameno); hdr.framecount = swapshort (hdr.framecount); } Int loadild (const std :: string & amp; file, frame & amp; frame) {int i; FILE * ild = fopen (file.c_str (), & quot; rb & quot;); if (! ild) {std :: cerr & lt; & lt; & quot; Can not open & quot; & lt; & lt; file & lt; & lt; std :: endl; return -1; } Ilda_hdr hdr; loadildahdr (ild, hdr); for (int f = 0; f & lt; hdr.framecount; f ++) {std :: cout & lt; & lt; & quot; Frame & quot; & lt; & lt; hdr.frameno & lt; & lt; & quot; of & quot; & lt; & lt; hdr.framecount & lt; & lt; & quot; & quot; & lt; & lt; hdr.count & lt; & lt; & quot; points & quot; & lt; & lt; std :: endl; icoord3d * tmp = (icoord3d *) calloc (hdr.count, sizeof (icoord3d)); if (fread (tmp, sizeof (icoord3d), hdr.count, ild)! = hdr.count) {std :: cerr & lt; & lt; & quot; Error while reading frame & quot; & lt; & lt; std :: endl; return -1; } For (i = 0; i & lt; hdr.count; i ++) {coord3d point (swapshort (tmp [i] .x), swapshort (tmp [i] .y), swapshort (tmp [i] .z), tmp [i] .state); frame.points.push_back (point); } Free (tmp); loadildahdr (ild, hdr); } Fclose (ild); return 0; } Short outBuffer [128]; int process () {frame * frame = & amp; rframe; short * sx = & amp; outBuffer [0]; short * sy = & amp; outBuffer [1]; for (int frm = 0; frm & lt; 64; frm ++) {struct coord3d * c = & amp; frame- & gt; points [frame- & gt; position]; * sx = 4095 - (2047 + (2048 * c- & gt; x / 32768)) * scale; * sy = (2047 + (2048 * c- & gt; y / 32768)) * scale; if (c- & gt; state & amp; BLANK) {* sx | = 1 & lt; & lt; 15; } Else {* sx & amp; = ~ (1 & lt; & lt; 15); } + Sx = 2; sy + = 2; subpos ++; if (subpos == divider) {subpos = 0; if (c- & gt; state & amp; LAST) frame- & gt; position = 0; else frame- & gt; position = (frame- & gt; position + 1)% frame- & gt; points.size (); }} Return 0; } Int main (int argc, char ** argv) {libusb_device_handle * dev; libusb_context * ctx = NULL; int ret, actual; ret = libusb_init (& amp; ctx); if (ret & lt; 0) {fprintf (stderr, & quot; Could not initialize libusb \ n & quot;); return EXIT_FAILURE; } Libusb_set_debug (ctx, 3); dev = libusb_open_device_with_vid_pid (ctx, 0x1cbe, 0x0003); if (dev == NULL) {fprintf (stderr, & quot; Can not open device \ n & quot;); return EXIT_FAILURE; } Else printf (& quot; Device opened \ n & quot;); if (libusb_kernel_driver_active (dev, 0) == 1) {fprintf (stderr, & quot; Kernel driver active \ n & quot;); libusb_detach_kernel_driver (dev, 0); } Ret = libusb_claim_interface (dev, 0); if (ret & lt; 0) {fprintf (stderr, & quot; Could not claim interface \ n & quot;); return EXIT_FAILURE; } // To maintain our sample rate struct timespec ts; ts.tv_sec = 0; ts.tv_nsec = 2000000; memset (& amp; rframe, 0, sizeof (frame)); if (loadild (argv [1], rframe) & lt; 0) {fprintf (stderr, & quot; Failed to load ILDA \ n & quot;); return EXIT_FAILURE; } While (1) {process (); if (nanosleep (& amp; ts, NULL)! = 0) fprintf (stderr, & quot; Nanosleep failed & quot;); ret = libusb_bulk_transfer (dev, (1 | LIBUSB_ENDPOINT_OUT), (unsigned char *) & amp; outBuffer, 256, & amp; actual, 0); if (ret! = 0 || actual! = 256) fprintf (stderr, & quot; Write error \ n & quot;); } Libusb_release_interface (dev, 0); libusb_close (dev); libusb_exit (ctx); return 0; } & Lt; / code & gt; pre>
The functions of the main () code> pre> using nanosleep also governed by the frequency with which new data is sent to the microcontroller.
Full source code of the controller firmware are available on GitHub .
Plans for the Future h4> It is planned to finish these things still to a state similar to the originally intended laser harp. For this purpose only one instead of two mirrors, since the laser beam moves along only one axis. The principle of operation of the harp is that the controller ignites and extinguishes laser beam at certain times it creating laser "keyboard" in the air. Artist, blocking hand in glove reflective bright laser beam activates the photosensitive element at the base of "harp". Since the microcontroller knows at what moment which part of the keyboard, he "painted" that can determine which of the beams has been blocked. Then it's up to the formation of the corresponding MIDI-message and sending it to a computer or connected to form a hardware synthesizer sound.
Source: habrahabr.ru/post/225531/