Skip to content
This repository was archived by the owner on Sep 3, 2020. It is now read-only.

Commit b64203b

Browse files
Merge pull request #42 from TheThingsNetwork/develop
Packet forwarder release v2.0.2
2 parents 2ac53a3 + 1074390 commit b64203b

12 files changed

Lines changed: 290 additions & 174 deletions

File tree

.make/halv1/build.make

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ else
99
endif
1010

1111
# Build the HAL
12-
hal.build: lora_gateway/libloragw/libloragw.a
12+
hal.build: lora_gateway/libloragw/inc/$(PLATFORM).h lora_gateway/libloragw/libloragw.a
1313

1414
### library.cfg configuration file processing
1515

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ The configuration file generated by `packet-forwarder configure` is stored at `$
5151
* `--verbose` or `-v`: Show debugging information (optional)
5252
* `--downlink-send-margin`: Change downlink send margin, in milliseconds (optional ; [see documentation](docs/IMPLEMENTATION/DOWNLINKS.md))
5353
* `--gps-path`: Set GPS path to enable GPS support (optional ; default: empty)
54+
* `--ignore-crc`: Ignore CRC check, and send uplink packets upstream even if they are CRC-invalid.
5455

5556
## <a name="contribute"></a>Contributing
5657

cmd/start.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,11 @@ var startCmd = &cobra.Command{
5959
}
6060
}
6161

62+
ignoreCRC := config.GetBool("ignore-crc")
63+
if ignoreCRC {
64+
ctx.Warn("CRC check disabled, packets with invalid CRC will be sent upstream")
65+
}
66+
6267
ttnConfig := &pktfwd.TTNConfig{
6368
ID: config.GetString("id"),
6469
Key: config.GetString("key"),
@@ -67,6 +72,7 @@ var startCmd = &cobra.Command{
6772
Router: config.GetString("router"),
6873
Version: config.GetString("version"),
6974
DownlinksSendMargin: time.Duration(config.GetInt64("downlink-send-margin")) * time.Millisecond,
75+
IgnoreCRC: ignoreCRC,
7076
}
7177

7278
conf, err := pktfwd.FetchConfig(ctx, ttnConfig)
@@ -92,6 +98,7 @@ func init() {
9298
startCmd.PersistentFlags().String("run-trace", "", "File to which write the runtime trace of the packet forwarder. Can later be read with `go tool trace <trace_file>`.")
9399
startCmd.PersistentFlags().Int("reset-pin", 0, "GPIO pin associated to the reset pin of the board")
94100
startCmd.PersistentFlags().BoolP("verbose", "v", false, "Show debug logs")
101+
startCmd.PersistentFlags().Bool("ignore-crc", false, "Send packets upstream even if CRC validation is incorrect")
95102

96103
viper.BindPFlags(startCmd.PersistentFlags())
97104

docs/INSTALL_INSTRUCTIONS/IMST_RPI.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ To follow this manual, you must have a Raspberry Pi with an IMST ic880a board, c
44

55
## Download and run
66

7-
1. Download the [Raspberry Pi + IMST build](https://ttnreleases.blob.core.windows.net/packet_forwarder/master/imst-rpi-pktfwd.zip) of the packet forwarder.
7+
1. Download the [Raspberry Pi + IMST build](https://ttnreleases.blob.core.windows.net/packet-forwarder/master/imst-rpi-pktfwd.tar.gz) of the packet forwarder.
88

99
2. Configure the packet forwarder:
1010

docs/INSTALL_INSTRUCTIONS/KERLINK.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ Before installing the TTN Packet Forwarder, we recommend **updating the Station
1313

1414
*Note: Before installing the new packet forwarder, make sure you removed any other packet forwarder installed on your Kerlink IoT Station. If you don't have any important files stored on the disk, the safest way to make sure of that is to update the Station to the latest firmware available, which will reset the file system in the process.*
1515

16-
1. Download the [Kerlink build](https://ttnreleases.blob.core.windows.net/packet_forwarder/master/kerlink-iot-station-pktfwd.zip) of the packet forwarder.
16+
1. Download the [Kerlink build](https://ttnreleases.blob.core.windows.net/packet-forwarder/master/kerlink-iot-station-pktfwd.tar.gz) of the packet forwarder.
1717

1818
2. In the folder, you will find several files: a `create-package.sh` script and a binary file, that we will call `packet-forwarder`.
1919

docs/INSTALL_INSTRUCTIONS/MULTITECH.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
*Note: Before installing the new packet forwarder, make sure you removed any other packet forwarder installed on your Multitech Conduit.*
88

9-
1. Download the [Multitech Conduit package](https://ttnreleases.blob.core.windows.net/packet_forwarder/master/multitech-conduit-pktfwd.tar.gz) of the packet forwarder.
9+
1. Download the [Multitech Conduit package](https://ttnreleases.blob.core.windows.net/packet-forwarder/master/multitech-conduit-pktfwd.tar.gz) of the packet forwarder.
1010

1111
2. In the archive, you will find an `create-package.sh` file, a `multitech-installer.sh`, as well as the executable binary. Execute the `create-package.sh` file, with the binary as a first argument:
1212

pktfwd/manager.go

Lines changed: 137 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ type Manager struct {
3535
bootTimeSetters multipleBootTimeSetter
3636
foundBootTime bool
3737
isGPS bool
38+
ignoreCRC bool
3839
downlinksSendMargin time.Duration
3940
}
4041

@@ -55,6 +56,7 @@ func NewManager(ctx log.Interface, conf util.Config, netClient NetworkClient, gp
5556
// At the beginning, until we get our first uplinks, we keep a high polling rate to the concentrator
5657
uplinkPollingRate: initUplinkPollingRate,
5758
downlinksSendMargin: runConfig.DownlinksSendMargin,
59+
ignoreCRC: runConfig.IgnoreCRC,
5860
}
5961
}
6062

@@ -77,13 +79,14 @@ func (m *Manager) run() error {
7779
func (m *Manager) handler(runStart time.Time) (err error) {
7880
// First, we'll handle the case when the user wants to end the program
7981
c := make(chan os.Signal)
82+
defer close(c)
8083
signal.Notify(c, os.Interrupt, os.Kill, syscall.SIGABRT)
8184

8285
// We'll start the routines, and attach them a context
8386
bgCtx, cancel := context.WithCancel(context.Background())
8487
defer cancel()
85-
var routinesErr = make(chan error)
86-
go m.startRoutines(bgCtx, routinesErr, runStart)
88+
routinesErr := m.startRoutines(bgCtx, runStart)
89+
defer close(routinesErr)
8790

8891
// Finally, we'll listen to the different issues
8992
select {
@@ -126,67 +129,74 @@ func (m *Manager) setBootTime(bootTime time.Time) {
126129
m.uplinkPollingRate = stableUplinkPollingRate
127130
}
128131

129-
func (m *Manager) uplinkRoutine(bgCtx context.Context, errc chan error, runStart time.Time) {
130-
m.ctx.Info("Waiting for uplink packets")
131-
for {
132-
packets, err := wrapper.Receive()
133-
if err != nil {
134-
errc <- errors.Wrap(err, "Uplink packets retrieval error")
135-
return
136-
}
137-
if len(packets) == 0 { // Empty payload => we sleep, then reiterate.
138-
time.Sleep(m.uplinkPollingRate)
139-
continue
140-
}
141-
142-
m.ctx.WithField("NbPackets", len(packets)).Info("Received uplink packets")
143-
if !m.foundBootTime {
144-
// First packets received => find concentrator boot time
145-
err = m.findConcentratorBootTime(packets, runStart)
132+
func (m *Manager) uplinkRoutine(bgCtx context.Context, runStart time.Time) chan error {
133+
errC := make(chan error)
134+
go func() {
135+
m.ctx.Info("Waiting for uplink packets")
136+
defer close(errC)
137+
for {
138+
packets, err := wrapper.Receive()
146139
if err != nil {
147-
m.ctx.WithError(err).Warn("Error when computing concentrator boot time - using packet forwarder run start time")
148-
m.setBootTime(runStart)
140+
errC <- errors.Wrap(err, "Uplink packets retrieval error")
141+
return
142+
}
143+
if len(packets) == 0 { // Empty payload => we sleep, then reiterate.
144+
time.Sleep(m.uplinkPollingRate)
145+
continue
149146
}
150-
}
151147

152-
validPackets, err := wrapUplinkPayload(packets, m.netClient.GatewayID())
153-
if err != nil {
154-
continue
155-
}
156-
m.statusMgr.HandledRXBatch(len(validPackets), len(packets))
157-
if len(validPackets) == 0 {
158-
m.ctx.Warn("Packets received, but with invalid CRC - ignoring")
159-
time.Sleep(m.uplinkPollingRate)
160-
continue
161-
}
148+
m.ctx.WithField("NbPackets", len(packets)).Info("Received uplink packets")
149+
if !m.foundBootTime {
150+
// First packets received => find concentrator boot time
151+
err = m.findConcentratorBootTime(packets, runStart)
152+
if err != nil {
153+
m.ctx.WithError(err).Warn("Error when computing concentrator boot time - using packet forwarder run start time")
154+
m.setBootTime(runStart)
155+
}
156+
}
157+
158+
validPackets := wrapUplinkPayload(m.ctx, packets, m.ignoreCRC, m.netClient.GatewayID())
159+
m.statusMgr.HandledRXBatch(len(validPackets), len(packets))
160+
if len(validPackets) == 0 {
161+
// Packets received, but with invalid CRC - ignoring
162+
time.Sleep(m.uplinkPollingRate)
163+
continue
164+
}
162165

163-
m.ctx.WithField("NbValidPackets", len(validPackets)).Info("Received valid packets - sending them to the back-end")
164-
m.netClient.SendUplinks(validPackets)
166+
m.ctx.WithField("NbValidPackets", len(validPackets)).Info("Sending valid uplink packets")
167+
m.netClient.SendUplinks(validPackets)
165168

166-
select {
167-
case <-bgCtx.Done():
168-
errc <- nil
169-
return
170-
default:
171-
continue
169+
select {
170+
case <-bgCtx.Done():
171+
errC <- nil
172+
return
173+
default:
174+
continue
175+
}
172176
}
173-
}
177+
}()
178+
return errC
174179
}
175180

176-
func (m *Manager) gpsRoutine(bgCtx context.Context, errC chan error) {
177-
m.ctx.Info("Starting GPS update routine")
178-
for {
179-
select {
180-
case <-bgCtx.Done():
181-
return
182-
default:
183-
// The GPS time reference and coordinates are updated at `gpsUpdateRate`
184-
err := wrapper.UpdateGPSData(m.ctx)
185-
if err != nil {
186-
errC <- errors.Wrap(err, "GPS update error")
181+
func (m *Manager) gpsRoutine(bgCtx context.Context) chan error {
182+
errC := make(chan error)
183+
go func() {
184+
m.ctx.Info("Starting GPS update routine")
185+
defer close(errC)
186+
for {
187+
select {
188+
case <-bgCtx.Done():
189+
return
190+
default:
191+
// The GPS time reference and coordinates are updated at `gpsUpdateRate`
192+
err := wrapper.UpdateGPSData(m.ctx)
193+
if err != nil {
194+
errC <- errors.Wrap(err, "GPS update error")
195+
}
187196
}
188197
}
189-
}
198+
}()
199+
return errC
190200
}
191201

192202
func (m *Manager) downlinkRoutine(bgCtx context.Context) {
@@ -206,57 +216,86 @@ func (m *Manager) downlinkRoutine(bgCtx context.Context) {
206216
}
207217
}
208218

209-
func (m *Manager) statusRoutine(bgCtx context.Context, errC chan error) {
210-
for {
211-
select {
212-
case <-time.After(statusRoutineSleepRate):
213-
rtt, err := m.netClient.Ping()
214-
if err != nil {
215-
errC <- errors.Wrap(err, "Network server health check error")
216-
continue
217-
}
218-
219-
status, err := m.statusMgr.GenerateStatus(rtt)
220-
if err != nil {
221-
errC <- errors.Wrap(err, "Gateway status computation error")
219+
func (m *Manager) statusRoutine(bgCtx context.Context) chan error {
220+
errC := make(chan error)
221+
go func() {
222+
defer close(errC)
223+
for {
224+
select {
225+
case <-time.After(statusRoutineSleepRate):
226+
rtt, err := m.netClient.Ping()
227+
m.ctx.WithField("RTT", rtt).Debug("Ping to the router successful")
228+
if err != nil {
229+
errC <- errors.Wrap(err, "Network server health check error")
230+
return
231+
}
232+
233+
status, err := m.statusMgr.GenerateStatus(rtt)
234+
if err != nil {
235+
errC <- errors.Wrap(err, "Gateway status computation error")
236+
return
237+
}
238+
239+
err = m.netClient.SendStatus(*status)
240+
if err != nil {
241+
errC <- errors.Wrap(err, "Gateway status transmission error")
242+
return
243+
}
244+
case <-bgCtx.Done():
222245
return
223246
}
247+
}
248+
}()
249+
return errC
250+
}
224251

225-
err = m.netClient.SendStatus(*status)
226-
if err != nil {
227-
errC <- errors.Wrap(err, "Gateway status transmission error")
228-
return
229-
}
230-
case <-bgCtx.Done():
231-
return
252+
func (m *Manager) networkRoutine(bgCtx context.Context) chan error {
253+
errC := make(chan error)
254+
go func() {
255+
defer close(errC)
256+
if err := m.netClient.RefreshRoutine(bgCtx); err != nil {
257+
errC <- errors.Wrap(err, "Couldn't refresh account server token")
232258
}
233-
}
259+
}()
260+
return errC
234261
}
235262

236-
func (m *Manager) startRoutines(bgCtx context.Context, err chan error, runTime time.Time) {
237-
var errC = make(chan error)
238-
upCtx, upCancel := context.WithCancel(bgCtx)
239-
downCtx, downCancel := context.WithCancel(bgCtx)
240-
statsCtx, statsCancel := context.WithCancel(bgCtx)
241-
gpsCtx, gpsCancel := context.WithCancel(bgCtx)
242-
243-
go m.uplinkRoutine(upCtx, errC, runTime)
244-
go m.downlinkRoutine(downCtx)
245-
go m.statusRoutine(statsCtx, errC)
246-
if m.isGPS {
247-
go m.gpsRoutine(gpsCtx, errC)
248-
}
249-
select {
250-
case routineErr := <-errC:
251-
err <- routineErr
252-
close(errC)
253-
case <-bgCtx.Done():
254-
err <- nil
255-
}
256-
upCancel()
257-
gpsCancel()
258-
downCancel()
259-
statsCancel()
263+
func (m *Manager) startRoutines(bgCtx context.Context, runTime time.Time) chan error {
264+
err := make(chan error)
265+
go func() {
266+
upCtx, upCancel := context.WithCancel(bgCtx)
267+
downCtx, downCancel := context.WithCancel(bgCtx)
268+
statusCtx, statusCancel := context.WithCancel(bgCtx)
269+
gpsCtx, gpsCancel := context.WithCancel(bgCtx)
270+
networkCtx, networkCancel := context.WithCancel(bgCtx)
271+
272+
go m.downlinkRoutine(downCtx)
273+
uplinkErrors := m.uplinkRoutine(upCtx, runTime)
274+
statusErrors := m.statusRoutine(statusCtx)
275+
networkErrors := m.networkRoutine(networkCtx)
276+
var gpsErrors chan error
277+
if m.isGPS {
278+
gpsErrors = m.gpsRoutine(gpsCtx)
279+
}
280+
select {
281+
case uplinkError := <-uplinkErrors:
282+
err <- errors.Wrap(uplinkError, "Uplink routine error")
283+
case statusError := <-statusErrors:
284+
err <- errors.Wrap(statusError, "Status routine error")
285+
case networkError := <-networkErrors:
286+
err <- errors.Wrap(networkError, "Network routine error")
287+
case gpsError := <-gpsErrors:
288+
err <- errors.Wrap(gpsError, "GPS routine error")
289+
case <-bgCtx.Done():
290+
err <- nil
291+
}
292+
upCancel()
293+
gpsCancel()
294+
downCancel()
295+
statusCancel()
296+
networkCancel()
297+
}()
298+
return err
260299
}
261300

262301
func (m *Manager) shutdown() error {

0 commit comments

Comments
 (0)