added options and example

master
Kevin Golding 5 years ago
parent cfe7772b7d
commit afd1b58560

@ -1,2 +1,35 @@
Go port of the POCSAG::Encode Perl module. Go port of the POCSAG::Encode Perl module.
Example usage
```
package main
import (
"fmt"
"log"
"github.com/kgolding/go-pocsagencode"
)
func main() {
messages := []*pocsagencode.Message{
&pocsagencode.Message{1300100, "Hello Pager!"},
}
for i := 0; i < 50; i++ {
addr := uint32(1200000 + i*100)
messages = append(messages, &pocsagencode.Message{addr, fmt.Sprintf("Hello pager number %d", addr)})
}
log.Println("Sending", len(messages), "messages")
var burst pocsagencode.Burst
for len(messages) > 0 {
burst, messages = pocsagencode.Generate(messages)
// Options can be set as below for MaxLen and PreambleBits
// burst, messages = pocsagencode.Generate(messages, pocsagencode.OptionPreambleBits(250))
log.Println("Burst", burst.String())
// Send Burst to the FSK modem here...
}
log.Println("Done")
}
```

Binary file not shown.

@ -0,0 +1,30 @@
package main
import (
"fmt"
"log"
"github.com/kgolding/go-pocsagencode"
)
func main() {
messages := []*pocsagencode.Message{
&pocsagencode.Message{1300100, "Hello Pager!"},
}
for i := 0; i < 50; i++ {
addr := uint32(1200000 + i*100)
messages = append(messages, &pocsagencode.Message{addr, fmt.Sprintf("Hello pager number %d", addr)})
}
log.Println("Sending", len(messages), "messages")
var burst pocsagencode.Burst
for len(messages) > 0 {
burst, messages = pocsagencode.Generate(messages)
// Options can be set as below for MaxLen and PreambleBits
// burst, messages = pocsagencode.Generate(messages, pocsagencode.OptionPreambleBits(250))
log.Println("Burst", burst.String())
// Send Burst to the FSK modem here...
}
log.Println("Done")
}

@ -0,0 +1,40 @@
package pocsagencode
import (
"encoding/binary"
"fmt"
)
type Burst []uint32
// String return a formated multiline string with the
func (b Burst) String() string {
s := ""
preambleCount := 0
preambleOver := false
for _, w := range b {
if !preambleOver {
if w == pocsagPreambleWord {
preambleCount++
continue
} else {
s += fmt.Sprintf("[%d bits of 1010101010... (0xAA) preamble] ", preambleCount*32)
preambleOver = true
}
}
if w == pocsagFrameSyncWord {
s += "[Batch start/sync] "
}
s += fmt.Sprintf("%X ", w)
}
return s
}
// Bytes returns a []byte
func (b Burst) Bytes() []byte {
buf := make([]byte, len(b)*4)
for i, w := range b {
binary.BigEndian.PutUint32(buf[i*4:], w)
}
return buf
}

@ -0,0 +1,20 @@
package pocsagencode
type Options struct {
MaxLen int
PreambleBits int
}
type OptionFn func(*Options)
func OptionMaxLen(v int) OptionFn {
return func(o *Options) {
o.MaxLen = v
}
}
func OptionPreambleBits(v int) OptionFn {
return func(o *Options) {
o.PreambleBits = v
}
}

@ -120,8 +120,8 @@ func reverseBits(in byte) byte {
} }
// appendContentText appends text message content to the transmission blob // appendContentText appends text message content to the transmission blob
func appendContentText(content string) (int, []uint32) { func appendContentText(content string) (int, Burst) {
out := make([]uint32, 0) out := make(Burst, 0)
debugf("appendContentText: %s", content) debugf("appendContentText: %s", content)
bitpos := 0 bitpos := 0
@ -186,7 +186,7 @@ func appendContentText(content string) (int, []uint32) {
} }
// appendMessage appends a single message to the end of the transmission blob. // appendMessage appends a single message to the end of the transmission blob.
func appendMessage(startpos int, msg *Message) (int, []uint32) { func appendMessage(startpos int, msg *Message) (int, Burst) {
// expand the parameters of the message // expand the parameters of the message
addr := msg.Addr addr := msg.Addr
function := byte(0) function := byte(0)
@ -202,7 +202,7 @@ func appendMessage(startpos int, msg *Message) (int, []uint32) {
debugf(" frame_addr is %d, current position %d", frameAddr, startpos) debugf(" frame_addr is %d, current position %d", frameAddr, startpos)
// append idle codewords, until we're in the right frame for this address // append idle codewords, until we're in the right frame for this address
tx := make([]uint32, 0) tx := make(Burst, 0)
pos := 0 pos := 0
for uint32(startpos+pos)%16 != frameAddrCw { for uint32(startpos+pos)%16 != frameAddrCw {
debugf(" inserting IDLE codewords in position %d (%d)", startpos+pos, (startpos+pos)%16) debugf(" inserting IDLE codewords in position %d (%d)", startpos+pos, (startpos+pos)%16)
@ -228,8 +228,8 @@ func appendMessage(startpos int, msg *Message) (int, []uint32) {
// insertSCS inserts Synchronisation Codewords before every 8 POCSAG frames // insertSCS inserts Synchronisation Codewords before every 8 POCSAG frames
// (frame is SC+ 64 bytes of address and message codewords) // (frame is SC+ 64 bytes of address and message codewords)
func insertSCS(tx []uint32) []uint32 { func insertSCS(tx Burst) Burst {
out := make([]uint32, 0) out := make(Burst, 0)
// each batch is SC + 8 frames, each frame is 2 codewords, // each batch is SC + 8 frames, each frame is 2 codewords,
// each codeword is 32 bits, so we must insert an SC // each codeword is 32 bits, so we must insert an SC
@ -294,9 +294,17 @@ func selectMsg(pos int, msgListRef []*Message) int {
// any messages which did not fit in the transmission, given the maximum // any messages which did not fit in the transmission, given the maximum
// transmission length (in bytes) given in the first parameter. They can be passed // transmission length (in bytes) given in the first parameter. They can be passed
// in the next Generate() call and sent in the next brrraaaap. // in the next Generate() call and sent in the next brrraaaap.
func Generate(maxLen int, preambleBits int, messages []*Message) ([]uint32, []*Message) { func Generate(messages []*Message, optionFns ...OptionFn) (Burst, []*Message) {
txWithoutScs := make([]uint32, 0) options := &Options{
debugf("generate_transmission, maxlen: %d", maxLen) MaxLen: 3000,
PreambleBits: 576,
}
for _, opt := range optionFns {
opt(options)
}
txWithoutScs := make(Burst, 0)
debugf("generate_transmission, maxlen: %d", options.MaxLen)
pos := 0 pos := 0
for len(messages) > 0 { for len(messages) > 0 {
@ -315,11 +323,11 @@ func Generate(maxLen int, preambleBits int, messages []*Message) ([]uint32, []*M
nextLenBytes := nextLen * 4 nextLenBytes := nextLen * 4
debugf("after this message of %d codewords, burst will be %d codewords and %d bytes long\n", appendLen, nextLen, nextLenBytes) debugf("after this message of %d codewords, burst will be %d codewords and %d bytes long\n", appendLen, nextLen, nextLenBytes)
if nextLenBytes > maxLen { if nextLenBytes > int(options.MaxLen) {
if pos == 0 { if pos == 0 {
debugf("burst would become too large (%d > %d) with first message alone - discarding!", nextLenBytes, maxLen) debugf("burst would become too large (%d > %d) with first message alone - discarding!", nextLenBytes, options.MaxLen)
} else { } else {
debugf("burst would become too large (%d > %d) - returning msg in queue", nextLenBytes, maxLen) debugf("burst would become too large (%d > %d) - returning msg in queue", nextLenBytes, options.MaxLen)
messages = append([]*Message{msg}, messages...) messages = append([]*Message{msg}, messages...)
break break
} }
@ -331,7 +339,7 @@ func Generate(maxLen int, preambleBits int, messages []*Message) ([]uint32, []*M
// if the burst is empty, return it as completely empty // if the burst is empty, return it as completely empty
if pos == 0 { if pos == 0 {
return []uint32{}, messages return Burst{}, messages
} }
// append a couple of IDLE codewords, otherwise many pagers will // append a couple of IDLE codewords, otherwise many pagers will
@ -348,12 +356,12 @@ func Generate(maxLen int, preambleBits int, messages []*Message) ([]uint32, []*M
burstLen = len(burst) burstLen = len(burst)
debugf("transmission with SCs: %d bytes, %d codewords\n%X\n", burstLen*4, burstLen, burst) debugf("transmission with SCs: %d bytes, %d codewords\n%X\n", burstLen*4, burstLen, burst)
if preambleBits > 0 { if options.PreambleBits > 0 {
preambleWords := preambleBits / 32 preambleWords := options.PreambleBits / 32
if preambleBits%32 > 0 { if options.PreambleBits%32 > 0 {
preambleWords++ preambleWords++
} }
preamble := make([]uint32, preambleWords) preamble := make(Burst, preambleWords)
for i := range preamble { for i := range preamble {
preamble[i] = pocsagPreambleWord preamble[i] = pocsagPreambleWord
} }

@ -1,21 +1,19 @@
package pocsagencode package pocsagencode
import ( import (
// "log"
// "os"
"testing" "testing"
) )
func Test_Encode(t *testing.T) { func Test_Encode(t *testing.T) {
// SetLogger(log.New(os.Stdout, "POCSAG ", log.LstdFlags)) // SetLogger(log.New(os.Stdout, "POCSAG ", log.LstdFlags))
enc, left := Generate(3000, 576, []*Message{ enc, left := Generate([]*Message{
&Message{1300100, "happy christmas!"}, &Message{1300100, "happy christmas!"},
}) })
if len(left) != 0 { if len(left) != 0 {
t.Errorf("expect no message left, got %v", left) t.Errorf("expect no message left, got %v", left)
} }
expect := []uint32{ expect := Burst{
// 18 words, 576 bits of preamble // 18 words, 576 bits of preamble
0xAAAAAAAA, 0xAAAAAAAA, 0xAAAAAAAA, 0xAAAAAAAA,
0xAAAAAAAA, 0xAAAAAAAA, 0xAAAAAAAA, 0xAAAAAAAA, 0xAAAAAAAA, 0xAAAAAAAA, 0xAAAAAAAA, 0xAAAAAAAA, 0xAAAAAAAA, 0xAAAAAAAA, 0xAAAAAAAA, 0xAAAAAAAA, 0xAAAAAAAA, 0xAAAAAAAA, 0xAAAAAAAA, 0xAAAAAAAA,
@ -27,7 +25,7 @@ func Test_Encode(t *testing.T) {
} }
if len(enc) != len(expect) { if len(enc) != len(expect) {
t.Errorf("expected:\n%X\ngot:\n%X\n", expect, enc) t.Errorf("expected:\n%s\ngot:\n%s\n", expect, enc)
} else { } else {
for i, w := range expect { for i, w := range expect {
if w != enc[i] { if w != enc[i] {
@ -35,4 +33,6 @@ func Test_Encode(t *testing.T) {
} }
} }
} }
t.Log(enc)
t.Log(enc.Bytes())
} }

Loading…
Cancel
Save