func MakeREMOp(response, err, more bool, op int) uint8 {
	var out uint8
	if response {
		out |= 0x80
	}
	if err {
		out |= 0x40
	}
	if more {
		out |= 0x20
	}
	out |= uint8(op)
	return out
}
MakeREMOp composes uint8 with response error and more bits set, combined with operation code
package control
import (
	"strings"
	"github.com/pkg/errors"
	log "github.com/sirupsen/logrus"
)
const Mode = 6
const (
	OpReadStatus    = 1
	OpReadVariables = 2
)
func NormalizeData(data []byte) (map[string]string, error) {
	result := map[string]string{}
	pairs := strings.Split(string(data), ",")
	for _, pair := range pairs {
		split := strings.Split(pair, "=")
		if len(split) != 2 {
			log.Debugf("WARNING: Malformed packet, bad k=v pair '%s'", pair)
			continue
		}
		k := strings.TrimSpace(split[0])
		v := strings.TrimSpace(strings.Trim(split[1], `"`))
		result[k] = v
	}
	if len(result) == 0 {
		return result, errors.Errorf("Malformed packet, no k=v pairs decoded")
	}
	return result, nil
}
// NTPControlMsgHead structure is described in NTPv3 RFC1305 Appendix B. NTP Control Messages.
// We don't have Data defined here as data size is variable and binary package
// simply doesn't support reading or writing structs with non-fixed fields.
type NTPControlMsgHead struct {
	// 0: 00 Version(3bit) Mode(3bit)
	VnMode uint8
	// 1: Response Error More Operation(5bit)
	REMOp uint8
	// 2-3: Sequence (16bit)
	Sequence uint16
	// 4-5: Status (16bit)
	Status uint16
	// 6-7: Association ID (16bit)
	AssociationID uint16
	// 8-9: Offset (16bit)
	Offset uint16
	// 10-11: Count (16bit)
	Count uint16
	// 12+: Data (up to 468 bits)
	// then goes [468]uint8 of data that we have in NTPControlMsg
}
// NTPControlMsg is just a NTPControlMsgHead with data.
type NTPControlMsg struct {
	NTPControlMsgHead
	Data []uint8
}
// LeapDesc stores human-readable descriptions of LI (leap indicator) field
var LeapDesc = [4]string{"none", "add_sec", "del_sec", "alarm"}
// ClockSourceDesc stores human-readable descriptions of ClockSource field
var ClockSourceDesc = [10]string{
	"unspec",     // 00
	"pps",        // 01
	"lf_radio",   // 02
	"hf_radio",   // 03
	"uhf_radio",  // 04
	"local",      // 05
	"ntp",        // 06
	"other",      // 07
	"wristwatch", // 08
	"telephone",  // 09
}
// SystemEventDesc stores human-readable descriptions of SystemEvent field
var SystemEventDesc = [17]string{
	"unspecified",             // 00
	"freq_not_set",            // 01
	"freq_set",                // 02
	"spike_detect",            // 03
	"freq_mode",               // 04
	"clock_sync",              // 05
	"restart",                 // 06
	"panic_stop",              // 07
	"no_system_peer",          // 08
	"leap_armed",              // 09
	"leap_disarmed",           // 0a
	"leap_event",              // 0b
	"clock_step",              // 0c
	"kern",                    // 0d
	"TAI...",                  // 0e
	"stale leapsecond values", // 0f
	"clockhop",                // 10
}
// FlashDescMap maps bit mask with corresponding flash status
var FlashDescMap = map[uint16]string{
	0x0001: "pkt_dup",
	0x0002: "pkt_bogus",
	0x0004: "pkt_unsync",
	0x0008: "pkt_denied",
	0x0010: "pkt_auth",
	0x0020: "pkt_stratum",
	0x0040: "pkt_header",
	0x0080: "pkt_autokey",
	0x0100: "pkt_crypto",
	0x0200: "peer_stratum",
	0x0400: "peer_dist",
	0x0800: "peer_loop",
	0x1000: "peer_unreach",
}
// ReadFlashStatusWord returns list of flashers (as strings) decoded from flash status word
func ReadFlashStatusWord(flash uint16) []string {
	flashers := []string{}
	for mask, message := range FlashDescMap {
		if flash&mask > 0 {
			flashers = append(flashers, message)
		}
	}
	return flashers
}
// SystemStatusWord stores parsed SystemStatus 16bit word.
type SystemStatusWord struct {
	LI                 uint8
	ClockSource        uint8
	SystemEventCounter uint8
	SystemEventCode    uint8
}
// Word encodes SystemStatusWord as uint16 word
func (ssw *SystemStatusWord) Word() uint16 {
	var out uint16
	out |= uint16(ssw.LI) << 14
	out |= uint16(ssw.ClockSource) << 8
	out |= uint16(ssw.SystemEventCounter) << 4
	out |= uint16(ssw.SystemEventCode)
	return out
}
// ReadSystemStatusWord transforms SystemStatus 16bit word into usable struct.
func ReadSystemStatusWord(b uint16) *SystemStatusWord {
	return &SystemStatusWord{
		LI:                 uint8((b & 0xc000) >> 14), // first 2 bits
		ClockSource:        uint8((b & 0x3f00) >> 8),  // next 6 bits
		SystemEventCounter: uint8((b & 0xf0) >> 4),    // 4 bits
		SystemEventCode:    uint8((b & 0xf)),          // last 4 bits
	}
}
// PeerStatus word decoded. Sadly values used by ntpd are different from RFC for v2 and v3 of NTP.
// Actual values are from http://doc.ntp.org/4.2.6/decode.html#peer
type PeerStatus struct {
	Broadcast   bool
	Reachable   bool
	AuthEnabled bool
	AuthOK      bool
	Configured  bool
}
// Byte encodes PeerStatus as uint8
func (ps *PeerStatus) Byte() uint8 {
	var out uint8
	if ps.Configured {
		out |= 0x10
	}
	if ps.AuthOK {
		out |= 0x8
	}
	if ps.AuthEnabled {
		out |= 0x4
	}
	if ps.Reachable {
		out |= 0x2
	}
	if ps.Broadcast {
		out |= 0x1
	}
	return out
}
// Here go peer selection statuses, as described in http://doc.ntp.org/current-stable/decode.html#peer
const (
	// SelReject means peer is discarded as not valid (TEST10-TEST13)
	SelReject uint8 = 0
	// SelFalseTick means peer is discarded by intersection algorithm
	SelFalseTick uint8 = 1
	// SelExcess means peer is discarded by table overflow (not used)
	SelExcess uint8 = 2
	// SelOutlier means peer is discarded by the cluster algorithm
	SelOutlier uint8 = 3
	// SelCandidate means peer is included by the combine algorithm
	SelCandidate uint8 = 4
	// SelBackup means peer is a backup (more than tos maxclock sources)
	SelBackup uint8 = 5
	// SelSYSPeer means peer is a system peer (main syncronization source)
	SelSYSPeer uint8 = 6
	// SelPPSPeer means peer is a PPS peer (when the prefer peer is valid)
	SelPPSPeer uint8 = 7
)
// PeerSelect maps PeerSelection uint8 to human-readable string taken from http://doc.ntp.org/4.2.6/decode.html#peer
var PeerSelect = [8]string{"reject", "falsetick", "excess", "outlyer", "candidate", "backup", "sys.peer", "pps.peer"}
func ReadPeerStatus(b uint8) PeerStatus {
	return PeerStatus{
		Configured:  b&0x10 != 0,
		AuthOK:      b&0x8 != 0,
		AuthEnabled: b&0x4 != 0,
		Reachable:   b&0x2 != 0,
		Broadcast:   b&0x1 != 0,
	}
}
type PeerStatusWord struct {
	PeerStatus       PeerStatus
	PeerSelection    uint8
	PeerEventCounter uint8
	PeerEventCode    uint8
}
func (psw *PeerStatusWord) Word() uint16 {
	var out uint16
	psByte := uint16(psw.PeerStatus.Byte())
	out |= psByte << 11
	out |= uint16(psw.PeerSelection) << 8
	out |= uint16(psw.PeerEventCounter) << 4
	out |= uint16(psw.PeerEventCode)
	return out
}
func ReadPeerStatusWord(b uint16) *PeerStatusWord {
	status := uint8((b & 0xf800) >> 11)  
	return &PeerStatusWord{
		PeerStatus:       ReadPeerStatus(status),
		PeerSelection:    uint8((b & 0x700) >> 8),  
		PeerEventCounter: uint8((b & 0xf0) >> 4),   
		PeerEventCode:    uint8((b & 0xf)),         
	}
}
func MakeVnMode(version int, mode int) uint8 {
	var out uint8
	out |= uint8(version) << 3
	out |= uint8(mode)
	return out
}