/* This file is part of LED Pattern Editor.
*
* Copyright (C) 2010 Philipp Zabel
*
* LED Pattern Editor 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.
*
* LED Pattern Editor 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 LED Pattern Editor. If not, see .
*/
class LedPatternRX51 : LedPattern {
public string led_map;
public List engine1;
public List engine2;
public void parse (string line) {
string[] key_value = line.split ("=");
if (key_value.length != 2) {
print ("pattern line does not contain '=': %s\n", line);
return;
}
string[] p = key_value[1].split (";");
if (p.length != 6) {
print ("pattern does not contain 6 components: %d\n", p.length);
return;
}
if (p[4].length > 16*4 || p[5].length > 16*4) {
print ("pattern too long!\n");
return;
}
name = key_value[0];
priority = p[0].to_int ();
screen_on = p[1].to_int ();
timeout = p[2].to_int ();
led_map = p[3];
engine1 = parse_pattern (p[4]);
engine2 = parse_pattern (p[5]);
if (engine1.first ().data.code != 0x9d80) {
print ("engine1 pattern doesn't start with refresh mux command\n");
}
if (engine2.first ().data.code != 0x9d80) {
print ("engine2 pattern doesn't start with refresh mux command\n");
}
on_changed ();
}
private List parse_pattern (string pattern) {
var list = new List ();
var length = pattern.length;
if (length % 4 != 0)
return list;
char *p = ((char*) pattern) + length - 4;
while (p >= (char*) pattern) {
var command = new LedCommandRX51.with_code ((uint16) ((string) p).to_ulong (null, 16));
command.changed.connect (on_changed);
list.prepend (command);
p[0] = '\0';
p -= 4;
}
return list;
}
public string dump () {
return "%s=%d;%d;%d;%s;%s;%s".printf (name, priority, screen_on, timeout, led_map,
dump_pattern (engine1), dump_pattern (engine2));
}
private string dump_pattern (List list) {
string result = "";
foreach (LedCommandRX51 command in list) {
result += "%04x".printf (command.code);
}
return result;
}
public LedPatternRX51 copy () {
var pattern = new LedPatternRX51 ();
pattern.name = name.dup ();
pattern.priority = priority;
pattern.screen_on = screen_on;
pattern.timeout = timeout;
pattern.duration = duration;
pattern.led_map = led_map;
pattern.engine1 = deep_copy (pattern, engine1);
pattern.engine2 = deep_copy (pattern, engine2);
return pattern;
}
public List deep_copy (LedPatternRX51 pattern, List list) {
var list2 = new List ();
foreach (LedCommandRX51 command in list) {
var command2 = command.copy ();
command2.changed.connect (pattern.on_changed);
list2.append (command2);
}
return list2;
}
public void replace_with (LedPatternRX51 pattern) {
name = pattern.name;
priority = pattern.priority;
screen_on = pattern.screen_on;
timeout = pattern.timeout;
duration = pattern.duration;
led_map = pattern.led_map;
engine1 = deep_copy (this, pattern.engine1);
engine2 = deep_copy (this, pattern.engine2);
changed ();
}
void on_changed () {
// calculate timing and level info
double time = 0;
int level = 0;
foreach (LedCommandRX51 command in engine1) {
command.time = time;
time += command.duration;
if (command.type == CommandType.SET_PWM) {
level = command.level;
} else {
command.level = level;
level += command.steps;
}
if (level < 0)
level = 0;
if (level > 255)
level = 255;
}
duration = time;
changed ();
}
}
class LedCommandRX51 : LedCommand {
public uint16 code;
public LedCommandRX51 () {
}
public LedCommandRX51.with_code (uint16 _code) {
code = _code;
if ((code & 0x8000) == 0) {
if (code == 0x0000) {
type = CommandType.REPEAT;
} else if ((code & 0x3e00) != 0) {
type = CommandType.RAMP_WAIT;
steps = code & 0xff;
step_time = code >> 9;
if ((code & 0x4000) == 0)
step_time = (code >> 9) * 0.49;
else {
step_time = ((code & 0x3e00) >> 9) * 15.6;
}
duration = step_time * (steps + 1);
if ((code & 0x100) != 0)
steps = -steps;
} else {
type = CommandType.SET_PWM;
level = code & 0xff;
}
} else {
if (code == 0x9d80)
type = CommandType.RESET_MUX;
if (code == 0xc000)
type = CommandType.STOP;
//if (code == 0xe0??)
// type = CommandType.TRIGGER_WAIT;
}
}
public override void set_pwm (int _level) {
code = 0x4000 | _level;
base.set_pwm (_level);
}
public override void ramp_wait (double _step_time, int _steps) requires (_step_time >= 0.49) {
int step_time;
if (_step_time <= 31*0.49) {
step_time = (int) ((_step_time + 0.001) / 0.49);
code = (uint16) step_time << 9;
_step_time = step_time * 0.49;
} else if (_step_time <= 31*15.6) {
step_time = (int) ((_step_time + 0.01) / 15.6);
code = 0x4000 | (step_time << 9);
_step_time = step_time * 15.6;
} else {
return;
}
if (_steps < 0) {
code |= 0x100 | (-_steps);
} else {
code |= _steps;
}
base.ramp_wait (_step_time, _steps);
}
public LedCommandRX51 copy () {
var command = new LedCommandRX51 ();
command.type = type;
command.time = time;
command.step_time = step_time;
command.duration = duration;
command.level = level;
command.steps = steps;
command.code = code;
return command;
}
}