/* * scanout.c * * Copyright © 2019 Thomas White * * This file is part of NanoLight. * * NanoLight 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 3 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, see . * */ #include #include #include #include #include "nanolight.h" static void set_val(int *dmx, int base_addr, int attr_offset, float value, int sixteenbit) { /* Minus one to convert DMX address to indexing in 'dmx' array */ int pos = base_addr + attr_offset - 1; if ( sixteenbit ) { int val = value * 65535; dmx[pos] = (val & 0xff00) >> 8; dmx[pos+1] = val & 0xff; } else { dmx[pos] = value * 255; } } static void set_prism(int *dmx, struct fixture *fix, int prism) { int i; if ( prism > fix->cls->n_prisms ) return; for ( i=0; icls->n_prism_chans; i++ ) { int idx = fix->cls->n_prism_chans * prism + i; int chan = fix->cls->prism_chans[i]; dmx[fix->base_addr+chan-1] = fix->cls->prism_vals[idx] & 0xff; } if ( fix->cls->prism_flags[prism] & PRISM_ROTATE ) { float rotate_val; rotate_val = (fix->prism_rotate + 1.0)/2.0; set_val(dmx, fix->base_addr, fix->cls->prism_rotate_offset, rotate_val, 0); } if ( fix->cls->prism_flags[prism] & PRISM_SPIN ) { float rotate_val; rotate_val = (fix->prism_spin + 1.0)/2.0; set_val(dmx, fix->base_addr, fix->cls->prism_spin_offset, rotate_val, 0); } } static void set_gobo(int *dmx, struct fixture *fix, int gobo) { int i; if ( gobo > fix->cls->n_gobos ) return; for ( i=0; icls->n_gobo_chans; i++ ) { int idx = fix->cls->n_gobo_chans * gobo + i; int chan = fix->cls->gobo_chans[i]; dmx[fix->base_addr+chan-1] = fix->cls->gobo_vals[idx] & 0xff; } if ( fix->cls->gobo_flags[gobo] & GOBO_ROTATE ) { float rotate_val; rotate_val = (fix->gobo_rotate + 1.0)/2.0; set_val(dmx, fix->base_addr, fix->cls->gobo_rotate_offset, rotate_val, 0); } if ( fix->cls->gobo_flags[gobo] & GOBO_SPIN ) { float rotate_val; rotate_val = (fix->gobo_spin + 1.0)/2.0; set_val(dmx, fix->base_addr, fix->cls->gobo_spin_offset, rotate_val, 0); } } int scanout_all(struct nanolight *nl) { SoupSession *sess; SoupMessage *msg; int i; int dmx[512]; char str[8200]; signed int universe = -1; /* Start from zero */ for ( i=0; i<512; i++ ) dmx[i] = 0; /* Loop over fixtures and set values */ for ( i=0; in_fixtures; i++ ) { int j; struct fixture *fix = &nl->fixtures[i]; struct fixture_class *cls = fix->cls; if ( universe < 0 ) universe = fix->universe; if ( fix->universe != universe ) { fprintf(stderr, "Sorry, only one universe for now!\n"); abort(); } for ( j=0; jn_magic; j++ ) { dmx[fix->base_addr + cls->magic_chans[j] - 1] = cls->magic_vals[j]; } if ( cls->attributes & INTENSITY ) { set_val(dmx, fix->base_addr, cls->intensity_offset, fix->intensity, cls->attributes16 & INTENSITY); } if ( cls->attributes & PANTILT ) { float pan_val, tilt_val; pan_val = (fix->pan + 1.0)/2.0; tilt_val = (fix->tilt + 1.0)/2.0; set_val(dmx, fix->base_addr, cls->pan_offset, pan_val, cls->attributes16 & PANTILT); set_val(dmx, fix->base_addr, cls->tilt_offset, tilt_val, cls->attributes16 & PANTILT); } if ( (cls->attributes & COLOUR) && (cls->properties & COL_CMY) ) { set_val(dmx, fix->base_addr, cls->cyan_offset, fix->cyan, cls->attributes16 & COL_CMY); set_val(dmx, fix->base_addr, cls->magenta_offset, fix->magenta, cls->attributes16 & COL_CMY); set_val(dmx, fix->base_addr, cls->yellow_offset, fix->yellow, cls->attributes16 & COL_CMY); } if ( (cls->attributes & COLOUR) && (cls->properties & COL_RGB) ) { set_val(dmx, fix->base_addr, cls->red_offset, fix->red, cls->attributes16 & COL_RGB); set_val(dmx, fix->base_addr, cls->green_offset, fix->green, cls->attributes16 & COL_RGB); set_val(dmx, fix->base_addr, cls->blue_offset, fix->blue, cls->attributes16 & COL_RGB); } if ( cls->attributes & FOCUS ) { set_val(dmx, fix->base_addr, cls->focus_offset, fix->focus, cls->attributes16 & FOCUS); } if ( cls->attributes & ZOOM ) { set_val(dmx, fix->base_addr, cls->zoom_offset, fix->zoom, cls->attributes16 & ZOOM); } if ( cls->attributes & FROST ) { set_val(dmx, fix->base_addr, cls->frost_offset, fix->frost, cls->attributes16 & FROST); } if ( cls->attributes & IRIS ) { set_val(dmx, fix->base_addr, cls->iris_offset, fix->iris, cls->attributes16 & IRIS); } if ( cls->attributes & GOBO ) { set_gobo(dmx, fix, fix->gobo); } if ( cls->attributes & PRISM ) { set_prism(dmx, fix, fix->prism); } } if ( universe == -1 ) return 0; /* Nothing to do! */ /* Loop over DMX channels and prepare request */ snprintf(str, 16, "u=%i&d=", universe); for ( i=0; i<512; i++ ) { char tmp[6]; snprintf(tmp, 5, "%i,", dmx[i]); strcat(str, tmp); } /* Send request to OLA */ sess = soup_session_new(); msg = soup_message_new("POST", "http://127.0.0.1:9090/set_dmx"); soup_message_set_request(msg, "application/x-www-form-urlencoded", SOUP_MEMORY_TEMPORARY, str, strlen(str)); soup_session_send_message(sess, msg); g_object_unref(msg); g_object_unref(sess); return 0; }