init
This commit is contained in:
parent
abfb03189a
commit
40d0fcff6f
16 changed files with 732 additions and 0 deletions
87
README
Normal file
87
README
Normal file
|
|
@ -0,0 +1,87 @@
|
||||||
|
|
||||||
|
Maps midi signals coming from ALSA midi devices to shell commands
|
||||||
|
For a release build: `$ make clean ; make -B RELEASE=true`
|
||||||
|
|
||||||
|
usage: midiMap <config file>
|
||||||
|
This is a daemon program, it does not start any background process by itself and needs to be constantly running for the mapping to be active
|
||||||
|
|
||||||
|
This program is in early stage but is fully functional without any major errors
|
||||||
|
|
||||||
|
TODO:
|
||||||
|
- Use integrated C MIDI control
|
||||||
|
- Support for multiple identical devices
|
||||||
|
- Support for system reserved commands
|
||||||
|
- Options
|
||||||
|
- Better error handling on wrong config file format
|
||||||
|
|
||||||
|
|
||||||
|
See 'example.mim' for an example config file
|
||||||
|
|
||||||
|
|
||||||
|
-- COMMAND FORMAT --
|
||||||
|
|
||||||
|
Format is a regular shell format
|
||||||
|
|
||||||
|
-- Environment
|
||||||
|
- Global
|
||||||
|
$channel: channel of the
|
||||||
|
$id: id of the note/controller
|
||||||
|
|
||||||
|
- Note
|
||||||
|
$velocity: velocity of the note
|
||||||
|
|
||||||
|
- Controller
|
||||||
|
$value: value of the controller (remapped)
|
||||||
|
$rawvalue: original value of the controller
|
||||||
|
|
||||||
|
|
||||||
|
-- FILE FORMAT --
|
||||||
|
[<device>,<device>]
|
||||||
|
|
||||||
|
- <device> format:
|
||||||
|
{
|
||||||
|
name=<name>
|
||||||
|
commands=[<command>,<command>]
|
||||||
|
}
|
||||||
|
-
|
||||||
|
*name: string referring to client name of the device ($ aseqdump -l)
|
||||||
|
|
||||||
|
- command format (global):
|
||||||
|
{
|
||||||
|
type=<note/controller>
|
||||||
|
id=<x>
|
||||||
|
shell=<shell command>
|
||||||
|
channel=<*/x>
|
||||||
|
}
|
||||||
|
-
|
||||||
|
*id: value from 0 to 127 referring to id of note/controller
|
||||||
|
> mandatory
|
||||||
|
*shell: shell command to be executed
|
||||||
|
> mandatory
|
||||||
|
*channel: value from 0 to 16 for channel. Can use * for any channel
|
||||||
|
> optional, default *
|
||||||
|
|
||||||
|
|
||||||
|
- <command> format (note)
|
||||||
|
{
|
||||||
|
trigger=<x:y/x>
|
||||||
|
}
|
||||||
|
-
|
||||||
|
*trigger: note velocity from 0 to 127 that triggers the command. Can enter an interval x:y or single value
|
||||||
|
> optional, default 1:127
|
||||||
|
|
||||||
|
- <command> format (note)
|
||||||
|
{
|
||||||
|
range=<x:y>
|
||||||
|
remap=<x:y>
|
||||||
|
float=<true/false>
|
||||||
|
}
|
||||||
|
-
|
||||||
|
*range: controller value from 0 to 127 that triggers command. Can enter an interval x:y or single value
|
||||||
|
> optional, default 0:127
|
||||||
|
*remap: remaps the range to given interval. Interval can be inversed and float
|
||||||
|
> optional, default same as range
|
||||||
|
*float: boolean value defining if output is a floating point value
|
||||||
|
> optional, default false
|
||||||
|
|
||||||
|
- Comments can be written inside {} by doing //=<COMMENT>
|
||||||
68
example.mim
Normal file
68
example.mim
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
[
|
||||||
|
|
||||||
|
{
|
||||||
|
name=Launch Control
|
||||||
|
commands=[
|
||||||
|
{
|
||||||
|
type=note
|
||||||
|
id=9
|
||||||
|
channel=0
|
||||||
|
trigger=1:127
|
||||||
|
shell=echo "Note $id on ch$channel v$velocity"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type=note
|
||||||
|
id=9
|
||||||
|
channel=0
|
||||||
|
trigger=0
|
||||||
|
shell=echo "Note $id off ch$channel"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
//=KNOB L1
|
||||||
|
//=displays value 0:127 for knob 41 from any channel
|
||||||
|
type=controller
|
||||||
|
id=41
|
||||||
|
channel=*
|
||||||
|
shell=echo "Knob #$id ch$channel:$value"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
//=KNOB L2
|
||||||
|
//=displays value -100:100 for knob 42 on channel 0
|
||||||
|
type=controller
|
||||||
|
id=42
|
||||||
|
channel=0
|
||||||
|
remap=-100:100
|
||||||
|
float=true
|
||||||
|
shell=echo "Knob #$id ch$channel:$value r:$rawvalue"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
//=KNOB L3 H1
|
||||||
|
//=displays value 0:1:0 for knob 42 on channel 1 (first half)
|
||||||
|
type=controller
|
||||||
|
id=42
|
||||||
|
channel=1
|
||||||
|
range=0:63
|
||||||
|
remap=0:1
|
||||||
|
float=true
|
||||||
|
shell=echo "Knob #$id ch$channel:$value"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
//=KNOB L3 H2
|
||||||
|
//=displays value 0:1:0 for knob 42 on channel 1 (second half)
|
||||||
|
type=controller
|
||||||
|
id=42
|
||||||
|
channel=1
|
||||||
|
range=64:127
|
||||||
|
remap=1:0
|
||||||
|
float=true
|
||||||
|
shell=echo "Knob #$id ch$channel:$value"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
,
|
||||||
|
{
|
||||||
|
name=Launchpad S
|
||||||
|
commands=[]
|
||||||
|
}
|
||||||
|
|
||||||
|
]
|
||||||
1
include/Filedat.hpp
Symbolic link
1
include/Filedat.hpp
Symbolic link
|
|
@ -0,0 +1 @@
|
||||||
|
/home/zawz/code/c/tool/zFiledat/Filedat.hpp
|
||||||
38
include/command.hpp
Normal file
38
include/command.hpp
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
#ifndef COMMAND_HPP
|
||||||
|
#define COMMAND_HPP
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class NoteCommand
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
NoteCommand(uint8_t i, uint8_t ch, uint8_t l, uint8_t h, std::string sh);
|
||||||
|
|
||||||
|
uint8_t id;
|
||||||
|
uint8_t channel;
|
||||||
|
uint8_t low;
|
||||||
|
uint8_t high;
|
||||||
|
std::string shell;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ControllerCommand
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
ControllerCommand(uint8_t i, int8_t ch, uint8_t l, uint8_t h, float ml, float mm, bool fl, std::string sh);
|
||||||
|
|
||||||
|
uint8_t id;
|
||||||
|
int8_t channel;
|
||||||
|
uint8_t min;
|
||||||
|
uint8_t max;
|
||||||
|
float mapMin;
|
||||||
|
float mapMax;
|
||||||
|
bool floating;
|
||||||
|
std::string shell;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //COMMAND_HPP
|
||||||
38
include/device.hpp
Normal file
38
include/device.hpp
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
#ifndef DEVICE_HPP
|
||||||
|
#define DEVICE_HPP
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
#include "command.hpp"
|
||||||
|
|
||||||
|
#include "Filedat.hpp"
|
||||||
|
|
||||||
|
class Device
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Device();
|
||||||
|
virtual ~Device();
|
||||||
|
|
||||||
|
bool start_loop();
|
||||||
|
|
||||||
|
bool import_chunk(Chunk const& ch);
|
||||||
|
Chunk export_chunk();
|
||||||
|
|
||||||
|
std::string name;
|
||||||
|
bool busy;
|
||||||
|
|
||||||
|
uint32_t nb_command;
|
||||||
|
std::vector<NoteCommand> noteCommands[128];
|
||||||
|
std::vector<ControllerCommand> ctrlCommands[128];
|
||||||
|
// std::vector<Command> systCommands;
|
||||||
|
|
||||||
|
std::thread thread;
|
||||||
|
private:
|
||||||
|
static void loop(Device* dev);
|
||||||
|
};
|
||||||
|
|
||||||
|
extern std::vector<Device*> device_list;
|
||||||
|
|
||||||
|
#endif //DEVICE_HPP
|
||||||
1
include/options.hpp
Symbolic link
1
include/options.hpp
Symbolic link
|
|
@ -0,0 +1 @@
|
||||||
|
/home/zawz/code/c/tool/zOptions/options.hpp
|
||||||
1
include/stringTools.hpp
Symbolic link
1
include/stringTools.hpp
Symbolic link
|
|
@ -0,0 +1 @@
|
||||||
|
/home/zawz/code/c/tool/stringTools/stringTools.hpp
|
||||||
8
include/system.hpp
Normal file
8
include/system.hpp
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
#ifndef SYSTEM_HPP
|
||||||
|
#define SYSTEM_HPP
|
||||||
|
|
||||||
|
void device_check();
|
||||||
|
|
||||||
|
void announce_loop();
|
||||||
|
|
||||||
|
#endif //SYSTEM_HPP
|
||||||
36
makefile
Normal file
36
makefile
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
IDIR=include
|
||||||
|
SRCDIR=src
|
||||||
|
ODIR=obj
|
||||||
|
BINDIR=bin
|
||||||
|
|
||||||
|
NAME = zmidimap
|
||||||
|
|
||||||
|
CC=g++
|
||||||
|
CXXFLAGS= -I$(IDIR) -Wall -pedantic -std=c++17
|
||||||
|
ifeq ($(RELEASE),true)
|
||||||
|
BINDIR=.
|
||||||
|
else
|
||||||
|
CXXFLAGS += -g
|
||||||
|
endif
|
||||||
|
|
||||||
|
LDFLAGS = -lpthread
|
||||||
|
|
||||||
|
# automatically finds .hpp
|
||||||
|
DEPS = $(shell if [ -n "$(ld $(IDIR))" ] ; then ls $(IDIR)/*.hpp ; fi)
|
||||||
|
# automatically finds .cpp and makes the corresponding .o rule
|
||||||
|
OBJ = $(shell ls $(SRCDIR)/*.cpp | sed 's/.cpp/.o/g;s|$(SRCDIR)/|$(ODIR)/|g')
|
||||||
|
|
||||||
|
$(ODIR)/%.o: $(SRCDIR)/%.cpp $(DEPS)
|
||||||
|
$(CC) $(CXXFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
|
$(BINDIR)/$(NAME): $(OBJ) $(DEPS)
|
||||||
|
$(CC) $(CXXFLAGS) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
|
test: $(BINDIR)/$(NAME)
|
||||||
|
$(BINDIR)/$(NAME)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm $(ODIR)/*.o
|
||||||
|
|
||||||
|
clear:
|
||||||
|
rm $(BINDIR)/$(NAME)
|
||||||
1
src/Filedat.cpp
Symbolic link
1
src/Filedat.cpp
Symbolic link
|
|
@ -0,0 +1 @@
|
||||||
|
/home/zawz/code/c/tool/zFiledat/Filedat.cpp
|
||||||
22
src/command.cpp
Normal file
22
src/command.cpp
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
#include "command.hpp"
|
||||||
|
|
||||||
|
NoteCommand::NoteCommand(uint8_t i, uint8_t ch, uint8_t l, uint8_t h, std::string sh)
|
||||||
|
{
|
||||||
|
this->id=i;
|
||||||
|
this->channel=ch;
|
||||||
|
this->low=l;
|
||||||
|
this->high=h;
|
||||||
|
this->shell=sh;
|
||||||
|
}
|
||||||
|
|
||||||
|
ControllerCommand::ControllerCommand(uint8_t i, int8_t ch, uint8_t l, uint8_t h, float ml, float mh, bool fl, std::string sh)
|
||||||
|
{
|
||||||
|
this->id=i;
|
||||||
|
this->channel=ch;
|
||||||
|
this->min=l;
|
||||||
|
this->max=h;
|
||||||
|
this->mapMin=ml;
|
||||||
|
this->mapMax=mh;
|
||||||
|
this->floating=fl;
|
||||||
|
this->shell=sh;
|
||||||
|
}
|
||||||
289
src/device.cpp
Normal file
289
src/device.cpp
Normal file
|
|
@ -0,0 +1,289 @@
|
||||||
|
#include "device.hpp"
|
||||||
|
|
||||||
|
#include "stringTools.hpp"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#define KILL_COMMAND_FH "kill -s INT $(ps -f | grep \"aseqdump -p "
|
||||||
|
#define KILL_COMMAND_SH "\" | grep -v grep | awk '{print $2}' | head -n1)"
|
||||||
|
|
||||||
|
std::vector<Device*> device_list;
|
||||||
|
|
||||||
|
static void sh(std::string const& string)
|
||||||
|
{
|
||||||
|
system(string.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
Device::Device()
|
||||||
|
{
|
||||||
|
busy=false;
|
||||||
|
nb_command=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Device::~Device()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Device::start_loop()
|
||||||
|
{
|
||||||
|
if(this->busy)
|
||||||
|
return false;
|
||||||
|
this->busy = true;
|
||||||
|
this->thread = std::thread(Device::loop, this);
|
||||||
|
this->thread.detach();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Device::import_chunk(Chunk const& ch)
|
||||||
|
{
|
||||||
|
Chunk& cch = ch["commands"];
|
||||||
|
this->name=ch["name"].strval();
|
||||||
|
for(int i=0 ; i<cch.listSize() ; i++)
|
||||||
|
{
|
||||||
|
Chunk& tch=cch[i];
|
||||||
|
std::string tstr=tch["type"].strval();
|
||||||
|
if(tstr == "system") //type system
|
||||||
|
{
|
||||||
|
throw std::runtime_error("System commands not implemented yet");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int8_t channel;
|
||||||
|
uint8_t id;
|
||||||
|
std::string shell;
|
||||||
|
|
||||||
|
//id
|
||||||
|
id=stoi(tch["id"].strval());
|
||||||
|
|
||||||
|
//channel
|
||||||
|
if(tch["channel"].strval()=="*")
|
||||||
|
channel=-1;
|
||||||
|
else
|
||||||
|
channel=stoi(tch["channel"].strval());
|
||||||
|
|
||||||
|
//shell
|
||||||
|
shell=tch["shell"].strval();
|
||||||
|
|
||||||
|
//type
|
||||||
|
if(tstr == "note") //type note
|
||||||
|
{
|
||||||
|
uint8_t low;
|
||||||
|
uint8_t high;
|
||||||
|
std::string tt;
|
||||||
|
|
||||||
|
//trigger
|
||||||
|
tt=tch["trigger"].strval();
|
||||||
|
auto tpos=tt.find(':');
|
||||||
|
if(tpos == std::string::npos)
|
||||||
|
{
|
||||||
|
//single value
|
||||||
|
low=stoi(tt);
|
||||||
|
high=low;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//range
|
||||||
|
low=stoi(tt.substr(0,tpos));
|
||||||
|
tpos++;
|
||||||
|
high=stoi(tt.substr(tpos, tt.size()-tpos));
|
||||||
|
}
|
||||||
|
this->noteCommands[id].push_back(NoteCommand(id,channel,low,high,shell));
|
||||||
|
this->nb_command++;
|
||||||
|
}
|
||||||
|
else if(tstr == "controller") //type controller
|
||||||
|
{
|
||||||
|
uint8_t min=0;
|
||||||
|
uint8_t max=127;
|
||||||
|
float mapMin;
|
||||||
|
float mapMax;
|
||||||
|
bool floating=false;
|
||||||
|
|
||||||
|
//range
|
||||||
|
Chunk* ttch=tch.subChunkPtr("range");
|
||||||
|
if(ttch != nullptr)
|
||||||
|
{
|
||||||
|
std::string range=ttch->strval();
|
||||||
|
auto tpos=range.find(':');
|
||||||
|
if(tpos == std::string::npos)
|
||||||
|
{
|
||||||
|
//single value
|
||||||
|
min=stoi(range);
|
||||||
|
max=min;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//range
|
||||||
|
min=stoi(range.substr(0,tpos));
|
||||||
|
tpos++;
|
||||||
|
max=stoi(range.substr(tpos, range.size()-tpos));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//remap
|
||||||
|
ttch=tch.subChunkPtr("remap");
|
||||||
|
if(ttch != nullptr)
|
||||||
|
{
|
||||||
|
std::string map=ttch->strval();
|
||||||
|
auto tpos=map.find(':');
|
||||||
|
mapMin=stof(map.substr(0,tpos));
|
||||||
|
tpos++;
|
||||||
|
mapMax=stof(map.substr(tpos, map.size()-tpos));
|
||||||
|
}
|
||||||
|
|
||||||
|
//floating
|
||||||
|
ttch=tch.subChunkPtr("float");
|
||||||
|
if(ttch != nullptr)
|
||||||
|
{
|
||||||
|
std::string tfl=ttch->strval();
|
||||||
|
if( tfl == "true" || tfl == "yes" || tfl == "y")
|
||||||
|
floating=true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mapMin=min;
|
||||||
|
mapMax=max;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->ctrlCommands[id].push_back(ControllerCommand(id,channel,min,max,mapMin,mapMax,floating,shell));
|
||||||
|
this->nb_command++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Command type " + tstr + " doesn't exist");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Device::loop(Device* dev)
|
||||||
|
{
|
||||||
|
std::string command = "aseqdump -p '" + dev->name + '\'';
|
||||||
|
FILE *stream = popen(command.c_str(), "r");
|
||||||
|
char* buff = NULL;
|
||||||
|
size_t buff_size = 0;
|
||||||
|
|
||||||
|
while (getline(&buff, &buff_size, stream) > 0)
|
||||||
|
{
|
||||||
|
if ( (strstr(buff, "Port unsubscribed") != NULL) ) // distonnected
|
||||||
|
{
|
||||||
|
std::string kill_command=KILL_COMMAND_FH + dev->name + KILL_COMMAND_SH;
|
||||||
|
system(kill_command.c_str()); // kill the process
|
||||||
|
dev->busy=false;
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (index(buff, ':') != NULL) // MIDI command
|
||||||
|
{
|
||||||
|
if (strstr(buff, "System exclusive") != NULL)
|
||||||
|
{
|
||||||
|
printf("%s", buff);
|
||||||
|
//do stuff
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int t;
|
||||||
|
char type;
|
||||||
|
int8_t channel;
|
||||||
|
int ctid;
|
||||||
|
uint8_t value;
|
||||||
|
char* pos=NULL;
|
||||||
|
bool note_off=false;
|
||||||
|
|
||||||
|
if (strstr(buff,"Note off") != NULL)
|
||||||
|
note_off=true;
|
||||||
|
|
||||||
|
//channel read
|
||||||
|
pos=index(buff, ',');
|
||||||
|
t=1;
|
||||||
|
while (*(pos-t-1) != ' ')
|
||||||
|
t++;
|
||||||
|
channel = std::stoi( std::string(pos-t, t) );
|
||||||
|
pos+=2;
|
||||||
|
|
||||||
|
//type
|
||||||
|
if (*pos == 'c') //controller signal
|
||||||
|
type='c';
|
||||||
|
else if (*pos == 'n') //note signal
|
||||||
|
type='n';
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Unknown MIDI signal\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//ctid read
|
||||||
|
while (*(pos) != ' ')
|
||||||
|
pos++;
|
||||||
|
pos++;
|
||||||
|
t=1;
|
||||||
|
while ( isNum(*(pos+t)) )
|
||||||
|
t++;
|
||||||
|
ctid = std::stoi( std::string(pos, t) );
|
||||||
|
pos+=t+2;
|
||||||
|
|
||||||
|
|
||||||
|
//value read
|
||||||
|
if(!note_off)
|
||||||
|
{
|
||||||
|
while (*(pos) != ' ')
|
||||||
|
pos++;
|
||||||
|
pos++;
|
||||||
|
t=1;
|
||||||
|
while ( isNum(*(pos+t)) )
|
||||||
|
t++;
|
||||||
|
value = std::stoi( std::string(pos, t));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
value=0;
|
||||||
|
|
||||||
|
if (type == 'n')
|
||||||
|
{
|
||||||
|
for( auto it : dev->noteCommands[ctid])
|
||||||
|
{
|
||||||
|
if((it.channel == -1 || it.channel == channel) && it.low <= value && it.high >= value)
|
||||||
|
{
|
||||||
|
std::string command="id=" + std::to_string(ctid) + ";channel=" + std::to_string(channel) + ";velocity=" + std::to_string(value) + ";";
|
||||||
|
command += it.shell;
|
||||||
|
std::thread(sh, command).detach();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(type == 'c')
|
||||||
|
{
|
||||||
|
for( auto it : dev->ctrlCommands[ctid])
|
||||||
|
{
|
||||||
|
if((it.channel == -1 || it.channel == channel) && it.min <= value && it.max >= value)
|
||||||
|
{
|
||||||
|
//remapping of value
|
||||||
|
float result;
|
||||||
|
if(it.min == it.max)
|
||||||
|
result = it.mapMin;
|
||||||
|
else
|
||||||
|
result=(value-it.min)*(it.mapMax-it.mapMin)/(it.max-it.min)+it.mapMin;
|
||||||
|
|
||||||
|
//command execution
|
||||||
|
std::string command="id=" + std::to_string(ctid) + ";channel=" + std::to_string(channel) + ";rawvalue=" + std::to_string(value) + ";value=";
|
||||||
|
if(it.floating)
|
||||||
|
command += std::to_string(result);
|
||||||
|
else
|
||||||
|
command += std::to_string((long int) result);
|
||||||
|
command += ";" + it.shell;
|
||||||
|
std::thread(sh, command).detach();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Device '%s' disconnected\n", dev->name.c_str());
|
||||||
|
|
||||||
|
pclose(stream);
|
||||||
|
free(buff);
|
||||||
|
}
|
||||||
79
src/main.cpp
Normal file
79
src/main.cpp
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "device.hpp"
|
||||||
|
#include "system.hpp"
|
||||||
|
|
||||||
|
#include "Filedat.hpp"
|
||||||
|
#include "options.hpp"
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
|
||||||
|
signal(SIGCHLD, SIG_IGN); //signal that we aren't expecting returns from child processes
|
||||||
|
|
||||||
|
OptionSet options;
|
||||||
|
options.addOption(Option('f',"file",true));
|
||||||
|
|
||||||
|
auto argvec = argVector(argc, argv);
|
||||||
|
|
||||||
|
auto t = options.getOptions(argvec);
|
||||||
|
std::vector<std::string> arg=t.first;
|
||||||
|
if( !t.second )
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Unexpected error\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arg.size() <= 0 || arg[0] == "")
|
||||||
|
{
|
||||||
|
fprintf(stderr, "No config file specified\n");
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
Filedat file(arg[0]);
|
||||||
|
if (!file.readTest())
|
||||||
|
{
|
||||||
|
fprintf(stderr, "File '%s' unavailable\n", arg[0].c_str());
|
||||||
|
return 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Loading config file '%s'\n", arg[0].c_str());
|
||||||
|
bool import_ok;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
import_ok = file.importFile();
|
||||||
|
|
||||||
|
if(import_ok)
|
||||||
|
{
|
||||||
|
for(int i=0 ; i<file.chunk().listSize() ; i++)
|
||||||
|
{
|
||||||
|
Device *newDevice = new Device;
|
||||||
|
newDevice->import_chunk(file.chunk()[i]);
|
||||||
|
device_list.push_back(newDevice);
|
||||||
|
printf("Added device '%s' with %d commands\n", newDevice->name.c_str(), newDevice->nb_command);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Unknown config file error\n");
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Starting scan for devices\n");
|
||||||
|
announce_loop();
|
||||||
|
|
||||||
|
for(auto it : device_list)
|
||||||
|
{
|
||||||
|
delete it;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (std::exception& e)
|
||||||
|
{
|
||||||
|
std::cerr << "Exception: " << e.what() << std::endl;
|
||||||
|
return 11;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
1
src/options.cpp
Symbolic link
1
src/options.cpp
Symbolic link
|
|
@ -0,0 +1 @@
|
||||||
|
/home/zawz/code/c/tool/zOptions/options.cpp
|
||||||
1
src/stringTools.cpp
Symbolic link
1
src/stringTools.cpp
Symbolic link
|
|
@ -0,0 +1 @@
|
||||||
|
/home/zawz/code/c/tool/stringTools/stringTools.cpp
|
||||||
61
src/system.cpp
Normal file
61
src/system.cpp
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
#include "system.hpp"
|
||||||
|
|
||||||
|
#include "device.hpp"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#define ANNOUNCE_COMMAND "aseqdump -p System:1"
|
||||||
|
#define LIST_COMMAND "aseqdump -l | tail -n +2 | tr -s ' ' | cut -d' ' -f3-"
|
||||||
|
|
||||||
|
void device_check()
|
||||||
|
{
|
||||||
|
char* buff = NULL;
|
||||||
|
size_t buff_size = 0;
|
||||||
|
FILE *stream = popen(LIST_COMMAND, "r");
|
||||||
|
std::string str;
|
||||||
|
|
||||||
|
getline(&buff, &buff_size, stream); //discard the first line
|
||||||
|
while ( getline(&buff, &buff_size, stream) > 0 ) //retrieve device lines
|
||||||
|
{
|
||||||
|
str += buff;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( auto it : device_list ) // iterate devices
|
||||||
|
{
|
||||||
|
if( !it->busy && str.find(it->name) != std::string::npos ) //device detected
|
||||||
|
{
|
||||||
|
printf("Device '%s' found\n", it->name.c_str());
|
||||||
|
it->start_loop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(buff != NULL)
|
||||||
|
free(buff);
|
||||||
|
}
|
||||||
|
|
||||||
|
void announce_loop()
|
||||||
|
{
|
||||||
|
char* buff = NULL;
|
||||||
|
size_t buff_size = 0;
|
||||||
|
FILE *stream = popen(ANNOUNCE_COMMAND,"r");
|
||||||
|
|
||||||
|
if (stream == NULL)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ( getline(&buff, &buff_size, stream) > 0 )
|
||||||
|
{
|
||||||
|
if ( (strstr(buff, "Port start") != NULL) || (strstr(buff,"Port subscribed") != NULL) )
|
||||||
|
device_check();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(buff != NULL)
|
||||||
|
free(buff);
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue