// Copyright 2012 (C) Matthew Brejza
//
// This program 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.
//currently assumes strings begin with $$ when looking for the start of string
// -should be able to change the start sequence
package rtty;
public class Bits_to_chars {
//bits2char
private int _bit2char_i=0; //counter for number of bits into char
private boolean _bit2char_last_bit = false; //last bit in a window (used in bits2char)
private int _bitmask=0; //idle/active state of bits2char
private int _current_char=0; //current working value for bits2char
private boolean _next_start = false; //when high the next bit should be a start bit
private int _data_bits = 7;
private int _stop_bits=1;
private double _average_stop_bits;
private int _bits_since_last=0;
private int _total_average=0;
private boolean _first_start_found_stop_av = false;
private int _previous_bits;
private int _search_pattern;
private int _search_mask;
private int _search_len;
private int _bit_grouping_total_50 = 0;
private int _bits_count = 0;
private int _this_grouping = 0;
private boolean _last_bit = false;
public enum Method { WAIT_FOR_START_BIT, FIXED_POSITION };
public Method _decoding_method = Method.WAIT_FOR_START_BIT;
public double average_stop_bits()
{
double out = _average_stop_bits/_total_average;
if (_total_average>7)
{
_average_stop_bits = 0;
_bits_since_last = 0;
_total_average = 0;
_first_start_found_stop_av = false;
}
System.out.println("AT: "+_average_stop_bits/_total_average);
return out;
}
public Bits_to_chars(int default_data_bits, Method default_method) {
// TODO Auto-generated constructor stub
_decoding_method = default_method;
_data_bits = default_data_bits;
_update_pattern();
}
public Bits_to_chars(int default_data_bits, int default_stops, Method default_method) {
// TODO Auto-generated constructor stub
_decoding_method = default_method;
_data_bits = default_data_bits;
_stop_bits = default_stops;
_update_pattern();
}
public void DataBits (int bits)
{
_data_bits = bits;
_update_pattern();
}
public void StopBits (int stops)
{
_stop_bits = stops;
_update_pattern();
}
public double Average_bit_period()
{
if (_bits_count > 0)
return _bit_grouping_total_50/_bits_count;
else
return 0;
}
private void _update_pattern()
{
if (_stop_bits >=5)
return ;
if (_data_bits > 8 || _data_bits < 7)
return ;
int backwardsdollar;
if (_data_bits == 8)
backwardsdollar = 36;
else
backwardsdollar = 18;
_search_pattern = backwardsdollar; //1 start bit then $
for (int i = 0; i < _stop_bits; i++)
{
_search_pattern = _search_pattern << 1;
_search_pattern += 1; //the stop bits
}
_search_pattern = _search_pattern << (1+_data_bits);
_search_pattern += backwardsdollar; //1 start bit then $
for (int i = 0; i < _stop_bits; i++)
{
_search_pattern = _search_pattern << 1;
_search_pattern += 1; //the stop bits
}
_search_mask = (1 << (1+_data_bits+_stop_bits+1+_data_bits+_stop_bits)) - 1 ;
_search_len = (1+_data_bits+_stop_bits+1+_data_bits+_stop_bits);
}
private String bits2chars_fixed (boolean[] input)
{
//TODO: THIS!
String out = "";
if (input.length < 1)
{
System.out.println("bits2chars: 0 input");
return "";
}
int i = 0;
int start_score=0;
//loop over input
for (; i < input.length; i++)
{
//calculate probability of start sequence
_previous_bits = _previous_bits << 1;
if (input[i])
_previous_bits += 1;
start_score = Integer.bitCount( (~(_previous_bits ^ _search_pattern)) & _search_mask);
if (start_score >= (double)_search_len*1)
{
_bit2char_i = 0;
_bitmask = 1; //next loop start extracting
_current_char = 0;
_next_start = true;
out = out + "$$";
}
else if (_next_start)
{
_next_start = false;
}
else if (_bitmask > 0) //if currently processing a character, read next bit
{
if (input[i]) //if 1
_current_char = _current_char + _bitmask;
_bitmask = _bitmask << 1; //increment pointers and mask
_bit2char_i++;
if (_bit2char_i >= _data_bits) //if finished character
{
_bitmask = 0;
_bit2char_i = 0;
out = out + (char)_current_char;
_current_char = 0;
}
}
else //count number of stop bits
{
_bit2char_i++;
if (_bit2char_i >= _stop_bits)
{
_bitmask = 1;
_bit2char_i = 0;
_next_start = true;
_current_char = 0;
}
}
}
_bit2char_last_bit = input[input.length-1];
return out;
}
public String bits2chars (double[] input)
{
return bits2chars(input, _data_bits);
}
public String bits2chars (double[] input, int data_bits)
{
boolean[] out = new boolean[input.length];
for (int i = 0; i < input.length; i++)
{
if (input[i]<0)
out[i] = true;
else
out[i] = false;
}
return bits2chars(out,data_bits);
}
public String bits2chars (boolean[] input)
{
return bits2chars(input,_data_bits);
}
public String bits2chars (boolean[] input, int data_bits)
{
if (_decoding_method == Method.FIXED_POSITION)
return bits2chars_fixed(input);
//reset bit grouping counters
_bit_grouping_total_50 = 0;
_this_grouping = 0;
_bits_count = 0;
String out = "";
//_average_stop_bits = 0;
//_bits_since_last = 0;
//_total_average = 0;
//_first_start_found_stop_av = false;
if (input.length < 1)
{
System.out.println("bits2chars: 0 input");
return "";
}
int i = 0;
//special case to handle [i-1] in main loop
if (_bitmask <= 0)
{
if ((!input[0]) && (_bit2char_last_bit))
{
_bitmask = 1;
}
i = 1;
}
//loop over input
for (; i < input.length; i++)
{
if (_bitmask > 0) //if currently processing a character, read next bit
{
//this bit counts bit periods signal is high or low to work out incorrect baud rates
//looks for 50 bauds when demodulated as 300 baud
_this_grouping++;
if (input[i] != _last_bit)
{
_bit_grouping_total_50 += _this_grouping;
_bits_count++;
_this_grouping = 0;
}
if (input[i]) //if 1
_current_char = _current_char + _bitmask;
_bitmask = _bitmask << 1; //increment pointers and mask
_bit2char_i++;
if (_bit2char_i >= data_bits) //if finished character
{
_bitmask = 0;
_bit2char_i = 0;
out = out + (char)_current_char;
_current_char = 0;
}
}
else //look for start of char
{
if ((!input[i]) && (input[i-1]))
{
_bitmask = 1;
//now average stops part
_first_start_found_stop_av = true;
if (_bits_since_last > 0 && _bits_since_last < 5)
{
_total_average++;
_average_stop_bits = _average_stop_bits + _bits_since_last;
}
_bits_since_last = 0;
}
else if (_first_start_found_stop_av)
_bits_since_last++;
}
_last_bit = input[i];
}
_bit2char_last_bit = input[input.length-1];
return out;
}
}