#![deny(missing_docs)]
use std::fmt;
use std::io;
use std::net::SocketAddr;
use std::thread;
use std::time::{Duration, Instant};
use std::sync::Arc;
use futures::future::Either;
use tokio::net::UdpSocket;
use tokio::prelude::*;
use tokio::timer::Delay;
use futures::sync::mpsc::{Sender, Receiver};
use rosc::decoder::decode;
use rosc::encoder::encode;
use rosc::{OscMessage, OscPacket, OscType};
use crossbeam::queue::ArrayQueue;
use futures::*;
use log::*;
pub const SERIALOSC_PORT: i32 = 12002;
const START_PORT: i32 = 10_000;
const DEVICE_ENUMERATION_TIMEOUT_MS: u64 = 500;
fn toidx(x: i32, y: i32, width: i32) -> usize {
(y * width + x) as usize
}
fn build_osc_message(addr: &str, args: Vec<OscType>) -> OscPacket {
let message = OscMessage {
addr: addr.to_owned(),
args: Some(args),
};
OscPacket::Message(message)
}
fn new_bound_socket() -> UdpSocket {
let mut port = START_PORT;
loop {
let server_addr = format!("127.0.0.1:{}", port).parse().unwrap();
let bind_result = UdpSocket::bind(&server_addr);
match bind_result {
Ok(socket) => break socket,
Err(e) => {
warn!("bind error: {}", e.to_string());
if port > 65535 {
panic!("Could not bind socket: port exhausted");
}
}
}
port += 1;
}
}
#[derive(Debug)]
pub enum DeviceChangeEvent {
Added(String),
Removed(String),
}
#[derive(Debug)]
struct MonomeInfo {
port: Option<i32>,
host: Option<String>,
prefix: Option<String>,
id: Option<String>,
size: Option<(i32, i32)>,
rotation: Option<i32>,
}
impl MonomeInfo {
fn new() -> MonomeInfo {
MonomeInfo {
port: None,
host: None,
prefix: None,
id: None,
size: None,
rotation: None,
}
}
fn complete(&self) -> bool {
self.port.is_some()
&& self.host.is_some()
&& self.prefix.is_some()
&& self.id.is_some()
&& self.size.is_some()
&& self.rotation.is_some()
}
fn fill(&mut self, packet: OscPacket) {
match packet {
OscPacket::Message(message) => {
if message.addr.starts_with("/sys") {
if let Some(args) = message.args {
if message.addr.starts_with("/sys/port") {
if let OscType::Int(port) = args[0] {
self.port = Some(port);
}
} else if message.addr.starts_with("/sys/host") {
if let OscType::String(ref host) = args[0] {
self.host = Some(host.to_string());
}
} else if message.addr.starts_with("/sys/id") {
if let OscType::String(ref id) = args[0] {
self.id = Some(id.to_string());
}
} else if message.addr.starts_with("/sys/prefix") {
if let OscType::String(ref prefix) = args[0] {
self.prefix = Some(prefix.to_string());
}
} else if message.addr.starts_with("/sys/rotation") {
if let OscType::Int(rotation) = args[0] {
self.rotation = Some(rotation);
}
} else if message.addr.starts_with("/sys/size") {
if let OscType::Int(x) = args[0] {
if let OscType::Int(y) = args[1] {
self.size = Some((x, y));
}
}
}
}
}
}
OscPacket::Bundle(_bundle) => {
error!("Bundle during setup!?");
}
}
}
}
struct Transport {
device_port: i32,
socket: UdpSocket,
tx: Arc<ArrayQueue<Vec<u8>>>,
rx: Receiver<Vec<u8>>,
}
impl Transport {
pub fn new(
device_port: i32,
socket: UdpSocket,
tx: Arc<ArrayQueue<Vec<u8>>>,
rx: Receiver<Vec<u8>>,
) -> Transport {
Transport {
device_port,
socket,
tx,
rx,
}
}
}
impl Future for Transport {
type Item = ();
type Error = io::Error;
fn poll(&mut self) -> Poll<(), io::Error> {
loop {
match self.rx.poll() {
Ok(fut) => {
match fut {
Async::Ready(b) => {
let device_address = format!("127.0.0.1:{}", self.device_port);
let addr: SocketAddr = device_address.parse().unwrap();
if b.is_some() {
let _amt =
try_ready!(self.socket.poll_send_to(&b.unwrap(), &addr));
} else {
break;
}
}
Async::NotReady => {
break;
}
}
}
Err(e) => {
error!("Error on future::mpsc {:?}", e);
}
}
}
loop {
let mut buf = vec![0; 1024];
match self.socket.poll_recv(&mut buf) {
Ok(fut) => match fut {
Async::Ready(_ready) => match self.tx.push(buf) {
Ok(()) => {
continue;
}
Err(e) => {
error!("receive from monome, {}", e);
}
},
Async::NotReady => {
return Ok(Async::NotReady);
}
},
Err(e) => {
return Err(e);
}
}
}
}
}
pub struct Monome {
name: String,
device_type: MonomeDeviceType,
port: i32,
host: String,
id: String,
prefix: String,
rotation: i32,
size: (i32, i32),
q: Arc<ArrayQueue<Vec<u8>>>,
tx: Sender<Vec<u8>>,
}
#[derive(Debug)]
pub enum KeyDirection {
Up,
Down,
}
pub enum MonomeEvent {
GridKey {
x: i32,
y: i32,
direction: KeyDirection,
},
Tilt {
n: i32,
x: i32,
y: i32,
z: i32,
},
EncoderDelta {
n: usize,
delta: i32,
},
EncoderKey {
n: usize,
direction: KeyDirection,
},
}
pub trait IntoAddrAndArgs<'a, B> {
fn as_addr_frag_and_args(&self) -> (String, B);
}
impl<'a> IntoAddrAndArgs<'a, OscType> for i32 {
fn as_addr_frag_and_args(&self) -> (String, OscType) {
("level/".to_string(), OscType::Int(*self))
}
}
impl<'a> IntoAddrAndArgs<'a, OscType> for bool {
fn as_addr_frag_and_args(&self) -> (String, OscType) {
("".to_string(), OscType::Int(if *self { 1 } else { 0 }))
}
}
impl<'a> IntoAddrAndArgs<'a, Vec<OscType>> for &'a [u8; 64] {
fn as_addr_frag_and_args(&self) -> (String, Vec<OscType>) {
let mut osctype_vec = Vec::with_capacity(64);
for item in self.iter().map(|i| OscType::Int(i32::from(*i))) {
osctype_vec.push(item);
}
("level/".to_string(), osctype_vec)
}
}
impl<'a> IntoAddrAndArgs<'a, Vec<OscType>> for u8 {
fn as_addr_frag_and_args(&self) -> (String, Vec<OscType>) {
let mut osctype_vec = Vec::with_capacity(1);
osctype_vec.push(OscType::Int(i32::from(*self)));
("".to_string(), osctype_vec)
}
}
impl<'a> IntoAddrAndArgs<'a, Vec<OscType>> for &'a [u8; 8] {
fn as_addr_frag_and_args(&self) -> (String, Vec<OscType>) {
let mut osctype_vec = Vec::with_capacity(8);
for item in self.iter().map(|i| OscType::Int(i32::from(*i))) {
osctype_vec.push(item);
}
("".to_string(), osctype_vec)
}
}
impl<'a> IntoAddrAndArgs<'a, Vec<OscType>> for &'a [bool; 64] {
fn as_addr_frag_and_args(&self) -> (String, Vec<OscType>) {
assert!(self.len() >= 64);
let mut masks = [0 as u8; 8];
for i in 0..8 {
let mut mask: u8 = 0;
for j in (0..8).rev() {
let idx = toidx(j, i, 8);
mask = mask.rotate_left(1) | if self[idx] { 1 } else { 0 };
}
masks[i as usize] = mask;
}
let mut osctype_vec = Vec::with_capacity(8);
for item in masks.iter().map(|i| OscType::Int(i32::from(*i))) {
osctype_vec.push(item);
}
("".to_string(), osctype_vec)
}
}
#[derive(PartialEq, Clone)]
pub enum MonomeDeviceType {
Grid,
Arc,
Unknown,
}
impl From<&str> for MonomeDeviceType {
fn from(string: &str) -> MonomeDeviceType {
if string.contains("arc") {
MonomeDeviceType::Arc
} else {
MonomeDeviceType::Grid
}
}
}
impl fmt::Display for MonomeDeviceType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"{}",
if *self == MonomeDeviceType::Grid {
"grid"
} else {
"arc"
}
)
}
}
impl fmt::Debug for MonomeDeviceType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self)
}
}
#[derive(Debug)]
pub struct MonomeDevice {
name: String,
device_type: MonomeDeviceType,
port: i32,
}
impl fmt::Display for MonomeDevice {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}: {} ({})", self.name, self.device_type, self.port)
}
}
impl MonomeDevice {
fn new(name: &str, device_type: &str, port: i32) -> MonomeDevice {
MonomeDevice {
name: name.to_string(),
device_type: device_type.into(),
port,
}
}
pub fn device_type(&self) -> MonomeDeviceType {
return self.device_type.clone();
}
pub fn name(&self) -> String {
return self.name.clone();
}
pub fn port(&self) -> i32 {
return self.port;
}
}
impl Monome {
pub fn register_device_change_callback_with_port(
serialosc_port: i32,
callback: fn(DeviceChangeEvent),
) {
let mut socket = new_bound_socket();
thread::spawn(move || {
let server_port = socket.local_addr().unwrap().port();
let addr = format!("127.0.0.1:{}", serialosc_port).parse().unwrap();
let packet = build_osc_message(
"/serialosc/notify",
vec![
OscType::String("127.0.0.1".to_string()),
OscType::Int(i32::from(server_port)),
],
);
let mut bytes: Vec<u8>;
let mut need_notify_msg = true;
loop {
bytes = encode(&packet).unwrap();
if need_notify_msg {
socket = socket
.send_dgram(bytes, &addr)
.wait()
.map(|(s, _)| s)
.unwrap();
need_notify_msg = false;
}
socket = socket.recv_dgram(vec![0u8; 1024]).and_then(|(socket, data, _, _)| {
match decode(&data).unwrap() {
OscPacket::Message(message) => {
if let Some(ref args) = message.args {
if message.addr.starts_with("/serialosc/add") {
need_notify_msg = true;
if let OscType::String(ref id) = args[0] {
callback(DeviceChangeEvent::Added(id.to_string()));
}
} else if message.addr.starts_with("/serialosc/remove") {
if let OscType::String(ref id) = args[0] {
need_notify_msg = true;
callback(DeviceChangeEvent::Removed(id.to_string()));
}
} else {
debug!("⇦ Unexpected message receive on device change event socket {:?}", message);
}
}
}
_ => {
debug!("⇦ Could not decode {:?}", data);
}
}
Ok(socket)
})
.wait()
.map(|socket| socket)
.unwrap();
}
});
}
pub fn register_device_change_callback(callback: fn(DeviceChangeEvent)) {
Monome::register_device_change_callback_with_port(SERIALOSC_PORT, callback)
}
fn setup<S>(
prefix: S,
device: &MonomeDevice,
) -> Result<(MonomeInfo, UdpSocket, String, MonomeDeviceType, i32), String>
where
S: Into<String>,
{
let (name, device_type, port) = (
device.name.to_string(),
device.device_type.clone(),
device.port,
);
let device_address = format!("127.0.0.1:{}", port);
let add = device_address.parse();
let addr: SocketAddr = add.unwrap();
let socket = new_bound_socket();
let server_port = socket.local_addr().unwrap().port();
let packet = build_osc_message("/sys/port", vec![OscType::Int(i32::from(server_port))]);
let bytes: Vec<u8> = encode(&packet).unwrap();
let socket = socket
.send_dgram(bytes, &addr)
.wait()
.map(|(s, _)| s)
.unwrap();
let local_addr = socket.local_addr().unwrap().ip();
let packet = build_osc_message("/sys/host", vec![OscType::String(local_addr.to_string())]);
let bytes: Vec<u8> = encode(&packet).unwrap();
let socket = socket
.send_dgram(bytes, &addr)
.wait()
.map(|(s, _)| s)
.unwrap();
let packet = build_osc_message("/sys/prefix", vec![OscType::String(prefix.into())]);
let bytes: Vec<u8> = encode(&packet).unwrap();
let socket = socket
.send_dgram(bytes, &addr)
.wait()
.map(|(s, _)| s)
.unwrap();
let packet = build_osc_message("/sys/info", vec![]);
let bytes: Vec<u8> = encode(&packet).unwrap();
let mut socket = socket
.send_dgram(bytes, &addr)
.wait()
.map(|(s, _)| s)
.unwrap();
let mut info = MonomeInfo::new();
let socket = loop {
socket = socket
.recv_dgram(vec![0u8; 1024])
.and_then(|(socket, data, _, _)| {
let packet = decode(&data).unwrap();
info.fill(packet);
Ok(socket)
})
.wait()
.map(|socket| socket)
.unwrap();
if info.complete() {
break socket;
}
};
Ok((info, socket, name, device_type, port))
}
pub fn enumerate_devices_with_port(serialosc_port: i32) -> Result<Vec<MonomeDevice>, String> {
let socket = new_bound_socket();
let mut devices = Vec::<MonomeDevice>::new();
let server_port = socket.local_addr().unwrap().port();
let server_ip = socket.local_addr().unwrap().ip().to_string();
let packet = build_osc_message(
"/serialosc/list",
vec![
OscType::String(server_ip),
OscType::Int(i32::from(server_port)),
],
);
let bytes: Vec<u8> = encode(&packet).unwrap();
let addr = format!("127.0.0.1:{}", serialosc_port).parse().unwrap();
let (mut socket, _) = socket.send_dgram(bytes, &addr).wait().unwrap();
loop {
let fut = socket.recv_dgram(vec![0u8; 1024]).select2(Delay::new(
Instant::now() + Duration::from_millis(DEVICE_ENUMERATION_TIMEOUT_MS),
));
let task = tokio::runtime::current_thread::block_on_all(fut);
socket = match task {
Ok(Either::A(((s, data, _, _), _))) => {
socket = s;
let packet = decode(&data).unwrap();
match packet {
OscPacket::Message(message) => {
if message.addr == "/serialosc/device" {
if let Some(args) = &message.args {
if let [OscType::String(ref name), OscType::String(ref device_type), OscType::Int(port)] =
args.as_slice()
{
devices.push(MonomeDevice::new(name, device_type, *port));
}
} else {
break;
}
}
}
OscPacket::Bundle(_bundle) => {
eprintln!("Unexpected bundle received during setup");
}
};
socket
}
Ok(Either::B(_)) => {
break;
}
Err(e) => {
panic!("{:?}", e);
}
};
}
Ok(devices)
}
pub fn enumerate_devices() -> Result<Vec<MonomeDevice>, String> {
Monome::enumerate_devices_with_port(SERIALOSC_PORT)
}
pub fn new<S>(prefix: S) -> Result<Monome, String>
where
S: Into<String>,
{
Monome::new_with_port(prefix, SERIALOSC_PORT)
}
pub fn new_with_port<S>(prefix: S, serialosc_port: i32) -> Result<Monome, String>
where
S: Into<String>,
{
let devices = Monome::enumerate_devices_with_port(serialosc_port)?;
if devices.is_empty() {
return Err("No devices detected".to_string());
}
Monome::from_device(&devices[0], prefix.into())
}
pub fn from_device<S>(device: &MonomeDevice, prefix: S) -> Result<Monome, String>
where
S: Into<String>,
{
let prefix = prefix.into();
let (info, socket, name, device_type, device_port) = Monome::setup(&*prefix, device)?;
let (sender, receiver) = futures::sync::mpsc::channel(16);
let q = Arc::new(ArrayQueue::new(32));
let q2 = q.clone();
let t = Transport::new(device_port, socket, q, receiver);
thread::spawn(move || {
tokio::run(t.map_err(|e| error!("server error = {:?}", e)));
});
Ok(Monome {
tx: sender,
q: q2,
name: name.to_string(),
device_type,
host: info.host.unwrap(),
id: info.id.unwrap(),
port: device_port,
prefix,
rotation: info.rotation.unwrap(),
size: info.size.unwrap(),
})
}
pub fn set<'a, A>(&mut self, x: i32, y: i32, arg: A)
where
A: IntoAddrAndArgs<'a, OscType>,
{
if self.device_type != MonomeDeviceType::Grid {
error!("Called grid method on something that is not an grid.");
return;
}
let (frag, arg) = arg.as_addr_frag_and_args();
self.send(
&format!("/grid/led/{}set", frag).to_string(),
vec![OscType::Int(x), OscType::Int(y), arg],
);
}
pub fn all<'a, A>(&mut self, arg: A)
where
A: IntoAddrAndArgs<'a, OscType>,
{
if self.device_type != MonomeDeviceType::Grid {
error!("Called grid method on something that is not an grid.");
return;
}
let (frag, arg) = arg.as_addr_frag_and_args();
self.send(&format!("/grid/led/{}all", frag).to_string(), vec![arg]);
}
pub fn set_all(&mut self, leds: &[bool]) {
if self.device_type != MonomeDeviceType::Grid {
error!("Called grid method on something that is not an grid.");
return;
}
let width_in_quad = self.size.0 / 8;
let height_in_quad = self.size.1 / 8;
let width = self.size.0;
let quad_size: i32 = 8;
let mut masks = [0 as u8; 8];
for a in 0..height_in_quad {
for b in 0..width_in_quad {
for i in 0..8 {
let mut mask: u8 = 0;
for j in (0..8).rev() {
let idx = toidx(b * quad_size + j, a * quad_size + i, width);
mask = mask.rotate_left(1) | if leds[idx] { 1 } else { 0 };
}
masks[i as usize] = mask;
}
self.map(b * 8, a * 8, &masks);
}
}
}
pub fn set_all_intensity(&mut self, leds: &[u8]) {
if self.device_type != MonomeDeviceType::Grid {
error!("Called grid method on something that is not an grid.");
return;
}
let width_in_quad = self.size.0 / 8;
let height_in_quad = self.size.1 / 8;
let width = self.size.0;
let quad_size = 8;
let mut quad = [0 as u8; 64];
for a in 0..height_in_quad {
for b in 0..width_in_quad {
for i in 0..8 as i32 {
for j in 0..8 as i32 {
let idx = toidx(b * quad_size + j, a * quad_size + i, width);
quad[(i * 8 + j) as usize] = leds[idx];
}
}
self.map(b * 8, a * 8, &quad);
}
}
}
pub fn map<'a, A>(&mut self, x_offset: i32, y_offset: i32, masks: A)
where
A: IntoAddrAndArgs<'a, Vec<OscType>> + Sized,
{
if self.device_type != MonomeDeviceType::Grid {
error!("Called grid method on something that is not an grid.");
return;
}
let (frag, mut arg) = masks.as_addr_frag_and_args();
let mut args = Vec::with_capacity(2 + arg.len());
args.push(OscType::Int(x_offset));
args.push(OscType::Int(y_offset));
args.append(&mut arg);
self.send(&format!("/grid/led/{}map", frag), args);
}
pub fn row<'a, A>(&mut self, x_offset: i32, y: i32, leds: &A)
where
A: IntoAddrAndArgs<'a, Vec<OscType>>,
{
if self.device_type != MonomeDeviceType::Grid {
error!("Called grid method on something that is not an grid.");
return;
}
let (frag, arg) = leds.as_addr_frag_and_args();
let mut args = Vec::with_capacity((2 + arg.len()) as usize);
args.push(OscType::Int(x_offset));
args.push(OscType::Int(y));
args.append(&mut arg.to_vec());
self.send(&format!("/grid/led/{}row", frag), args);
}
pub fn col<'a, A>(&mut self, x: i32, y_offset: i32, leds: &A)
where
A: IntoAddrAndArgs<'a, Vec<OscType>>,
{
if self.device_type != MonomeDeviceType::Grid {
error!("Called grid method on something that is not an grid.");
return;
}
let (frag, mut arg) = leds.as_addr_frag_and_args();
let mut args = Vec::with_capacity((2 + arg.len()) as usize);
args.push(OscType::Int(x));
args.push(OscType::Int(y_offset));
args.append(&mut arg);
self.send(&format!("/grid/led/{}col", frag), args);
}
pub fn ring_set(&mut self, n: usize, index: u32, intensity: u32) {
if self.device_type != MonomeDeviceType::Arc {
error!("Called arc method on something that is not an arc.");
return;
}
let mut args = Vec::with_capacity(3);
args.push(OscType::Int(n as i32));
args.push(OscType::Int(index as i32));
args.push(OscType::Int(intensity as i32));
self.send("/ring/set", args);
}
pub fn ring_all(&mut self, n: usize, intensity: u32) {
if self.device_type != MonomeDeviceType::Arc {
error!("Called arc method on something that is not an arc.");
return;
}
let mut args = Vec::with_capacity(2);
args.push(OscType::Int(n as i32));
args.push(OscType::Int(intensity as i32));
self.send("/ring/all", args);
}
pub fn ring_range(&mut self, n: usize, start_offset: usize, end_offset: usize, intensity: u32) {
if self.device_type != MonomeDeviceType::Arc {
error!("Called arc method on something that is not an arc.");
return;
}
let mut args = Vec::with_capacity(4);
args.push(OscType::Int(n as i32));
args.push(OscType::Int(start_offset as i32));
args.push(OscType::Int(end_offset as i32));
args.push(OscType::Int(intensity as i32));
self.send("/ring/range", args);
}
pub fn ring_map(&mut self, n: usize, values: &[u8; 64]) {
let mut args = Vec::with_capacity(65);
args.push(OscType::Int(n as i32));
for v in values.iter() {
args.push(OscType::Int(i32::from(*v)));
}
self.send("/ring/map", args);
}
pub fn tilt_all(&mut self, on: bool) {
self.send(
"/tilt/set",
vec![OscType::Int(0), OscType::Int(if on { 1 } else { 0 })],
);
}
pub fn set_rotation(&mut self, rotation: i32) {
self.send_no_prefix("/sys/rotation", vec![OscType::Int(rotation)]);
self.rotation = rotation;
}
pub fn set_prefix(&mut self, prefix: String) {
self.send_no_prefix("/sys/prefix", vec![OscType::String(prefix.clone())]);
self.prefix = prefix;
}
pub fn name(&self) -> String {
self.name.clone()
}
pub fn device_type(&self) -> MonomeDeviceType {
self.device_type.clone()
}
pub fn port(&self) -> i32 {
self.port
}
pub fn host(&self) -> String {
self.host.clone()
}
pub fn id(&self) -> String {
self.id.clone()
}
pub fn prefix(&self) -> String {
self.prefix.clone()
}
pub fn rotation(&self) -> i32 {
self.rotation
}
pub fn size(&self) -> (i32, i32) {
self.size
}
pub fn width(&self) -> usize {
self.size.0 as usize
}
pub fn height(&self) -> usize {
self.size.1 as usize
}
fn send(&mut self, addr: &str, args: Vec<OscType>) {
let with_prefix = format!("{}{}", self.prefix, addr);
self.send_no_prefix(&with_prefix, args);
}
fn send_no_prefix(&mut self, addr: &str, args: Vec<OscType>) {
let message = OscMessage {
addr: addr.to_owned(),
args: Some(args),
};
let packet = OscPacket::Message(message);
debug!("⇨ {:?}", packet);
let bytes: Vec<u8> = encode(&packet).unwrap();
match self.tx.try_send(bytes) {
Ok(()) => {}
Err(b) => {
let full = b.is_full();
let disconnected = b.is_disconnected();
error!("full: {:?}, disconnected: {:?}", full, disconnected);
}
}
}
pub fn poll(&mut self) -> Option<MonomeEvent> {
match self.q.pop() {
Ok(buf) => self.parse(&buf),
Err(crossbeam::queue::PopError) => {
None
}
}
}
fn parse(&self, buf: &[u8]) -> Option<MonomeEvent> {
let packet = decode(buf).unwrap();
debug!("⇦ {:?}", packet);
match packet {
OscPacket::Message(message) => {
if message.addr.starts_with("/serialosc") {
if message.addr == "/serialosc/device" {
info!("/serialosc/device");
} else if message.addr == "/serialosc/add" {
if let Some(args) = message.args {
if let OscType::String(ref device_name) = args[0] {
info!("device added: {}", device_name);
} else {
warn!("unexpected message for prefix {}", message.addr);
}
} else if message.addr == "/serialosc/remove" {
if let Some(args) = message.args {
if let OscType::String(ref device_name) = args[0] {
info!("device removed: {}", device_name);
} else {
warn!("unexpected message for prefix {}", message.addr);
}
}
};
}
} else if message.addr.starts_with("/sys") {
debug!("/sys received: {:?}", message);
} else if message.addr.starts_with(&self.prefix) {
if let Some(args) = &message.args {
if message
.addr
.starts_with(&format!("{}/grid/key", self.prefix))
{
if let [OscType::Int(x), OscType::Int(y), OscType::Int(v)] =
args.as_slice()
{
info!("Key: {}:{} {}", *x, *y, *v);
let direction = if *v == 1 {
KeyDirection::Down
} else {
KeyDirection::Up
};
return Some(MonomeEvent::GridKey {
x: *x,
y: *y,
direction,
});
}
error!("Invalid /grid/key message received {:?}.", message);
} else if message.addr.starts_with(&format!("{}/tilt", self.prefix)) {
if let [OscType::Int(n), OscType::Int(x), OscType::Int(y), OscType::Int(z)] =
args.as_slice()
{
info!("Tilt {} {},{},{}", *n, *x, *y, *z);
return Some(MonomeEvent::Tilt {
n: *n,
x: *x,
y: *y,
z: *z,
});
}
error!("Invalid /tilt message received {:?}.", message);
} else if message
.addr
.starts_with(&format!("{}/enc/delta", self.prefix))
{
if let [OscType::Int(n), OscType::Int(delta)] = args.as_slice() {
info!("Encoder delta {} {}", *n, *delta);
return Some(MonomeEvent::EncoderDelta {
n: *n as usize,
delta: *delta,
});
}
error!("Invalid /end/delta message received {:?}.", message);
} else if message
.addr
.starts_with(&format!("{}/enc/key", self.prefix))
{
if let [OscType::Int(n), OscType::Int(direction)] = args.as_slice() {
info!("Encoder key {} {}", *n, *direction);
return Some(MonomeEvent::EncoderKey {
n: *n as usize,
direction: if *direction == 1 {
KeyDirection::Down
} else {
KeyDirection::Up
},
});
}
error!("Invalid /end/key message received {:?}.", message);
} else {
error!("not handled: {:?}", message.addr);
}
}
}
None
}
OscPacket::Bundle(_bundle) => {
panic!("wtf.");
}
}
}
}
impl fmt::Debug for Monome {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let rv = write!(
f,
"Monome {}\n\ttype: {}\n\tport: {}\n\thost: {}\n\t\
id: {}\n\tprefix: {}\n\trotation: {}",
self.name,
self.device_type,
self.port,
self.host,
self.id,
self.prefix,
self.rotation
);
if self.device_type == MonomeDeviceType::Grid {
return write!(f, "\n\tsize: {}:{}", self.size.0, self.size.1);
}
rv
}
}
impl fmt::Display for Monome {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}", self)
}
}
#[cfg(test)]
mod tests {
use crate::build_osc_message;
use crate::Monome;
use crate::SERIALOSC_PORT;
use rosc::decoder::decode;
use rosc::encoder::encode;
use rosc::{OscPacket, OscType};
use std::sync::{Arc, Condvar, Mutex};
use std::thread;
use tokio::net::UdpSocket;
use tokio::prelude::*;
#[test]
fn setup() {
let pair = Arc::new((Mutex::new(false), Condvar::new()));
let pair2 = pair.clone();
thread::spawn(move || {
let fake_device_port = 1234;
let device_addr = format!("127.0.0.1:{}", fake_device_port).parse().unwrap();
let device_socket = UdpSocket::bind(&device_addr).unwrap();
let serialosc_addr = format!("127.0.0.1:{}", SERIALOSC_PORT + 1).parse().unwrap();
let serialosc_socket = UdpSocket::bind(&serialosc_addr).unwrap();
{
let &(ref lock, ref cvar) = &*pair2;
let mut started = lock.lock().unwrap();
*started = true;
cvar.notify_all();
}
let (socket, data, _, _) = serialosc_socket.recv_dgram(vec![0u8; 1024]).wait().unwrap();
let packet = decode(&data).unwrap();
let msg = match packet {
OscPacket::Message(m) => m,
OscPacket::Bundle(_b) => panic!("unexpected bundle"),
};
assert!(msg.addr == "/serialosc/list");
assert!(msg.args.is_some());
let app_port = if let OscType::Int(port) = msg.args.unwrap()[1] {
port
} else {
panic!("bad message");
};
let packet = build_osc_message(
"/serialosc/device",
vec![
OscType::String("monome grid test".into()),
OscType::String("m123123".into()),
OscType::Int(1234),
],
);
let bytes: Vec<u8> = encode(&packet).unwrap();
let app_addr = format!("127.0.0.1:{}", app_port).parse().unwrap();
let (mut socket, _) = socket.send_dgram(bytes, &app_addr).wait().unwrap();
fn receive_from_app_and_expect(
socket: UdpSocket,
expected_addr: String,
) -> (UdpSocket, Option<Vec<OscType>>) {
let (socket, data, _, _) = socket.recv_dgram(vec![0u8; 1024]).wait().unwrap();
let packet = decode(&data).unwrap();
let msg = match packet {
OscPacket::Message(m) => m,
OscPacket::Bundle(_b) => panic!("unexpected bundle"),
};
assert!(msg.addr == expected_addr);
(socket, msg.args)
}
let (device_socket, args) =
receive_from_app_and_expect(device_socket, "/sys/port".into());
let port = if let OscType::Int(port) = args.unwrap()[0] {
assert!(port == 10000);
port
} else {
panic!("bad port");
};
assert!(port == 10000);
let (device_socket, args) =
receive_from_app_and_expect(device_socket, "/sys/host".into());
let argss = args.unwrap();
let host = if let OscType::String(ref host) = argss[0] {
host
} else {
panic!("bad host");
};
assert!(host == "127.0.0.1");
let (device_socket, args) =
receive_from_app_and_expect(device_socket, "/sys/prefix".into());
let argss = args.unwrap();
let prefix = if let OscType::String(ref prefix) = argss[0] {
prefix
} else {
panic!("bad prefix");
};
assert!(prefix == "/plop");
let (_device_socket, args) =
receive_from_app_and_expect(device_socket, "/sys/info".into());
assert!(args.is_none());
let message_addrs = vec![
"/sys/port",
"/sys/host",
"/sys/id",
"/sys/prefix",
"/sys/rotation",
"/sys/size",
];
let message_args = vec![
vec![OscType::Int(fake_device_port)],
vec![OscType::String("127.0.0.1".into())],
vec![OscType::String("monome blabla".into())],
vec![OscType::String("/plop".into())],
vec![OscType::Int(0)],
vec![OscType::Int(16), OscType::Int(8)],
];
assert!(message_addrs.len() == message_args.len());
for i in 0..message_addrs.len() {
let packet = build_osc_message(message_addrs[i], message_args[i].clone());
let bytes: Vec<u8> = encode(&packet).unwrap();
socket = socket
.send_dgram(bytes, &app_addr)
.map(|(socket, _)| socket)
.wait()
.unwrap();
}
});
let &(ref lock, ref cvar) = &*pair;
let mut started = lock.lock().unwrap();
while !*started {
started = cvar.wait(started).unwrap();
}
let _m = Monome::new_with_port("/plop".to_string(), SERIALOSC_PORT + 1).unwrap();
}
}