Keelan Lightfoot 7 years ago
parent
commit
c0d45acc38
8 changed files with 263 additions and 465 deletions
  1. 11
    38
      code.go
  2. 24
    102
      common.go
  3. 16
    42
      decoder.go
  4. 73
    81
      demodulator.go
  5. 33
    59
      dsp.go
  6. 47
    71
      encoder.go
  7. 9
    4
      examples/main.go
  8. 50
    68
      modulator.go

+ 11
- 38
code.go View File

1
+// Copyright (C) 2017 Keelan Lightfoot
2
+// Copyright (C) 2007-2008 Board of Regents of the University of Wisconsin
3
+//             System (Univ. of Wisconsin-Madison, Trace R&D Center)
4
+// Copyright (C) 2007-2008 Omnitor AB
5
+// Copyright (C) 2007-2008 Voiceriver Inc
6
+//
7
+// This library is free software; you can redistribute it and/or modify it
8
+// under the terms of the GNU Lesser General Public License as published by
9
+// the Free Software Foundation; either version 2.1 of the License, or (at
10
+// your option) any later version.
11
+
1
 package openbaudot
12
 package openbaudot
2
 
13
 
3
 import "unicode"
14
 import "unicode"
4
 
15
 
5
-/*
6
- * OBL openbaudot Library
7
- *
8
- * Copyright (C) 2017 Keelan Lightfoot
9
- * Copyright (C) 2007-2008 Board of Regents of the University of Wisconsin
10
- *                   System (Univ. of Wisconsin-Madison, Trace R&D Center)
11
- * Copyright (C) 2007-2008 Omnitor AB
12
- * Copyright (C) 2007-2008 Voiceriver Inc
13
- *
14
- * This software was developed with support from the National Institute on
15
- * Disability and Rehabilitation Research, US Dept of Education under Grant
16
- * # H133E990006 and H133E040014
17
- *
18
- * This library is free software; you can redistribute it and/or modify it
19
- * under the terms of the GNU Lesser General Public License as published by
20
- * the Free Software Foundation; either version 2.1 of the License, or (at
21
- * your option) any later version.
22
- *
23
- * This library is distributed in the hope that it will be useful, but
24
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
25
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
26
- * License for more details.
27
- *
28
- * You should have received a copy of the GNU Lesser General Public License
29
- * along with this library; if not, write to the Free Software Foundation,
30
- * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
31
- *
32
- * Please send a copy of any improved versions of the library to:
33
- * Jeff Knighton, Voiceriver Inc, jeff.knighton@voiceriver.com
34
- * Gunnar Hellstrom, Omnitor AB, Box 92054, 12006 Stockholm, SWEDEN
35
- * Gregg Vanderheiden, Trace Center, U of Wisconsin, Madison, Wi 53706
36
- *
37
- * file...: obl.go
38
- * original author.: Keelan Lightfoot
39
- * Created: 20 May 2017
40
- *
41
- */
42
-
43
 const (
16
 const (
44
 	shiftUnknown = iota
17
 	shiftUnknown = iota
45
 	shiftLetter
18
 	shiftLetter

+ 24
- 102
common.go View File

1
+// Copyright (C) 2017 Keelan Lightfoot
2
+// Copyright (C) 2007-2008 Board of Regents of the University of Wisconsin
3
+//             System (Univ. of Wisconsin-Madison, Trace R&D Center)
4
+// Copyright (C) 2007-2008 Omnitor AB
5
+// Copyright (C) 2007-2008 Voiceriver Inc
6
+//
7
+// This library is free software; you can redistribute it and/or modify it
8
+// under the terms of the GNU Lesser General Public License as published by
9
+// the Free Software Foundation; either version 2.1 of the License, or (at
10
+// your option) any later version.
11
+
12
+// Package openbaudot provides a set of tools to encode, modulate, demodulate and
13
+// baudot/TTY/RTTY data streams
1
 package openbaudot
14
 package openbaudot
2
 
15
 
3
 import "math"
16
 import "math"
4
 
17
 
5
-/*
6
- * OBL openbaudot Library
7
- *
8
- * Copyright (C) 2017 Keelan Lightfoot
9
- * Copyright (C) 2007-2008 Board of Regents of the University of Wisconsin
10
- *                   System (Univ. of Wisconsin-Madison, Trace R&D Center)
11
- * Copyright (C) 2007-2008 Omnitor AB
12
- * Copyright (C) 2007-2008 Voiceriver Inc
13
- *
14
- * This software was developed with support from the National Institute on
15
- * Disability and Rehabilitation Research, US Dept of Education under Grant
16
- * # H133E990006 and H133E040014
17
- *
18
- * This library is free software; you can redistribute it and/or modify it
19
- * under the terms of the GNU Lesser General Public License as published by
20
- * the Free Software Foundation; either version 2.1 of the License, or (at
21
- * your option) any later version.
22
- *
23
- * This library is distributed in the hope that it will be useful, but
24
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
25
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
26
- * License for more details.
27
- *
28
- * You should have received a copy of the GNU Lesser General Public License
29
- * along with this library; if not, write to the Free Software Foundation,
30
- * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
31
- *
32
- * Please send a copy of any improved versions of the library to:
33
- * Jeff Knighton, Voiceriver Inc, jeff.knighton@voiceriver.com
34
- * Gunnar Hellstrom, Omnitor AB, Box 92054, 12006 Stockholm, SWEDEN
35
- * Gregg Vanderheiden, Trace Center, U of Wisconsin, Madison, Wi 53706
36
- *
37
- * file...: obl.go
38
- * original author.: Keelan Lightfoot
39
- * Created: 20 May 2017
40
- *
41
- */
42
-
43
 const (
18
 const (
44
-
45
-	// LETR  Letters Baudot code
46
-	LETR byte = 0x1f
47
-	// FIGR Figures Baudot code
48
-	FIGR byte = 0x1b
49
-	// CRLFThresh start looking for space
50
-	CRLFThresh = 60
51
-	// CRLFForce force CR-LF
52
-	CRLFForce = 72
53
-
54
-	// ModStateIdle no data in mod buffer, idling
55
-	ModStateIdle = 0
56
-	// ModStateStart modulating start bit
57
-	ModStateStart = 1
58
-	// ModStateBit modulating a baudot bit
59
-	ModStateBit = 2
60
-	// ModStateStop modulating stop bit
61
-	ModStateStop = 3
62
-	// ModStateHold modulating hold tone
63
-	ModStateHold = 4
64
-
65
-	// LPFOrder Low pass filter order
66
-	LPFOrder = 20 // 20
67
-
68
-	/* oblDemodulate() state machine states */
69
-
70
-	// DemodStateWaitStart wait for start bit
71
-	DemodStateWaitStart = 0 /**/
72
-	// DemodStateSample sampling demod bits
73
-	DemodStateSample = 1 /**/
74
-	// DemodStateWaitStop wait for stop bit
75
-	DemodStateWaitStop = 2 /**/
76
-
77
-	// MinThresh ratio for vaild signal
78
-	MinThresh = 3
79
-
80
-	/* auto baud detection state machine states */
81
-
82
-	// AutobaudStateWaitStart waiting for start bit
83
-	AutobaudStateWaitStart = 0
84
-	// AutobaudStateWaitZeroX waiting for zero crossing
85
-	AutobaudStateWaitZeroX = 1
86
-	// AutobaudStateWaitStop waiting for stop bit
87
-	AutobaudStateWaitStop = 2
88
-	// AutobaudStateDisabled disabled
89
-	AutobaudStateDisabled = 3
90
-
91
-	/* top level state machines states */
92
-
93
 	// EventDemodChar is fun
19
 	// EventDemodChar is fun
94
 	EventDemodChar = iota
20
 	EventDemodChar = iota
95
 	// EventDemodAbort is fun
21
 	// EventDemodAbort is fun
102
 	EventIdle
28
 	EventIdle
103
 )
29
 )
104
 
30
 
105
-/* precomputed constants for demodDsp */
31
+// Callback is func
32
+type Callback func(event int, data interface{})
106
 
33
 
107
-var (
108
-	// sampleRate Sample rate
109
-	sampleRate = 8000
110
-	// Beta filter bandwidth factor
111
-	Beta = 0.95 //.95
112
-)
34
+// ModemSettings is fun
35
+type ModemSettings struct {
36
+	Baud       float64
37
+	StopBits   float64
38
+	DataBits   int
39
+	SampleRate int
40
+}
113
 
41
 
114
-func multq(x, y int16) int16 {
42
+func multq15(x, y int16) int16 {
115
 	return int16((int(x) * int(y)) >> 15)
43
 	return int16((int(x) * int(y)) >> 15)
116
-
117
 }
44
 }
118
 
45
 
119
-// abs16 returns the absolute value of x.
120
 func abs16(x int16) int16 {
46
 func abs16(x int16) int16 {
121
 	if x < 0 {
47
 	if x < 0 {
122
 		return -x
48
 		return -x
124
 	return x
50
 	return x
125
 }
51
 }
126
 
52
 
127
-// absint returns the absolute value of x.
128
 func absint(x int) int {
53
 func absint(x int) int {
129
 	if x < 0 {
54
 	if x < 0 {
130
 		return -x
55
 		return -x
132
 	return x
57
 	return x
133
 }
58
 }
134
 
59
 
135
-func calculateW(oneF int, zeroF int) (float64, float64) {
60
+func calculateW(oneF int, zeroF int, sampleRate int) (float64, float64) {
136
 	wOne := (2 * math.Pi * float64(oneF) / float64(sampleRate))   //1400 // WOne 1 freq in normalised rads
61
 	wOne := (2 * math.Pi * float64(oneF) / float64(sampleRate))   //1400 // WOne 1 freq in normalised rads
137
 	wZero := (2 * math.Pi * float64(zeroF) / float64(sampleRate)) //1800 // WZero 0 freq in normazlised rads
62
 	wZero := (2 * math.Pi * float64(zeroF) / float64(sampleRate)) //1800 // WZero 0 freq in normazlised rads
138
 	return wOne, wZero
63
 	return wOne, wZero
139
 }
64
 }
140
-
141
-// Callback is func
142
-type Callback func(event int, data interface{})

+ 16
- 42
decoder.go View File

1
-package openbaudot
1
+// Copyright (C) 2017 Keelan Lightfoot
2
+// Copyright (C) 2007-2008 Board of Regents of the University of Wisconsin
3
+//             System (Univ. of Wisconsin-Madison, Trace R&D Center)
4
+// Copyright (C) 2007-2008 Omnitor AB
5
+// Copyright (C) 2007-2008 Voiceriver Inc
6
+//
7
+// This library is free software; you can redistribute it and/or modify it
8
+// under the terms of the GNU Lesser General Public License as published by
9
+// the Free Software Foundation; either version 2.1 of the License, or (at
10
+// your option) any later version.
2
 
11
 
3
-/*
4
- * OBL openbaudot Library
5
- *
6
- * Copyright (C) 2017 Keelan Lightfoot
7
- * Copyright (C) 2007-2008 Board of Regents of the University of Wisconsin
8
- *                   System (Univ. of Wisconsin-Madison, Trace R&D Center)
9
- * Copyright (C) 2007-2008 Omnitor AB
10
- * Copyright (C) 2007-2008 Voiceriver Inc
11
- *
12
- * This software was developed with support from the National Institute on
13
- * Disability and Rehabilitation Research, US Dept of Education under Grant
14
- * # H133E990006 and H133E040014
15
- *
16
- * This library is free software; you can redistribute it and/or modify it
17
- * under the terms of the GNU Lesser General Public License as published by
18
- * the Free Software Foundation; either version 2.1 of the License, or (at
19
- * your option) any later version.
20
- *
21
- * This library is distributed in the hope that it will be useful, but
22
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
23
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
24
- * License for more details.
25
- *
26
- * You should have received a copy of the GNU Lesser General Public License
27
- * along with this library; if not, write to the Free Software Foundation,
28
- * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
29
- *
30
- * Please send a copy of any improved versions of the library to:
31
- * Jeff Knighton, Voiceriver Inc, jeff.knighton@voiceriver.com
32
- * Gunnar Hellstrom, Omnitor AB, Box 92054, 12006 Stockholm, SWEDEN
33
- * Gregg Vanderheiden, Trace Center, U of Wisconsin, Madison, Wi 53706
34
- *
35
- * file...: obl.go
36
- * original author.: Keelan Lightfoot
37
- * Created: 20 May 2017
38
- *
39
- */
12
+package openbaudot
40
 
13
 
41
-// Decoder is fun
14
+// Decoder converts a stream of bytes representing baudot codes into a stream
15
+// of unicode runes.
42
 type Decoder struct {
16
 type Decoder struct {
43
 	input   chan byte
17
 	input   chan byte
44
 	output  chan rune
18
 	output  chan rune
45
 	charset *CodeSet
19
 	charset *CodeSet
46
 }
20
 }
47
 
21
 
48
-// NewDecoder is fun
22
+// NewDecoder creates a new decoder.
49
 func NewDecoder(input chan byte, output chan rune, charset *CodeSet) *Decoder {
23
 func NewDecoder(input chan byte, output chan rune, charset *CodeSet) *Decoder {
50
 	d := new(Decoder)
24
 	d := new(Decoder)
51
 	d.input = input
25
 	d.input = input
60
 	shift := shiftLetter
34
 	shift := shiftLetter
61
 	for c := range d.input {
35
 	for c := range d.input {
62
 		switch c {
36
 		switch c {
63
-		case LETR:
37
+		case d.charset.UnshiftCode:
64
 			shift = shiftLetter
38
 			shift = shiftLetter
65
 			//obl.callback(EventDemodCase, Letters)
39
 			//obl.callback(EventDemodCase, Letters)
66
-		case FIGR:
40
+		case d.charset.ShiftCode:
67
 			shift = shiftFigure
41
 			shift = shiftFigure
68
 		//	obl.callback(EventDemodCase, Figures)
42
 		//	obl.callback(EventDemodCase, Figures)
69
 		default:
43
 		default:

+ 73
- 81
demodulator.go View File

1
+// Copyright (C) 2017 Keelan Lightfoot
2
+// Copyright (C) 2007-2008 Board of Regents of the University of Wisconsin
3
+//             System (Univ. of Wisconsin-Madison, Trace R&D Center)
4
+// Copyright (C) 2007-2008 Omnitor AB
5
+// Copyright (C) 2007-2008 Voiceriver Inc
6
+//
7
+// This library is free software; you can redistribute it and/or modify it
8
+// under the terms of the GNU Lesser General Public License as published by
9
+// the Free Software Foundation; either version 2.1 of the License, or (at
10
+// your option) any later version.
11
+
1
 package openbaudot
12
 package openbaudot
2
 
13
 
3
 import "math"
14
 import "math"
4
 
15
 
5
-/*
6
- * OBL openbaudot Library
7
- *
8
- * Copyright (C) 2017 Keelan Lightfoot
9
- * Copyright (C) 2007-2008 Board of Regents of the University of Wisconsin
10
- *                   System (Univ. of Wisconsin-Madison, Trace R&D Center)
11
- * Copyright (C) 2007-2008 Omnitor AB
12
- * Copyright (C) 2007-2008 Voiceriver Inc
13
- *
14
- * This software was developed with support from the National Institute on
15
- * Disability and Rehabilitation Research, US Dept of Education under Grant
16
- * # H133E990006 and H133E040014
17
- *
18
- * This library is free software; you can redistribute it and/or modify it
19
- * under the terms of the GNU Lesser General Public License as published by
20
- * the Free Software Foundation; either version 2.1 of the License, or (at
21
- * your option) any later version.
22
- *
23
- * This library is distributed in the hope that it will be useful, but
24
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
25
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
26
- * License for more details.
27
- *
28
- * You should have received a copy of the GNU Lesser General Public License
29
- * along with this library; if not, write to the Free Software Foundation,
30
- * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
31
- *
32
- * Please send a copy of any improved versions of the library to:
33
- * Jeff Knighton, Voiceriver Inc, jeff.knighton@voiceriver.com
34
- * Gunnar Hellstrom, Omnitor AB, Box 92054, 12006 Stockholm, SWEDEN
35
- * Gregg Vanderheiden, Trace Center, U of Wisconsin, Madison, Wi 53706
36
- *
37
- * file...: obl.go
38
- * original author.: Keelan Lightfoot
39
- * Created: 20 May 2017
40
- *
41
- */
16
+const (
17
+	demodStateWaitStart = iota
18
+	demodStateSample
19
+	demodStateWaitStop
20
+
21
+	autobaudStateWaitStart = iota
22
+	autobaudStateWaitZeroX
23
+	autobaudStateWaitStop
24
+	autobaudStateDisabled
25
+)
42
 
26
 
43
 // Demodulator is fun
27
 // Demodulator is fun
44
 type Demodulator struct {
28
 type Demodulator struct {
54
 	samplesPerBit int
38
 	samplesPerBit int
55
 	dsp           *dsp
39
 	dsp           *dsp
56
 	dataBits      int
40
 	dataBits      int
41
+	sampleRate    int
57
 	autobaud      struct {
42
 	autobaud      struct {
58
 		enabled  bool    // audio baud detection enable/disable flag
43
 		enabled  bool    // audio baud detection enable/disable flag
59
 		state    int     // auto buad detection state mach state
44
 		state    int     // auto buad detection state mach state
63
 }
48
 }
64
 
49
 
65
 // NewDemodulator is fun
50
 // NewDemodulator is fun
66
-func NewDemodulator(baud float64, stopBits float64, dataBits int, input chan int16, output chan byte) *Demodulator {
51
+func NewDemodulator(s ModemSettings, input chan int16, output chan byte) *Demodulator {
67
 
52
 
68
 	d := new(Demodulator)
53
 	d := new(Demodulator)
69
 	d.input = input
54
 	d.input = input
70
 	d.output = output
55
 	d.output = output
71
-	d.state = DemodStateWaitStart
56
+	d.state = demodStateWaitStart
72
 	//d.lettersFigures = Letters
57
 	//d.lettersFigures = Letters
73
-	d.baud = baud
74
-	d.dataBits = dataBits
75
-	d.samplesPerBit = int(float64(sampleRate) / d.baud)
58
+	d.baud = s.Baud
59
+	d.dataBits = s.DataBits
60
+	d.sampleRate = s.SampleRate
61
+	d.samplesPerBit = int(float64(d.sampleRate) / d.baud)
62
+
63
+	wOne, wZero := calculateW(2125, 2295, d.sampleRate)
76
 
64
 
77
-	wOne, wZero := calculateW(2125, 2295)
65
+	lfpOrder := 20
66
+	beta := 0.95 //.95
78
 
67
 
79
 	d.dsp = &dsp{
68
 	d.dsp = &dsp{
80
-		c1: int16((2.0 * math.Cos(wOne) * Beta) * 32768),
81
-		c2: int16(Beta * Beta * 32768),
82
-		c3: int16((2.0 * math.Cos(wZero) * Beta) * 32768),
69
+		c1:         int16((2.0 * math.Cos(wOne) * beta) * 32768),
70
+		c2:         int16(beta * beta * 32768),
71
+		c3:         int16((2.0 * math.Cos(wZero) * beta) * 32768),
72
+		demLpfIn:   make([]int16, lfpOrder),
73
+		demTotalIn: make([]int16, lfpOrder),
74
+		lpfOrder:   lfpOrder,
83
 	}
75
 	}
84
 
76
 
85
 	d.autobaud.estimate = d.baud
77
 	d.autobaud.estimate = d.baud
86
 	if d.autobaud.enabled {
78
 	if d.autobaud.enabled {
87
-		d.autobaud.state = AutobaudStateWaitStart
79
+		d.autobaud.state = autobaudStateWaitStart
88
 	} else {
80
 	} else {
89
-		d.autobaud.state = AutobaudStateDisabled
81
+		d.autobaud.state = autobaudStateDisabled
90
 	}
82
 	}
91
 	go d.run()
83
 	go d.run()
92
 	return d
84
 	return d
111
 		nextState = d.state
103
 		nextState = d.state
112
 
104
 
113
 		switch d.state {
105
 		switch d.state {
114
-		case DemodStateWaitStart:
106
+		case demodStateWaitStart:
115
 			/*
107
 			/*
116
 			   The demodulator sits in this state when it
108
 			   The demodulator sits in this state when it
117
-			   is waiting for a start bit.  When a sampleRateK
109
+			   is waiting for a start bit.  When a d.sampleRateK
118
 			   "0" (1800 Hz) start-bit is detected that is
110
 			   "0" (1800 Hz) start-bit is detected that is
119
 			   above a minimum threshold it transitions
111
 			   above a minimum threshold it transitions
120
 			   out of this state.
112
 			   out of this state.
121
 			*/
113
 			*/
122
 			if d.dsp.signalPresent() {
114
 			if d.dsp.signalPresent() {
123
-				d.sample = int(float64(sampleRate)/d.baud + float64(sampleRate)/(2*d.baud))
115
+				d.sample = int(float64(d.sampleRate)/d.baud + float64(d.sampleRate)/(2*d.baud))
124
 				d.baudot = 0
116
 				d.baudot = 0
125
 				d.bit = 0
117
 				d.bit = 0
126
-				nextState = DemodStateSample
118
+				nextState = demodStateSample
127
 			}
119
 			}
128
-		case DemodStateSample:
120
+		case demodStateSample:
129
 
121
 
130
 			d.sample--
122
 			d.sample--
131
 			if d.sample == 0 {
123
 			if d.sample == 0 {
140
 					d.output <- d.baudot
132
 					d.output <- d.baudot
141
 					//fmt.Printf("Demodulator done %d\n", d.baudot)
133
 					//fmt.Printf("Demodulator done %d\n", d.baudot)
142
 
134
 
143
-					d.sample = int(float64(sampleRate) / d.baud)
144
-					nextState = DemodStateWaitStop
135
+					d.sample = int(float64(d.sampleRate) / d.baud)
136
+					nextState = demodStateWaitStop
145
 				} else {
137
 				} else {
146
 					/* sample next bit 1 bit-period later */
138
 					/* sample next bit 1 bit-period later */
147
-					d.sample = int(float64(sampleRate) / d.baud)
139
+					d.sample = int(float64(d.sampleRate) / d.baud)
148
 				}
140
 				}
149
 			}
141
 			}
150
 
142
 
151
-			/* check for sampleRateK signal drop out */
143
+			/* check for d.sampleRateK signal drop out */
152
 
144
 
153
 			//return d.demTotal != 0 && d.demLpf < -1*MinThresh*d.demTotal
145
 			//return d.demTotal != 0 && d.demLpf < -1*MinThresh*d.demTotal
154
 
146
 
156
 				d.minSigTimeout++
148
 				d.minSigTimeout++
157
 
149
 
158
 				/* If signal drops out for approx one bit period
150
 				/* If signal drops out for approx one bit period
159
-				   assume we have lost sampleRateK signal */
151
+				   assume we have lost d.sampleRateK signal */
160
 				if d.minSigTimeout > d.samplesPerBit {
152
 				if d.minSigTimeout > d.samplesPerBit {
161
-					nextState = DemodStateWaitStart
153
+					nextState = demodStateWaitStart
162
 				}
154
 				}
163
 			} else {
155
 			} else {
164
 				d.minSigTimeout = 0
156
 				d.minSigTimeout = 0
165
 			}
157
 			}
166
 
158
 
167
-		case DemodStateWaitStop:
159
+		case demodStateWaitStop:
168
 
160
 
169
 			/* wait until we are in the middle of stop bit */
161
 			/* wait until we are in the middle of stop bit */
170
 
162
 
171
 			d.sample--
163
 			d.sample--
172
 			if d.sample == 0 {
164
 			if d.sample == 0 {
173
-				nextState = DemodStateWaitStart
165
+				nextState = demodStateWaitStart
174
 			}
166
 			}
175
 
167
 
176
 		}
168
 		}
195
 		nextState = d.autobaud.state
187
 		nextState = d.autobaud.state
196
 
188
 
197
 		switch d.autobaud.state {
189
 		switch d.autobaud.state {
198
-		case AutobaudStateWaitStart:
190
+		case autobaudStateWaitStart:
199
 			/* start bit kicks off this state machine */
191
 			/* start bit kicks off this state machine */
200
-			if d.state == DemodStateSample {
201
-				nextState = AutobaudStateWaitZeroX
192
+			if d.state == demodStateSample {
193
+				nextState = autobaudStateWaitZeroX
202
 				d.autobaud.zeroX = 0
194
 				d.autobaud.zeroX = 0
203
 			}
195
 			}
204
-		case AutobaudStateWaitZeroX:
196
+		case autobaudStateWaitZeroX:
205
 
197
 
206
 			d.autobaud.zeroX++
198
 			d.autobaud.zeroX++
207
 
199
 
210
 
202
 
211
 				/* determine distance to closest edge assuming 50 baud */
203
 				/* determine distance to closest edge assuming 50 baud */
212
 
204
 
213
-				dist75 := sampleRate / 75
205
+				dist75 := d.sampleRate / 75
214
 				edge = 0
206
 				edge = 0
215
 				for i := 0; i < (d.dataBits + 1); i++ {
207
 				for i := 0; i < (d.dataBits + 1); i++ {
216
 					dist = absint(edge - d.autobaud.zeroX)
208
 					dist = absint(edge - d.autobaud.zeroX)
217
 					if dist < dist75 {
209
 					if dist < dist75 {
218
 						dist75 = dist
210
 						dist75 = dist
219
 					}
211
 					}
220
-					edge += sampleRate / 75
212
+					edge += d.sampleRate / 75
221
 				}
213
 				}
222
 
214
 
223
 				/* determine distance to closest edge assuming 50 baud */
215
 				/* determine distance to closest edge assuming 50 baud */
224
 
216
 
225
-				dist50 := sampleRate / 50
217
+				dist50 := d.sampleRate / 50
226
 				edge = 0
218
 				edge = 0
227
 				for i := 0; i < (d.dataBits + 1); i++ {
219
 				for i := 0; i < (d.dataBits + 1); i++ {
228
 					dist = absint(edge - d.autobaud.zeroX)
220
 					dist = absint(edge - d.autobaud.zeroX)
229
 					if dist < dist50 {
221
 					if dist < dist50 {
230
 						dist50 = dist
222
 						dist50 = dist
231
 					}
223
 					}
232
-					edge += sampleRate / 50
224
+					edge += d.sampleRate / 50
233
 				}
225
 				}
234
 
226
 
235
 				/* determine distance to closest edge assuming 47 baud */
227
 				/* determine distance to closest edge assuming 47 baud */
236
 
228
 
237
-				dist47 := sampleRate / 47
229
+				dist47 := d.sampleRate / 47
238
 				edge = 0
230
 				edge = 0
239
 				for i := 0; i < (d.dataBits + 1); i++ {
231
 				for i := 0; i < (d.dataBits + 1); i++ {
240
 					dist = absint(edge - d.autobaud.zeroX)
232
 					dist = absint(edge - d.autobaud.zeroX)
241
 					if dist < dist47 {
233
 					if dist < dist47 {
242
 						dist47 = dist
234
 						dist47 = dist
243
 					}
235
 					}
244
-					edge += sampleRate / 47
236
+					edge += d.sampleRate / 47
245
 				}
237
 				}
246
 
238
 
247
 				/* determine distance to closest edge assuming 45 baud */
239
 				/* determine distance to closest edge assuming 45 baud */
248
 
240
 
249
-				dist45 := sampleRate / 45
241
+				dist45 := d.sampleRate / 45
250
 				edge = 0
242
 				edge = 0
251
 				for i := 0; i < (d.dataBits + 1); i++ {
243
 				for i := 0; i < (d.dataBits + 1); i++ {
252
 					dist = absint(edge - d.autobaud.zeroX)
244
 					dist = absint(edge - d.autobaud.zeroX)
253
 					if dist < dist45 {
245
 					if dist < dist45 {
254
 						dist45 = dist
246
 						dist45 = dist
255
 					}
247
 					}
256
-					edge += sampleRate / 45
248
+					edge += d.sampleRate / 45
257
 				}
249
 				}
258
 
250
 
259
 				/* update 3-point smoothed distance estimates */
251
 				/* update 3-point smoothed distance estimates */
291
 
283
 
292
 				//printf("obl.autobaud_zerox: %d dist50: %02d dist47: %02d dist45: %02d est: %d\n",
284
 				//printf("obl.autobaud_zerox: %d dist50: %02d dist47: %02d dist45: %02d est: %d\n",
293
 				//       obl.autobaud_zerox, dist50Smooth, dist47Smooth, dist45Smooth, obl.dem_baud_est);
285
 				//       obl.autobaud_zerox, dist50Smooth, dist47Smooth, dist45Smooth, obl.dem_baud_est);
294
-				nextState = AutobaudStateWaitStop
286
+				nextState = autobaudStateWaitStop
295
 			}
287
 			}
296
 
288
 
297
-			/* reset autobaud state machine, e.g. if sampleRateK drops out before
289
+			/* reset autobaud state machine, e.g. if d.sampleRateK drops out before
298
 			   we get a zero crossing */
290
 			   we get a zero crossing */
299
 
291
 
300
-			if d.state != DemodStateSample {
301
-				nextState = AutobaudStateWaitStop
292
+			if d.state != demodStateSample {
293
+				nextState = autobaudStateWaitStop
302
 			}
294
 			}
303
 
295
 
304
-		case AutobaudStateWaitStop:
305
-			if d.state == DemodStateWaitStop {
306
-				nextState = AutobaudStateWaitStart
296
+		case autobaudStateWaitStop:
297
+			if d.state == demodStateWaitStop {
298
+				nextState = autobaudStateWaitStart
307
 			}
299
 			}
308
 
300
 
309
-		case AutobaudStateDisabled:
301
+		case autobaudStateDisabled:
310
 
302
 
311
 		default:
303
 		default:
312
 
304
 

+ 33
- 59
dsp.go View File

1
-package openbaudot
1
+// Copyright (C) 2017 Keelan Lightfoot
2
+// Copyright (C) 2007-2008 Board of Regents of the University of Wisconsin
3
+//             System (Univ. of Wisconsin-Madison, Trace R&D Center)
4
+// Copyright (C) 2007-2008 Omnitor AB
5
+// Copyright (C) 2007-2008 Voiceriver Inc
6
+//
7
+// This library is free software; you can redistribute it and/or modify it
8
+// under the terms of the GNU Lesser General Public License as published by
9
+// the Free Software Foundation; either version 2.1 of the License, or (at
10
+// your option) any later version.
2
 
11
 
3
-/*
4
- * OBL openbaudot Library
5
- *
6
- * Copyright (C) 2017 Keelan Lightfoot
7
- * Copyright (C) 2007-2008 Board of Regents of the University of Wisconsin
8
- *                   System (Univ. of Wisconsin-Madison, Trace R&D Center)
9
- * Copyright (C) 2007-2008 Omnitor AB
10
- * Copyright (C) 2007-2008 Voiceriver Inc
11
- *
12
- * This software was developed with support from the National Institute on
13
- * Disability and Rehabilitation Research, US Dept of Education under Grant
14
- * # H133E990006 and H133E040014
15
- *
16
- * This library is free software; you can redistribute it and/or modify it
17
- * under the terms of the GNU Lesser General Public License as published by
18
- * the Free Software Foundation; either version 2.1 of the License, or (at
19
- * your option) any later version.
20
- *
21
- * This library is distributed in the hope that it will be useful, but
22
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
23
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
24
- * License for more details.
25
- *
26
- * You should have received a copy of the GNU Lesser General Public License
27
- * along with this library; if not, write to the Free Software Foundation,
28
- * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
29
- *
30
- * Please send a copy of any improved versions of the library to:
31
- * Jeff Knighton, Voiceriver Inc, jeff.knighton@voiceriver.com
32
- * Gunnar Hellstrom, Omnitor AB, Box 92054, 12006 Stockholm, SWEDEN
33
- * Gregg Vanderheiden, Trace Center, U of Wisconsin, Madison, Wi 53706
34
- *
35
- * file...: obl.go
36
- * original author.: Keelan Lightfoot
37
- * Created: 20 May 2017
38
- *
39
- */
12
+package openbaudot
40
 
13
 
41
 type dsp struct {
14
 type dsp struct {
42
-	demOne      [2]float64      // previous 2 output samples of one filter
43
-	demOneQ0    [2]int16        // previous 2 output samples of one filter
44
-	demZero     [2]float64      // previous 2 output samples of zero filter
45
-	demZeroQ0   [2]int16        // previous 2 output samples of one filter
46
-	demLpfIn    [LPFOrder]int16 // previous LPFOrder LPF input samples
47
-	pdemLpfIn   int             // ptr to oldest LPF input sample
48
-	demLpf      int             // current LPF output value
49
-	demTotalIn  [LPFOrder]int16 // previous LPFOrder energy input samples
50
-	pdemTotalIn int             // ptr to oldest energy sample
51
-	demTotal    int             // current energy output value
52
-	c1, c2, c3  int16           // precomputed values for demod_dsp
53
-
15
+	demOne      [2]float64 // previous 2 output samples of one filter
16
+	demOneQ0    [2]int16   // previous 2 output samples of one filter
17
+	demZero     [2]float64 // previous 2 output samples of zero filter
18
+	demZeroQ0   [2]int16   // previous 2 output samples of one filter
19
+	demLpfIn    []int16    // previous LPFOrder LPF input samples
20
+	pdemLpfIn   int        // ptr to oldest LPF input sample
21
+	demLpf      int        // current LPF output value
22
+	demTotalIn  []int16    // previous LPFOrder energy input samples
23
+	pdemTotalIn int        // ptr to oldest energy sample
24
+	demTotal    int        // current energy output value
25
+	c1, c2, c3  int16      // precomputed values for demod_dsp
26
+	lpfOrder    int        // LPFOrder Low pass filter order
27
+	minThresh   int        // MinThresh ratio for vaild signal
54
 }
28
 }
55
 
29
 
56
 func (d *dsp) edgeDetected() bool {
30
 func (d *dsp) edgeDetected() bool {
57
-	return d.demLpf > MinThresh*d.demTotal
31
+	return d.demLpf > d.minThresh*d.demTotal
58
 }
32
 }
59
 
33
 
60
 func (d *dsp) dropout() bool {
34
 func (d *dsp) dropout() bool {
61
-	return absint(d.demLpf) < MinThresh*d.demTotal || d.demTotal == 0
35
+	return absint(d.demLpf) < d.minThresh*d.demTotal || d.demTotal == 0
62
 }
36
 }
63
 
37
 
64
 func (d *dsp) signalPresent() bool {
38
 func (d *dsp) signalPresent() bool {
65
-	return d.demTotal != 0 && d.demLpf < -1*MinThresh*d.demTotal
39
+	return d.demTotal != 0 && d.demLpf < -1*d.minThresh*d.demTotal
66
 }
40
 }
67
 
41
 
68
 func (d *dsp) onePresent() bool {
42
 func (d *dsp) onePresent() bool {
74
 	sam >>= 5
48
 	sam >>= 5
75
 
49
 
76
 	oneQ0 := sam
50
 	oneQ0 := sam
77
-	oneQ0 += multq(d.c1, d.demOneQ0[0])
78
-	oneQ0 -= multq(d.c2, d.demOneQ0[1])
51
+	oneQ0 += multq15(d.c1, d.demOneQ0[0])
52
+	oneQ0 -= multq15(d.c2, d.demOneQ0[1])
79
 	d.demOneQ0[1] = d.demOneQ0[0]
53
 	d.demOneQ0[1] = d.demOneQ0[0]
80
 	d.demOneQ0[0] = oneQ0
54
 	d.demOneQ0[0] = oneQ0
81
 
55
 
82
 	zeroQ0 := sam
56
 	zeroQ0 := sam
83
-	zeroQ0 += multq(d.c3, d.demZeroQ0[0])
84
-	zeroQ0 -= multq(d.c2, d.demZeroQ0[1])
57
+	zeroQ0 += multq15(d.c3, d.demZeroQ0[0])
58
+	zeroQ0 -= multq15(d.c2, d.demZeroQ0[1])
85
 	d.demZeroQ0[1] = d.demZeroQ0[0]
59
 	d.demZeroQ0[1] = d.demZeroQ0[0]
86
 	d.demZeroQ0[0] = zeroQ0
60
 	d.demZeroQ0[0] = zeroQ0
87
 
61
 
89
 	d.demLpf -= int(d.demLpfIn[d.pdemLpfIn])
63
 	d.demLpf -= int(d.demLpfIn[d.pdemLpfIn])
90
 	d.demLpf += int(x)
64
 	d.demLpf += int(x)
91
 	d.demLpfIn[d.pdemLpfIn] = x
65
 	d.demLpfIn[d.pdemLpfIn] = x
92
-	d.pdemLpfIn = (d.pdemLpfIn + 1) % LPFOrder
66
+	d.pdemLpfIn = (d.pdemLpfIn + 1) % d.lpfOrder
93
 
67
 
94
 	/* now work out total energy estimate, this is used to
68
 	/* now work out total energy estimate, this is used to
95
 	   determine if a valid signal is present by comparing
69
 	   determine if a valid signal is present by comparing
99
 	d.demTotal -= int(d.demTotalIn[d.pdemTotalIn])
73
 	d.demTotal -= int(d.demTotalIn[d.pdemTotalIn])
100
 	d.demTotal += int(x)
74
 	d.demTotal += int(x)
101
 	d.demTotalIn[d.pdemTotalIn] = x
75
 	d.demTotalIn[d.pdemTotalIn] = x
102
-	d.pdemTotalIn = (d.pdemTotalIn + 1) % LPFOrder
76
+	d.pdemTotalIn = (d.pdemTotalIn + 1) % d.lpfOrder
103
 }
77
 }

+ 47
- 71
encoder.go View File

1
-package openbaudot
1
+// Copyright (C) 2017 Keelan Lightfoot
2
+// Copyright (C) 2007-2008 Board of Regents of the University of Wisconsin
3
+//             System (Univ. of Wisconsin-Madison, Trace R&D Center)
4
+// Copyright (C) 2007-2008 Omnitor AB
5
+// Copyright (C) 2007-2008 Voiceriver Inc
6
+//
7
+// This library is free software; you can redistribute it and/or modify it
8
+// under the terms of the GNU Lesser General Public License as published by
9
+// the Free Software Foundation; either version 2.1 of the License, or (at
10
+// your option) any later version.
2
 
11
 
3
-/*
4
- * OBL openbaudot Library
5
- *
6
- * Copyright (C) 2017 Keelan Lightfoot
7
- * Copyright (C) 2007-2008 Board of Regents of the University of Wisconsin
8
- *                   System (Univ. of Wisconsin-Madison, Trace R&D Center)
9
- * Copyright (C) 2007-2008 Omnitor AB
10
- * Copyright (C) 2007-2008 Voiceriver Inc
11
- *
12
- * This software was developed with support from the National Institute on
13
- * Disability and Rehabilitation Research, US Dept of Education under Grant
14
- * # H133E990006 and H133E040014
15
- *
16
- * This library is free software; you can redistribute it and/or modify it
17
- * under the terms of the GNU Lesser General Public License as published by
18
- * the Free Software Foundation; either version 2.1 of the License, or (at
19
- * your option) any later version.
20
- *
21
- * This library is distributed in the hope that it will be useful, but
22
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
23
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
24
- * License for more details.
25
- *
26
- * You should have received a copy of the GNU Lesser General Public License
27
- * along with this library; if not, write to the Free Software Foundation,
28
- * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
29
- *
30
- * Please send a copy of any improved versions of the library to:
31
- * Jeff Knighton, Voiceriver Inc, jeff.knighton@voiceriver.com
32
- * Gunnar Hellstrom, Omnitor AB, Box 92054, 12006 Stockholm, SWEDEN
33
- * Gregg Vanderheiden, Trace Center, U of Wisconsin, Madison, Wi 53706
34
- *
35
- * file...: obl.go
36
- * original author.: Keelan Lightfoot
37
- * Created: 20 May 2017
38
- *
39
- */
12
+package openbaudot
40
 
13
 
41
 // Encoder is fun
14
 // Encoder is fun
42
 type Encoder struct {
15
 type Encoder struct {
43
-	input    chan rune
44
-	output   chan byte
45
-	autoWrap bool // true for auto CRLF mode
46
-	autoCRLF bool
47
-	charset  *CodeSet
16
+	input           chan rune
17
+	output          chan byte
18
+	autoWrap        bool // true for auto CRLF mode
19
+	autoCRLF        bool
20
+	charset         *CodeSet
21
+	crlfThresh      int // start looking for a space to replace with a crlf at this threshold
22
+	crlfForceThresh int // force a crlf if it hasn't happend by this threshold
48
 }
23
 }
49
 
24
 
50
 // NewEncoder is fun
25
 // NewEncoder is fun
53
 	e.input = input
28
 	e.input = input
54
 	e.output = output
29
 	e.output = output
55
 	e.charset = charset
30
 	e.charset = charset
56
-
31
+	e.crlfThresh = 60
32
+	e.crlfForceThresh = 72
57
 	go e.run()
33
 	go e.run()
58
 	return e
34
 	return e
59
 }
35
 }
60
 
36
 
61
 // EncodeString is fun
37
 // EncodeString is fun
62
-func (t *Encoder) EncodeString(s string) {
38
+func (e *Encoder) EncodeString(s string) {
63
 	go func() {
39
 	go func() {
64
 		for _, c := range s {
40
 		for _, c := range s {
65
-			t.input <- c
41
+			e.input <- c
66
 		}
42
 		}
67
 	}()
43
 	}()
68
 }
44
 }
69
 
45
 
70
-func (t *Encoder) run() {
46
+func (e *Encoder) run() {
71
 
47
 
72
 	var modCase int           // current Letters/Figures state
48
 	var modCase int           // current Letters/Figures state
73
 	var charsWithoutCRLF int  // number of chars we have handled without inserting a CR-LF
49
 	var charsWithoutCRLF int  // number of chars we have handled without inserting a CR-LF
74
 	var charsWithoutShift int // number of chars we have handled without seeing a shift
50
 	var charsWithoutShift int // number of chars we have handled without seeing a shift
75
-	for r := range t.input {
76
-		c := t.charset.toCode(r)
51
+	for r := range e.input {
52
+		c := e.charset.toCode(r)
77
 
53
 
78
 		/*this rune can either be rendered as a Figures character,
54
 		/*this rune can either be rendered as a Figures character,
79
 		  a Letters character or WHITESPACE which can be rendered by
55
 		  a Letters character or WHITESPACE which can be rendered by
92
 			we must send something, so we'll choose the more common
68
 			we must send something, so we'll choose the more common
93
 			Letters case*/
69
 			Letters case*/
94
 			if modCase == shiftUnknown {
70
 			if modCase == shiftUnknown {
95
-				t.output <- t.charset.unshift()
71
+				e.output <- e.charset.unshift()
96
 			}
72
 			}
97
 
73
 
98
 			modCase = shiftWhitespace
74
 			modCase = shiftWhitespace
101
 			  our modulator's current state, so add a new case char
77
 			  our modulator's current state, so add a new case char
102
 			  here*/
78
 			  here*/
103
 			if c.shift == shiftLetter {
79
 			if c.shift == shiftLetter {
104
-				t.output <- t.charset.unshift()
80
+				e.output <- e.charset.unshift()
105
 			} else {
81
 			} else {
106
-				t.output <- t.charset.shift()
82
+				e.output <- e.charset.shift()
107
 			}
83
 			}
108
 
84
 
109
 			/*and save our current state*/
85
 			/*and save our current state*/
119
 		   at least every 72 characters. */
95
 		   at least every 72 characters. */
120
 		if charsWithoutShift > 70 {
96
 		if charsWithoutShift > 70 {
121
 			if modCase == shiftWhitespace {
97
 			if modCase == shiftWhitespace {
122
-				t.output <- t.charset.unshift() /*doesn't matter which, so how 'bout LETR*/
98
+				e.output <- e.charset.unshift() /*doesn't matter which, so how 'bout LETR*/
123
 			} else if modCase == shiftLetter {
99
 			} else if modCase == shiftLetter {
124
-				t.output <- t.charset.unshift()
100
+				e.output <- e.charset.unshift()
125
 			} else {
101
 			} else {
126
-				t.output <- t.charset.shift()
102
+				e.output <- e.charset.shift()
127
 			}
103
 			}
128
 			charsWithoutShift = 0
104
 			charsWithoutShift = 0
129
 		}
105
 		}
131
 		/* we need to ensure that we send a carriage return/linefeed
107
 		/* we need to ensure that we send a carriage return/linefeed
132
 		 * at least every 72 characters, but we start looking for a
108
 		 * at least every 72 characters, but we start looking for a
133
 		 * space character starting at 60 characters */
109
 		 * space character starting at 60 characters */
134
-		if !t.autoWrap {
110
+		if !e.autoWrap {
135
 			/*we just insert our regular character*/
111
 			/*we just insert our regular character*/
136
-			t.output <- c.toByte()
112
+			e.output <- c.toByte()
137
 
113
 
138
-			if t.autoCRLF {
114
+			if e.autoCRLF {
139
 				if r == '\n' {
115
 				if r == '\n' {
140
-					t.output <- t.charset.toByte('\r')
116
+					e.output <- e.charset.toByte('\r')
141
 				} else if r == '\r' {
117
 				} else if r == '\r' {
142
-					t.output <- t.charset.toByte('\n')
118
+					e.output <- e.charset.toByte('\n')
143
 				}
119
 				}
144
 			}
120
 			}
145
 
121
 
146
-		} else if (charsWithoutCRLF > 59) && (modCase == shiftWhitespace) {
122
+		} else if (charsWithoutCRLF > e.crlfThresh) && (modCase == shiftWhitespace) {
147
 			/*insert the cr-lf instead of the space character*/
123
 			/*insert the cr-lf instead of the space character*/
148
-			t.output <- t.charset.toByte('\r')
149
-			t.output <- t.charset.toByte('\n')
124
+			e.output <- e.charset.toByte('\r')
125
+			e.output <- e.charset.toByte('\n')
150
 			charsWithoutCRLF = 0
126
 			charsWithoutCRLF = 0
151
-		} else if charsWithoutCRLF > 70 {
127
+		} else if charsWithoutCRLF > e.crlfForceThresh {
152
 			/*insert the cr-lf followed by the character*/
128
 			/*insert the cr-lf followed by the character*/
153
-			t.output <- t.charset.toByte('\r')
154
-			t.output <- t.charset.toByte('\n')
155
-			t.output <- c.toByte()
129
+			e.output <- e.charset.toByte('\r')
130
+			e.output <- e.charset.toByte('\n')
131
+			e.output <- c.toByte()
156
 			charsWithoutCRLF = 0
132
 			charsWithoutCRLF = 0
157
 		} else {
133
 		} else {
158
 			/*we just insert our regular character*/
134
 			/*we just insert our regular character*/
159
-			t.output <- c.toByte()
135
+			e.output <- c.toByte()
160
 
136
 
161
-			if t.autoCRLF {
137
+			if e.autoCRLF {
162
 				if r == '\n' {
138
 				if r == '\n' {
163
-					t.output <- t.charset.toByte('\r')
139
+					e.output <- e.charset.toByte('\r')
164
 				} else if r == '\r' {
140
 				} else if r == '\r' {
165
-					t.output <- t.charset.toByte('\n')
141
+					e.output <- e.charset.toByte('\n')
166
 				}
142
 				}
167
 			}
143
 			}
168
 
144
 

+ 9
- 4
examples/main.go View File

8
 )
8
 )
9
 
9
 
10
 func main() {
10
 func main() {
11
-	baud := 45.45
12
-	stopBits := 2.0
11
+
12
+	s := openbaudot.ModemSettings{
13
+		Baud:       45.45,
14
+		StopBits:   2,
15
+		DataBits:   5,
16
+		SampleRate: 8000,
17
+	}
13
 
18
 
14
 	charset := openbaudot.USTTY.Initialize()
19
 	charset := openbaudot.USTTY.Initialize()
15
 
20
 
23
 	done := make(chan struct{})
28
 	done := make(chan struct{})
24
 
29
 
25
 	encoder := openbaudot.NewEncoder(encoderIn, modulatorIn, charset)
30
 	encoder := openbaudot.NewEncoder(encoderIn, modulatorIn, charset)
26
-	modulator := openbaudot.NewModulator(baud, stopBits, 5, modulatorIn, modulatorOut)
31
+	modulator := openbaudot.NewModulator(s, modulatorIn, modulatorOut)
27
 
32
 
28
 	callback := func(event int, data interface{}) {
33
 	callback := func(event int, data interface{}) {
29
 		switch event {
34
 		switch event {
44
 		}
49
 		}
45
 	}()
50
 	}()
46
 
51
 
47
-	openbaudot.NewDemodulator(baud, stopBits, 5, demodulatorIn, decoderIn)
52
+	openbaudot.NewDemodulator(s, demodulatorIn, decoderIn)
48
 	openbaudot.NewDecoder(decoderIn, decoderOut, charset)
53
 	openbaudot.NewDecoder(decoderIn, decoderOut, charset)
49
 
54
 
50
 	running := true
55
 	running := true

+ 50
- 68
modulator.go View File

1
+// Copyright (C) 2017 Keelan Lightfoot
2
+// Copyright (C) 2007-2008 Board of Regents of the University of Wisconsin
3
+//             System (Univ. of Wisconsin-Madison, Trace R&D Center)
4
+// Copyright (C) 2007-2008 Omnitor AB
5
+// Copyright (C) 2007-2008 Voiceriver Inc
6
+//
7
+// This library is free software; you can redistribute it and/or modify it
8
+// under the terms of the GNU Lesser General Public License as published by
9
+// the Free Software Foundation; either version 2.1 of the License, or (at
10
+// your option) any later version.
11
+
1
 package openbaudot
12
 package openbaudot
2
 
13
 
3
 import "math"
14
 import "math"
4
 
15
 
5
-/*
6
- * OBL openbaudot Library
7
- *
8
- * Copyright (C) 2017 Keelan Lightfoot
9
- * Copyright (C) 2007-2008 Board of Regents of the University of Wisconsin
10
- *                   System (Univ. of Wisconsin-Madison, Trace R&D Center)
11
- * Copyright (C) 2007-2008 Omnitor AB
12
- * Copyright (C) 2007-2008 Voiceriver Inc
13
- *
14
- * This software was developed with support from the National Institute on
15
- * Disability and Rehabilitation Research, US Dept of Education under Grant
16
- * # H133E990006 and H133E040014
17
- *
18
- * This library is free software; you can redistribute it and/or modify it
19
- * under the terms of the GNU Lesser General Public License as published by
20
- * the Free Software Foundation; either version 2.1 of the License, or (at
21
- * your option) any later version.
22
- *
23
- * This library is distributed in the hope that it will be useful, but
24
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
25
- * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
26
- * License for more details.
27
- *
28
- * You should have received a copy of the GNU Lesser General Public License
29
- * along with this library; if not, write to the Free Software Foundation,
30
- * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
31
- *
32
- * Please send a copy of any improved versions of the library to:
33
- * Jeff Knighton, Voiceriver Inc, jeff.knighton@voiceriver.com
34
- * Gunnar Hellstrom, Omnitor AB, Box 92054, 12006 Stockholm, SWEDEN
35
- * Gregg Vanderheiden, Trace Center, U of Wisconsin, Madison, Wi 53706
36
- *
37
- * file...: obl.go
38
- * original author.: Keelan Lightfoot
39
- * Created: 20 May 2017
40
- *
41
- */
16
+const (
17
+	modStateIdle = iota
18
+	modStateStart
19
+	modStateBit
20
+	modStateStop
21
+	modStateHold
22
+)
42
 
23
 
43
 // Modulator is fun
24
 // Modulator is fun
44
 type Modulator struct {
25
 type Modulator struct {
45
 	input  chan byte
26
 	input  chan byte
46
 	output chan int16
27
 	output chan int16
47
 
28
 
48
-	baud           float64 // modulator baud rate
49
-	dataBits       int
50
-	samplesPerBit  int    // number of samples for one bit
51
-	phaseQ16       uint16 // phase acc 0..2math.Pi -> 0..65536
52
-	amplitude      int16  // peak modulator amplitude for one tone
53
-	numStopBits    int    // number of stop bits
54
-	numStopSamples int    // number of samples for stop bit
55
-	wOneQ16        uint16 // scaled one freq 0..2math.Pi -> 0..65536
56
-	wZeroQ16       uint16 // scaled zero freq 0..2math.Pi -> 0..65536
57
-	sinLutQ15      []int16
58
-
59
-	callback Callback
29
+	baud            float64 // modulator baud rate
30
+	dataBits        int
31
+	samplesPerBit   int     // number of samples for one bit
32
+	phaseQ16        uint16  // phase acc 0..2math.Pi -> 0..65536
33
+	amplitude       int16   // peak modulator amplitude for one tone
34
+	numStopHalfBits int     // number of stop bits
35
+	numStopSamples  int     // number of samples for stop bit
36
+	wOneQ16         uint16  // scaled one freq 0..2math.Pi -> 0..65536
37
+	wZeroQ16        uint16  // scaled zero freq 0..2math.Pi -> 0..65536
38
+	sinLutQ15       []int16 // sine lookup table
39
+	sampleRate      int     // sample rate
40
+	callback        Callback
60
 }
41
 }
61
 
42
 
62
 // NewModulator is fun
43
 // NewModulator is fun
63
-func NewModulator(baud float64, stopBits float64, dataBits int, input chan byte, output chan int16) *Modulator {
44
+func NewModulator(s ModemSettings, input chan byte, output chan int16) *Modulator {
64
 
45
 
65
 	m := new(Modulator)
46
 	m := new(Modulator)
66
 	// mod.input = make(chan code)
47
 	// mod.input = make(chan code)
69
 	m.input = input
50
 	m.input = input
70
 	m.output = output
51
 	m.output = output
71
 
52
 
72
-	m.baud = baud
73
-	m.dataBits = dataBits
74
-	m.samplesPerBit = int(float64(sampleRate) / m.baud)
75
-	m.numStopBits = int(math.Floor(stopBits / .5))
76
-	m.numStopSamples = m.numStopBits * m.samplesPerBit / 2
53
+	m.baud = s.Baud
54
+	m.dataBits = s.DataBits
55
+	m.sampleRate = s.SampleRate
56
+	m.samplesPerBit = int(float64(m.sampleRate) / m.baud)
57
+	m.numStopHalfBits = int(math.Floor(s.StopBits / .5))
58
+	m.numStopSamples = m.numStopHalfBits * m.samplesPerBit / 2
77
 	m.amplitude = 16384
59
 	m.amplitude = 16384
78
 
60
 
79
-	wOne, wZero := calculateW(2125, 2295)
61
+	wOne, wZero := calculateW(2125, 2295, m.sampleRate)
80
 
62
 
81
 	m.wOneQ16 = uint16((65536 / (2.0 * math.Pi)) * wOne)
63
 	m.wOneQ16 = uint16((65536 / (2.0 * math.Pi)) * wOne)
82
 	m.wZeroQ16 = uint16((65536 / (2.0 * math.Pi)) * wZero)
64
 	m.wZeroQ16 = uint16((65536 / (2.0 * math.Pi)) * wZero)
106
 	*/
88
 	*/
107
 	if bit != 0 {
89
 	if bit != 0 {
108
 		m.phaseQ16 += m.wOneQ16
90
 		m.phaseQ16 += m.wOneQ16
109
-		m.output <- multq(m.amplitude, m.sinLutQ15[m.phaseQ16>>2])
91
+		m.output <- multq15(m.amplitude, m.sinLutQ15[m.phaseQ16>>2])
110
 
92
 
111
 	} else {
93
 	} else {
112
 		m.phaseQ16 += m.wZeroQ16
94
 		m.phaseQ16 += m.wZeroQ16
113
-		m.output <- multq(m.amplitude, m.sinLutQ15[m.phaseQ16>>2])
95
+		m.output <- multq15(m.amplitude, m.sinLutQ15[m.phaseQ16>>2])
114
 	}
96
 	}
115
 }
97
 }
116
 
98
 
127
 	for {
109
 	for {
128
 		nextState = modState
110
 		nextState = modState
129
 		switch modState {
111
 		switch modState {
130
-		case ModStateIdle:
112
+		case modStateIdle:
131
 			select {
113
 			select {
132
 			case c = <-m.input:
114
 			case c = <-m.input:
133
 				modSample = 0
115
 				modSample = 0
134
-				nextState = ModStateStart
116
+				nextState = modStateStart
135
 				//obl.callback(EventTransmitState, TransmitStart)
117
 				//obl.callback(EventTransmitState, TransmitStart)
136
 				idleSamples = 0
118
 				idleSamples = 0
137
 			default:
119
 			default:
138
 				m.modulate(0)
120
 				m.modulate(0)
139
 
121
 
140
-				if idleSamples < sampleRate {
122
+				if idleSamples < m.sampleRate {
141
 					idleSamples++
123
 					idleSamples++
142
-				} else if idleSamples == sampleRate {
124
+				} else if idleSamples == m.sampleRate {
143
 					if m.callback != nil {
125
 					if m.callback != nil {
144
 						m.callback(EventIdle, 0)
126
 						m.callback(EventIdle, 0)
145
 					}
127
 					}
146
 					idleSamples++
128
 					idleSamples++
147
 				}
129
 				}
148
 			}
130
 			}
149
-		case ModStateStart:
131
+		case modStateStart:
150
 			m.modulate(0)
132
 			m.modulate(0)
151
 			modSample++
133
 			modSample++
152
 			// after sending start bit send LSB data bit
134
 			// after sending start bit send LSB data bit
154
 				modNbit = 0
136
 				modNbit = 0
155
 				modBit = int(c & 0x1)
137
 				modBit = int(c & 0x1)
156
 				modSample = 0
138
 				modSample = 0
157
-				nextState = ModStateBit
139
+				nextState = modStateBit
158
 			}
140
 			}
159
-		case ModStateBit:
141
+		case modStateBit:
160
 			m.modulate(modBit)
142
 			m.modulate(modBit)
161
 			modSample++
143
 			modSample++
162
 			// when this data bit complete, send next data bit
144
 			// when this data bit complete, send next data bit
165
 				modNbit++
147
 				modNbit++
166
 				modBit = int((c >> uint(modNbit)) & 0x1)
148
 				modBit = int((c >> uint(modNbit)) & 0x1)
167
 				if modNbit == m.dataBits {
149
 				if modNbit == m.dataBits {
168
-					nextState = ModStateStop
150
+					nextState = modStateStop
169
 				}
151
 				}
170
 			}
152
 			}
171
-		case ModStateStop:
153
+		case modStateStop:
172
 			m.modulate(1)
154
 			m.modulate(1)
173
 			modSample++
155
 			modSample++
174
 			// when stop bit complete start transmission of next char, or enter idle state
156
 			// when stop bit complete start transmission of next char, or enter idle state
175
 			if modSample == m.numStopSamples {
157
 			if modSample == m.numStopSamples {
176
 				modSample = 0
158
 				modSample = 0
177
-				nextState = ModStateIdle
159
+				nextState = modStateIdle
178
 			}
160
 			}
179
 			// 	(obl.callback)(obl,OBL_EVENT_TX_STATE, OBL_TRANSMIT_STOP);
161
 			// 	(obl.callback)(obl,OBL_EVENT_TX_STATE, OBL_TRANSMIT_STOP);
180
 		}
162
 		}