All uncommited features, attempting to simplify features in fd
This commit is contained in:
parent
e4c109543b
commit
b8bc954aed
|
|
@ -139,13 +139,21 @@ class Display {
|
|||
}
|
||||
|
||||
public setFraming () {
|
||||
this.framing= true;
|
||||
this.framing = true;
|
||||
}
|
||||
|
||||
public unsetFraming () {
|
||||
this.framing = false;
|
||||
}
|
||||
|
||||
public blank () {
|
||||
this.unsetFocus();
|
||||
this.unsetFraming();
|
||||
this.updateSize();
|
||||
this.clear();
|
||||
this.updateScreen();
|
||||
}
|
||||
|
||||
private onResize (event : any) {
|
||||
this.updateSize();
|
||||
this.clear();
|
||||
|
|
@ -513,6 +521,10 @@ class Client {
|
|||
this.display.updateImage();
|
||||
}
|
||||
|
||||
private receiveBlank (msg : Message) {
|
||||
this.display.blank();
|
||||
}
|
||||
|
||||
public sendOffset (x : number, y : number) {
|
||||
this.client.send(JSON.stringify({ cmd : 'offset', x, y }));
|
||||
}
|
||||
|
|
@ -525,6 +537,10 @@ class Client {
|
|||
this.client.send(JSON.stringify({ cmd : 'scale', scale }));
|
||||
}
|
||||
|
||||
public sendBlank () {
|
||||
this.client.send(JSON.stringify({ cmd : 'blank' }));
|
||||
}
|
||||
|
||||
/**
|
||||
* HELPERS
|
||||
**/
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
import 'dotenv/config';
|
||||
import type { Logger } from 'winston';
|
||||
import { FD } from '../fd';
|
||||
export declare class CLI {
|
||||
private log;
|
||||
log: Logger;
|
||||
private args;
|
||||
private fd;
|
||||
fd: FD;
|
||||
private camera;
|
||||
private display;
|
||||
private bin;
|
||||
|
|
@ -19,5 +21,5 @@ export declare class CLI {
|
|||
private parseLine;
|
||||
private parse;
|
||||
private execute;
|
||||
private frame;
|
||||
private expose;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,17 +12,21 @@ const display_1 = require("../display");
|
|||
const files_1 = require("../files");
|
||||
const delay_1 = require("../delay");
|
||||
const camera_1 = require("../camera");
|
||||
let cli;
|
||||
var Actions;
|
||||
(function (Actions) {
|
||||
Actions[Actions["LOAD"] = 0] = "LOAD";
|
||||
Actions[Actions["DISPLAY"] = 1] = "DISPLAY";
|
||||
Actions[Actions["DELAY"] = 2] = "DELAY";
|
||||
Actions[Actions["EXPOSE"] = 0] = "EXPOSE";
|
||||
Actions[Actions["DELAY"] = 1] = "DELAY";
|
||||
Actions[Actions["FORWARD"] = 2] = "FORWARD";
|
||||
Actions[Actions["BACKWARD"] = 3] = "BACKWARD";
|
||||
Actions[Actions["GOTO"] = 4] = "GOTO";
|
||||
})(Actions || (Actions = {}));
|
||||
class CLI {
|
||||
constructor() {
|
||||
this.mock = true;
|
||||
this.mock = false;
|
||||
this.log = (0, log_1.createLog)('fm');
|
||||
this.settings();
|
||||
this.args = {};
|
||||
this.display = new display_1.Display(this.width, this.height);
|
||||
this.fd = new fd_1.FD(this.bin, this.width, this.height, this.host, this.port, this.displayStr, this.mock);
|
||||
this.camera = new camera_1.Camera(this.mock);
|
||||
|
|
@ -35,7 +39,9 @@ class CLI {
|
|||
await this.parse(this.args.input);
|
||||
await (0, delay_1.delay)(2000);
|
||||
}
|
||||
await (0, delay_1.delay)(5000);
|
||||
this.fd.exit();
|
||||
process.exit(0);
|
||||
}
|
||||
settings() {
|
||||
//parse args
|
||||
|
|
@ -47,9 +53,26 @@ class CLI {
|
|||
}
|
||||
parseLine(line) {
|
||||
let parts;
|
||||
let cmd = {};
|
||||
let cmdChar;
|
||||
if (line.trim() === '') {
|
||||
return null;
|
||||
}
|
||||
parts = line.split(',');
|
||||
if (parts.length > 0) {
|
||||
cmdChar = parts[0].trim().toUpperCase()[0];
|
||||
switch (cmdChar) {
|
||||
case 'E':
|
||||
cmd.action = Actions.EXPOSE;
|
||||
break;
|
||||
case 'D':
|
||||
cmd.action = Actions.DELAY;
|
||||
cmd.time = 1000;
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
async parse(filePath) {
|
||||
|
|
@ -81,18 +104,18 @@ class CLI {
|
|||
case Actions.DELAY:
|
||||
await (0, delay_1.delay)(cmd.time);
|
||||
break;
|
||||
case Actions.DISPLAY:
|
||||
await this.frame(cmd);
|
||||
case Actions.EXPOSE:
|
||||
await this.expose(cmd);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// await this.load(img, 100, 200, 640, 640);
|
||||
//await this.load(img, 100, 200, 640, 640);
|
||||
//await delay(2000);
|
||||
//await this.display(img, [ 4000 ] );
|
||||
//await delay(8000);
|
||||
}
|
||||
async frame(cmd) {
|
||||
async expose(cmd) {
|
||||
const start = Date.now();
|
||||
let load;
|
||||
let open;
|
||||
|
|
@ -120,6 +143,29 @@ class CLI {
|
|||
}
|
||||
exports.CLI = CLI;
|
||||
if (require.main === module) {
|
||||
new CLI();
|
||||
cli = new CLI();
|
||||
}
|
||||
async function exitHandler(options, exitCode) {
|
||||
if (options.cleanup) {
|
||||
cli.log.info(`Cleaning up...`);
|
||||
try {
|
||||
await cli.fd.exit();
|
||||
}
|
||||
catch (err) {
|
||||
cli.log.error('Error cleanly exiting filmout_display (fd) executable', err);
|
||||
}
|
||||
}
|
||||
exitCode == 'SIGINT' ? cli.log.info(`exit: ${exitCode}`) : cli.log.error(`exit: ${exitCode}`, new Error(`Exited with non-zero code: "${exitCode}"`));
|
||||
if (options.exit)
|
||||
process.exit();
|
||||
}
|
||||
// do something when app is closing
|
||||
process.on('exit', exitHandler.bind(null, { cleanup: true }));
|
||||
// catches ctrl+c event
|
||||
process.on('SIGINT', exitHandler.bind(null, { exit: true }));
|
||||
// catches "kill pid" (for example: nodemon restart)
|
||||
process.on('SIGUSR1', exitHandler.bind(null, { exit: true }));
|
||||
process.on('SIGUSR2', exitHandler.bind(null, { exit: true }));
|
||||
// catches uncaught exceptions
|
||||
process.on('uncaughtException', exitHandler.bind(null, { exit: true }));
|
||||
//# sourceMappingURL=index.js.map
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,6 @@
|
|||
export type ExposureSingle = [number];
|
||||
export type ExposureChannels = [number, number, number];
|
||||
export declare class Exposure {
|
||||
constructor();
|
||||
static map(value: number, start1: number, stop1: number, start2: number, stop2: number): number;
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.Exposure = void 0;
|
||||
class Exposure {
|
||||
constructor() {
|
||||
}
|
||||
static map(value, start1, stop1, start2, stop2) {
|
||||
if (value < start1) {
|
||||
value = start1;
|
||||
}
|
||||
else if (value > stop1) {
|
||||
value = stop1;
|
||||
}
|
||||
const ratio = (value - start1) / (stop1 - start1);
|
||||
const mappedValue = start2 + (stop2 - start2) * ratio;
|
||||
return mappedValue;
|
||||
}
|
||||
}
|
||||
exports.Exposure = Exposure;
|
||||
module.exports = { Exposure };
|
||||
//# sourceMappingURL=index.js.map
|
||||
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/exposure/index.ts"],"names":[],"mappings":";;;AAIA,MAAa,QAAQ;IACpB;IAEA,CAAC;IAEM,MAAM,CAAC,GAAG,CAAE,KAAc,EAAE,MAAe,EAAE,KAAc,EAAE,MAAe,EAAE,KAAc;QAClG,IAAI,KAAK,GAAG,MAAM,EAAE,CAAC;YACpB,KAAK,GAAG,MAAM,CAAC;QAChB,CAAC;aAAM,IAAI,KAAK,GAAG,KAAK,EAAE,CAAC;YAC1B,KAAK,GAAG,KAAK,CAAC;QACf,CAAC;QAEA,MAAM,KAAK,GAAY,CAAC,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,KAAK,GAAG,MAAM,CAAC,CAAC;QAC3D,MAAM,WAAW,GAAY,MAAM,GAAG,CAAC,KAAK,GAAG,MAAM,CAAC,GAAG,KAAK,CAAC;QAE/D,OAAO,WAAW,CAAC;IAErB,CAAC;CACD;AAlBD,4BAkBC;AAED,MAAM,CAAC,OAAO,GAAG,EAAE,QAAQ,EAAE,CAAC"}
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
declare enum Action {
|
||||
export declare enum Action {
|
||||
NONE = 0,
|
||||
LOAD = 1,
|
||||
DISPLAY = 2,
|
||||
STOP = 3
|
||||
}
|
||||
declare enum Mode {
|
||||
export declare enum Mode {
|
||||
RGB = 0,
|
||||
BW = 1,
|
||||
INVERT = 2,
|
||||
|
|
@ -51,6 +51,7 @@ export declare class FD {
|
|||
private socketConnected;
|
||||
private waiting;
|
||||
private mock;
|
||||
private mode;
|
||||
constructor(bin: string, width: number, height: number, host: string, port: number, display?: string, mock?: boolean);
|
||||
private startDisplay;
|
||||
private startClient;
|
||||
|
|
@ -64,5 +65,6 @@ export declare class FD {
|
|||
isConnected(): boolean;
|
||||
private test;
|
||||
exit(): Promise<void>;
|
||||
setMode(mode: Mode): void;
|
||||
}
|
||||
export type { Action, Mode, fdOutgoingPosition, fdOutgoingMessage, fdIncomingMessage, fdResult };
|
||||
export type { fdOutgoingPosition, fdOutgoingMessage, fdIncomingMessage, fdResult };
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.FD = void 0;
|
||||
exports.FD = exports.Mode = exports.Action = void 0;
|
||||
const net_1 = __importDefault(require("net"));
|
||||
const log_1 = require("../log");
|
||||
const shell_1 = require("../shell");
|
||||
|
|
@ -14,7 +14,7 @@ var Action;
|
|||
Action[Action["LOAD"] = 1] = "LOAD";
|
||||
Action[Action["DISPLAY"] = 2] = "DISPLAY";
|
||||
Action[Action["STOP"] = 3] = "STOP";
|
||||
})(Action || (Action = {}));
|
||||
})(Action || (exports.Action = Action = {}));
|
||||
var Mode;
|
||||
(function (Mode) {
|
||||
Mode[Mode["RGB"] = 0] = "RGB";
|
||||
|
|
@ -23,7 +23,7 @@ var Mode;
|
|||
Mode[Mode["BW_INVERT"] = 3] = "BW_INVERT";
|
||||
Mode[Mode["RGB_CHANNELS"] = 4] = "RGB_CHANNELS";
|
||||
Mode[Mode["INVERT_CHANNELS"] = 5] = "INVERT_CHANNELS";
|
||||
})(Mode || (Mode = {}));
|
||||
})(Mode || (exports.Mode = Mode = {}));
|
||||
class FD {
|
||||
constructor(bin, width, height, host, port, display = null, mock = false) {
|
||||
this.env = null;
|
||||
|
|
@ -33,6 +33,7 @@ class FD {
|
|||
this.socketConnected = false;
|
||||
this.waiting = null;
|
||||
this.mock = false;
|
||||
this.mode = Mode.RGB;
|
||||
this.bin = bin;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
|
|
@ -127,6 +128,7 @@ class FD {
|
|||
async load(image, x, y, w, h) {
|
||||
const msg = {
|
||||
action: Action.LOAD,
|
||||
mode: this.mode,
|
||||
image,
|
||||
position: {
|
||||
x,
|
||||
|
|
@ -166,6 +168,7 @@ class FD {
|
|||
async display(image, exposure = []) {
|
||||
const msg = {
|
||||
action: Action.DISPLAY,
|
||||
mode: this.mode,
|
||||
image,
|
||||
exposure
|
||||
};
|
||||
|
|
@ -258,7 +261,13 @@ class FD {
|
|||
if (this.shell !== null)
|
||||
this.shell.kill();
|
||||
}
|
||||
setMode(mode) {
|
||||
if (mode !== this.mode) {
|
||||
this.log.info(`Set mode to: ${mode}`);
|
||||
}
|
||||
this.mode = mode;
|
||||
}
|
||||
}
|
||||
exports.FD = FD;
|
||||
module.exports = { FD };
|
||||
module.exports = { FD, Action, Mode, };
|
||||
//# sourceMappingURL=index.js.map
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -246,6 +246,9 @@ async function cmd(msg) {
|
|||
case 'framing':
|
||||
await framing();
|
||||
break;
|
||||
case 'blank':
|
||||
await blank();
|
||||
break;
|
||||
case 'offset':
|
||||
offset(msg);
|
||||
break;
|
||||
|
|
@ -307,6 +310,15 @@ async function start() {
|
|||
function stop() {
|
||||
sequence.stop();
|
||||
}
|
||||
async function blank() {
|
||||
if (focusImage !== null) {
|
||||
await stopFocus();
|
||||
}
|
||||
if (framingImage !== null) {
|
||||
await stopFraming();
|
||||
}
|
||||
await send({ cmd: 'blank' });
|
||||
}
|
||||
async function send(msg) {
|
||||
const msgStr = JSON.stringify(msg);
|
||||
wss.clients.forEach((client) => {
|
||||
|
|
@ -344,6 +356,7 @@ async function focus() {
|
|||
};
|
||||
}
|
||||
focusImage = await testimage_1.TestImage.Focus(pos.w, pos.h);
|
||||
fd.setMode(fd_1.Mode.RGB);
|
||||
await fd.load(focusImage, pos.x, pos.y, pos.w, pos.h);
|
||||
await fd.display(focusImage);
|
||||
send({ cmd: 'focus' });
|
||||
|
|
@ -381,6 +394,7 @@ async function framing() {
|
|||
};
|
||||
}
|
||||
framingImage = await testimage_1.TestImage.Frame(pos.w, pos.h);
|
||||
fd.setMode(fd_1.Mode.RGB);
|
||||
await fd.load(framingImage, pos.x, pos.y, pos.w, pos.h);
|
||||
await fd.display(framingImage);
|
||||
send({ cmd: 'framing' });
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -9,6 +9,7 @@
|
|||
"version": "0.0.1",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"argparse": "^2.0.1",
|
||||
"body-parser": "^1.20.2",
|
||||
"dotenv": "^16.4.5",
|
||||
"express": "^4.19.2",
|
||||
|
|
@ -1063,6 +1064,12 @@
|
|||
"node": "^12.13.0 || ^14.15.0 || >=16.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/argparse": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
|
||||
"license": "Python-2.0"
|
||||
},
|
||||
"node_modules/array-flatten": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
|
||||
|
|
@ -4145,6 +4152,11 @@
|
|||
"readable-stream": "^3.6.0"
|
||||
}
|
||||
},
|
||||
"argparse": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
||||
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
|
||||
},
|
||||
"array-flatten": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
"typescript": "^5.4.5"
|
||||
},
|
||||
"dependencies": {
|
||||
"argparse": "^2.0.1",
|
||||
"body-parser": "^1.20.2",
|
||||
"dotenv": "^16.4.5",
|
||||
"express": "^4.19.2",
|
||||
|
|
|
|||
118
src/cli/index.ts
118
src/cli/index.ts
|
|
@ -3,29 +3,35 @@ import { readFile, lstat} from 'fs/promises';
|
|||
import type { Stats } from 'fs';
|
||||
import { tmpdir, EOL } from 'os';
|
||||
import { join, basename } from 'path';
|
||||
import { ArgumentParser } from 'argparse';
|
||||
import type { Logger } from 'winston';
|
||||
import { createLog } from '../log';
|
||||
|
||||
import { envInt, envString} from '../env';
|
||||
import { FD } from '../fd';
|
||||
import type { fdOutgoingPosition, fdResult } from '../fd';
|
||||
import { FD, Mode, Action } from '../fd';
|
||||
import type { fdOutgoingPosition, fdResult} from '../fd';
|
||||
import { Display, Dimensions } from '../display';
|
||||
import { Files } from '../files';
|
||||
import type { ImageObject } from '../files';
|
||||
import { delay } from '../delay';
|
||||
import { Camera } from '../camera';
|
||||
import { TestImage } from '../testimage';
|
||||
|
||||
let cli : CLI;
|
||||
|
||||
enum Actions {
|
||||
LOAD,
|
||||
DISPLAY,
|
||||
DELAY
|
||||
EXPOSE,
|
||||
DELAY,
|
||||
FORWARD,
|
||||
BACKWARD,
|
||||
GOTO
|
||||
}
|
||||
|
||||
interface Args {
|
||||
input? : string;
|
||||
width? : number;
|
||||
height? : number;
|
||||
mock: boolean;
|
||||
mock?: boolean;
|
||||
}
|
||||
|
||||
interface CMD {
|
||||
|
|
@ -35,9 +41,9 @@ interface CMD {
|
|||
}
|
||||
|
||||
export class CLI {
|
||||
private log : Logger;
|
||||
public log : Logger;
|
||||
private args : Args;
|
||||
private fd : FD;
|
||||
public fd : FD;
|
||||
private camera : Camera;
|
||||
private display: Display;
|
||||
|
||||
|
|
@ -46,7 +52,7 @@ export class CLI {
|
|||
private height : number;
|
||||
private host : string;
|
||||
private port : number;
|
||||
private mock : boolean = true;
|
||||
private mock : boolean = false;
|
||||
private displayStr : string | null;
|
||||
|
||||
private lastImage : string | null;
|
||||
|
|
@ -54,6 +60,7 @@ export class CLI {
|
|||
constructor () {
|
||||
this.log = createLog('fm');
|
||||
this.settings();
|
||||
this.args = this.getArgs();
|
||||
this.display = new Display(this.width, this.height);
|
||||
this.fd = new FD(this.bin, this.width, this.height, this.host, this.port, this.displayStr, this.mock);
|
||||
this.camera = new Camera(this.mock);
|
||||
|
|
@ -67,7 +74,9 @@ export class CLI {
|
|||
await this.parse(this.args.input);
|
||||
await delay(2000)
|
||||
}
|
||||
await delay(5000);
|
||||
this.fd.exit();
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
private settings () {
|
||||
|
|
@ -80,12 +89,23 @@ export class CLI {
|
|||
this.port = envInt('FD_PORT', 8082);
|
||||
}
|
||||
|
||||
private parseLine (line : string) : CMD {
|
||||
let parts : string[];
|
||||
if (line.trim() === '') {
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
private getArgs () {
|
||||
const parser = new ArgumentParser({
|
||||
description: 'Filmout manager CLI application',
|
||||
});
|
||||
/*
|
||||
parser.addArgument(['-f', '--file'], {
|
||||
help: 'Path to a file',
|
||||
type: String, // Explicitly define type
|
||||
required: true,
|
||||
});
|
||||
|
||||
parser.addArgument(['-v', '--verbose'], {
|
||||
help: 'Enable verbose output',
|
||||
action: 'storeTrue', // Boolean flag
|
||||
});
|
||||
*/
|
||||
return parser.parseArgs();
|
||||
}
|
||||
|
||||
private async parse (filePath : string) {
|
||||
|
|
@ -112,26 +132,56 @@ export class CLI {
|
|||
}
|
||||
}
|
||||
|
||||
private parseLine (line : string) : CMD {
|
||||
let parts : string[];
|
||||
let cmd : CMD = {} as CMD;
|
||||
let cmdChar : string;
|
||||
|
||||
if (line.trim() === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
this.log.info(`LINE: ${line.trim()}`);
|
||||
|
||||
parts = line.split(',');
|
||||
|
||||
if (parts.length > 0) {
|
||||
cmdChar = parts[0].trim().toUpperCase()[0];
|
||||
switch (cmdChar) {
|
||||
case 'E' :
|
||||
cmd.action = Actions.EXPOSE;
|
||||
break;
|
||||
case 'D':
|
||||
cmd.action = Actions.DELAY;
|
||||
cmd.time = 1000;
|
||||
break;
|
||||
default :
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private async execute (cmd : CMD) {
|
||||
if (cmd === null) return;
|
||||
switch (cmd.action) {
|
||||
case Actions.DELAY:
|
||||
await delay(cmd.time);
|
||||
break;
|
||||
case Actions.DISPLAY :
|
||||
await this.frame(cmd);
|
||||
case Actions.EXPOSE :
|
||||
await this.expose(cmd);
|
||||
break;
|
||||
default :
|
||||
break;
|
||||
}
|
||||
// await this.load(img, 100, 200, 640, 640);
|
||||
//await this.load(img, 100, 200, 640, 640);
|
||||
//await delay(2000);
|
||||
|
||||
//await this.display(img, [ 4000 ] );
|
||||
//await delay(8000);
|
||||
}
|
||||
|
||||
private async frame (cmd : CMD) {
|
||||
private async expose (cmd : CMD) {
|
||||
const start : number = Date.now();
|
||||
let load : number;
|
||||
let open : number;
|
||||
|
|
@ -160,5 +210,31 @@ export class CLI {
|
|||
}
|
||||
|
||||
if (require.main === module) {
|
||||
new CLI();
|
||||
}
|
||||
cli = new CLI();
|
||||
}
|
||||
|
||||
async function exitHandler(options : any, exitCode : string) {
|
||||
if (options.cleanup) {
|
||||
cli.log.info(`Cleaning up...`);
|
||||
try {
|
||||
await cli.fd.exit();
|
||||
} catch (err) {
|
||||
cli.log.error('Error cleanly exiting filmout_display (fd) executable', err);
|
||||
}
|
||||
}
|
||||
exitCode == 'SIGINT' ? cli.log.info(`exit: ${exitCode}`) : cli.log.error(`exit: ${exitCode}`, new Error(`Exited with non-zero code: "${exitCode}"`));
|
||||
if (options.exit) process.exit();
|
||||
}
|
||||
|
||||
// do something when app is closing
|
||||
process.on('exit', exitHandler.bind(null,{cleanup:true}));
|
||||
|
||||
// catches ctrl+c event
|
||||
process.on('SIGINT', exitHandler.bind(null, {exit:true}));
|
||||
|
||||
// catches "kill pid" (for example: nodemon restart)
|
||||
process.on('SIGUSR1', exitHandler.bind(null, {exit:true}));
|
||||
process.on('SIGUSR2', exitHandler.bind(null, {exit:true}));
|
||||
|
||||
// catches uncaught exceptions
|
||||
process.on('uncaughtException', exitHandler.bind(null, {exit:true}));
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
|
||||
export type ExposureSingle = [ number ];
|
||||
export type ExposureChannels = [number, number, number];
|
||||
|
||||
export class Exposure {
|
||||
constructor () {
|
||||
|
||||
}
|
||||
|
||||
public static map (value : number, start1 : number, stop1 : number, start2 : number, stop2 : number) : number {
|
||||
if (value < start1) {
|
||||
value = start1;
|
||||
} else if (value > stop1) {
|
||||
value = stop1;
|
||||
}
|
||||
|
||||
const ratio : number = (value - start1) / (stop1 - start1);
|
||||
const mappedValue : number = start2 + (stop2 - start2) * ratio;
|
||||
|
||||
return mappedValue;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { Exposure };
|
||||
|
|
@ -5,20 +5,15 @@ import { createLog } from '../log'
|
|||
import { Shell } from '../shell';
|
||||
import { delay } from '../delay';
|
||||
|
||||
enum Action {
|
||||
export enum Action {
|
||||
NONE,
|
||||
LOAD,
|
||||
DISPLAY,
|
||||
STOP
|
||||
}
|
||||
|
||||
enum Mode {
|
||||
RGB,
|
||||
BW,
|
||||
INVERT,
|
||||
BW_INVERT,
|
||||
RGB_CHANNELS,
|
||||
INVERT_CHANNELS
|
||||
export enum Mode {
|
||||
RGB
|
||||
}
|
||||
|
||||
interface fdOutgoingPosition {
|
||||
|
|
@ -66,6 +61,8 @@ export class FD {
|
|||
private waiting : Function = null;
|
||||
private mock : boolean = false;
|
||||
|
||||
private mode : Mode = Mode.RGB;
|
||||
|
||||
constructor (bin: string, width : number, height : number, host : string, port : number, display : string = null, mock : boolean = false) {
|
||||
this.bin = bin;
|
||||
this.width = width;
|
||||
|
|
@ -167,6 +164,7 @@ export class FD {
|
|||
public async load (image : string, x : number, y : number, w : number, h : number) : Promise<fdResult> {
|
||||
const msg : fdOutgoingMessage = {
|
||||
action : Action.LOAD,
|
||||
mode : this.mode,
|
||||
image,
|
||||
position : {
|
||||
x,
|
||||
|
|
@ -206,6 +204,7 @@ export class FD {
|
|||
public async display (image : string, exposure : number[] = []) : Promise<fdResult> {
|
||||
const msg : fdOutgoingMessage = {
|
||||
action : Action.DISPLAY,
|
||||
mode : this.mode,
|
||||
image,
|
||||
exposure
|
||||
};
|
||||
|
|
@ -304,8 +303,15 @@ export class FD {
|
|||
if (this.client !== null) this.client.end();
|
||||
if (this.shell !== null) this.shell.kill();
|
||||
}
|
||||
|
||||
public setMode (mode : Mode) {
|
||||
if (mode !== this.mode) {
|
||||
this.log.info(`Set mode to: ${mode}`);
|
||||
}
|
||||
this.mode = mode;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { FD };
|
||||
module.exports = { FD, Action, Mode,};
|
||||
|
||||
export type { Action, Mode, fdOutgoingPosition, fdOutgoingMessage, fdIncomingMessage, fdResult };
|
||||
export type { fdOutgoingPosition, fdOutgoingMessage, fdIncomingMessage, fdResult };
|
||||
|
|
|
|||
17
src/index.ts
17
src/index.ts
|
|
@ -21,7 +21,7 @@ import { Files } from './files';
|
|||
import type { SequenceObject, VideoObject, ImageObject } from './files';
|
||||
import { delay } from './delay';
|
||||
import { TestImage } from './testimage';
|
||||
import { FD } from './fd';
|
||||
import { FD, Mode, Action} from './fd';
|
||||
import type { fdOutgoingPosition } from './fd';
|
||||
import { Display, Dimensions } from './display';
|
||||
import { FFMPEG } from './ffmpeg';
|
||||
|
|
@ -234,6 +234,9 @@ async function cmd (msg : Message) {
|
|||
case 'framing' :
|
||||
await framing();
|
||||
break;
|
||||
case 'blank' :
|
||||
await blank();
|
||||
break;
|
||||
case 'offset' :
|
||||
offset(msg);
|
||||
break;
|
||||
|
|
@ -305,6 +308,16 @@ function stop () {
|
|||
sequence.stop();
|
||||
}
|
||||
|
||||
async function blank () {
|
||||
if (focusImage !== null) {
|
||||
await stopFocus();
|
||||
}
|
||||
if (framingImage !== null) {
|
||||
await stopFraming();
|
||||
}
|
||||
await send({ cmd : 'blank' });
|
||||
}
|
||||
|
||||
async function send (msg : Message) {
|
||||
const msgStr : string = JSON.stringify(msg);
|
||||
wss.clients.forEach((client : WebSocket ) => {
|
||||
|
|
@ -343,6 +356,7 @@ async function focus () {
|
|||
}
|
||||
}
|
||||
focusImage = await TestImage.Focus(pos.w, pos.h);
|
||||
fd.setMode(Mode.RGB);
|
||||
await fd.load (focusImage, pos.x, pos.y, pos.w, pos.h);
|
||||
await fd.display(focusImage);
|
||||
send({ cmd : 'focus' });
|
||||
|
|
@ -381,6 +395,7 @@ async function framing () {
|
|||
}
|
||||
}
|
||||
framingImage = await TestImage.Frame(pos.w, pos.h);
|
||||
fd.setMode(Mode.RGB);
|
||||
await fd.load (framingImage, pos.x, pos.y, pos.w, pos.h);
|
||||
await fd.display(framingImage);
|
||||
send({ cmd : 'framing' });
|
||||
|
|
|
|||
|
|
@ -32,6 +32,24 @@ html, body{
|
|||
display: none;
|
||||
}
|
||||
|
||||
#overlayWrapper {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
overflow: hidden;
|
||||
}
|
||||
#overlayMessage{
|
||||
display: inline-block;
|
||||
color: #fff;
|
||||
background: rgba(125, 125, 125, 0.5);
|
||||
border-radius: 8px;
|
||||
padding: 10px 20px;
|
||||
margin: 25vh auto;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#frame{
|
||||
text-align: center !important;
|
||||
font-family: monospace;
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ declare class Display {
|
|||
unsetFocus(): void;
|
||||
setFraming(): void;
|
||||
unsetFraming(): void;
|
||||
blank(): void;
|
||||
private onResize;
|
||||
}
|
||||
declare class Client {
|
||||
|
|
@ -93,9 +94,11 @@ declare class Client {
|
|||
sendFraming(): void;
|
||||
private receiveFraming;
|
||||
private receiveUnframing;
|
||||
private receiveBlank;
|
||||
sendOffset(x: number, y: number): void;
|
||||
sendSize(width: number, height: number): void;
|
||||
sendScale(scale: number): void;
|
||||
sendBlank(): void;
|
||||
fullscreen(): void;
|
||||
exitFullscreen(): void;
|
||||
private active;
|
||||
|
|
|
|||
|
|
@ -117,6 +117,13 @@ class Display {
|
|||
unsetFraming() {
|
||||
this.framing = false;
|
||||
}
|
||||
blank() {
|
||||
this.unsetFocus();
|
||||
this.unsetFraming();
|
||||
this.updateSize();
|
||||
this.clear();
|
||||
this.updateScreen();
|
||||
}
|
||||
onResize(event) {
|
||||
this.updateSize();
|
||||
this.clear();
|
||||
|
|
@ -421,6 +428,9 @@ class Client {
|
|||
this.display.unsetFraming();
|
||||
this.display.updateImage();
|
||||
}
|
||||
receiveBlank(msg) {
|
||||
this.display.blank();
|
||||
}
|
||||
sendOffset(x, y) {
|
||||
this.client.send(JSON.stringify({ cmd: 'offset', x, y }));
|
||||
}
|
||||
|
|
@ -430,6 +440,9 @@ class Client {
|
|||
sendScale(scale) {
|
||||
this.client.send(JSON.stringify({ cmd: 'scale', scale }));
|
||||
}
|
||||
sendBlank() {
|
||||
this.client.send(JSON.stringify({ cmd: 'blank' }));
|
||||
}
|
||||
fullscreen() {
|
||||
if (!document.fullscreenElement) {
|
||||
document.documentElement.requestFullscreen();
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1 @@
|
|||
E,test/grayscale_43.jpg,500
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 59 KiB |
|
|
@ -121,6 +121,7 @@
|
|||
<button id="close" class="manualCtrl" onclick="client.sendCameraClose()">Close</button>
|
||||
<button id="focus" class="manualCtrl" onclick="client.sendFocus();">Focus</button>
|
||||
<button id="framing" class="manualCtrl" onclick="client.sendFraming();">Framing</button>
|
||||
<button id="blank" class="manualCtrl" onclick="client.sendBlank();">Blank</button>
|
||||
</form>
|
||||
</fieldset>
|
||||
</div>
|
||||
|
|
@ -276,7 +277,11 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="overlay"></div>
|
||||
<div id="overlay">
|
||||
<div id="overlayWrapper">
|
||||
<div id="overlayMessage" onclick="window.location.reload();">Refresh</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
const WEBSOCKET_PORT = {{wsPort}};
|
||||
</script>
|
||||
|
|
|
|||
Loading…
Reference in New Issue