func DoForwardData(appDlCh, appUlCh, crossCh chan []byte, device string) { siface := &serial.Config{Name: device, Baud: 57600} serReader, err := serial.OpenPort(siface) if err != nil { fmt.Println("error opening serial interface:", err.Error()) os.Exit(1) } defer serReader.Close() ser := SerialReader{serReader} serCh := devreader.MakeChannel(ser) LOOP: for { select { case payload := <-serCh: crossCh <- payload fmt.Printf("read nfc data\n- ascii: %s\n- hex: %x\n", string(payload), string(payload)) case _, more := <-appDlCh: if !more { close(appUlCh) break LOOP } } } fmt.Println("stopped forwarding nfc data") }
// args: // - addr: multicast group/address to listen to // - port: port number; addr:port builds the mcast socket // - iface: name of network interface to listen to // - d_dl_sock: // - stopch: func ListenUDPMcast(addr, port, iface string, d_dl_sock *zmq.Socket, stopch chan bool) { eth, err := net.InterfaceByName(iface) if err != nil { fmt.Println("Error interface:", err.Error()) os.Exit(1) } group := net.ParseIP(addr) if group == nil { fmt.Println("Error: invalid group address:", addr) os.Exit(1) } // listen to all udp packets on mcast port c, err := net.ListenPacket("udp4", "0.0.0.0:"+port) if err != nil { fmt.Println("Error listening for mcast:", err.Error()) os.Exit(1) } // close the listener when the application closes defer c.Close() // join mcast group p := ipv4.NewPacketConn(c) if err := p.JoinGroup(eth, &net.UDPAddr{IP: group}); err != nil { fmt.Println("Error joining:", err.Error()) os.Exit(1) } fmt.Println("Listening on " + addr + ":" + port) // enable transmissons of control message if err := p.SetControlMessage(ipv4.FlagDst, true); err != nil { fmt.Println("Error control message", err.Error()) } c1 := devreader.MakeChannel(UMSocket{p, group}) LOOP: for { select { case v1 := <-c1: fmt.Println("received UDP multicast") // forward to coord node d_dl_sock.Send(string(v1), 0) case <-stopch: break LOOP } } }
func ListenCoordNode(d_ul_sock *zmq.Socket, u_conn *net.UDPConn, stopch chan bool) { fmt.Println("Listening to coordinator node uplink") cn_ch := devreader.MakeChannel(CNSocket{d_ul_sock}) LOOP: for { select { case cn_buf := <-cn_ch: fmt.Println("received from coordinator node") u_conn.Write([]byte(cn_buf)) fmt.Println("sent coord node response over UDP") case <-stopch: break LOOP } } }
// main goroutine loop func DoSerialDataRequest(dlCh, ulCh chan []byte, device string) { // trailing LQI, ED, RX status, RX slot; TODO, all zeros for now // I have to add one 0x00 to remove server error!! why!! var trail = []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00} c := &serial.Config{Name: device, Baud: 9600} s, err := serial.OpenPort(c) if err != nil { fmt.Println("error opening serial interface:", err.Error()) os.Exit(1) } defer s.Close() serial := SerialReader{s} rxch := devreader.MakeChannel(serial) // automatic serial sender just for testing stopch := make(chan bool) go testWriteSerial(stopch) // handshake hello := Message{1, []byte{}} msgHello := hello.GenerateMessage() s.Write(msgHello) fmt.Println("sent hello:", hex.EncodeToString(msgHello), "waiting for ack...") buf, err := receiveWithTimeout(rxch, 10) fmt.Println("received hello ack:", hex.EncodeToString(buf)) if err != nil { fmt.Println("error reading serial handshake:", err.Error()) os.Exit(1) } rcvd := Message{} rcvd.ParseBuffer(buf) if rcvd.mtype != 2 { fmt.Println("invalid hello ack") os.Exit(1) } LOOP: for { select { case buf, more := <-dlCh: if !more { fmt.Println("stopping serial worker...") close(ulCh) break LOOP } wdcReq := WDC_REQ{} wdcReq.ParseWDCReq(buf) if wdcReq.MSDULEN != len(wdcReq.MSDU) { fmt.Println("MSDU length mismatch, on frame:", wdcReq.MSDULEN, ", received:", len(wdcReq.MSDU)) continue } MSDU := make([]byte, len(wdcReq.MSDU)) copy(MSDU, wdcReq.MSDU) // if I don't do this the MSDU gets corrupted!?!?!? MPDU := MakeMPDU([]byte{0x01, 0x98}, wdcReq.DSTPAN, wdcReq.DSTADDR, []byte{0xff, 0xff}, []byte{0xff, 0xff}, MSDU) app := Message{mtype: 3, data: MPDU} msgApp := app.GenerateMessage() s.Write(msgApp) fmt.Println("written to serial:", hex.EncodeToString(msgApp)) case buf := <-rxch: if len(buf) == 0 { continue } rcvd := Message{} err := rcvd.ParseBuffer(buf) if err != nil { fmt.Println("error parsing buffer:", err.Error(), hex.EncodeToString(buf)) continue } switch rcvd.mtype { case 1, 2: continue case 3: ind := MakeWDCInd(rcvd.data, trail) // rcvd.data must be an MPDU ulCh <- ind case 4: fmt.Println("received debug message:", hex.EncodeToString(rcvd.data)) } } } fmt.Println("serial worker stopped") }
// FOR LOOPBACK TESTING ONLY, simply exits when device not available // TODO: hard code path func testWriteSerial(stopch chan bool) { c := &serial.Config{Name: "/dev/pts/4", Baud: 9600} s, err := serial.OpenPort(c) if err != nil { fmt.Println("error opening loopback test serial interface:", err.Error()) close(stopch) return } defer s.Close() serial := SerialReader{s} testrxch := devreader.MakeChannel(serial) LOOP: for { select { case <-stopch: break LOOP case buf := <-testrxch: if len(buf) == 0 { continue } rcvd := Message{} err := rcvd.ParseBuffer(buf) if err != nil { fmt.Println("error parsing buffer:", err.Error()) debug := Message{4, buf} msgDebug := debug.GenerateMessage() s.Write(msgDebug) continue } switch rcvd.mtype { case 1: helloAck := Message{2, []byte{}} msgHelloAck := helloAck.GenerateMessage() s.Write(msgHelloAck) test := Message{4, []byte{0xde, 0xad, 0xca, 0xfe}} msgTest := test.GenerateMessage() s.Write(msgTest) case 2: continue case 3: fmt.Println("received application message:", hex.EncodeToString(rcvd.data)) case 4: fmt.Println("received debug message:", hex.EncodeToString(rcvd.data)) } case <-time.After(30 * time.Second): msg := Message{mtype: 4, data: []byte{0xde, 0xad, 0xbe, 0xef}} buf := msg.GenerateMessage() s.Write(buf) fmt.Println("test: written to serial:", hex.EncodeToString(buf)) } } fmt.Println("testWriteSerial stopped") }
func main() { nodeSerial := flag.String("nodeSerial", "", "serial device to connect to node") wdcSerial := flag.String("wdcSerial", "", "serial device to connect to wdc") fwdSerial := flag.String("fwdSerial", "", "serial device to read and forward data from a real node") // TODO: enable list of serial interfaces nJamming := flag.Int("nJamming", 0, "number of sensors sending jamming data") nSensors := flag.Int("nSensors", 0, "number of sensors sending arbitrary data") secure := flag.Bool("sec", true, "apply security processing") flag.Parse() // check serial devices if *wdcSerial == "" { fmt.Println("serial connection to wdc is not provided") os.Exit(1) } // register interrupt signal intrCh := make(chan os.Signal) signal.Notify(intrCh, os.Interrupt) // register total nodes and corresponding handler goroutines mapNodes := make(map[int]node) for i := 0; i < *nJamming; i++ { mapNodes[i] = node{app.DoSendJamming, ""} } for i := *nJamming; i < *nJamming+*nSensors; i++ { mapNodes[i] = node{app.DoSendData, ""} } if *fwdSerial != "" { mapNodes[*nJamming+*nSensors] = node{app.DoForwardData, *fwdSerial} } // configure serial device connecting to wdc siface := &serial.Config{Name: *wdcSerial, Baud: 9600} serReader, err := serial.OpenPort(siface) if err != nil { fmt.Println("error opening serial interface:", err.Error()) os.Exit(1) } defer serReader.Close() ser := SerialReader{serReader} wdcCh := devreader.MakeChannel(ser) for addr, curnode := range mapNodes { // if nodeSerial is used, we just need one passthrough goroutine if *nodeSerial != "" { dlCh := make(chan []byte) ulCh := make(chan []byte) go worker.DoSerialDataRequest(dlCh, ulCh, *nodeSerial) break } // otherwise, start one goroutine per node go func(addr int, curnode node) { nodeAddr := make([]byte, 2) binary.LittleEndian.PutUint16(nodeAddr, uint16(addr)) // channel for receiving wdc message nodeWdcCh := make(chan []byte) nodeWdcChannels = append(nodeWdcChannels, nodeWdcCh) // channels for node's processing goroutine dlCh := make(chan []byte) ulCh := make(chan []byte) chPool = append(chPool, ulCh) // channels for node's application goroutine appDlCh := make(chan []byte) appUlCh := make(chan []byte) // channel for sharing data between worker and app crossCh := make(chan []byte) go curnode.appFunction(appDlCh, appUlCh, crossCh, curnode.device) go worker.DoDataRequest(nodeAddr, dlCh, ulCh, appDlCh, appUlCh, crossCh, *secure) LOOP: for { select { case wdcReq, more := <-nodeWdcCh: if !more { close(dlCh) break LOOP } reqmsg := worker.WDC_REQ{} reqmsg.ParseWDCReq([]byte(wdcReq)) if bytes.Equal(reqmsg.DSTADDR, nodeAddr) || bytes.Equal(reqmsg.DSTADDR, []byte{0xff, 0xff}) { // only process message that is sent to us or broadcast dlCh <- []byte(wdcReq) } case nodeInd := <-ulCh: mutex.Lock() serReader.Write(nodeInd) // ignore error on wdc serial write mutex.Unlock() fmt.Println("sent node uplink message") } } fmt.Println("node stopped") }(addr, curnode) } MAINLOOP: for { select { case wdcReq := <-wdcCh: go func() { // process wdc message in a separate goroutine wdcRes := worker.ProcessMessage(wdcReq) if wdcRes != nil { mutex.Lock() serReader.Write(wdcRes) // ignore error on wdc serial write mutex.Unlock() fmt.Println("sent answer to WDC request") } }() // if MAC_DATA_REQUEST, pass it to node goroutines if len(wdcReq) != 0 && wdcReq[1] == 0x17 { for _, ch := range nodeWdcChannels { ch <- wdcReq } } case <-intrCh: for idx := range nodeWdcChannels { close(nodeWdcChannels[idx]) <-chPool[idx] } break MAINLOOP } } fmt.Println("program stopped") }