add numeric message encoding

master
Kevin Golding 4 years ago
parent 83ba725969
commit 9bb56dc6c8

@ -1,4 +1,4 @@
Go port of the POCSAG::Encode Perl module. Golang port of the `POCSAG::Encode` Perl module extended to support Numeric as well as AlphaNumeric messages.
Example usage Example usage
@ -6,7 +6,6 @@ Example usage
package main package main
import ( import (
"fmt"
"log" "log"
"github.com/kgolding/go-pocsagencode" "github.com/kgolding/go-pocsagencode"
@ -14,12 +13,7 @@ import (
func main() { func main() {
messages := []*pocsagencode.Message{ messages := []*pocsagencode.Message{
&pocsagencode.Message{1300100, "Hello Pager!"}, &pocsagencode.Message{1300100, "Hello Pager!", false},
}
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") log.Println("Sending", len(messages), "messages")

@ -1,29 +1,49 @@
package main package main
import ( import (
"flag"
"fmt" "fmt"
"log"
"os" "os"
"path/filepath"
"strconv" "strconv"
pc "github.com/kgolding/go-pocsagencode" pc "github.com/kgolding/go-pocsagencode"
) )
func main() { func main() {
if len(os.Args) != 3 { var num bool
fmt.Printf("Usage: %s <pager addr> <text message>\ne.g. %s 13100100 'Hello world!'\n", os.Args[0], os.Args[0]) var debug bool
flag.BoolVar(&num, "num", false, "send as numeric message")
flag.BoolVar(&debug, "v", false, "verbose logging")
flag.Parse()
if len(flag.Args()) != 2 {
me := filepath.Base(os.Args[0])
fmt.Printf(`
Usage: %s [-num] <pager addr> <text or numeric message>
Examples: %s 13100100 'Hello world!'
%s -num 13100100 9876\n`, me, me, me)
os.Exit(1) os.Exit(1)
} }
addr, err := strconv.Atoi(os.Args[1]) addr, err := strconv.Atoi(flag.Arg(0))
if err != nil { if err != nil {
fmt.Println("Invalid pager addr - must be a number") fmt.Println("Invalid pager addr - must be a number")
os.Exit(2) os.Exit(2)
} }
messages := []*pc.Message{ messages := []*pc.Message{
&pc.Message{ &pc.Message{
Addr: uint32(addr), Addr: uint32(addr),
Content: os.Args[2], Content: flag.Arg(0),
IsNumeric: num,
}, },
} }
if debug {
pc.SetLogger(log.New(os.Stdout, "", log.Lshortfile))
}
burst, _ := pc.Generate(messages) burst, _ := pc.Generate(messages)
fmt.Printf("Message: %s\n\n", burst.String()) fmt.Printf("Message: %s\n\n", burst.String())

@ -9,12 +9,12 @@ import (
func main() { func main() {
messages := []*pocsagencode.Message{ messages := []*pocsagencode.Message{
&pocsagencode.Message{1300100, "Hello Pager!"}, &pocsagencode.Message{1300100, "Hello Pager!", false},
} }
for i := 0; i < 50; i++ { for i := 0; i < 50; i++ {
addr := uint32(1200000 + i*100) addr := uint32(1200000 + i*100)
messages = append(messages, &pocsagencode.Message{addr, fmt.Sprintf("Hello pager number %d", addr)}) messages = append(messages, &pocsagencode.Message{addr, fmt.Sprintf("Hello pager number %d", addr), false})
} }
log.Println("Sending", len(messages), "messages") log.Println("Sending", len(messages), "messages")

@ -6,8 +6,9 @@ import (
// Message is a single POCSAG Alphanumeric message // Message is a single POCSAG Alphanumeric message
type Message struct { type Message struct {
Addr uint32 Addr uint32
Content string Content string
IsNumeric bool
} }
var logger *log.Logger var logger *log.Logger
@ -185,6 +186,81 @@ func appendContentText(content string) (int, Burst) {
return pos, out return pos, out
} }
// appendContentNumeric appends numeric message content to the transmission blob
func appendContentNumeric(content string) (int, Burst) {
out := make(Burst, 0)
debugf("appendContentNumeric: %s", content)
// 084 2.6]195-3U7[
charMap := map[byte]byte{
'0': 0, '8': 1, '4': 2, ' ': 3, '2': 4, '.': 5, '6': 6, ']': 7,
'1': 8, '9': 9, '5': 10, '-': 11, '3': 12, 'U': 13, '7': 14, '[': 15,
}
bitpos := 0
word := uint32(0)
leftbits := 0
pos := 0
// walk through characters in message
for i, r := range content {
var char byte
var ok bool
// set char from the charMap, and skip the character is not in the map
if char, ok = charMap[byte(r)]; !ok {
debugf("skipping invlaid char '%s'", string(r))
continue
}
debugf(" char %d: %d [%X]\n", i, char, char)
// if the bits won't fit:
if bitpos+4 > 20 {
space := 20 - bitpos
// leftbits least significant bits of $char are left over in the next word
leftbits = 4 - space
debugf(" bits of char won't fit since bitpos is %d, got %d bits free, leaving %d bits in next word", bitpos, space, leftbits)
}
word |= (uint32(char) << uint(31-4-bitpos))
bitpos += 4
if bitpos >= 20 {
debugf(" appending word: %X\n", word)
out = append(out, appendMessageCodeword(word))
pos++
word = 0
bitpos = 0
}
if leftbits > 0 {
word |= (uint32(char) << uint(31-leftbits))
bitpos = leftbits
leftbits = 0
}
}
if bitpos > 0 {
debugf(" got %d bits in word at end of text, word: %X", bitpos, word)
step := 0
for bitpos < 20 {
if step == 2 {
word |= (1 << uint(30-bitpos))
}
bitpos++
step++
if step == 4 {
step = 0
}
}
out = append(out, appendMessageCodeword(word))
pos++
}
return pos, out
}
// 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, Burst) { func appendMessage(startpos int, msg *Message) (int, Burst) {
// expand the parameters of the message // expand the parameters of the message
@ -217,7 +293,13 @@ func appendMessage(startpos int, msg *Message) (int, Burst) {
pos++ pos++
// Next, append the message contents // Next, append the message contents
contentEncLen, contentEnc := appendContentText(content) var contentEncLen int
var contentEnc Burst
if msg.IsNumeric {
contentEncLen, contentEnc = appendContentNumeric(content)
} else {
contentEncLen, contentEnc = appendContentText(content)
}
tx = append(tx, contentEnc...) tx = append(tx, contentEnc...)
pos += contentEncLen pos += contentEncLen
@ -296,7 +378,7 @@ func selectMsg(pos int, msgListRef []*Message) int {
// in the next Generate() call and sent in the next brrraaaap. // in the next Generate() call and sent in the next brrraaaap.
func Generate(messages []*Message, optionFns ...OptionFn) (Burst, []*Message) { func Generate(messages []*Message, optionFns ...OptionFn) (Burst, []*Message) {
options := &Options{ options := &Options{
MaxLen: 3000, MaxLen: 2000,
PreambleBits: 576, PreambleBits: 576,
} }
for _, opt := range optionFns { for _, opt := range optionFns {

@ -1,13 +1,51 @@
package pocsagencode package pocsagencode
import ( import (
"log"
"os"
"testing" "testing"
) )
func Test_Encode(t *testing.T) { func init() {
SetLogger(log.New(os.Stdout, "POCSAG ", log.LstdFlags))
// Comment below to enable debug logging
SetLogger(nil)
}
func Test_Encode_Numeric(t *testing.T) {
enc, left := Generate([]*Message{
&Message{1300100, "12[3]", true},
})
if len(left) != 0 {
t.Errorf("expect no message left, got %v", left)
}
expect := Burst{
// 18 words, 576 bits of preamble
0xAAAAAAAA, 0xAAAAAAAA,
0xAAAAAAAA, 0xAAAAAAAA, 0xAAAAAAAA, 0xAAAAAAAA, 0xAAAAAAAA, 0xAAAAAAAA, 0xAAAAAAAA, 0xAAAAAAAA,
0xAAAAAAAA, 0xAAAAAAAA, 0xAAAAAAAA, 0xAAAAAAAA, 0xAAAAAAAA, 0xAAAAAAAA, 0xAAAAAAAA, 0xAAAAAAAA,
// The real data starts here
0x7CD215D8, 0x7A89C197, 0x7A89C197, 0x7A89C197, 0x7A89C197, 0x7A89C197, 0x7A89C197, 0x7A89C197,
0x7A89C197, 0x4F5A0109, 0xC27E3D14, 0x7A89C197, 0x7A89C197,
}
if len(enc) != len(expect) {
t.Errorf("expected:\n%s\ngot:\n%s\n", expect, enc)
} else {
for i, w := range expect {
if w != enc[i] {
t.Errorf("expected:%X got:%X at index %d\n", w, enc[i], i)
}
}
}
}
func Test_Encode_Alpha(t *testing.T) {
// SetLogger(log.New(os.Stdout, "POCSAG ", log.LstdFlags)) // SetLogger(log.New(os.Stdout, "POCSAG ", log.LstdFlags))
enc, left := Generate([]*Message{ enc, left := Generate([]*Message{
&Message{1300100, "happy christmas!"}, &Message{1300100, "happy christmas!", false},
}) })
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)

Loading…
Cancel
Save